Trong các bài trước chúng ta đã làm quen với Facebook Messenger chatbot viết bằng Go. Trong bài này tôi giới thiệu việc triển khai chatbot server trên môi trường AWS Lambda.
Tại sao lại Lambda
Để đưa chatbot vào hoạt động chúng ta không thể để nó chạy local mãi được. Chúng ta có nhiều cách để triển khai server cho chatbot như mua hoặc thuê host, sử dụng các dịch vụ PAAS như heroku hay sử dụng dịch vụ FAAS như AWS Lambda hay Google Cloud Functions. Ở đây tôi chọn Lambda vì những ưu thế sau:
- Cung cấp sẵn HTTPS: Dịch vụ API Gateway của AWS gắn với Lambda luôn cung cấp URL HTTPS.
- Khả năng mở rộng: Do chúng ta làm Messenger chatbot nên khả năng cùng lúc phải xử lý tin nhắn từ nhiều người dùng là bình thường. Lambda hỗ trợ tốt việc này khi nó dễ dàng chạy cả ngàn server để phục vụ các yêu cầu cùng lúc.
- Gói miễn phí: Hiện tại AWS miễn phí 1 triệu yêu cầu mỗi tháng cho API Gateway và Lambda. Lượng miễn phí này đủ cho chúng ta dùng cho đến khi có lượng người dùng đủ lớn. Do đó Lambda khá phù hợp cho sinh viên hoặc các startup cần thử nghiệm nhanh mà chi phí hạn hẹp.
Trước khi tìm hiểu cách đưa chatbot server lên Lambda, chúng ta hãy cùng tìm hiểu các dịch vụ của Amazon Web Services dùng trong dự án.
Amazon Web Services
Chắc hẳn chúng ta ai cũng từng nghe đến Amazon, trang thương mại điện tử lớn nhất thế giới. Khởi nguồn của nó là một trang bán sách trực tuyến, sau này mới mở rộng kinh doanh sang cách mặt hàng khác. Trong suốt 24 năm hoạt động, đội ngũ IT của Amazon đã tạo ra rất nhiều dịch vụ và công cụ để phục vụ cho trang web amazon.com và các nhu cầu khác của công ty. Dần dần những dịch vụ này được mở rộng cho bên ngoài thuê sử dụng và hình thành nên Amazon Web Services (AWS) dịch vụ cloud hàng đầu thế giới. 3/4 lợi nhuận của Amazon đến từ AWS. Hiện tại AWS cung cấp 20 nhóm dịch vụ gồm hàng trăm dịch vụ khác nhau. Có thể nói bạn nghĩ mình cần gì đó là AWS có sẵn dịch vụ hoặc có thể kết hợp các dịch vụ lại để phục vụ bạn.
Lambda
Lambda là dịch vụ của AWS theo mô hình serverless hướng dịch vụ hàm (Function As A Service - FAAS). Lambda chứa các hàm thực thi và khi được gọi, một server nhỏ được khởi chạy để thực thi hàm này. Sau khi chạy xong, server sẽ tắt đi.
Lambda hoạt động theo nguyên tắt hướng sự kiện, nghĩa là cách dịch vụ khác trong AWS sau khi được Lambda đăng ký nhận sự kiện thì khi có sự kiện tương ứng của dịch vụ đó xảy ra, Lambda sẽ nhận sự kiện và server chứa hàm chức năng sẽ được gọi. Nhiều server chứa hàm chức năng được gọi cùng lúc nếu nhiều sự kiện tương ứng xảy ra đồng thời. Hiện tại có 20 dịch vụ là nguồn tạo sự kiện gọi Lambda.
Lambda hỗ trợ xây dựng hàm chức năng từ nhiều ngôn ngữ khác nhau như Go, NodeJS, Python, Java, v.v..
Ưu điểm của Lambda:
- Giúp chúng ta không phải bận tâm quản lý server, chỉ cần lo hàm chức năng là đủ.
- Server chỉ được chạy khi có sự kiện tương ứng nên chúng ta chỉ phải trả tiền cho những gì sử dụng. Hiện tại Lambda tính phí theo công thức: thời gian chạy x bộ nhớ sử dụng.
- Hiện tại Lambda được miễn phí 1 triệu lần gọi mỗi tháng.
Nhược điểm của Lambda:
- Thời gian xử lý tối đa là 15 phút. Hết thời gian này server sẽ tự tắt. Trước đây thời gian tối đa là 5 phút.
- Một lần chạy là mỗi lần khởi động server nên Lambda hoạt động theo mô hình stateless, không có lưu trạng thái.
- Debug lambda không đơn giản.
API Gateway
Như ở trên có đề cập, Lambda chỉ nhận sự kiện từ các dịch vụ của AWS nên để nhận từ bên ngoài Lambda cần một dịch vụ khác gọi hay nói cách khác là nhận sự kiện của một dịch vụ mà bên ngoài gọi được đến dịch vụ đó. Với các cuộc gọi HTTP thì dịch vụ tương ứng là API Gateway.
API Gateway cung cấp 1 URL và cho phép bên ngoại gọi đến. Lúc này API Gateway sẽ chuyển dữ liệu nó nhận được đến Lambda tương ứng rồi chờ nhận dữ liệu phản hồi từ Lambda và trả về cho nơi đã gọi nó. Thời gian hoạt động tối đa hiện nay của API Gateway là 29 giây nghĩa là sau 29 giây, mọi phản hồi từ Lambda là vô giá trị, API Gateway sẽ không trả về cho bên gọi nữa.
GoBot trên Lambda với apex up
Đăng ký tài khoản AWS
Để có thể sử dụng Lambda, việc đầu tiên chúng ta phải làm là đăng ký tài khoản AWS. Lưu ý là AWS đòi chúng ta cung cấp thông tin thẻ tín dụng mới cho phép sử dụng vì lý do các dịch vụ trên AWS có thu phí. Tuy nhiên AWS luôn dành một khoản miễn phí cho chúng ta nếu biết tận dụng. Bước đăng ký tôi sẽ không nêu ở đây nhưng bạn nào gặp khó khăn cứ nêu ở comment, tôi sẽ giúp.
Bước tiếp theo chúng ta phải làm là tạo người dùng tương tác với AWS và tạo vai trò (role) để khi thực thi trên Lambda dùng khi cần tương tác các dịch vụ khác.
Tạo người dùng
Khi tạo tài khoản AWS, bạn đã có tài khoản cao cấp nhất có quyền trên mọi dịch vụ mà AWS cung cấp cho bạn. Bạn không nên sử dụng nó để lập trình vì nếu lộ kẻ gian có thể dùng nó để tạo hàng loạt server cũng như sử dụng vô tội vạ các dịch vụ mà bạn là người phải trả tiền.
Để tạo một tài khoản khác phục vụ cho việc lập trình bạn thực hiện theo các bước như sau:
(1) Vào trang tạo người dùng tại đây, chọn "Add user" :
(2) Chọn tên, ở đây tôi chọn 'gobot'. Sau đó chọn kiểu truy cập là 'Programmatic access' nghĩa là chỉ dùng để tương tác qua API hoặc CLI, không vào trang web quản lý (console) được. Sau đó chọn "Next: Permission" để thêm quyền cho user này.
(3) Tiếp theo chọn quyền, ở đây để đơn giản tôi chọn "Administration Access" nghĩa là có thể tương tác mọi dịch vụ. Sau đó chọn "Next:Review"
(4) Ở màn hình review nếu thấy mọi thông tin chính xác, hãy chọn "Create user" để hoàn tất việc tạo người dùng mới.
(5) Như vậy việc tạo người dùng hoàn tất, chúng ta cần tải file .csv về hoặc copy 2 thông tin access key và secret key để dùng sau na.
(6) Tạo thư mục ~/.aws để lưu trữ các thông tin cần cho việc tương tác với các dịch vụ AWS sau này. Tại thư mục .aws, tạo 2 file như sau:
- File "credentials" lưu các cặp access key và secret key đại diện các người dùng để tương tác sử dụng các dịch vụ AWS. Cấu trúc file này có dạng như sau:
[gobot]
aws_access_key_id = xxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxx
Lúc này mở Terminal lên gõ "export AWS_PROFILE=gobot" là các dịch vụ kết nối AWS có thể dùng thông tin này để chứng thực người dùng. Nếu bạn sử dụng Windows, hãy xem hướng dẫn tại đây.
- File "config" mô tả thông tin khu vực (region) mà chúng ta định thao tác và định dạng xuất:
[profile gobot]
region=us-east-1
output=json
Ở đây tôi chọn region hoạt động là Bắc Virginia ở Mỹ (US East (N. Virginia)) và định dạng xuất là json. Các bạn lưu ý là mỗi region sẽ lưu trữ khác nhau nên nếu bạn tạo ở region này thì đừng đi kiếm nó ở region khác. Thông tin region hiện tại ở console là góc trên bên trái:
Do chatbot server nói chuyện trực tiếp với Facebook nên tôi đặt ở Mỹ tiện hơn là ở gần Việt Nam. Ở Mỹ thì region này là rẻ nhất. Gần Việt Nam thì có Singapore với mã region là ap-southeast-1.
Tạo vai trò
Khi dịch vụ đưa lên Lambda và chạy thì vai trò mà chúng ta tạo ở đây sẽ quyết định dịch vụ chúng ta có thể tương tác được với các dịch vụ nào của AWS. Để tạo vai trò chúng ta thực hiện theo các bước sau:
(1) Tại chức năng IAM ở trên mà chúng ta đã tạo người dùng, chọn Role từ danh sách chức năng bên trái.
(2) Chọn "Create role" để tạo vai trò mới:
(3) Chọn đối tượng sử dụng vai trò, ở đây chúng ta chọn Lambda. Chọn "Next: Permissions" để thêm các quyền cho vai trò này.
(4) Thêm policies là các quyền mà AWS đã quy định sẵn, ở đây hiện tại tôi chọn AWSLambdaBasicExecutionRole. Chọn "Next: Review" để xem lại các thông tin đã chọn.
(5) Ở đây chúng ta cần đặt tên cho vai trò mới, tôi chọn là GoBot rồi chọn "Create role"
(6) Như bên dưới có thể thấy là role đã được tạo xong
Apex Up
Apex up là công cụ giúp chúng ta đưa dịch vụ lên Lambda mà không cần phải vào AWS console để tạo từng bước phức tạp hay chạy lệnh AWS CLI rối rắm. Với Apex Up, mọi việc chỉ đơn giản là tạo file up.json rồi gõ up từ dòng lệnh là xong.
Đầu tiên chúng ta cần cài đặt Apex Up. Các bạn xem hướng dẫn tại đây. Tiếp theo chúng ta tạo file up.json trong thư mục dự án như bên dưới:
{
"name": "gobot",
"profile": "gobot",
"regions": ["us-east-1"],
"lambda": {
"role": "<role ARN>",
"memory": 128
}
}
Role ARN ở trên có thể lấy như sau: Chọn vai trò đã tạo ở trên, ở đây là GoBot, màn hình sau xuất hiện. Chọn nút copy ở vùng đánh dấu đỏ để copy chuỗi ARN rồi dán vào file up.json ở trên.
Lambda khi chạy không cố định port (có lẽ nhiều server ảo chạy cùng lúc nên nếu chạy port cố định sẽ không chạy được) nên thay vì để "8080" như trước đây chúng ta phải gọi hàm lấy giá trị biến môi trường "PORT" để lấy port cần chạy do khi chạy Lambda truyền port sẽ chạy ở đây. Hàm main trong main.go được sửa lại như sau:
func main() {
r := mux.NewRouter()
r.HandleFunc("/", chatbotHandler)
if err := http.ListenAndServe(":"+os.Getenv("PORT"), r); err != nil {
log.Fatal(err.Error())
}
}
Mọi thứ lúc này đã sẵn sàng để đưa lên Lambda rồi. Việc còn lại là đến thư mục dự án ở Terminal hoặc Command Prompt, thực hiện các thao tác sau:
- Lệnh export để thiết lập profile mình chọn là gobot để khi gọi up, nó sẽ lấy được access key và secret key của user gobot để tương tác.
- Lệnh up sẽ tiến hành biên dịch, đóng gói rồi đưa dịch vụ của chúng ta lên Lambda và cấu hình API Gateway tương ứng. Nếu xem ở dịch vụ S3, bạn sẽ thấy có 1 bucket mới được tạo cho tên bắt đầu là up
- Lệnh up url sẽ cung cấp cho chúng ta URL đến API Gateway tương ứng. Chép URL này, mang lên dán vào webhook trong Facebook app, thay thế cho link ngrok trước đây rồi test lại sẽ thấy chatbot server hoạt động tốt.
Như vậy chúng ta đã hoàn tất việc xây dựng Facebook Messenger chatbot từ việc tạo page cho đến triển khai dịch vụ trên Lambda.
Tóm tắt:
- Lambda là cách triển khai chatbot server hiệu quả và rẻ nhất.
- AWS có rất nhiều dịch vụ khác nhau.
- Cần tạo thêm user để sử dụng cho việc tương tác với các dịch vụ AWS khi lập trình. Tuyệt đối không cung cấp cặp key cho ai và đưa vào git repo.
- Apex up là công cụ đưa server lên Lambda nhanh chóng và tiện lợi.