+6

[AWS Serverless] - Tạo một Serverless API trên AWS APIGW Và Lambda với ngôn ngữ Golang

Serverless là gì

Hồi mới đầu mình nghe về keyword "Serverless" mình cũng suy nghĩ sâu xa lắm. Nhưng khi tiếp xúc nhiều với các nền tảng Public Cloud như là AWS hoặc GCP thì mình mới tự rút gọn lại, để nhủ thầm với bản thân một câu khi gặp từ khóa này, và mình cũng nói với mấy bạn Fresher mà mình làm mentor trong công ty. Nhận định bên dưới là góc nhìn chủ quan của mình thôi.

"Cứ service nào mà lúc vào cài đặt mà không thấy hệ điều hành đâu(Windows Server hoặc Linux), nghĩa là nó nằm ẩn bên dưới nên mình không cần phải quản lý OS thì cứ cho nó là Serverless"

Vì mình sử dụng AWS trong bài viết hôm nay nên mình lấy dịch vụ của AWS làm ví dụ:

  • AWS API Gateway: làm nơi tiếp nhận các request đầu vào, xử lý việc xác thực và đảm nhiệm luôn việc chuyển đổi cấu trúc gói tin(request/response). Bạn thấy dịch vụ này dùng rất nhiều năng lượng tính toán để xử lý đầu vào của API nhưng khi cài đặt thì mình chỉ cần tập trung vào Logic mà mình muốn xử lý, không cần quan tâm đến cấu hình Server bên dưới Ram,CPU có chạy nổi không. Tất nhiên là AWS vẫn sẽ tính tiền mình rồi, cách tính thế nào bạn lên trang này để tìm hiểu thêm.
  • AWS Lambda: Đây sẽ là nhân vật chính của bài viết hôm nay. Dịch vụ này của AWS cho phép mình upload đoạn code hoặc gói build của mình lên và chạy trực tiếp, mình cũng không thấy được hệ điều hành bên dưới của nó là Windows Server hay Linux đâu cả. nên cứ xếp nó vô loại Serverless.

Có thể ở một số nhà cung cấp Public Cloud hoặc Private Cloud sẽ có một số dạng dịch vụ không áp dụng được công thức trên của mình, tuy nhiên đa số cách dịch vụ của các Public Cloud lớn mà mình từng sử dụng thì hầu hết áp dụng được.

Tại sao phải dùng Serverless, đang dùng như truyền thống tại sao phải đổi ?

Chắc hẳn các bạn đã dùng qua dịch vụ hosting cũng đã biết, khi mình thuê một VPS hoặc trên AWS có dịch vụ EC2 thì bảng giá sẽ tính theo thời gian sử dụng, đối với cấu hình càng cao thì mức chi phí trên giờ càng lớn. Đối với các doanh nghiệp lớn thì chi phí đầu tư ban đầu này cho các cụm máy chủ thì con số càng khủng khiếp.

Quay lại Serverless thì thường các dịch vụ này, lấy ví dụ như là AWS Lambda, nhân vật chính của chúng ta hôm nay. Thì chi phí sẽ được tính trên số lượng request và thời gian xử lý của mỗi request. Việc mình dựng lên nhưng số lượng request ít hoặc tạm thời chưa có người dùng thì chi phí hầu như là không phải trả gì cho AWS, trừ khi mình sử dụng gói Provisioned thì AWS sẽ cung cấp cho mình các Lambda có thời gian start nhanh hơn bình thường một chút. Tí xuống phần khuyết điểm của Serverless mình nói thêm.

Ngoài ra, việc triển khai Lambda giúp giảm khá nhiều thời gian bỏ ra cho các công đoạn setup môi trường, hệ điều hành phù hợp, runtime phù hợp cho từng ngôn ngữ lập trình. Hoặc nếu mình dùng Docker thì cũng phải đảm bảo việc Docker runtime hoạt động liên tục không gián đoạn. Việc gián đoạn dịch vụ do lỗi máy lạnh, cúp điện thực ra xảy ra khá thường xuyên nên cũng là một yếu tố khi sử dụng Serverless sẽ đỡ suy nghĩ hơn các vấn đề đấy.

