CDC atau Change Data Capture adalah metode untuk menangkap/mencatat semua perubahan data pada database, baik itu data UPDATE, DELETE termasuk juga INSERT.
Ada beberapa metode CDC:
- CDC dengan MySQL trigger
- CDC dengan Timestamp
- CDC dengan Binary log
Disini kita akan belajar bagaimana melakukan CDC dengan binary log pada MySQL 8.0.36.
Alur CDC
Contoh CDC dengan binary log, misalkan ada INSERT data baru pada database, maka data INSERT tersebut akan ditangkap/capture/disimpan kedalam log MySQL, yang disebut binary log. Kemudian binary log tersebut dikonsumsi oleh go-mysql-replication (istilahnya pipeline), lalu datanya dikirim ke data warehouse untuk kebutuhan analytics.
Jadi setelah binary log terbuat, go-mysql-replication akan mengkonsumsi / membaca isi file binary log (yang mana berisi statement INSERT, UPDATE dan DELETE). Setelah dibaca, data akan dikirim ke data warehouse.
Namun, disini kita hanya akan belajar sampai go-mysql-replication saja (tidak sampai kirim data ke data warehouse). Di go-mysql-replication kita akan belajar bagaimana membaca isi file binary log menggunakan bahasa pemrograman golang.
Prerequisites
- MySQL 8.0.36
- go versi 1.22.1
- go-mysql-replication versi 1.7.0
- Ubuntu 22.04
Setup binary log di MySQL
Untuk mengaktifkan binary log, kita harus setup dulu konfigurasinya. Buka file mysqld.conf. Disini saya menggunakan Ubuntu 22.04.
vi /etc/mysql/mysql.conf.d/mysqld.cnf
Lalu tambahkan konfigurasi berikut dibaris paling akhir mysqld.conf
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_expire_logs_seconds = 2592000
max_binlog_size = 100M
binlog_row_image = FULL
binlog_row_metadata = FULL
binlog_format = ROW
Penjelasan:
- server-id, ID unik untuk server MySQL. Diperlukan ketika mengaktifkan binary log.
- log_bin, dimana file binary log disimpan. Dalam contoh ini, akan disimpan di /var/log/mysql/mysql-bin.log. Maksud dari mysql-bin.log, artinya akan terbuat file dengan incremental number yaitu mysql-bin.000001, mysql-bin.000002, dst.
- binlog_expire_logs_seconds, berapa lama file binary log disimpan. 259200 seconds artinya hanya 3 hari file binary log akan disimpan. Jika lebih dari itu, maka file lamanya akan dihapus secara otomatis.
- max_binlog_size, ukuran maksimal pada masing-masing file binary log. Contoh diset 100M, maka file mysql-bin.000001 berukuran maksimal sebesar 100M, mysql-bin.000002 sebesar 100M juga, dst.
- binlog_row_image, diset FULL agar data sebelum dan sesudah UPDATE disimpan juga ke binary log. Contoh, misal data ‘ABCD’ di UPDATE menjadi ‘DCBA’. Maka ABCD dan DCBA akan tersimpan semua di binary log.
Kira-kira seperti ini lognya: - binlog_row_metadata, diset FULL agar metadata tersimpan juga di binary log. Contoh metadata yang akan tersimpan adalah nama kolom pada database.
- binlog_format, diset ROW agar semua perubahan per ROW tercapture. Misal kita melakukan UPDATE yang berefek mengubah beberapa rows, dimana kolom class A terdapat 2 rows:
UPDATE tb_test SET column2='SAMA' WHERE class='A';
Maka di binary log akan tertulis sebanyak 2 log:
Setelah itu restart mysql
service mysql restart
Cek di MySQL, seharusnya binary log sudah mulai tergenerate:
SHOW MASTER STATUS;
Contoh diatas, posisi binary log berada pada file mysql-bin.000055 dan posisi (byte) ke 157.
Kita juga bisa lihat di folder /var/log/mysql akan ada file mysql-bin.000055 disana:
Download go-mysql-replication
Pastikan go sudah terinstall dulu di komputer kalian. Go yang saya gunakan versi 1.22.1.
Setelah go terinstall, kita siapkan dulu workspace projectnya. Saya akan taruh projectnya di /home/<user>/my_go_project.
cd /home/moko/
mkdir my_go_project
cd my_go_project
Lalu init dulu go projectnya. Saya beri nama projectnya go-mysql-replication
go mod init go-mysql-replication
Download go-mysql-replication versi 1.7.0
go get github.com/go-mysql-org/go-mysql@v1.7.0
Test go-mysql-replication
Sekarang lanjut ke codingan. Contoh codingannya sudah ada digithub officialnya disini.
Kita buat 1 file dengan nama main.go. Lalu masukkan script dibawah ini. Yang diblock tebal harap sesuaikan dengan credential mysql kalian. ServerID=100 adalah ID server untuk go-mysql-replication, kalian bisa ubah IDnya sesuka kalian (kecuali ID 1, karena sudah dipakai diatas).
Kemudian set posisi binary lognya ke mysql-bin.000055 dan 157 sesuai yang diatas.
main.go
package main
import (
"github.com/go-mysql-org/go-mysql/replication"
"os"
"github.com/go-mysql-org/go-mysql/mysql"
"context"
"time"
)
func main() {
// Create a binlog syncer with a unique server id, the server id must be different from other MySQL's.
// flavor is mysql or mariadb
cfg := replication.BinlogSyncerConfig {
ServerID: 100,
Flavor: "mysql",
Host: "127.0.0.1",
Port: 3306,
User: "root",
Password: "abcd",
}
syncer := replication.NewBinlogSyncer(cfg)
// Start sync with specified binlog file and position
streamer, _ := syncer.StartSync(mysql.Position{"mysql-bin.000055", 157})
// or you can start a gtid replication like
// streamer, _ := syncer.StartSyncGTID(gtidSet)
// the mysql GTID set likes this "de278ad0-2106-11e4-9f8e-6edd0ca20947:1-2"
// the mariadb GTID set likes this "0-1-100"
for {
ev, _ := streamer.GetEvent(context.Background())
// Dump event
ev.Dump(os.Stdout)
}
// or we can use a timeout context
for {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
ev, err := streamer.GetEvent(ctx)
cancel()
if err == context.DeadlineExceeded {
// meet timeout
continue
}
ev.Dump(os.Stdout)
}
}
Kemudian jalankan:
go mod tidy
go run main.go
Jika berhasil, maka akan tampil seperti ini:
Jika kita test INSERT data baru, misal seperti ini:
Maka diterminal akan ada data baru:
Test update data:
Di terminal akan ada data updatenya:
Test delete data:
Kesimpulan
- Insert data akan tercapture dengan event: WriteRowsEventV2
- Update data, event: UpdateRowsEventV2
- Delete data, event: DeleteRowsEventV2
Ditutorial selanjutnya kita akan belajar cara mengextract data dari event WriteRowsEventV2, UpdateRowsEventV2, dan DeleteRowsEventV2. Akan saya update linknya disini.