AWS Lambda based Java
Bài đăng được viết bởi Mansi Y Doshi, Consultant and Aditya Goteti, Sr. Lead Consultant.
Các doanh nghiệp đang hiện đại hóa và di chuyển ứng dụng của họ sang AWS Cloud để cải thiện khả năng mở rộng, giảm chi phí, đổi mới và giảm thời gian tiếp thị các tính năng mới. Các ứng dụng cũ thường được xây dựng bằng RDBMS làm giải pháp phụ trợ duy nhất.
Hiện đại hóa các ứng dụng Java cũ bằng microservices yêu cầu chia nhỏ một ứng dụng nguyên khối thành nhiều dịch vụ độc lập. Mỗi microservice thực hiện một công việc cụ thể và yêu cầu cơ sở dữ liệu riêng để lưu trữ dữ liệu, nhưng một cơ sở dữ liệu không phù hợp với mọi trường hợp sử dụng. Các ứng dụng hiện đại yêu cầu cơ sở dữ liệu được xây dựng có mục đích phục vụ cho các nhu cầu và mô hình dữ liệu cụ thể của chúng.
Bài đăng này thảo luận về một số trường hợp sử dụng phổ biến đối với một kho dữ liệu như vậy, Amazon MemoryDB for Redis, được xây dựng để mang lại độ bền cũng như khả năng đọc và ghi nhanh hơn.
Trường hợp sử dụng
Nhóm công nghệ hiện đại thường bắt đầu bằng phần phụ trợ tương tác với cơ sở dữ liệu bền bỉ như MongoDB, Amazon Aurora hoặc Amazon DynamoDB để đáp ứng nhu cầu duy trì dữ liệu của họ.
Tuy nhiên, khi lưu lượng truy cập tăng lên, việc thêm một lớp bộ nhớ đệm như ElastiCache thường là hợp lý. Điều này được điền dữ liệu theo logic dịch vụ mỗi lần đọc cơ sở dữ liệu, sao cho các lần đọc tiếp theo của cùng một dữ liệu trở nên nhanh hơn. Mặc dù ElastiCache có hiệu quả nhưng bạn phải quản lý và thanh toán cho hai nguồn dữ liệu riêng biệt cho cùng một dữ liệu. Bạn cũng phải viết logic tùy chỉnh để xử lý việc đọc/ghi bộ nhớ đệm bên cạnh logic đọc/ghi hiện có được sử dụng cho cơ sở dữ liệu lâu bền.
Trong khi các cơ sở dữ liệu truyền thống như MySQL, Postgres và DynamoDB cung cấp độ bền dữ liệu với chi phí phải trả là tốc độ, thì các kho dữ liệu tạm thời như ElastiCache đánh đổi độ bền để có tốc độ đọc/ghi nhanh hơn (thường trong vòng micro giây). ElastiCache cung cấp khả năng ghi và đọc nhất quán mạnh mẽ trên nút chính của mỗi phân đoạn và cuối cùng là đọc nhất quán từ các bản sao đọc. Có khả năng dữ liệu mới nhất được ghi vào nút chính bị mất trong quá trình chuyển đổi dự phòng, điều này khiến ElastiCache nhanh nhưng không bền.
MemoryDB giải quyết cả hai vấn đề này. Nó cung cấp tính nhất quán mạnh mẽ trên nút chính và tính nhất quán cuối cùng khi đọc trên các nút bản sao. Mô hình nhất quán của MemoryDB giống như ElastiCache dành cho Redis. Tuy nhiên, trong MemoryDB, dữ liệu không bị mất khi chuyển đổi dự phòng, cho phép client đọc dữ liệu ghi của họ từ dữ liệu sơ bộ bất kể lỗi nút. Chỉ dữ liệu được lưu giữ thành công trong nhật ký giao dịch Multi-AZ mới hiển thị. Các nút bản sao cuối cùng vẫn nhất quán. Do mô hình giao dịch phân tán của nó, MemoryDB có thể cung cấp cả độ bền và thời gian phản hồi micro giây.
MemoryDB lý tưởng nhất cho các dịch vụ đọc nhiều và nhạy cảm với độ trễ, như dịch vụ cấu hình, tìm kiếm, xác thực và bảng xếp hạng. Chúng phải hoạt động ở độ trễ đọc micro giây và vẫn có thể duy trì dữ liệu để có tính sẵn sàng và độ bền cao. Các dịch vụ như bảng xếp hạng, có hàng triệu bản ghi, thường chia dữ liệu thành các phần/đợt nhỏ hơn và xử lý chúng song song. Điều này cần một kho lưu trữ dữ liệu có thể thực hiện các phép tính nhanh chóng và cũng có thể lưu trữ kết quả tạm thời. Redis có thể xử lý hàng triệu thao tác mỗi giây và lưu trữ các phép tính tạm thời để truy xuất nhanh, đồng thời chạy các hoạt động khác (như tổng hợp). Vì Redis là đơn luồng, nên từ quan điểm thực thi lệnh, nó cũng giúp tránh việc đọc và ghi sai.
Một trường hợp sử dụng khác là dịch vụ cấu hình, nơi người dùng lưu trữ, thay đổi và truy xuất dữ liệu cấu hình của họ. Trong các hệ thống phân tán lớn, thường có hàng trăm dịch vụ độc lập tương tác với nhau bằng API REST được xác định rõ ràng. Các dịch vụ này phụ thuộc vào dữ liệu cấu hình để thực hiện các hành động cụ thể. Dịch vụ cấu hình phải cung cấp thông tin cần thiết ở độ trễ thấp để tránh gây tắc nghẽn cho các dịch vụ phụ thuộc khác.
MemoryDB có thể đọc ở độ trễ micro giây trong thời gian dài. Nó cũng lưu giữ dữ liệu trên nhiều Availability Zones. Nó sử dụng nhật ký giao dịch trên nhiều Availability Zones để cho phép chuyển đổi dự phòng nhanh, khôi phục cơ sở dữ liệu và khởi động lại node. Bạn có thể sử dụng nó làm cơ sở dữ liệu chính mà không cần duy trì bộ đệm khác để giảm độ trễ truy cập dữ liệu. Điều này cũng làm giảm nhu cầu duy trì dịch vụ bộ nhớ đệm bổ sung, giúp giảm chi phí hơn nữa.
Những trường hợp sử dụng này rất phù hợp để sử dụng MemoryDB. Tiếp theo, bạn sẽ thấy cách truy cập, lưu trữ và truy xuất dữ liệu trong MemoryDB từ hàm AWS Lambda dựa trên Java.
Tổng quan
Blog này trình bày cách xây dựng cụm Amazon MemoryDB và tích hợp nó với AWS Lambda. Amazon API Gateway và Lambda có thể được ghép nối với nhau để tạo ra một ứng dụng hướng tới client, ứng dụng này có thể dễ bảo trì hơn, có khả năng mở rộng cao và bảo mật. Cả hai đều là dịch vụ được quản lý hoàn toàn mà không cần cung cấp hoặc quản lý máy chủ. Chúng có thể tiết kiệm chi phí khi so sánh với việc chạy ứng dụng trên máy chủ cho khối lượng công việc có thời gian nhàn rỗi dài. Bằng cách sử dụng trình ủy quyền Lambda, bạn cũng có thể viết mã tùy chỉnh để kiểm soát quyền truy cập vào API của mình.
Hướng dẫn
Các bước sau đây trình bày cách cung cấp cụm Amazon MemoryDB cùng với Amazon VPC, subnet, security groups và tích hợp cụm đó với hàm Lambda bằng Java Redis/Jedis. Ở đây, Lambda được định cấu hình để kết nối với cùng một VPC nơi MemoryDB được cung cấp. Các bước bao gồm việc cung cấp thông qua AWS SAM.
Điều kiện tiên quyết
- Tạo tài khoản AWS nếu bạn chưa có và đăng nhập
- Định cấu hình tài khoản của bạn và thiết lập quyền truy cập MemoryDB.
- Java 8 trở lên
- Cài đặt Maven
- Java Redis
- Cài đặt AWS SAM
Tạo cụm MemoryDB
Tham khảo serverless template để thiết lập nhanh và tùy chỉnh theo yêu cầu. AWS SAM template tạo VPC, subnet, security group, cụm MemoryDB, API Gateway và Lambda.
Để truy cập cụm MemoryDB từ Lambda, security group của Lambda sẽ được thêm vào security group của cụm. Cụm MemoryDB luôn được khởi chạy trong VPC. Nếu subnet không được chỉ định, cụm sẽ được khởi chạy vào Amazon VPC mặc định của bạn.
Bạn cũng có thể sử dụng VPC và subnet hiện có của mình rồi tùy chỉnh template cho phù hợp. Nếu bạn đang tạo VPC mới, bạn có thể thay đổi CIDR block và các giá trị cấu hình khác nếu cần. Đảm bảo tên máy chủ DNS và DNS Support của VPC được bật. Sử dụng phần tham số tùy chọn để tùy chỉnh template. Các tham số cho phép bạn nhập các giá trị tùy chỉnh vào mẫu của mình mỗi khi bạn tạo hoặc cập nhật ngăn xếp.
Khuyến nghị
Khi yêu cầu về khối lượng công việc của bạn thay đổi, bạn có thể muốn tăng hiệu suất của cụm hoặc giảm chi phí bằng cách mở rộng quy mô vào/ra cụm. Để cải thiện hiệu suất đọc/ghi, bạn có thể mở rộng quy mô cụm của mình theo chiều ngang bằng cách tăng số lượng bản sao đọc hoặc phân đoạn để đọc và ghi xuyên suốt tương ứng.
Để giảm chi phí trong trường hợp các phiên bản được cung cấp quá mức, bạn có thể thực hiện mở rộng quy mô theo chiều dọc bằng cách giảm kích thước cụm của mình hoặc thu nhỏ quy mô bằng cách tăng kích thước để khắc phục tình trạng tắc nghẽn CPU/áp lực bộ nhớ. Cả tỷ lệ dọc và tỷ lệ ngang đều được áp dụng mà không có thời gian ngừng hoạt động và không cần phải khởi động lại cụm. Bạn có thể tùy chỉnh các tham số sau trong bộ nhớ DBCluster theo yêu cầu.
NodeType: db.t4g.small
NumReplicasPerShard: 2
NumShards: 2
Trong MemoryDB, tất cả thao tác ghi được thực hiện trên nút chính trong phân đoạn và tất cả thao tác đọc được thực hiện trên nút dự phòng. Việc xác định đúng số lượng bản sao đọc, loại nút và phân đoạn trong một cụm là rất quan trọng để có được hiệu suất tối ưu và tránh mọi chi phí bổ sung do cung cấp quá mức tài nguyên. Bạn nên luôn bắt đầu với số lượng tài nguyên cần thiết ở mức tối thiểu và mở rộng quy mô nếu cần.
Bản sao cải thiện khả năng mở rộng quy mô đọc và bạn nên có ít nhất hai bản sao đọc trên mỗi phân đoạn nhưng tùy thuộc vào kích thước của tải trọng và đối với khối lượng công việc đọc nặng, con số này có thể nhiều hơn hai. Việc thêm nhiều bản sao chỉ có quyền đọc hơn mức yêu cầu sẽ không mang lại bất kỳ cải thiện hiệu suất nào và còn gây thêm chi phí. Việc đo điểm chuẩn sau đây được thực hiện bằng công cụ điểm chuẩn Redis. Việc đo điểm chuẩn chỉ được thực hiện trên các yêu cầu GET để mô phỏng khối lượng công việc nặng về đọc.
Số liệu trên cả hai cụm gần như giống nhau với 10 triệu yêu cầu với tải trọng dữ liệu 1kb cho mỗi yêu cầu. Khi tăng kích thước payload lên 5kb và số lượng yêu cầu GET lên 20 triệu, cụm có hai bản chính và hai bản sao không thể xử lý, trong khi cụm thứ hai được xử lý thành công. Để đạt được kích thước phù hợp, nên thử nghiệm tải trên môi trường dàn dựng/tiền sản xuất với tải tương tự như sản xuất.
Tạo hàm Lambda và cho phép truy cập vào cụm MemoryDB
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.0</version>
</dependency>
Cách đơn giản nhất để kết nối hàm Lambda với cụm MemoryDB là định cấu hình hàm đó trong cùng một VPC nơi cụm MemoryDB được khởi chạy.
Để tạo Lambda, hãy thêm code sau vào tệp template.yaml trong phần Resources:
Handler: helloworld.App::handleRequest
Runtime: java8
MemorySize: 512
Timeout: 900 #seconds
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
VpcConfig:
SecurityGroupIds:
– !GetAtt lambdaSG.GroupId
SubnetIds:
– !GetAtt privateSubnetA.SubnetId
– !GetAtt privateSubnetB.SubnetId
Environment:
Variables:
ClusterAddress: !GetAtt memoryDBCluster.ClusterEndpoint.Address
Java truy cập MemoryDB
- Trong codeJava, kết nối với Redis
HostAndPort hostAndPort = new HostAndPort(System.getenv(“ClusterAddress”), 6379);
JedisCluster jedisCluster = new JedisCluster(Collections.singleton(hostAndPort), 5000, 5000, 2, null, null, new GenericObjectPoolConfig (), true);
- Bây giờ bạn có thể thực hiện các thao tác set và get trên Redis
jedisCluster.set(“test”, “value”)
jedisCluster.get(“test”)
JedisCluster duy trì nhóm kết nối riêng và xử lý việc ngắt kết nối. Nhưng bạn cũng có thể tùy chỉnh cấu hình để đóng các kết nối không hoạt động bằng cách sử dụng đối tượng GenericObjectPoolConfig.
Dọn dẹp
Để xóa toàn bộ stack, hãy chạy lệnh “sam delete”.
Kết luận
Trong bài đăng này, bạn tìm hiểu cách cung cấp cụm MemoryDB và truy cập cụm đó bằng Lambda. MemoryDB phù hợp với các ứng dụng yêu cầu tốc độ đọc trong micro giây và ghi trong mili giây một chữ số cùng với khả năng lưu trữ lâu bền. Việc truy cập MemoryDB thông qua Lambda bằng API Gateway giúp giảm nhu cầu cung cấp và bảo trì máy chủ hơn nữa.