Master-Master Replication bằng Dynomite, giải pháp High Availability và Multithreading dành cho RedisDB

| Thứ Ba, 3 tháng 10, 2017
Mình đang xây dựng một hệ thống sử dụng RedisDB chủ yếu như là một lớp lưu trữ và caching gọn lẹ.
Performance của RedisDB thực sự tốt cho dự án. Và sau khi sử dụng RedisDB một thời gian, mình nhận thấy có một số khuyết điểm như sau:
1. Khi mình quyết định tạo 1 server cluster khác, tại một vùng khác và cần replicate lớp database, tôi đã gặp một problem lớn...

2. Redis làm việc đơn luồng, nên nó chỉ sử dụng 1 trong 12 CPU core của server, rất là lãng phí.
Redis đã support sẵn việc replicate trong file cấu hình, nhưng nó chỉ là "Single master — Multi slave", vì vậy tốc độ đọc của nó cũng tốt, trong khi tốc độ write từ server cluster vào trong con RedisDB master thì rất chậm.

Đó chính là lý do vì sao mình cần phải tìm cách Master-Master replication cho RedisDB, thế mà mình tìm thấy Dynomite! (https://github.com/Netflix/dynomite/)
Dynomite lấy cảm hứng từ Dynamo whitepaper, đơn giản, nó phân phối các lớp dynamo cho các storage engine và protocal khác nhau. Hiện tại đã có trong Redis và Memcached. Dynomite hỗ trợ multi-datacenter replication và được design cho các hệ thống high availability.
Sử dụng Dynomite không chỉ giúp chúng tôi có được master-master replication cho RedisDB mà còn giúp nó chạy đa luồng với tính sẵn sàng cao
Bắt đầu nào!

Đầu tiên, bạn có thể đọc topology của Dynomite để hiểu Datacenter là gì, rack là gì, etc...(https://github.com/Netflix/dynomite/wiki/Topology)
Lần setup này, mình có 2 datacenter (cho 2 cluster server) gọi là A và B, mỗi datacenter có 1 rack, mỗi rack có 2 node(dành cho 2 redis instance, việc này giúp mình chạy redis database trên 2 luồng)
Chạy nhiều redis instance trên 1 server
Sau đó, chúng ta cần install redis và học cách chạy multiple redis instance trên 1 con server, hoặc bạn có thể clone cái redis instance hiện tại vào các con server khác. Xem link này 

Nếu bạn đang sử dụng systemd, dưới đây là scirpt có thể hữu ích:

[Unit]
Description=Redis
After=network.target
[Service]
Type=simple
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis_6381.conf
ExecStop=/usr/local/bin/redis-cli -p 6381 shutdown
Restart=always
[Install]
WantedBy=multi-user.target
Đối với file .isf của Redis:
Make sure:
daemonize no
supervised systemd
Lưu ý là .conf của redis phải có quyền read để systemd có thể run. Check permission với ls -lh và bạn có thể run câu lệnh chmod 644 redis.conf
Setup Dynomite trên các server
Bắt đầu build lớp dynomite trên datacenter(server A)

$ cd /root
$ git clone git@github.com:Netflix/dynomite.git
$ cd dynomite
$ autoreconf -fvi
$ ./configure --enable-debug=yes
$ make
$ src/dynomite -h

Tạo vài file . yaml để chạy với Dynomite.
Bạn có thể học các viết chúng tại đây:
Example for .yaml files
Dưới đây là file .yaml trên server A (1.0.0.1) và B (1.0.0.2):
/root/dynomite/yaml_files/a-rack1-node1.yaml (For server A)
dyn_o_mite:
  datacenter: dc-a
  rack: rack1
  dyn_listen: 1.0.0.1:7379
  dyn_seeds:
  - 1.0.0.1:7380:rack1:dc-a:2147483647
  - 1.0.0.2:7379:rack1:dc-b:0
  - 1.0.0.2:7380:rack1:dc-b:2147483647
  listen: 0.0.0.0:8379
  servers:
  - 127.0.0.1:6379:1
  tokens: '0'
  secure_server_option: datacenter
  pem_key_file: dynomite.pem
  data_store: 0
  stats_listen: 127.0.0.1:22222
  read_consistency : DC_QUORUM
  write_consistency : DC_QUORUM
/root/dynomite/yaml_files/a-rack1-node2.yaml (cho server A) 
dyn_o_mite:
  datacenter: dc-a
  rack: rack1
  dyn_listen: 1.0.0.1:7380
  dyn_seeds:
  - 1.0.0.1:7379:rack1:dc-a:0
  - 1.0.0.2:7379:rack1:dc-b:0
  - 1.0.0.2:7380:rack1:dc-b:2147483647
  listen: 0.0.0.0:8379
  servers:
  - 127.0.0.1:6380:1
  tokens: '2147483647'
  secure_server_option: datacenter
  pem_key_file: dynomite.pem
  data_store: 0
  stats_listen: 127.0.0.1:22223
  read_consistency : DC_QUORUM
  write_consistency : DC_QUORUM
/root/dynomite/yaml_files/b-rack1-node1.yaml (cho server B) 
dyn_o_mite:
  datacenter: dc-b
  rack: rack1
  dyn_listen: 1.0.0.2:7379
  dyn_seeds:
  - 1.0.0.2:7380:rack1:dc-a:2147483647
  - 1.0.0.1:7379:rack1:dc-b:0
  - 1.0.0.1:7380:rack1:dc-b:2147483647
  listen: 0.0.0.0:8379
  servers:
  - 127.0.0.1:6379:1
  tokens: '0'
  secure_server_option: datacenter
  pem_key_file: dynomite.pem
  data_store: 0
  stats_listen: 127.0.0.1:22222
  read_consistency : DC_QUORUM
  write_consistency : DC_QUORUM
/root/dynomite/yaml_files/b-rack1-node2.yaml (cho server B) 
dyn_o_mite:
  datacenter: dc-b
  rack: rack1
  dyn_listen: 1.0.0.2:7380
  dyn_seeds:
  - 1.0.0.2:7379:rack1:dc-a:0
  - 1.0.0.1:7379:rack1:dc-b:0
  - 1.0.0.1:7380:rack1:dc-b:2147483647
  listen: 0.0.0.0:8379
  servers:
  - 127.0.0.1:6380:1
  tokens: '2147483647'
  secure_server_option: datacenter
  pem_key_file: dynomite.pem
  data_store: 0
  stats_listen: 127.0.0.1:22223
  read_consistency : DC_QUORUM
  write_consistency : DC_QUORUM
Một số lưu ý:
Mình giả sử là chúng ta có 2 redis instances chạy trên mỗi server, port 6379, 6380. Và không yêu cầu pass(vì dynomite không accept câu lệnh AUTH )
Công thức token là (nodeIndex is 0-based): token = (4294967295 / numberOfNodesInRack) * nodeIndex
Chúng ta cần mở cổng 7379 và 7380 giữa 2 server để Dynomite sử dụng những port này cho việc truyền data(config trong dyn_listen)
Bạn có thể lấy file dynomite.pem tại dynomite/conf/dynomite.pem
Bạn có thể tạo nhiều rack trên 1 máy chủ đơn(hoặc trên 1 cluster để RedisDB được high availability)
Xong, giờ chạy Dynomite
(Nếu bạn không thích chạy dynomite một cách thủ công như vậy, hãy cuộn xuống để xem phần setup systemd)
Trên server A:
Terminal 1: $ dynomite -c a-rack1-node1.yml
Terminal 2: $ dynomite -c a-rack1-node2.yml
Trên server B:
Terminal 1: $ dynomite -c b-rack1-node1.yml
Terminal 2: $ dynomite -c b-rack1-node2.yml

Đây chỉ là cách để start dynomite, mình đề nghị bạn nên setup dynomite sử dụng systemd hoặc vài hệ thống tương tự để giúp nó tự động restart trong trường hợp bị crash

Rồi, giờ Dynomite đang chạy, redis database của bạn đã được master-master replicated giữa 2 server, RedisDB chạy trên 2 luồng trên mỗi server, bạn có thể access đến RedisDB trên mỗi server sử dụng cổng 8379 hoặc 8380(config at listen: 0.0.0.0:8379)


Terminal 1: Access redis on server A
$ redis-cli -h 1.0.0.1 -p 8379
$ > SET test 123
Terminal 2: Access redis on server B
$ redis-cli -h 1.0.0.2 -p 8380
$ > GET test 
# You should see output result: 123


Dynomite trong Production: Setup Dynomite chạy như một service sử dụng systemd
Trong production, bạn không muốn chạy Dynomite bằng tay thủ công như trên vì đôi lúc nó sẽ bị crash(hiếm khi, nhưng nó xảy ra với mình 2 lần rồi đó!) và gây nên vấn đề downtime nghiêm trọng cho RedisDB của bạn. Vì vậy rất cần chạy chúng trong môi trường ảo hóa để giúp recover thằng Dynomite lại khi nó crash.
Mình dùng Ubuntu 16 vì vậy nó hoàn hảo cho việc này, Systemd, một hệ thống init được sử dụng trong các Linux distro để bootstrap các user space.
Mỗi dynomite node, chúng ta sẽ tạo một systemd service  riêng biệt cho nó. Giờ hãy vào server A trong thư mục /etc/systemd/system/, chúng ta tạo 1 file mới ‘dynomite_rack1_node1.service’ với nội dung như sau:

[Unit]
Description=Dynomite - Rack 1 - Node 1
ConditionPathExists=/root/dynomite
After=network.target

[Service]
Type=simple
User=root
Group=root
LimitNOFILE=1024

Restart=on-failure
RestartSec=1
startLimitIntervalSec=60

WorkingDirectory=/root/dynomite
ExecStart=/usr/local/sbin/dynomite -c /root/dynomite/yaml_files/a-rack1-node1.yaml

PermissionsStartOnly=true

[Install]
WantedBy=multi-user.target


Rồi, giờ load một service dynomite mới:
$ systemctl daemon-reload
$ systemctl enable dynomite_rack1_node1$ systemctl start dynomite_rack1_node1
Sau đó check status của nó
$ systemctl status dynomite_rack1_node1
Hơn nữa, bạn có thể check lại log bằng câu lệnh:
$ journalctl -f -u dynomite_rack1_node1



Đã xong node1 trong rack1 của datacenter A. Bạn có thể làm tương tự cho 3 node còn lại, chỉ cần tạo script tương tự nhưng khác đường dẫn cho các .yaml. Từ bây giờ, Dynomite sẽ tự động chạy lúc server reboot và nó sẽ recover lại mội khi crash. Không còn lo gì nữa.

0 nhận xét:

Đăng nhận xét

Next Prev
▲Top▲