Câu chuyện bắt đầu vào một buổi tối thu đầy gió và khói bụi tại quán bia hơi gần United Park. L và M, 2 developer tại công ty T nọ, tranh thủ chém gió sau một ngày cày sml

L: Ổn không M ?

M: Uhm, tôi ổn. À mà thực ra cũng đ** ổn lắm.

L: Vẫn là chuyện liên quan đến thằng Citus à ?

M: Uhm. Cứ tưởng nó chạy ổn. Ai ngờ đến phút cuối lại lòi ra một lỗi chẳng đâu vào đâu

L: Lỗi chi dợ ?

M: Nó đếch hỗ trợ foreign key constraint giữa 2 reference table ông ạ. Thế mới cay chớ !

L: Reference table ? 

M: Nó là ... À từ từ ! Tôi quên mất là ông đang quay cuồng với vụ DevOps nên không nắm rõ lắm về thằng Citus này. Để tôi tường thuật lại từ đầu cho

L: OK ! Tôi gọi 2 cốc nữa để ông tâm hự cho nó trôi chảy

M: Quá hay ! OK câu chuyện nó là như này: Chắc ông cũng biết là database dự án mình đang để ở 1 server ?

L: Đúng. Nó đang ở trên máy X. Sao ?

M: Hiện nó vẫn đang chạy ổn, nhưng đấy là bây giờ thôi. Sau này số lượng request nó nhiều lên ...

L: Ông sợ nó gánh không nổi ?

M: Uhm, nó mà lăn đùng ra chết thì anh em ra đê ở hết

L: Thế thì mình nhân bản cái database ấy ra nhiều máy khác nhau

M: Chính xác ! Trông ông thế mà cũng thông minh phết. Thằng Citus này sẽ giúp mình làm điều đó

L: Thế ông chạy thử trên máy ông chưa ?

M: Tôi chạy thử rồi. Tôi làm theo hướng dẫn trên trang http://docs.citusdata.com/en/v7.5/installation/single_machine_docker.html. Cài đặt bằng Docker. Sau khi cài xong thì tôi có 2 Docker Container: citus_master và citus_worker_1, mỗi cái chứa một PostgreSQL database

L: OK xong sao nữa ?

M: Theo yêu cầu của dự án mình toàn bộ bảng ở database trên máy X sẽ được copy sang database trên máy Y. Và dữ liệu ở 2 database này sẽ được đồng bộ với nhau, ý tôi là mỗi khi ông thực hiện thay đổi ở một bảng trên máy X thì ...

L: ... thì ở bảng tương ứng trên máy Y dữ liệu cũng sẽ thay đổi theo

M: Yep ! Và thằng Citus cung cấp cho mình một tính năng là reference table đáp ứng chính xác nhu cầu này.

L: Thế ông chạy thử thế nào ?

M: Quy trình là như này nhé:

1. Đầu tiên tôi tạo 2 bảng users và posts bên citus_master

2. Sau đó tôi chạy hàm

SELECT create_reference_table('users');
SELECT create_reference_table('posts');

để nhân bản 2 bảng này sang bên citus_worker_1

https://gist.github.com/handuy/394511e84ff3380f3764bafa277f2a52

3. Nhân bản xong thì tôi INSERT/DELTE/UPDATE dữ liệu ở citus_master và  citus_worker_1 để check xem dữ liệu 2 bên có đồng nhất với nhau không

4. Sau đó ở citus_master tôi tạo một schema là course, trong schema course tôi tạo một bảng lessons, rồi tôi thực hiện các lệnh INSERT/DELETE/UPDATE lên bảng course.lessons và tôi check xem bên citus_worker_1 có bảng lessons ở schema course tương ứng hay không

https://gist.github.com/handuy/e88b2284c4480a60e8464e6ac0417f76

5. Cuối cùng, tôi thử tạo 1 bảng series ở citus_worker_1 và check xem ở citus_master có bảng tương ứng hay không

https://gist.github.com/handuy/0336c4e8952ae2ea0f74ce135c740ab1

L: Kì công phết nhỉ. Vậy kết quả thế nào ?

M: Bảng nào được tạo ở citus_master thì cũng sẽ được tạo ra ở bên citus_worker_1, trường hợp tạo 1 schema rồi mới tạo bảng thì ở bên citus_worker_1 cũng sẽ có schema và bảng tương ứng. Còn nếu như tạo bảng ở citus_worker_1 thì citus nó sẽ báo lỗi:

ERROR:  cannot create reference table "series"
DETAIL:  There are no active worker nodes.

nghĩa là ông không thể copy dữ liệu từ citus_worker_1 sang citus_master được

L: Xem ra có vẻ ổn đấy chứ nhỉ ?

M: Uhm ban đầu tôi cũng nghĩ thế. Cho đến khi tôi gặp trường hợp một bảng có foreign key constraint link đến bảng khác:

ERROR: cannot create foreign key constraint because reference tables are not supported as the referencing table of a foreign constraint

DETAIL: Reference tables are only supported as the referenced table of a foreign key when the referencing table is a hash distributed table

Ông chạy thử file này thì biết:

https://gist.github.com/handuy/97ca5cdbee12f1a0d4ec89872ffe6831

Tôi còn tạo hẳn issue trên github, ông có thể xem câu trả lời của Citus:


https://github.com/citusdata/citus/issues/2378#issuecomment-420623639

L: Sao ông không thử drop foreign key constraints trước, sau đó chạy hàm create_reference_table, rồi cuối cùng mới tạo lại foreign key constraints ?

M: Tôi cũng đã xài thử kế đó rồi ông ạ. Vẫn đ** ăn thua ! Sau khi drop foreign key constraint xong thì đúng là có tạo reference table được thật, nhưng khổ nỗi đến bước tạo lại foreign key constraint thì citus nó lại đếch cho tạo. Thế mới khốn nạn đời tôi chứ lị:

https://gist.github.com/handuy/04129ae754b3d7d171a5744a07f6bc16

M: Mà tôi hỏi ông, foreign key contraint là cái hết sức cơ bản, không có thì còn ra thể thống gì nữa chớ !

L: Uhm ok tôi hiểu. Thôi ông làm cốc bia đã !

M: *Ực ực ực*

L: Thế giờ ông tính sao ? Không tạo database dự phòng nữa à ?

M: Hihi, thực ra không xài Citus thì tôi vẫn còn cách khác. Sợ gì ! Quân tử phải biết chừa đường lui chớ

L: Ghê dữ ha ! Cách chi dợ ?

M: Tôi xài Streaming Replication được hỗ trợ sẵn trong PostgreSQL. Ngon hết xảy luôn ! Cái này để tuần sau tôi nói cho ông nha. Giờ muộn rồi anh em mình về mai còn cày tiếp

L: OK !