Có một câu chuyện được kể lại rằng, cách đây rất lâu … à cũng không lâu lắm 😂 một vài năm gì đấy, một thanh niên vẫn đang ngồi trên ghế trường đại học bắt đầu tập tững đi kiếm công việc Fresher Back End với trong kiến thức … chưa bao giờ non như thế. Nhưng ông trời không bao giờ phụ lòng người , anh ta đã tìm được 1 công việc Back End engineer trong 1 team với title cực xịn xò: Data Mining Team.
Những ngày anh ấy đi làm công việc rất suôn sẻ, cho đến khi nhận 1 task nôm na là xử lý những dữ liệu mới được insert vào bảng… nhưng phải realtime (nghe rất đao to bố lớn với 1 anh dev chưa có kinh nghiệm gì nhiều 😂). Việc deadline cận kề từ bài vở trên trường + mới chỉ nếm trải áp lực công việc khiến anh ấy thi thoảng đưa ra 1 số solution cực kì ngáo ngơ.
Và đúng như mong đợi, một ý tưởng không thể nào cồng kềnh hơn được anh ta implement đó là sử dụng loop và liên tục select với sleep time chỉ vỏn vẹn 100ms và ghi vào 1 biến local 😂
Sau 3 tiếng hì hục với ý tưởng đấy. Một cách nào đó a lead đã không review mà được accept merge request lên dev được test ngon lành cành đào và accept lên internal prod. Và buổi chiều đẹp trời ngay hôm đó 1 dòng tin nhắn của a sysadmin nhắn được tinh tinh lên: “Thành ơi!! Sao con xxxx của e chiếm nhiều connection ….”; 😅
Cũng không có gì khó hiểu vì việc tốn tài nguyên không cần thiết trên prod đều được các anh ops nắm đầu ngay.
1. Overview
Từ câu chuyện anh chàng dev vừa rồi (thực ra chả có anh nào ở đây cả 🤣) việc bắt những database bằng việc … “đấm" liên tục database bằng hàng loạt câu select là một Bad Solution cho problem này. Từ việc đi vào lòng đất đấy mình đã tham khảo và binlog của mysql là lựa chọn khá hợp lý cho solution này. Việc mình apply đã giải quyết được hầu hết các vấn đề mình đã kể trên cho task đó và cũng như implement cho những problem khác.
Kết hợp vừa binlog và listen nó sẽ giải quyết được các case việc tích hợp hệ thống, invalidate cache, …
Ok trước khi đi triển khai vào các bài toán, các use case cụ thể thì cùng mình đi tìm hiểu xem nó là gì trước đã nhé. Lets begin!!
2. Basic concept
2.1. What is binlog?
Hiểu đơn giản nó là một chuỗi các event được append vào trong file log được encode dưới dạng nhị phân; Nó mô tả các thay đổi với database cũng như các thao tác thay đổi dữ liệu với một table. Nó sinh ra với 2 mục đích chính :
- Đồng bộ dữ liệu: Trong mô hình replication, các thao tác thay đổi trên master sẽ được đồng bộ sang slave bằng cách các event xảy ra ở master sẽ được ghi vào binlog và gửi sang các node slave. Nó sẽ thực hiện lại các event trong binlog để tiến hành sync data.
- Khôi phục dữ liệu: Khi hệ thống gặp sự cố, các bản backup dữ liệu có thể không đủ để bạn có lại data toàn vẹn. Khi đó bạn có thể sử dụng lại binlog để chạy lại nhưng câu lệnh sau thời điểm data được backup.
2.2 Cấu trúc của binlog
Mysql sẽ lưu trữ 1 list các file ở vị trí mặc định hoặc ở vị trí chúng ta config. File binlog sẽ được tạo mới khi:
- Size của file vượt quá config
max_binlog_size
(mặc định sẽ là 1GB) - Db server reset
- Option flush log được gọi. Vd: Trong
mysqldump
có 1 flag—flush-logs
Bên trong nội dung 1 file binlog nó sẽ chứa các event dưới dạng nhị phân. Mỗi event đại diện cho một thao tác hoặc một nhóm thao tác trên cơ sở dữ liệu (1 transaction thành công sẽ được ghi nhận là 1 event)
Khi select ta có thể thấy 6 thành phần chính trong 1 event binlog:
Log_name
: Tên của file log.Pos
: Vị trí bắt đầu ghi của event trong file, và được encode, tổ chức dưới dạng binary.Event_type
: Loại event mà mình sẽ làm rõ ở mục sau.Server_id
: Id của server, nó sẽ liên quan đến mô hình replication. (Ngữ cảnh này nó xác định nguồn gốc file log)End_log_pos
: Vị trí cuối cùng của event được ghi trong file.Info
: Nội dung của event, có thể hiểu nó là nội dung decode → bắt đầu từ vị trí pos đến**End_log_pos**
.
Khi query event chúng ta sẽ không thấy rõ data được thay đổi như thế nào. Nếu muốn biết rõ chúng ta phải sử dụng utility mysqlbinlog log_file(Ex: ** mysqlbinlog -u root -p123456 -v --base64-output=DECODE-ROWS DESKTOP-37B1HHA-bin.000002**
)
2.3 Format
Có 3 format để lưu trữ 1 event:
STATEMENT
: Lưu trữ các statement làm thay đổi dữ liệu.ROW
: Lưu trữ các dữ liệu thay đổi.MIXED
: Lưu trữ cả statement làm thay đổi và dữ liệu thay đổi.
2.4. Event Type
Có khá nhiều event được define và nó đang và sẽ trong database.
Nhưng mục đích chính của chúng ta chỉ quan tâm đến những Event liên quan làm thay đổi dữ liệu trong database và capture chúng. Các Event Type sẽ nằm trong Header của mỗi Event. Dựa vào Header chúng ta có thể xây dựng 1 receiver client để tiến hành các logic.
Query events
: Những sự kiện này chứa các SQL statement được thực thi trên máy chủ cơ sở dữ liệu.Table Map events
: Những sự kiện này lưu trữ thông tin về cấu trúc của bảng bị thay đổi.Write Rows events
: Những sự kiện này thể hiện việc thêm record vào bảng.Update Rows events
: Những sự kiện này thể hiện việc modify 1 row tồn tại trong bảng.Delete Rows events
: Những sự kiện này thể hiện việc xóa 1 row tồn tại trong bảng.Xid Events
: Những sự kiện này thể cho việc kết thúc transaction.Rotate Events
: Những sự kiện này thể hiện cho việc khi quá trình ghi log tiến hành ở 1 file mới.
4. Conclusion
Việc enable binlog sẽ có thể chiếm 1 lượng tài nguyên lưu trữ khá lớn của hệ thống và làm cho hiệu suất chậm đi một chút. Chúng ta có thể hoàn toàn config tránh việc storage của hệ thống bị đầy.
Tuy nhiên, lợi ích của binlog cho phép bạn thiết lập sao chép, khôi phục và cũng nhưng tích vào hệ thống event capture thường lớn hơn sự suy giảm hiệu suất nhỏ này.
Ở bài viết sau chúng ta sẽ tiến hành triển khai 1 java app listen những thay đổi dữ liệu trong database trước khi chúng ta đến với các use case cụ thể. Các bạn đón chờ nhé.