Gắn thêm AWS Cloudfront vào hệ thống Serverless API: API Gateway - Lambda (Nodejs) - MongoDB Atlas
Lại một cuối tuần nữa đến, nhớ mới hồi nào còn event canh giựt cô hồn thấm thỏm lo sợ cô hồn mạng tràn vô manh động quá mà không có kịp scale thì server ngủm củ tỏi mà giờ đã gần cuối tháng, nằm gác cẳng lên kèo đợi bắc ấm nước pha miếng trà ăn bánh trung thu rồi.
Nghĩ ngồi không hoài làm thì sao để cuối năm có chuyện mà đi làm CHE được nên Chiên Da ráng bày thêm trò, trước là để đảm bảo an ninh hệ thống, tăng cường khả năng hiện đại hóa công nghệ hóa. Sau là để nhân dịp cuối năm sắp đến có nhiều chuyện mà tâm sự cùng lãnh đạo.
Mặc dù đại lễ của Tập đoàn Toàn đập đá đã diễn ra thành công tốt đẹp với niềm hoan hỉ cao độ từ các lãnh đạo cấp cao và may mắn thay hệ thống Serverless API mà Chiên Da đã thiết kế lần trước chưa gặp vấn đề nào nghiêm trọng. Nhưng với tinh thần quán triệt có mần mới có ăn nên Chiên Da tiếp tục tư vấn cải tiến giải pháp cho ngài Chủ tịch.
Nhưng mà hổng lẽ dễ thế thì nói làm gì nữa, review bảo với sếp sau khi đắn đo trong hơn một tuần lễ em quyết định enable cái checkbox thì khó lòng mà đòi tăng tiền công làm mướn được. Thế nên, Chiên Da quyết định sẽ gắn thêm AWS Cloudfront (CF) ở trước API Gateway ngoài việc hỗ trợ cache với nhiều tính năng hơn (có thể kể đến như là global distribution, content compression, customization cách cache dựa trên request attributes) thì CF còn có một lợi ích lớn nữa là sinh thêm việc giải quyết vấn đề về UPDATE, giúp tạo công ăn việc làm cho các bạn đồng nghiệp, song song đó tất nhiên là thêm vô mấy cục nữa trên cái diagram vốn đã rối rắm lần trước nay lại càng ngầu hơn nữa. Nếu cố gắng làm cho càng ít người hiểu được bản chất thật sự thì thật tuyệt vời vì dù sao điều đó cũng giúp đảm bảo an toàn nghề nghiệp trong bối cảnh nhà nhà thi đua layoffs như hiện nay - Chiên Da thầm nghĩ và cười nhếch mép một nụ cười tử tế.
AWS Cloudfront
CloudFront > Distributions > Create distribution, phần Origin domain chọn API Gateway, mặc định Protocol HTTPS only sẽ được chọn.
Default cache behavior: có một số tùy chọn cần quan tâm
- Allowed HTTP methods: chọn GET, HEAD, OPTIONS vì API chúng ta đã thiết kế Enable CORS nên sẽ cần cho phép method OPTIONS thực hiện preflight. Và với method OPTIONS chúng ta không cần phải cache vì dung lượng response rất nhỏ và cũng cần thiết cho việc thay đổi source code mà không phải tốn thời gian thực hiện invidation
Cache key and origin requests: chọn Cache policy and origin request policy (recommended). Do mặc định Recommended for API GTW là CachingDisabled, tuy nhiên trong nghiệp vụ thực tế mà em gái BA nóng bỏng đã gửi Chiên Da thì có đoạn “để gọi lấy thông tin là chính, việc cập nhật thông tin cũng cần nhưng không cần tức thì, chủ yếu dùng cho việc thống kê vào cuối ngày”, do đó việc lấy thông tin cần phải được xử lý nhanh nhất bằng cách cache, còn đoạn cập nhật thì chỉ chiếm phần nhỏ. Vì lý do đó mà chúng ta cần phải tự tạo một Cache policy riêng để phục vụ nhu cầu đặc thù: chọn Create cache policy. Chọn All query string except và điền query string không muốn cache trong mục Block tại khu vực Cache key settings.
Nếu cần thêm giải pháp Web Application Firewall (WAF) thì bạn hãy chọn Enable security protections, giá có thể tính luôn ngay tại đây rất tiện.
Với mỗi vùng địa lý thì sẽ có giá khác nhau (https://aws.amazon.com/cloudfront/pricing/, CF cũng là một trong những dịch vụ có chính sách Free Tier). Do đó, nếu chỉ phục vụ cho một vài khu vực nhất định nào đó thì bạn có thể chọn Price class phù hợp. Tất nhiên, nếu chặn hoàn toàn các traffic từ những vùng địa lý không hỗ trợ thì tốt còn đột nhiên vì vấn đề nào đó phát sinh nhiều request đột xuất từ những vùng này thì độ trễ sẽ rất cao.
Đoạn này hơi lằng nhằng, tuy nhiên do liên quan tới tiền bạc nên tui cũng ráng coi kỹ chút vì mấy cha sếp chỉ quan tâm bao nhiêu tiền. Tóm tắt như sau, nếu bạn chỉ phục vụ người dùng từ mấy khu vực châu Á như VN, Cam, Lào thì:
- Price Class All: đơn giản, trả phí cao hơn.
- Price Class 200: đây là lựa chọn phù hợp. Một số người dùng từ South America, Australia and New Zealand sẽ chấp nhận độ trễ cao.
- Price Class 100: độ trễ rất cao vì request sẽ được đưa đến edge locations gần nhất. Cụ thể là 2 khu vực North America, Europe and Israel
Ngoài ra còn có hình thức Savings Bundle bằng cách cam kết trả trước giúp giảm chi phí lên đến 30%.
Nếu bạn dự kiến sử dụng alias domain cùng với SSL riêng thì có thể cấu hình ở phần Alternate domain name (CNAME) - optional và Custom SSL certificate - optional (SSL phải được tạo trước trong AWS Certificate Manager).
Xử lý no-cache với một số endpoint
Có vẻ lúc nãy mình hơi phấn khích vì lý do nào đó nên đã chọn sai giải pháp, để cho CF xử lý các no-cache endpoint bằng custom policy query string khá phức tạp mà kết quả vẫn không đảm bảo, Chiên Da thầm nghĩ rồi sau đó xắn tay vào mở lại Lambda function.
Đơn giản chỉ cần bổ sung thêm đoạn "Cache-Control": "no-cache”
vào response header ở endpoint có nghiệp vụ no-cache là xong.
// Filename: app.mjs
'use strict';
console.log('init the function for CloudWatch event log');
/**
* Retrieves the device pinout based on the given event and context.
*
* @param {object} event - The event object containing the request information.
* @param {object} context - The context object containing the runtime information.
* @return {Promise<object>} The response object containing the pinout information.
*/
async function getDevicePinout(event, context) {
const allowOrigin = "Access-Control-Allow-Origin";
const allowHeaders = "Access-Control-Allow-Headers";
const allowMethods = "Access-Control-Allow-Methods";
const cacheControl = "Cache-Control";
const headers = {
[allowOrigin]: "*",
[allowHeaders]: "*",
[allowMethods]: "OPTIONS,POST,GET",
};
if (event.path.indexOf("/device-address") >= 0) {
headers[cacheControl] = "no-cache";
}
return {
statusCode: 200,
headers,
body: JSON.stringify({ path: event.path, result: new Date() }),
};
}
/**
* Handles the incoming request and returns the appropriate response based on the event and context.
*
* @param {Object} event - The event object containing information about the request.
* @param {Object} context - The context object containing information about the runtime environment.
* @return {Promise<Object>} The response object with a statusCode and body property.
*/
async function handleRequest(event, context) {
console.log('handleRequest', event)
//console.log('path', event.requestContext.http.path)
const { httpMethod, path } = event;
if ((httpMethod === "GET" || httpMethod === "OPTIONS") && path.indexOf("/device-detail") >= 0) {
return await getDevicePinout(event, context);
} else if (httpMethod === "POST" && path.indexOf("/device-detail") >=0) {
return await getDevicePinout(event, context);
} else if ((httpMethod === "GET" || httpMethod === "OPTIONS") && path.indexOf("/device-address") >= 0) {
// This method will get address of device and update the visit counter for summary
return await getDevicePinout(event, context);
} else {
return {
statusCode: 404,
body: "Not found",
};
}
}
/**
* Handles the incoming event and context, and returns the result of handleRequest.
*
* @param {Object} event - The event object.
* @param {Object} context - The context object.
* @return {Promise} A promise that resolves to the result of handleRequest.
*/
export const handler = async (event, context) => {
try {
return await handleRequest(event, context);
} catch (error) {
console.error("There was an error:", error);
return {
statusCode: 500,
body: JSON.stringify({
error: error.message,
message: 'fetch_error',
data: null,
}),
};
}
};
Như vậy, với endpoint /device-address thì header sẽ kèm theo no-cache giúp cho mỗi request có thể hit đến Lambda function để thực hiện các nghiệp vụ cần thiết. Chẳng hạn GET /device-address để lấy thông tin và cập nhật lại Database để ghi nhận thêm một lần query để tính lượt view.
Quả thật, không kẹt đầu dưới thì đầu trên sẽ thông suốt ngay tích tắt, chỉ tốn có chút ít thời gian ghé Trung Sơn mà khai mở tinh lực tức thì.
LTS: chúng tôi chưa có điều kiện kiểm chứng thực tế các thông tin về địa danh nổi tiếng này, xin quý độc giả cẩn trọng!
Kết
Trong việc xây dựng giải pháp, tâm phải tịnh!
Sau này trong lúc ngà ngà xỉn ở một cuộc liên hoan với chủ tịch, Chiên Da có thơ rằng:
"Cloudfront, như làn mây khẽ trôi, Như ánh sáng mờ ẩn trong vòi. Nơi đó, dịu dàng, mây bay đến, Truyền tải dữ liệu, vạn nơi tới.
Nghìn dòng thông tin, chảy êm đềm, Qua đám mây, vẫn giữ nguyên thêm. Từ server đến người dùng xa xôi, Liên kết tình yêu, tạo gắn kết thêm.
Cloudfront, như làn gió mát tràn, Mang theo sự tiện lợi dịch vụ ban. Cầu nối giữa khách hàng và dữ liệu, Kết nối vô tận, vạn vật gần."
Bên bờ mây. Thơ: ChatGPT. Dịch: Google Translate.
Anh Dũng
Sài Gòn một đêm cuối tháng 09/2023 trời vừa ngớt mưa.
All rights reserved