Outbox Pattern với Debezium – Phần 1

Khi làm việc với các ứng dụng microservices, việc trao đổi dữ liệu giữa các service với nhau luôn là điều cần thiết đó các bạn. Việc trao đổi dữ liệu này có thể xảy ra synchronously hoặc asynchronously và phải đảm bảo được tính nhất quán của dữ liệu.

Với synchronously, chúng ta có thể sử dụng RESTful Web Service, gRPC hay một synchronous API nào đó để các service này có thể trao đổi dữ liệu với nhau. Nhược điểm của việc call synchronously, đó là các service sẽ bị couple, phụ thuộc vào nhau. Service này phải biết thông tin của service kia để mà có thể gọi tới được. Đôi khi, mặc dù đã biết thông tin của Service đó rồi nhưng cũng sẽ xảy ra trường hợp Service đó không available để call tới vì vấn đề về network, internal error. Chúng ta có thể sử dụng một số công cụ Service Mesh để giải quyết các vấn đề này như retry, circuit breaker nhưng cũng có những hạn chế nhất định.

Một nhược điểm khác của việc sử dụng synchronous call đó là chúng ta không thể replay, process lại dữ liệu nếu request trước đó, cuối cùng cũng không thể hoàn thành.

Cả 2 nhược điểm trên, chúng ta có thể giải quyết bằng cách sử dụng một asynchronous call. Thay vì call trực tiếp tới service, chúng ta sẽ publish data vào một topic của một Message Broker như Apache Kafka, các service khác sẽ subscribe vào topic này để lấy data và process.

Một vấn đề có thể xảy ra về tính nhất quán của dữ liệu khi một ứng dụng khi lưu dữ liệu của mình, cần đồng thời public dữ liệu này vào một Message Broker để cho các service khác có thể lấy dữ liệu và process nhưng trong quá trình public dữ liệu này thì có lỗi xảy ra. Vấn đề này được gọi là Dual Writes problem đó các bạn!

Để giải quyết Dual Writes problem, giải pháp duy nhất mà chúng ta có thể làm đó là đầu tiên hãy lưu dữ liệu vào một trong 2 datasource: database hoặc Message Broker, sau đó thì có cơ chế để datasource còn lại lấy dữ liệu và process. Nếu các bạn chọn lưu dữ liệu vào Message Broker như Apache Kafka thì lại không phù hợp với nguyên tắc tính nhất quán Read-your-Write, một nguyên tắc về việc khi dữ liệu được thêm mới vào thì việc đọc dữ liệu lên phải bao gồm dữ liệu mới này. Khi sử dụng Message Broker để lưu dữ liệu ngay từ đầu, có thể dữ liệu chưa được synchronize qua database liền, do đó việc đọc dữ liệu từ database lên sẽ không bao gồm dữ liệu đó.

Chúng ta nên lưu dữ liệu vào database của service trước và sử dụng Outbox Pattern để populate dữ liệu này vào Message Broker đó các bạn!

Với Outbox Pattern, chúng ta sẽ cần định nghĩa một outbox table trong service database. Khi dữ liệu được lưu vào database thì cùng với đó, chúng ta sẽ insert một record vào outbox table. Record này sẽ chứa thông tin về event dữ liệu mới xảy ra và sẽ được public vào Message Broker để các service khác có thể biết và process event đó.

Chi tiết của việc implementation của Outbox Pattern, các bạn hãy đọc ở phần 2 nhé!

Add Comment