Bối cảnh
Bạn dùng redis để đệm dữ liệu cho 1 ứng dụng chat.
Một ngày đẹp trời, bạn đang đi nhậu với chiến hữu, sếp điện thoại kêu lên công ty gấp, server bị sập không truy cập được.
Bạn lật đật giã từ vũ khí và chạy lên công ty…
Server bị sập thì có vô vàn lý do: loại trừ lý do chủ quan là code cùi, code lỗi, thì còn các lý do khách quan mà không ai muốn nó xảy ra cả: server bảo trì, data center bị chập điện, rớt mạng, phần mềm trong máy xung đột, server bị virus…
Lúc này bạn sẽ nghĩ đến chuyện làm sao để nếu server có cúp điện thì hệ thống mình vẫn chạy bình thường. Google 1 hồi nó sẽ dẫn bạn đến khái niệm High Availability: khả năng đáp ứng cao.
High Availability – HA
HA được hiểu nôm na là (1) hệ thống mình có khả năng phục vụ liên tục và (2) chịu nhiệt cao (tức là khi nhiều người yêu cầu phục vụ thì anh cũng cân được tuốt).
Bài viết này mình sẽ tập trung vào mục (1).
Redis replication
Là phương pháp sử dụng “lính dự bị”, lên đảm nhiệm vai trò của “lính chủ lực” khi ông chủ lực kiệt sức chết.
Mình sẽ sử dụng 1 thằng chủ lực (master) và 2 thằng dự bị (slave).
Tổng cộng sẽ cần 3 server vật lý, sau này sẽ gọi là node để khỏi nhầm lẫn với redis server.
3 node này có IP lần lượt là:
master: 223.223.223.100
slave-1: 223.223.223.101
slave-2: 223.223.223.102
Cài đặt redis
Mình sử dụng Ubuntu 16.04.
Cài redis vào CẢ 3 NODE
sudo apt-add-repository ppa:chris-lea/redis-server
sudo apt-get update
sudo apt-get install redis-server -y
Cấu hình cho node master
Ở node master, mở file /etc/redis/redis.conf
lên và cấu hình:
Tìm đến dòng bind 127.0.0.1, đây là khai báo redis server sẽ lắng nghe request ở đâu.
Với cấu hình mặc định thì nó chỉ lắng nghe từ localhost (hiện tại đang là dòng 69) nên mình đổi về IP của node:
bind 223.223.223.100 127.0.0.1
Lưu lại file sau đó khởi động lại redis server:
sudo systemctl restart redis-server.service
Test thử server master
$ redis-cli -h 223.223.223.100
223.223.223.100:6379> info replication
Redis master output
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
Mặc định, redis server sẽ chạy ở cổng 6379.
Ghi dữ liệu vào để lát nữa đọc thử từ slave ra:
223.223.223.100:6379> set test 'this key was defined on the master server'
OK
Thoát redis server:
223.223.223.100:6379> exit
Cấu hình cho các node slave
Trên 2 node slave:
Trước khi cấu hình thì kết nối vào server để đảm bảo rằng nó chưa có dữ liệu bên master (tất nhiên )
$ redis-cli
127.0.0.1:6379> get test
(nil)
Tiếp đến, mở file /etc/redis/redis.conf
lên và cấu hình:
bind 223.223.223.101 127.0.0.1
slave 2:
bind 223.223.223.102 127.0.0.1
Tiếp, tìm đến dòng có slaveof <masterip> <masterport>
(dòng 281), điền vào:
slaveof 223.223.223.100 6379
hoặc
replicaof
Cấu hình này sẽ khai báo đây là node dự bị (slave) cho node chính 223.223.223.100 và liên lạc với nó thông qua cổng 6379-cổng mà bên kia đang lắng nghe.
OK, lưu lại rồi khởi động lại redis server:
sudo systemctl restart redis-server.service
Test thử server slave
Bây giờ mình sẽ vào server slave và đọc dữ liệu ở bên server master ra:
$ redis-cli
223.223.223.101:6379> get test
'this key was defined on the master server'
Kiểm tra thông tin về replication:
223.223.223.101:6379> info replication Redis slave output
# Replication
role:slave
master_host:223.223.223.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:1387
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
Nếu bạn kiểm tra thông tin tương tự bên server master thì sẽ thấy có chút cập nhật so với lúc nãy:
master$ redis-cli
223.223.223.100:6379> info replication Redis master output
# Replication
role:master
connected_slaves:2
slave0:ip=223.223.223.101,port=6379,state=online,offset=1737,lag=1
slave0:ip=223.223.223.102,port=6379,state=online,offset=10000,lag=1
master_repl_offset:1737
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:1736
OK, đến đây là xong phần redis replication. Tiếp đến, mình dùng sentinel để quản lý việc đưa salve lên làm master khi ông master bị down.
Sentinel
Cơ chế hoạt động
- Các sentinel sẽ luôn quan sát master server, khi master sập, các sentinels sẽ loan truyền nhau 1 tín hiệu sdown: tao thấy đại ca chết rồi thì phải.
- Khi đủ 1 số lượng n sentinel đồng ý rằng tao cũng thấy master sập rồi, tụi sentinels sẽ loan tiếp tín hiệu odown: nó thực sự chết rồi đó.
- Lúc này, tụi sentinels sẽ bầu chọn ra 1 slave để nâng cấp lên làm master mới, đồng thời cập nhật các cấu hình theo bộ máy chính quyền mới.
- Khi thằng master kia sống lại, nó sẽ được tham gia vào băng nhóm với vai trò slave.
Cài đặt và cấu hình
Cài đặt sentinel trên CẢ 3 NODE:
$ sudo apt-get install redis-sentinel -y
Mở file /etc/redis/sentinel.conf
và cấu hình:
daemonize yes
pidfile "/var/run/redis/redis-sentinel.pid"
logfile "/var/log/redis/redis-sentinel.log" bind 223.223.223.100
port 26379 sentinel monitor mymaster 223.223.223.100 6379 2
sentinel down-after-milliseconds mymaster 2000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
- bind 223.223.223.100: báo cho các sentinel ở node khác biết rằng tao đang lắng nghe ở địa chỉ này.
- port 26379: để cho dễ nhớ thì thường là lấy cổng của redis + 20000 rồi làm cổng sentinel.
- sentinel monitor mymaster 223.223.223.100 6379 2: lệnh này khai báo tao sẽ lắng nghe thằng master ở địa chỉ 223.223.223.100:6379, tham số cuối cùng (2) là số lượng sentinel tối thiểu để tham gia việc bầu chọn (lúc xác định đại ca chết, và bầu đại ca mới), mymaster là cái tên thôi.
- sentinel down-after-milliseconds mymaster 2000: sau 2000 mili giây mà không thấy đại ca phản hồi thì tao sẽ loan tin sdown đi.
- 2 config cuối cùng thì bạn có thể đọc thêm ở file config mặc định
Config cho 2 slave server cũng tương tự cho master, chỉ khác 1 chỗ duy nhất là địa chỉ để bind-dùng IP của slave server tương ứng:
daemonize yes
pidfile "/var/run/redis/redis-sentinel.pid"
logfile "/var/log/redis/redis-sentinel.log" bind 223.223.223.101
port 26379 sentinel monitor mymaster 223.223.223.100 6379 2
sentinel down-after-milliseconds mymaster 2000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
OK, bây giờ khởi động lại cả 3 sentinel:
sudo systemctl restart redis-server.service
Kiểm tra việc bầu cử
Đầu tiên, mở các file log ra để xem diễn biến băng nhóm:
master$ tailf /var/log/redis/redis-sentinel.log
_._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 3.0.2 (01888d1e/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 16379 | `-._ `._ / _.-' | PID: 57464 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 57464:X 07 Jul 16:33:18.109 # Sentinel runid is 978afe015b4554fdd131957ef688ca4ec3651ea1
57464:X 07 Jul 16:33:18.109 # +monitor master mymaster 223.223.223.100 6379 quorum 2
57464:X 07 Jul 16:33:18.111 * +slave slave 223.223.223.101:6381 223.223.223.101 6379 @ mymaster 223.223.223.100 6379
57464:X 07 Jul 16:33:18.205 * +sentinel sentinel 223.223.223.101:16379 223.223.223.101 16379 @ mymaster 223.223.223.100 6379
57464:X 07 Jul 16:33:18.111 * +slave slave 223.223.223.102:6381 223.223.223.102 6379 @ mymaster 223.223.223.100 6379
57464:X 07 Jul 16:33:18.205 * +sentinel sentinel 223.223.223.102:16379 223.223.223.102 16379 @ mymaster 223.223.223.100 6379
Kiểm tra xem ai đang là master
$ redis-cli -p 26379 sentinel get-master-addr-by-name mymaster 1) "223.223.223.100" 2) "6379"
Đánh sập master để bầu master mới Trên master server:
master$ sudo systemctl stop redis-server.service
Nhìn vào log, bạn sẽ thấy thông tin về việc loan tin và bầu cử:
57464:X 07 Jul 16:35:30.270 # +sdown master mymaster 223.223.223.100 6379
57464:X 07 Jul 16:35:30.301 # +new-epoch 1
57464:X 07 Jul 16:35:30.301 # +vote-for-leader 2a4d7647d2e995bd7315d8358efbd336d7fc79ad 1
57464:X 07 Jul 16:35:30.330 # +odown master mymaster 223.223.223.100 6379 #quorum 3/2
57464:X 07 Jul 16:35:30.330 # Next failover delay: I will not start a failover before Tue Jul 7 16:35:50 2015
57464:X 07 Jul 16:35:31.432 # +config-update-from sentinel 223.223.223.101:16379 223.223.223.101 16379 @ mymaster 223.223.223.101 6379
57464:X 07 Jul 16:35:31.432 # +switch-master mymaster 223.223.223.101 6379 223.223.223.101 6379
57464:X 07 Jul 16:35:31.432 * +slave slave 223.223.223.102:6379 223.223.223.102 6379 @ mymaster 223.223.223.101 6379
57464:X 07 Jul 16:35:36.519 # +sdown slave 223.223.223.102:6379 223.223.223.102 6379 @ mymaster 223.223.223.101 6379
Giờ thì kiểm tra xem cháu nào được lên làm đại ca:
$ redis-cli -p 16379 sentinel get-master-addr-by-name mymaster 1) "223.223.223.101" 2) "6379"
Bạn thử khởi động lại cháu đại ca lúc nãy, và xem trong log sẽ thấy nó được gia nhập băng nhóm lại, nhưng với vai trò là slave 😀
OK, từ nay trở đi, server có sập thì cũng cứ an tâm mà uống bia, mai tỉnh dậy rồi gọi ông đại ca cũ dậy sau :v
Nguồn bài viết: