This repository is a RESTful API inspired by a system that allows you to upload images and comment on them. There's a mixture of application being built together in one system architecture.
- .NET 5 - Containerized server application
- NodeJS - Lambda function
- MySQL - RDBMS
- Large image size up to 100MB upload
- Image file conversion
- Low latency query
- User submit the photo upload to our API.
- API received upload request and push image to S3-raw.
- Once push completed, API make a request to spin off a lambda function to perform image format conversion.
- Once conversion completed, lambda function feedback with response to API and update the database with new record.
- Upon successful update, API respond back to user saying your image has been successfully uploaded
Simplified flow:
User -> API (upload) -> Lambda (formatting) -> API (update) -> User
This approach allowed user to have immediate feedback on their photo upload to the server. However, user may feel impatient if their internet connectivity is slow because they have to wait util the whole process to be completed.
- User submit the photo upload to our API.
- Upon submission, the user will directly received a non-blocking response of the upload. User may continue to browse or do other stuff with the client app.
- API received request then push image to S3-raw.
- S3-raw will trigger a lambda to perform file conversion.
- Upon successful of file conversion, lambda send sqs msg to a msg queue that subcribed by our API service
- API service notified by polling the subscribed msg queue and send notification back to the user.
- User notified with a notification saying your image has been succesfully uploaded.
Simplified flow:
User -> API (upload) (decoupled)-> Lambda (formatting) -> API (update) -> User
This approach may have different user experience as in user cannot perform cancellation in the middle of the process. However, this is able to resolve problems that poor internet connection users are facing. Beside, this design enable our backend system process to be decoupled and offload to more different resources for faster processing.
This approach can be used for both sync and async behaviour.- The backbone of this design is based on a horizontal scaling of monolith application behind a load balancer.
- The applicaton is still monolith because all the APIs are packed in a same service and having concurrent transaction with the same database.
- This apporach is the most conventional approach for most enterprises because it fulfilled the ACID compliants where data consistency among services and database are persisted.
- This approach is much more easier and straightforward when comes in handling inconsistency traffic load. This is because Lambda function itself is a stateless isolated instance that perform small task very fast and efficient without intensive supervision.
- The API Gateway can be seen as a trigger for respective lambda functions and also act as a load balancer for the http request as well.
- However, there are limitations and trade-offs with this approach:
- Usually database has its preset on the number of concurrent connection pool. This will be a problem if there is a high number of concurrent connection coming from the lambdas and the database will become exhausted as more connection requests are formed.
- Lambda has short lifetime of 15mins and only accept small payload size. Its not recommended to handle certain blocking processing that is taking too long and will eventually causes a timeout such as the huge file upload for user with slow internet connectivity.
- We can observe that the services are fully isolated as in its individual micrservices.
- Databases are splitted and all transactions are performed seperatedly by event.
- Each services can be a subscriber / publisher.
- Possible problems:
- Data consistency may not applicable to ACID compliant (Eventual consistency)
- Duplicated and missing messages
Components:
- Containerized app services
- Message queues / brokers / Dead-letter queues
- Redis & RDBMS
The design is similar to the event driven approach. However, instead of seperating the database, we'll still prefer to stick with one centralised database. This approach may not be good for high frequency writes but there's a way to handle it using redis.
Redis is a key-value database where it perform on top of high speed volative memory like RAM.
- It able to perform very fast write and read, however it has its limitation in its persistence storage. So, we'll be using it as a layer of queue when handling high load of adding comment requests then we make a period insert into our sql database.
- Although we may have a slight delay in the insertion, but its still minimal as compared with direct insertion of any direct api request.
- User upload their image through REST protocol using multi-part upload to our containerized services (resolve large file timeout)
- Once uploaded, containerized services trigger lambda using API-gateway to perform image format conversion (offload to lambda and better network connectivity within the same cloud env)
- Lambda will response back to service client either fail or pass and perform database update together with sending back responses to client in real time.
- Checkout the repository and build the .Net 5 application using visual studio
- Do remember to append your AWS credential in App.config file in the root directory of the workspace
- Your service should be started immediately.
Local host examples:
- Image Upload: (POST)
http://localhost:8080/image/upload?file
Param | Description |
---|---|
file |
The file to upload |
- Add Comment: (POST)
- Request body: {image_id,comment}
http://localhost:8080/comment
Attribute | Description |
---|---|
image_id |
The id of the image |
comment |
The content of the comment |
- Get all Posts : (GET)
- (Optional) Cursor Pagination - Param (limit,nextCursor)
Endpoint | Description |
---|---|
http://localhost:8080/post |
Initial request. Return all the posts |
http://localhost:8080/post/?limit=5&nextCursor=10 |
Return only 5 posts starting from the 10th |
http://localhost:8080/post/?limit=5 |
Return only 5 posts starting from the beginning |