Tìm hiểu về Microservice - Phần 3: Quản lý CSDL trên Microservices
Hãy tưởng tượng, bạn đang xây dựng một hệ thống thương mại điện tử với Microservice Architecture. Ta cần có một cơ sở dữ liệu ở dạng như sau:
1. Yêu cầu
Các services cần đảm bảo mối quan hệ để việc deploy, deverlopment và scale được độc lập.
Một số business transantions cần truy vấn data thuộc sở hữu của các services khác nhau.
Một số business transactions cần được thực thi tính nhất quán và bất biến trên nhiều services. VD: Place Order cần xác minh rằng đơn hàng mới sẽ không vượt quá hạn tín dụng của khách hàng. Một số business transactions khác, phải cập nhấp data thuộc sở hữu của các services khác nhau.
Một số queries cần join data thuộc sở hữu của các services khác nhau.
Database đôi khi phải được nhân rộng hoặc phân chia để mở rộng quy mô.
Các services khác nhau có yêu cầu lưu trữ dữ liệu khác nhau. Đối với một số services, SQL như là sự lựa chọn tốt nhất. các services khác có thể cần một cơ sở dữ liueej như NoSQL như MongoDB.
2. Shared database
đây là một dạng database được chia sẻ cho nhiều services. Các services được tự do truy cập các bảng của nhau để đảm bảo ACID Transaction.
Ví dụ: OrderService và CustomersService tự do truy cập các bảng khác của nhau. OrderService có thể sử dụng ACID transaction sau để đảm bảo răng một đơn đặt hàng mới sẽ không vi phạm giới hạn tín dụng của khách hàng.
BEGIN TRANSACTION
```
SELECT ORDER_TOTAL
FROM ORDERS WHERE CUSTOMER_ID =?
```
SELECT CREDIT_LIMIT
FROM CUSTOMERS WHERE CUSTOMER_ID = ?
```
INSERT INTO ORDERS ...
```
COMMIT TRANSACTION
Lợi ích
Một Single database là đơn giản hơn để hoạt động.
Các deverlopers dễ dàng sử dụng ACID transaction để thực thi tính nhất quán dữ liệu.
Hạn chế
Development time coupling. ví dụ: sự thay đổi schema của DB sẽ gây ảnh hưởng đến nhiều services do chúng truy cập trực tiếp vào các tables, và trong khi các lập trình viên cho mỗi service là khác nhau thì rõ ràng coupling này làm chậm quá trình development.
Runtime coupling: tất cả các services truy cập vào cùng một CSDL, chúng có khả năng can thiệp lẫn nhau. Ví dụ: nếu một CustomerService transaction chạy mất nhiều thời gian và lock ORDER table thì Orderservice sẽ bị chặn.
Thực tế đối với hệ thống lớn, một DB đơn lẻ sẽ không thể đáp ứng đủ yêu cầu về lưu trữ và truy cập dữ liệu của tất cả các services.
3. Database per service
Đây là dạng database riêng cho mỗi service. Các services khác nếu muốn bỏ thao tác này thì cần thông qua API của service quản lý DB đó.
Có một số cách khác nhau để giữ DB của mối service là private. Bạn không cần phải cung cấp một máy chủ CSDL cho mỗi service. VÍ dụ đối với SQL:
Private-tables-per-service: mỗi service sở hữu một tập các tables chỉ được truy cập bởi services đó.
Schema-per-service: mỗi service có một chema riêng tư với service đó.
Database-server-per-service: mỗi service có một databse server riêng.
private_tables-per-service và shcema-per-service có chi phí thâp snhaast và việc sử dụng schema-per-service là tốt hơn vì nó làm cho quyền sở hữu trở nên rõ ràng. Trong khi đó, một số services có lượng truy cập cao sẽ cần có databse server của riêng nó.
Lợi ích
Giúp đảm bảo rằng các services được kết nối lỏng lẻo. Việc thay đổi CSDL của một service sẽ không làm ảnh hưởng đến bấ kí services nào khác.
Mỗi dịch vũ có thể sử dụng loại CSDL phù hợp với nhu cầu của nó.
Hạn chế
Việc thực hiện các tranaction trải rộng trên nhiều các services không đơn giản. Các transaction phân tán nên được hạn chế vì định lý CAP. hơn nữa, nhiều CSDL hiện đại không hỡ trợ chúng.
Việc thực hiện các queries cần join data trong nhiều CSDL là một thách thức.
Sự phức tạp của việc quản lý nhiều SQL và NoSQL.
Có nhiều patterns/solutions khác nhau để giải quyết bài toán query và transaction trên nhiều services:
Để thực hiện transaction trên nhiều services ta có thể sử dụng saga pattern.
Để thực hiện query trên nhiều services ta có thể sử dụng: API composition hoặc Command Query Responsibility Segregation (CQRS).
4. Saga pattern
Đối với các hệ thống lựa chọn mô hình Database per service, mỗi service sẽ có một databse riêng. Tuy nhiên một số transaction cần trải rộng trên nhiều services. Bạn cần một cơ chế để đảm bảo tính thống nhất của dữ liệu trên các services.
Giải pháp được đưa ra như sau: Ta sẽ coi mỗi một transaction trải rộng trên nhiều services là một saga. Và mỗi một Saga là một chuỗi các transaction cục bộ trên tửng service khác nhau. Nếu một transaction cục bộ thất bại thì saga sẽ thực hiện một loạt các transaction để rollback lại các thay đổi đã được thực hiện trước đó.
Có 2 cách để triển khai Saga
a. Events/Choreography-based saga
Service đầu tiên thực hiện transaction và sau đó pushlish một event. Event này được lắng nghe bởi một hoặc nhiều services thực hiện các transaction cục bộ và pushlish các event mới (hoặc không).
Transaction phân tán kết thúc khi service cuối cùng thực hiện transaction cục bộ của nó và khôn gpushlish bất kỳ event nào hoặc event được pushlish không được nghe thấy bởi bất kỳ services nào của saga.
Trong ví dụ này, hệ thống thương mại điện tử sẽ tạo ra đơn đặt hàng như sau:
order service sẽ tạo ra một đơn hàng ở trạng thái pending và gửi đi order_created_event.
payment service lắng nghe order_created_event, trừ tiền khách hàng và gửi đi bill_order_event.
stock service lắng nghe billed_order_event, cập nhập lại stock, chuẩn bị các sản phẩm và gửi đi order_prepared_event.
delivery service lắng nghe order_prepared_event, sau đó nhận và giao sản phẩm. Cuối cùng nó gửi đi order_delivery_event.
order service lắng nghe order_delivery_event và đặt lại trạng thái của đơn hàng.
Trong trường hợp trạng thái đơn hàng cần ập nhấp liên tục thì order service sẽ lắng nghe tất cá các sự kiện và cập nhập trạng thái cho đơn hàng.
Trong trường hợp có một lỗi xảy ra trong chuối transaction cục bộ. Bạn phải rollback những gì đã thay đổi.
Mô hình này thực sự rất dễ hiểu và các services có sự kết nối vô cùng lỏng lẻo. Nếu transaction của bạn chỉ có từ 2 đến 4 bước thì đây sẽ là sự lựa chọn. Tuy nhiên, chúng sẽ trở nên khó khăn khi bạn bổ sung, mở rộng transaction. Nó cũng gây khó khăn cho testing vfi bạn phải chạy tất cả các services.
b. Command/Orchestration-based saga
Sẽ có một service mới chiujt rách nhiệm điều phối các logic của saga. Nó cịu trách nhiệm duy nhất là nói cho mỗi service phải làm gì và khi nào. ssaga service giao tiếp từng service theo kiểu command/reply cho chung biết thực hiện thao tác nào.
Cách hoạt động:
Order service tạo ra một đơn hàng ở trạng thái pending và yêu cầu order saga orchestrator bắt đầu một order transaction.
OSO gửi lệnh EXECUTE PAYMENT dến payment service, và payment service trả lời bằng tin nhắn paymentexecute đối với oerder saga reply chanel.
OSO gửi lệnh prepare order đến stock service, và stock service trả lời mesage order prepared.
OSO gửi lệnh delivery order đến delivery sẻvice, và nhận lại order delivered mesage.
Việc rollback lại saga trở nên dễ dàng hơn nhiều khi bạn có một orchestration điều khiển mọi thứ:
Stock service gửi cho OSO một Out-Of-Stock mesage:
OSO nhận ra rằng transaction thất bại và bắt đầu rollback. Trong trường hợp này chỉ một thao tác duy nhất được thực hiện thành công trước khi thất bài, nên OSO sẽ gửi lệnh Refund client đến Payment service và đặt trạng thái của đơn hàng là không thành công.