一、背景
公司的業務在大量的使用redis,通路量大的業務我們有在使用codis叢集,redis 3.0叢集,說到redis 3.0叢集,我們線上已經跑了半年多了,叢集本身沒有出現過任務問題,但是由于我們這個業務是海外的,叢集建在aws的ec2上,由于ec2的網絡抖動或者ec2本身的原因,導緻主從切換,目前aws的技術正在跟進,這個叢集目前的qps 50w+,叢集本身已經做到了高可用和橫向擴充,但是,實際情況一些小的業務沒必要上叢集,單個執行個體就可以滿足業務需求,那麼我們就要想辦法如何保證單個執行個體的高可用,最近也在看相關的文檔,做一些測試,大家有在使用redis主從+lvs 漂vip的方案,也有使用redis主從+哨兵 漂vip的方案,甚至有在代碼邏輯做故障切換等等,各種各樣的方案都有,下面我介紹一下redis主從+哨兵 漂vip的方案,後面我們打算線上大規模的使用這個方案。
二、環境
1
2
3
4
5
6
7
8
<code>#redis</code>
<code>100.10.32.54:6400 主庫</code>
<code>100.10.32.55:6400 從庫</code>
<code>100.10.32.250 vip</code>
<code>#sentinel</code>
<code>100.10.32.54:26400 sentinel 本地節點</code>
<code>100.10.32.55:26400 sentinel 本地節點 </code>
<code>100.10.32.57:26400 sentinel 仲裁節點</code>
三、部署
1、安裝
<code>yum -y </code><code>install</code> <code>redis</code>
2、撰寫redis配置檔案(100.10.32.54 和100.10.32.55)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<code>vim </code><code>/etc/redis_6400</code><code>.conf</code>
<code>daemonize </code><code>yes</code>
<code>pidfile </code><code>"/var/run/redis_6400.pid"</code>
<code>port 6400</code>
<code>tcp-backlog 65535</code>
<code>bind 0.0.0.0</code>
<code>timeout 0</code>
<code>tcp-keepalive 0</code>
<code>loglevel notice</code>
<code>logfile </code><code>"/var/log/redis/redis_6400.log"</code>
<code>maxmemory 8gb</code>
<code>maxmemory-policy allkeys-lru</code>
<code>databases 16</code>
<code>save 900 1</code>
<code>save 300 10</code>
<code>save 60 10000</code>
<code>stop-writes-on-bgsave-error </code><code>yes</code>
<code>rdbcompression </code><code>yes</code>
<code>rdbchecksum </code><code>yes</code>
<code>dbfilename </code><code>"dump.rdb"</code>
<code>dir</code> <code>"/data/redis/6400"</code>
<code>slave-serve-stale-data </code><code>yes</code>
<code>slave-</code><code>read</code><code>-only </code><code>yes</code>
<code>repl-disable-tcp-nodelay no</code>
<code>slave-priority 100</code>
<code>appendonly no</code>
<code>appendfilename </code><code>"appendonly.aof"</code>
<code>appendfsync everysec</code>
<code>no-appendfsync-on-rewrite no</code>
<code>auto-aof-rewrite-percentage 100</code>
<code>auto-aof-rewrite-min-size 64mb</code>
<code>lua-</code><code>time</code><code>-limit 5000</code>
<code>slowlog-log-slower-than 10000</code>
<code>slowlog-max-len 128</code>
<code>notify-keyspace-events </code><code>""</code>
<code>hash</code><code>-max-ziplist-entries 512</code>
<code>hash</code><code>-max-ziplist-value 64</code>
<code>list-max-ziplist-entries 512</code>
<code>list-max-ziplist-value 64</code>
<code>set</code><code>-max-intset-entries 512</code>
<code>zset-max-ziplist-entries 128</code>
3、撰寫sentinel配置檔案(100.10.32.54 、100.10.32.55 和100.10.32.57)
<code>vim </code><code>/etc/redis-sentinel6400</code><code>.conf</code>
<code>port 26400</code>
<code>dir</code> <code>"/data/redis/redis_sentinels"</code>
<code>pidfile </code><code>"/var/run/redis/sentinel6400.pid"</code>
<code>logfile </code><code>"/data/redis/redis_sentinels/sentinel6400.log"</code>
<code>sentinel monitor master6400 100.10.32.54 6400 2</code>
<code>sentinel down-after-milliseconds master6400 6000</code>
<code>sentinel failover-timeout master6400 18000</code>
<code>sentinel client-reconfig-script master6400 </code><code>/opt/notify_master6400</code><code>.sh </code><code>##仲裁節點無需添加這行配置,client-reconfig-script參數是在sentinel做failover的過程中調用腳本漂vip到新的master上</code>
ps:
4、撰寫漂vip的腳本(100.10.32.54 、100.10.32.55)
<code>vim </code><code>/opt/notify_master6400</code><code>.sh</code>
<code>#!/bin/bash</code>
<code>master_ip=$6</code>
<code>local_ip=</code><code>'100.10.32.54'</code> <code>#從庫修改為100.10.32.55</code>
<code>vip=</code><code>'100.10.32.250'</code>
<code>netmask=</code><code>'24'</code>
<code>interface=</code><code>'eth0'</code>
<code>if</code> <code>[ ${master_ip} = ${local_ip} ]; </code><code>then</code>
<code> </code><code>/sbin/ip</code> <code>addr add ${vip}/${netmask} dev ${interface}</code>
<code> </code><code>/sbin/arping</code> <code>-q -c 3 -a ${vip} -i ${interface}</code>
<code> </code><code>exit</code> <code>0</code>
<code>else</code>
<code> </code><code>/sbin/ip</code> <code>addr del ${vip}/${netmask} dev ${interface}</code>
<code>fi</code>
<code>exit</code> <code>1</code>
<code>chmod</code> <code>+x </code><code>/opt/notify_master6400</code><code>.sh </code><code>#賦予可執行權限</code>
這裡大概說一下這個腳本的工作原理,sentinel在做failover的 過程中會傳出6個參數,分别是<master-name>、 <role>、 <state>、 <from-ip>、 <from-port>、 <to-ip> 、<to-port>,其中第6個參數from-ip也就是新的master的ip,對應腳本中的master_ip,下面的if判斷大家應該都很了然了,如果master_ip=local_ip,那就綁定vip,反之删除vip。
5、啟動redis服務(100.10.32.54、100.10.32.55)
<code>redis-server </code><code>/etc/redis_6400</code><code>.conf</code>
6、初始化主從(100.10.32.55)
<code>redis-cli -p 6400 slaveof 10.10.32.54 6400</code>
7、綁定vip到主庫(100.10.32.54)
<code>/sbin/ip</code> <code>addr add 100.10.32.250</code><code>/24</code> <code>dev eth0</code>
8、啟動sentinel服務(100.10.32.54、100.10.32.55、100.10.32.57)
<code>redis-server </code><code>/etc/redis-sentinel6400</code><code>.conf --sentinel</code>
至此,整個高可用方案已經搭建完成。
<code>[root@localhost tmp]</code><code># redis-cli -h 100.10.32.54 -p 6400 info replication</code>
<code># replication</code>
<code>role:master</code>
<code>connected_slaves:1</code>
<code>slave0:ip=100.10.32.55,port=6400,state=online,offset=72669,lag=1</code>
<code>master_repl_offset:72669</code>
<code>repl_backlog_active:1</code>
<code>repl_backlog_size:1048576</code>
<code>repl_backlog_first_byte_offset:2</code>
<code>repl_backlog_histlen:72668</code>
<code>[root@localhost tmp]</code><code># redis-cli -h 100.10.32.54 -p 26400 info sentinel</code>
<code># sentinel</code>
<code>sentinel_masters:1</code>
<code>sentinel_tilt:0</code>
<code>sentinel_running_scripts:0</code>
<code>sentinel_scripts_queue_length:0</code>
<code>master0:name=master6400,status=ok,address=100.10.32.54:6400,slaves=1,sentinels=3</code>
<code>[root@localhost tmp]</code><code># ip a |grep eth0</code>
<code>2: eth0: <broadcast,multicast,up,lower_up> mtu 1500 qdisc mq state up qlen 1000</code>
<code> </code><code>inet 100.10.32.54</code><code>/24</code> <code>brd 100.10.32.255 scope global eth0</code>
<code> </code><code>inet 100.10.32.250</code><code>/24</code> <code>scope global secondary eth0</code>
四、測試
1、把主庫停掉
<code>redis-cli -h 100.10.32.54 -p 6400 </code><code>shutdown</code>
2、看從庫是否提升為主庫
<code>[root@localhost tmp]</code><code># redis-cli -h 100.10.32.55 -p 6400 info replication</code>
<code>connected_slaves:0</code>
<code>master_repl_offset:0</code>
<code>repl_backlog_active:0</code>
<code>repl_backlog_first_byte_offset:0</code>
<code>repl_backlog_histlen:0</code>
3、看vip是否漂移到100.10.32.55上
<code> </code><code>inet 100.10.32.55</code><code>/24</code> <code>brd 100.10.32.255 scope global eth0</code>
4、看sentinel的監控狀态
<code>[root@localhost tmp]</code><code># redis-cli -p 26400 info sentinel</code>
<code>master0:name=master6400,status=ok,address=100.10.32.55:6400,slaves=1,sentinels=3</code>