Phát triển phần mềm có thể thách thức, nhưng maintain (bảo trì) nó thách thức hơn nhiều. Bảo trì bao gồm software patches và server maintenance. Trong bài này, chúng ta sẽ focus trên server management và maintenance.
Truyền thống, server là on-premises, nghĩa là mua và maintain physical hardware. Với cloud computing, server này không còn cần owned physically. Năm 2006, khi Amazon bắt đầu AWS và giới thiệu dịch vụ EC2, kỷ nguyên cloud computing hiện đại bắt đầu. Với loại service này, chúng ta không còn cần maintain physical server hoặc upgrade physical hardware. Điều này giải quyết nhiều vấn đề, nhưng server maintenance và resource management vẫn thuộc về chúng ta. Đưa những phát triển này lên level tiếp theo, chúng ta bây giờ có serverless technology.

Serverless Technology Là Gì?
Serverless technology giúp offload việc quản lý và provisioning server cho cloud provider. Trong bài này, chúng ta sẽ discuss AWS.
Thuật ngữ serverless không nghĩa là không có server hoàn toàn. Có server, nhưng nó được fully managed bởi cloud provider. In a sense, đối với user của serverless technology, không có visible server. Server không trực tiếp visible cho chúng ta, và việc quản lý chúng được automated bởi cloud provider. Đây là một số đặc điểm làm cho nó serverless:
- No operational management - Không cần patching server hoặc manage chúng cho high availability;
- Scale as needed - Từ serve chỉ vài user đến serve hàng triệu user;
- Pay as you go - Chi phí được managed dựa trên usage.
Serverless technology có thể categorized như sau:
- Compute (ví dụ, Lambda và Fargate)
- Storage (ví dụ, S3)
- Data Store (ví dụ, DynamoDB và Aurora)
- Integration (ví dụ, API Gateway, SNS, và SQS)
- Analytics (ví dụ, Kinesis và Athena)
Tại Sao Dùng Serverless Technology?
Chi Phí
Pay as you go là một trong những lợi thế chính của serverless technology. Khi có thay đổi không dự đoán được trong traffic volume, bạn cần scale server up hoặc down dựa trên usage pattern, nhưng scaling với self-managed autoscaling có thể difficult và inefficient. Serverless computing, như AWS Lambda, có thể dễ dàng giúp tiết kiệm chi phí vì không cần pay during idle times.
Developer Productivity
Vì serverless computing đề cập đến fully managed services do cloud provider cung cấp, không cần developer provision server hoặc develop server application. Developer có thể start coding ngay lập tức mà không cần manage server. Cách tiếp cận này cũng remove cần patching server hoặc managing autoscaling. Tiết kiệm all của time này giúp tăng developer productivity.
Elasticity
Serverless computing highly elastic và có thể scale up hoặc down dựa trên usage. Spike trong user có thể handled easily. Điều này có thể là major advantage và giúp tiết kiệm nhiều thời gian cho developer.
High Availability
Khi computing là serverless và managed bởi cloud provider và server có high uptime, failovers được handled automatically. Quản lý loại issue này yêu cầu specialized skills. Với serverless approach, ops' và developers' work có thể done bởi single person.
Cách Triển Khai Serverless Functionality Trong Ruby
Theo AWS, Ruby là một trong những ngôn ngữ widely used nhất trong AWS. Lambda bắt đầu support Ruby vào tháng 11 năm 2018. Chúng ta sẽ build web API trong Ruby chỉ dùng serverless technologies do AWS cung cấp.
Để tạo serverless infra trong AWS, chúng ta có thể đơn giản login vào AWS console và bắt đầu tạo chúng. Tuy nhiên, chúng ta muốn develop cái gì đó easily testable và facilitates disaster recovery. Chúng ta sẽ write serverless feature as code. Để làm vậy, AWS cung cấp serverless application model (SAM). SAM là framework dùng để build serverless applications trong AWS. Nó cung cấp YAML-based syntax cho thiết kế Lambda, databases, và APIs. AWS SAM applications có thể built dùng AWS SAM-CLI, có thể download qua link này.
AWS SAM CLI được built trên AWS Cloudformation. Nếu bạn familiar với viết IaC với CloudFormation, điều này sẽ rất đơn giản. Alternatively, bạn cũng có thể dùng serverless framework. Trong bài này, tôi sẽ dùng AWS SAM.

Trước khi dùng SAM CLI, hãy chắc chắn bạn có:
- AWS Profile Setup
- Docker installed
- SAM CLI installed
Chúng ta sẽ develop serverless application. Chúng ta sẽ bắt đầu bằng tạo một vài serverless infra, như DynamoDB và Lambda, trong application. Hãy bắt đầu với database:
DynamoDB
DynamoDB là serverless AWS-managed database service. Vì nó serverless, nó rất quick và easy setup. Để tạo DynamoDB, chúng ta define SAM template như sau:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
UsersTable:
Type: AWS::Serverless::SimpleTable
Properties:
PrimaryKey:
Name: id
Type: String
TableName: users
Với SAM CLI và template trên, chúng ta có thể tạo basic DynamoDB table. Đầu tiên, chúng ta cần build package cho serverless app. Cho việc này, chúng ta chạy lệnh sau. Nó sẽ build package và push lên s3. Hãy chắc chắn bạn đã tạo s3 bucket tên serverless-users-bucket trước khi chạy lệnh:
$ sam package --template-file sam.yaml \
--output-template-file out.yaml \
--s3-bucket serverless-users-bucket
S3 bây giờ trở thành source cho template và code cho serverless app, chúng ta sẽ nói về nó khi tạo Lambda function cho nó.
Chúng ta có thể deploy template này để tạo DynamoDB:
$ sam deploy --template-file out.yaml \
--stack-name serverless-users-app \
--capabilities CAPABILITY_IAM
Với này, chúng ta có DynamoDB setup. Tiếp theo, chúng ta sẽ tạo Lambda, nơi table này sẽ được dùng.
Lambda
Lambda là serverless computing service do AWS cung cấp. Nó có thể dùng để execute code on as-needed basis mà không yêu cầu actual server management, nơi code được execute. Lambda có thể dùng để run Async processes, REST APIs, hoặc scheduled jobs. Tất cả chúng ta cần là viết một handler function và push function lên AWS Lambda. Lambda sẽ làm việc execute task dựa trên events. Event có thể triggered bởi various sources, như API gateway, SQS, hoặc S3; nó cũng có thể triggered bởi codebase khác. Khi triggered, Lambda function này nhận event và context parameters. Giá trị trong các parameter này khác nhau dựa trên source của trigger. Chúng ta cũng có thể manually hoặc programmatically trigger Lambda function bằng cách pass这些 events cho handler. Handler nhận hai argument:
Event - Events thường là key-value hash pass từ source của trigger. Các giá trị này automatically passed khi triggered bởi various sources, như SQS, Kinesis, hoặc API gateway. Khi trigger manually, chúng ta có thể pass events ở đây. Event chứa input data cho Lambda function handler. Ví dụ, trong API gateway, request body chứa trong event này.
Context - Context là second argument trong handler function. Nó chứa specific details, bao gồm source của trigger, Lambda function name, version, request-id, và more.
Output của handler được pass back cho service triggered Lambda function. Output của Lambda function là return value của handler function.
AWS Lambda hỗ trợ bảy ngôn ngữ khác nhau bạn có thể code, bao gồm Ruby. Ở đây, chúng ta sẽ dùng AWS Ruby-sdk để connect đến DynamoDB.
Trước khi viết code, hãy tạo infra cho Lambda dùng SAM template:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: "Serverless users app"
Resources:
CreateUserFunction:
Type: AWS::Serverless::Function
Properties:
Handler: users.create
Runtime: ruby2.7
Policies:
- DynamoDBWritePolicy:
TableName: !Ref UsersTable
Environment:
Variables:
USERS_TABLE: !Ref UsersTable
Trong handler, chúng ta viết reference đến function sẽ executed as Handler: <filename>.<method_name>.
Tham khảo serverless policy template cho policy bạn có thể attach đến Lambda based on resource nó dùng. Vì Lambda function ghi vào DynamoDB, chúng ta dùng DynamoDBWritePolicy trong policies section.
Chúng ta cũng cung cấp env variable USERS_TABLE cho Lambda function để nó gửi request đến database chỉ định.
Vậy là những gì cần cho Lambda infra. Bây giờ, hãy viết code tạo user trong DynamoDB, mà Lambda function sẽ execute.
Thêm AWS record vào Gemfile:
# Gemfile
source 'https://rubygems.org' do
gem 'aws-record', '~> 2'
end
Thêm code ghi input vào DynamoDB:
# users.rb
require 'aws-record'
class UsersTable
include Aws::Record
set_table_name ENV['USERS_TABLE']
string_attr :id, hash_key: true
string_attr :body
end
def create(event:, context:)
body = event["body"]
id = SecureRandom.uuid
user = UsersTable.new(id: id, body: body)
user.save!
user.to_h
end
Rất quick và easy. AWS cung cấp gem aws-record cho truy cập DynamoDB, rất similar đến Rails' activerecord.
Tiếp theo, chạy lệnh sau để cài dependencies.
Lưu ý: Hãy chắc chắn bạn có cùng phiên bản Ruby như defined trong Lambda. Cho ví dụ ở đây, bạn cần Ruby2.7 installed trên machine.
# install dependencies
$ bundle install
$ bundle install --deployment
Package changes:
$ sam package --template-file sam.yaml \
--output-template-file out.yaml \
--s3-bucket serverless-users-bucket
Deploy:
sam deploy --template-file out.yaml \
--stack-name serverless-users-app \
--capabilities CAPABILITY_IAM
Với code này, chúng ta bây giờ có Lambda running, có thể ghi input vào database. Chúng ta có thể thêm API gateway trước Lambda để truy cập qua HTTP calls. API gateway cung cấp nhiều API management functionality, như rate limiting và authentication. Tuy nhiên, nó có thể trở nên expensive dựa trên usage. Có cheaper option dùng chỉ HTTP API without API management. Based on use case, bạn có thể chọn appropriate nhất.
AWS Lambda có một vài limits. Một số có thể modified, nhưng những cái khác fixed:
- Memory - Mặc định, Lambda có 128 MB memory trong execution time. Có thể tăng lên 3,008 MB increments of 64 MB.
- Timeout - Lambda function có time limit execute code. Default limit 3 seconds. Có thể tăng lên 900 seconds.
- Storage - Lambda cung cấp directory
/tmpcho storage. Limit của storage này 512 MB. - Request and Response size - Lên đến 6 MB cho synchronous trigger và 256 MB cho asynchronous trigger.
- Environment variable - Lên đến 4KB
Vì Lambda có một số limits này, tốt hơn viết code fit within limitations này. Trong trường hợp không, chúng ta có thể split code sao cho một Lambda trigger cái khác. Cũng có step function do AWS cung cấp, có thể dùng để sequence multiple Lambda functions.
Test Serverless Applications Locally Như Thế Nào?
Cho serverless applications, chúng ta cần vendor cung cấp managed serverless services. Chúng ta dependent on AWS để test application. Để test application, có một vài local options do AWS cung cấp. Một số open-source tools compatible với AWS serverless technologies cũng có thể dùng để test application locally.
Hãy test Lambda function và DynamoDB. Để làm vậy, chúng ta cần chạy chúng locally.
Đầu tiên, tạo docker network. Network sẽ giúp communicate giữa Lambda function và DynamoDB.
$ docker network create lambda-local --docker-network lambda-local
DynamoDB local là local version của DynamoDB do AWS cung cấp, chúng ta có thể dùng để test locally. Chạy DynamoDB local bằng cách chạy docker image sau:
$ docker run -p 8000:8000 --network lambda-local --name dynamodb amazon/dynamodb-local
Thêm dòng sau trong file user.rb. Điều này sẽ connect Lambda đến local DynamoDB:
local_client = Aws::DynamoDB::Client.new(
region: "local",
endpoint: 'https://dynamodb:8000'
)
UsersTable.configure_client(client: local_client)
Thêm file input.json, chứa input cho Lambda:
{
"name": "Milap Neupane",
"location": "Global"
}
Trước khi execute Lambda, chúng ta cần add table vào local DynamoDB. Để làm vậy, chúng ta sẽ dùng migration functionality do aws-migrate cung cấp. Hãy tạo file migrate.rb và thêm migration sau:
require 'aws-record'
require './users.rb'
local_client = Aws::DynamoDB::Client.new(
region: "local",
endpoint: 'https://localhost:8000'
)
migration = Aws::Record::TableMigration.new(UsersTable, client: local_client)
migration.create!(
provisioned_throughput: {
read_capacity_units: 5,
write_capacity_units: 5
}
)
migration.wait_until_available
Cuối cùng, execute Lambda locally dùng lệnh sau:
$ sam local invoke "CreateUserFunction" -t sam.yaml \
-e input.json \
--docker-network lambda-local
Điều này sẽ tạo user's data trong DynamoDB table.
Có options, như localstack, cho chạy AWS stacks locally.
Khi Nào Nên Dùng Serverless Computing?
Khi decide whether dùng serverless computing, chúng ta cần aware cả benefits và shortcomings. Based on các đặc điểm sau, chúng ta có thể decide khi nào dùng serverless approach:
Cost
- Khi application có idle time và inconsistent traffic, Lambdas tốt vì giúp reduce costs.
- Khi application có consistent traffic volume, dùng AWS Lambda có thể costly.
Performance
- Nếu application không performance-sensitive, dùng AWS Lambda là good choice.
- Lambdas có cold boot time, có thể gây slow response times during cold boot.
Background processing
- Lambda là good choice cho background processing. Một số open-source tools, như Sidekiq, có server scaling và maintenance overhead. Chúng ta có thể combine AWS Lambda và AWS SQS queue để process background jobs without hassle của server maintenance.
Concurrent processing
- Như chúng ta biết, concurrency trong Ruby không phải dễ dàng. Với Lambda, chúng ta có thể achieve concurrency without cần programming language support. Lambda có thể executed concurrently và helps improve performance.
Running Periodic hoặc one-time scripts
- Chúng ta dùng cron jobs execute Ruby codes, nhưng server maintenance cho cron jobs có thể difficult cho large-scale applications. Dùng event-based Lambdas helps scaling applications.
Đây là một số use cases cho Lambda functions trong serverless applications. Chúng ta không phải build everything serverless; chúng ta có thể build hybrid model cho use cases trên. Điều này helps scaling applications và increases developers' productivity. Serverless technologies đang evolve và getting better. Có other serverless technologies, như AWS Fargate và Google CloudRun, không có limitations của AWS Lambda.