Khuyết điểm của Serverless nói chung và Lambda (Cuộc sống không có ai hoàn hảo)

  1. Theo mình test thì khi sau một quãng thời gian không có request thì Lambda sẽ vào chế độ "nghỉ", nghĩa là không có instance nào chờ sẵn đó để nhận request nữa. Việc này dẫn tới khi chuyển từ chế độ "nghỉ" sang "hoạt động" thì mất một khoảng thời gian lâu hơn khi có request liên tục, mình xem thì khoảng 300-800ms. Nhưng bù lại khi request liên tục thì tốc độ phản hồi của Lambda khá nhanh, khoảng <50ms.
  2. Không phù hợp với các Workload nhận các gói tin nhỏ và liên tục, lúc này chi phí cho Lambda so sánh với lại EC2 hoặc VPS bên ngoài sẽ cao hơn. Bạn có thể tự tính và so sánh bằng link này.
  3. Việc mô hình chi phí khi "start small" giúp các doanh nghiệp và startup tiết kiệm được nhiều chi phí, nhưng đây cũng là con dao hai lưỡi nếu việc lên kế hoạch cho tương lai của công ty bạn chưa được lập ra đúng đắn. Lấy ví dụ việc có khoảng vài triệu request một tháng ở giai đoạn sơ khai của dự án, sau đó công ty phát triển thêm nhiều microservices bên trong, hệ thống cồng kềnh hơn và nếu lạm dụng AWS Lambda áp dụng luôn cho cả các workload chạy dài hơi thì lúc này chi phí sẽ rất chua đấy.

Nói miên man vậy đủ để các bạn nắm một phần bên ngoài của Serverless hoặc ở đây nhân vật chính là AWS Lambda, bây giờ mình vào công chiện chính là lập trình!

Chuẩn bị môi trường để triển khai API

  1. Cài đặt Nodejs(Vì mục 2 cài bằng NPM), chi tiết ở link này
  2. Cài đặt Serverless Framework, chi tiết ở link này
  3. Cài đặt AWS CLI, chi tiết ở link này
  4. Cài đặt Golang, chi tiết ở link này
  5. Do ví dụ sử dụng lệnh make nên mình sử dụng Ubuntu/MacOS.

Cài đặt AWS CLI để kết nối tài khoản AWS của bạn

aws configure

Các bạn cài đặt Client ID và Client Secret như bên dưới, 2 thông số còn lại optional bạn không cài cũng được.

AWS Access Key ID [****]:
AWS Secret Access Key [****]:
Default region name [us-west-1]: 
Default output format [None]:

Hãy xem cấu trúc chính của sourcecode nào !

Mình sử dụng luôn sourcecode của Serverless Framework để làm ví dụ, đầu tiên mình hãy clone project về

git clone https://github.com/serverless/examples.git

Sau đó mình vào phần ví dụ được viết bằng Golang để tạo HTTP API.

cd aws-golang-http-get-post

Trước khi chạy thì mình giới thiệu cho các bạn các thành phần chính của một project Serverless Framework:

serverless.yml

File này định nghĩa các dịch vụ mình sẽ tạo ra trên AWS sau khi deploy, bao gồm cả AWS APIGateway và AWS Lambda cùng với các IAM Role cần thiết. File dạng yml này sử dụng dấu cách đầu dòng tương tự Python nên các bạn lưu ý khi chỉnh sửa nhớ thụt dòng cho khớp.

provider:
  name: aws # Amazon Web Service
  runtime: go1.x # ngôn ngữ Golang

Phần này bạn định nghĩa Public Cloud mà mình muốn deploy API của mình lên, ở đây sử dụng AWS và Go 1.x.

functions:
  get:
    handler: bin/getBin  # gói build của Golang sẽ nằm ở đây và Serverless lấy nó đẩy lên AWS S3
    package:
      include:
        - ./bin/getBin 
    events:
      - http:
          path: get/{name}  # đây là sub path của API mình sẽ public 
          method: get  # HTTP Method là GET
          request:
            parameter:
              paths:
                name: true

Phần functions bạn thấy có 3 functions là Get, GetQuerry và Post cũng chính là 3 API mình sẽ public ra.

/getFolder/getExample.go

Đây chính là nơi mình viết các xử lý của mình bằng Golang, ở đây mình vào file đơn giản nhất là getExample.

// Handler function Using AWS Lambda Proxy Request
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

	//Get the path parameter that was sent
	name := request.PathParameters["name"]

	//Generate message that want to be sent as body
	message := fmt.Sprintf(" { \"Message\" : \"Hello %s \" } ", name)

	//Returning response with AWS Lambda Proxy Response
	return events.APIGatewayProxyResponse{Body: message, StatusCode: 200}, nil
}

Đoạn code này xử lý lấy queryString "name" từ URL sau đó chèn và in ra dòng chữ "Hello <name truyền vào>" . Bạn có thể thử điều chỉnh logic trong function này như là đổi đoạn message in ra hoặc thử kết nối database.

Chạy thôi nào !

Nếu các bạn sử dụng Ubuntu và MacOS thì chỉ cần chạy lệnh bên dưới ở ngoài root:

make deploy

Các bạn truy cập vào tài khoản AWS của mình, sau đó vào Cloudformation và chọn stack có tên bắt đầu bằng "goservice".

Vào tab Output để lấy API Endpoint.

image.png

Chúc các bạn thành công !


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.