05/09/2018, 14:44

Ứng dụng MySql Binary Log để giải quyết vấn đề tích hợp — P1

[Bài viết của tác giá Lê Minh Nghĩa] Tích hợp hệ thống là một trong các vấn đề cốt lõi của hệ thống lớn. Nó quyết định tính ổn định và chính xác của hệ thống. Làm thế nào để đảm bảo một service A có thể gửi thành công một message tới service B trong mọi trường hợp: network không ...

[Bài viết của tác giá Lê Minh Nghĩa]

Tích hợp hệ thống là một trong các vấn đề cốt lõi của hệ thống lớn. Nó quyết định tính ổn định và chính xác của hệ thống. Làm thế nào để đảm bảo một service A có thể gửi thành công một message tới service B trong mọi trường hợp: network không ổn định, ứng dụng có thể crash, server có thể tắt đột ngột…?

Trong loạt bài viết này, tôi sẽ trình bày dần các solution mà các kĩ sư tiki đang triển khai để giải quyết vấn đề tích hợp hệ thống.

Bài toán tổng quát của tích hợp là bài toán replicate ổn định trong hệ thống phân tán. Làm thế nào để nhiều hơn một system có thể trao đổi với nhau dữ liệu ổn định. Một system có thể hiểu là một service nghiệp vụ, một database, một message queue… Mỗi một quá trình trao đổi sẽ tác động tới sự thay đổi dữ liệu của một trong các hệ thống. VD service đơn hàng gửi một trạng thái đơn hàng thay đổi, service reporting nhân trạng thái thay đổi đơn hàng để kết sinh báo cáo, hay một thay đổi của mysql cần gửi thành công tới kafka…

Có hai yêu cầu với quá trình replicate các thay đổi:

  • Đảm bảo việc gửi thành công message
  • Đảm bảo thứ tự các message

Các kịch bản phổ biến thường được sử dụng trong thực tế:

Service A:

Begin Transation

Write To Database Service A

Call Serivce B To Send Message

End Transaction

hoặc

Begin Transaction

Write To Database Service A

End Transaction

Call Service B To Send Message

Trong hai kịch bản trên bất kỳ sự cố nào như đứt network, ứng dụng crash, server tắt đốt ngột đều có thể dẫn tới sự sai lệch:

  • Trường hợp đầu: nếu việc commit khi End Transaction gặp vấn đề, service B sẽ nhận được message, trong khi service A không thể ghi được dữ liệu vào database của mình thành công
  • Trường hợp thứ hai: nếu việc service A commit database thành công, nhưng send message tới service B lỗi thì B không nhận được message

Để giải quyết vấn đề trên, các kĩ sư của tiki tiếp cận theo hướng xây dựng transaction log để đảm bảo quá trình thay đổi được replicate ổn định. Nguyên lý các thay đổi cần được gửi đi sẽ được insert vào một temporary table đồng thời với quá trình ghi dữ liệu. Một background worker sẽ gửi tuần tự gửi các message đi. Bằng cách đó Service nguồn luôn đảm bảo ghi ổn định đồng thời dữ liệu thay đổi và dữ liệu message cần gửi đi.

Vấn đề tiếp theo cần giải quyết: làm thế nào để background worker có thể biết có các message mới được sinh ra để gửi đi? Có hai hướng tiếp cận để giải quyết vấn đề này:

  • Định kỳ scan table để biết có message mới gửi đi.
  • Tìm cách trigger các thay đổi từ database tới worker

Cách thứ nhất là cách tiếp cận đơn giản nhất dù performance có thể không thật tốt. Nhưng ổn định và dễ triển khai. Đây cũng là cách Kafka Connect sử dụng để tích hợp các database khác nhau với Kafka.

Cách thứ hai thì tuỳ vào đặc trưng của database để xây dựng cơ chế trigger các thay đổi. Nó tốt hơn về performance nhưng cũng đòi hỏi giải quyết nhiều vấn đề phức tạp hơn.

MySql Binary Log là một cơ chế của MySql dùng để lưu trữ các thay đổi của dữ liệu dưới dạng một file log. Tất cả các thay đổi sẽ được lưu thêm vào (append only) vào một file log được đánh số thứ tự. Mỗi thay đổi được đặc trưng bởi hai tham số: file log được ghi vào vị trí offset trên file log. MySql Binlog có ba loại:

  • Statement Based: lưu trữ các câu lệnh làm thay đổi dữ liệu
  • Row based: lưu trữ các dữ liệu thay đổi
  • Mixed: lưu trữ cả statement và data thay đổi của từng row

Tiếp theo đó, mysql hỗ trợ cơ chế replicate binary log. MySql sẽ streamming tất cả các thay đổi của database từ master tới slave. Toàn bộ binary log sẽ được replicate realtime tới slave.

Tiki sử dụng hai cơ chế trên để xây dựng background worker xác định các thay đổi gửi đi:

  • Sử dụng binary log format là row based
  • Worker đóng vai trò là slave để nhận các thay đổi từ master database mysql

Bằng giải pháp như vậy, worker sẽ nhận được các dữ liệu thay đổi real time rồi gửi đến các system đích khác, vd như gửi tới một message queue.

Nhưng việc áp dụng cơ chế binaray log sẽ phát sinh các vấn đề sau cần giải quyết:

  • Quản lý checkpoint: worker có thể tắt đột ngột, nếu khởi động lại làm thế nào để worker biết vị trí offset cuối cùng của file log để quay lại đọc tiếp?
  • MySql ghi log tất cả các thay đổi, worker chỉ lọc ra các thay đổi nhất định gửi đi. Làm thế nào để đảm bảo thứ tự commit checkpoint chính xác với thự tự các checkpoint đọc được?
  • Làm thế nào để đảm bảo performance của worker. Database tiki có thể ghi nhận tới 10k thay đổi một giây. Tất cả các thay đổi được streamming real time cho worker. Nếu worker không xử lý tốt sẽ dẫn tới độ trễ lớn.
  • Các cơ chế retry thế nào để đảm bảo tính chính xác và ổn định tuyệt đối của worker. Một ngày database tiki ghi nhận tầm 50 triệu lần thay đổi. Bất cứ sự rối loạn nào khi xử lý của worker đều có thể dẫn tới sự không ổn định và rất khó để truy vết, khắc phục.

Log là trung tâm của hệ thống phân tán, làm chủ được log là làm chủ được sự ổn định của quá trình tích hợp. Các phần tiếp theo sẽ trình bày tiếp các solution áp dụng để giải quyết lần lượt các vấn đề trên.

Techtalk Via engineering.tiki

0