前言
前些天一直在忙线上环境部署的事情,初步想的是,nginx(keepalive双机热备)+3(tomcat)+2redis(双机热备),但是后来由于阿里云服务器经典网络不提供虚拟IP,无法使用keepalive,nginx双机热备只能暂时先放弃,退而求其次,采用nginx+3tomcat+2redis(双机热备)。nginx+tomcat由于之前配置过,所以重点就落在redis双机热备上,毕竟是线上系统,适当的抗灾能力还是需要的,咱可不能像测试系统那么去玩,否则黑锅就有的背了,毕竟码代码赚点生活费也不容易。
在网上也查了一些资料,redis集群实现大概有以下几种方式:
1.redis-cluster,官方提供的集群搭建方案(过于重量级,比较适合后期数据量较大的时候的使用)
2.redis+keepalive(由于我们使用的阿里云服务器不支持虚拟IP,所以这套方案也就夭折了)
3.redis+zookeeper(需要引入zookeeper,对现有代码变动较大)
4.redis+sentinel(redis自带监控中间件)(代码变动小,配置少,而且能满足双机热备的需求)
基于我们目前的情况以及需求,经过初略对比,我们团队决定选用第四种方案redis+sentinel实现双机热备。
准备工作
1.安装redis-001(主)
$ wget http://download.redis.io/releases/redis-3.2.3.tar.gz
$ tar xzf redis-3.2.3.tar.gz
$ mv redis-3.2.3 redis-001
$ cd redis-001
$ make
2.安装redis-002(从)
$ wget http://download.redis.io/releases/redis-3.2.3.tar.gz
$ tar xzf redis-3.2.3.tar.gz
$ mv redis-3.2.3 redis-002
$ cd redis-002
$ make
3.修改redis-002端口为6380
$ cd /usr/tools/redis-002/
$ vim redis.conf
...找到port 6379改为6380...
4.修改redis默认配置
a.关闭ip绑定,注释redis.conf中bind 127.0.0.1
b.关闭保护模式,将protected-mode yes改为protected-mode no
5.启动redis-001,redis-002
$ cd tools/redis-001/
$ ./src/redis-server redis.conf
出现以下信息就表示启动成功了:
12513:M 09 Oct 11:15:49.061 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
12513:M 09 Oct 11:15:49.061 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
12513:M 09 Oct 11:15:49.061 * DB loaded from disk: 0.000 seconds
12513:M 09 Oct 11:15:49.061 * The server is now ready to accept connections on port 6379
redis主从复制
1.redis 复制的特点
1). 同一个Master可以同步多个Slaves。
2). Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
3). Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
4). Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
5). 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
6). Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。
2.redis复制原理
在Slave启动并连接到Master之后,它将主动发送一个SYNC命令。此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。
如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。
3.redis主从配置
前面也说了,redis主从配置很简单,只需要一个slaveof就可以搞定。
连接redis-002,执行slaveof 192.168.231.130 6379:
C:\Users\lenovo\Desktop\redis>D:
D:\>cd D:\Program Files\Redis-x64-3.0.5
D:\Program Files\Redis-x64-3.0.5>redis-cli.exe -h 192.168.231.130 -p 6380
192.168.231.130:6380> slaveof 192.168.231.130 6379
OK
192.168.231.130:6380>
执行完成后,可以看到服务器上redis-001控制台输出以下内容:
12513:M 09 Oct 11:15:49.061 * DB loaded from disk: 0.000 seconds
12513:M 09 Oct 11:15:49.061 * The server is now ready to accept connections on port 6379
12513:M 09 Oct 11:41:59.371 * Slave 192.168.231.130:6380 asks for synchronization
12513:M 09 Oct 11:41:59.371 * Full resync requested by slave 192.168.231.130:6380
12513:M 09 Oct 11:41:59.371 * Starting BGSAVE for SYNC with target: disk
12513:M 09 Oct 11:41:59.372 * Background saving started by pid 13673
13673:C 09 Oct 11:41:59.388 * DB saved on disk
13673:C 09 Oct 11:41:59.388 * RDB: 6 MB of memory used by copy-on-write
12513:M 09 Oct 11:41:59.462 * Background saving terminated with success
12513:M 09 Oct 11:41:59.462 * Synchronization with slave 192.168.231.130:6380 succeeded
redis-002控制台输出:
13581:S 09 Oct 11:41:59.361 * Connecting to MASTER 192.168.231.130:6379
13581:S 09 Oct 11:41:59.370 * MASTER <-> SLAVE sync started
13581:S 09 Oct 11:41:59.370 * Non blocking connect for SYNC fired the event.
13581:S 09 Oct 11:41:59.371 * Master replied to PING, replication can continue...
13581:S 09 Oct 11:41:59.371 * Partial resynchronization not possible (no cached master)
13581:S 09 Oct 11:41:59.374 * Full resync from master: e2f4e2608956ea6392482c2e0a9429efdebd2b53:1
13581:S 09 Oct 11:41:59.462 * MASTER <-> SLAVE sync: receiving 76 bytes from master
13581:S 09 Oct 11:41:59.463 * MASTER <-> SLAVE sync: Flushing old data
13581:S 09 Oct 11:41:59.463 * MASTER <-> SLAVE sync: Loading DB in memory
13581:S 09 Oct 11:41:59.463 * MASTER <-> SLAVE sync: Finished with success
但是这样做的话,重启redis-002后又会复原,所以通常我们会直接修改redis-002配置文件redis.conf,在末尾加上slaveof 192.168.231.130 6379部分,就永久有效了。
现在我们往redis-001中写入数据,就可以从redis-002中查询出来了,我们来测试一下,往redis-001中写入key为name,value为osc的数据。
192.168.231.130:6379> set name osc
OK
192.168.231.130:6379> keys *
1) "name"
192.168.231.130:6379>
查询redis-002中的数据,会发现同样存在name的key,并且值为osc
192.168.231.130:6380> keys *
1) "name"
192.168.231.130:6380> get name
"osc"
192.168.231.130:6380>
到目前为止,redis主从复制已经配置成功了,接下来就要开始重点工作,配置双机热备。
redis+sentinel双机热备
1.理论概念
双机热备特指基于高可用系统中的两台服务器的热备(或高可用),因两机高可用在国内使用较多,故得名双机热备,双机高可用按工作中的切换方式分为:主-备方式(Active-Standby方式)和双主机方式(Active-Active方式),主-备方式即指的是一台服务器处于某种业务的激活状态(即Active状态),另一台服务器处于该业务的备用状态(即Standby状态)。而双主机方式即指两种不同业务分别在两台服务器上互为主备状态(即Active-Standby和Standby-Active状态)。
大白话就是,当主服务器挂了之后,从服务器立马切换为主服务器继续工作,当原先主服务器修复完善启动后,会自动充当从服务器的角色继续工作。这样就很好的避免了,由于一台主机出现故障,系统挂点的现象出现。
Sentinel(哨兵)是用于监控redis集群中Master状态的工具,已经集成在redis官方版本中,可以直接配置使用。
2.Sentinel命令
PING :返回 PONG 。
SENTINEL masters :列出所有被监视的主服务器,以及这些主服务器的当前状态;
SENTINEL slaves <master name> :列出给定主服务器的所有从服务器,以及这些从服务器的当前状态;
SENTINEL get-master-addr-by-name <master name> : 返回给定名字的主服务器的 IP 地址和端口号。 如果这个主服务器正在执行故障转移操作, 或者针对这个主服务器的故障转移操作已经完成, 那么这个命令返回新的主服务器的 IP 地址和端口号;
SENTINEL reset <pattern> : 重置所有名字和给定模式 pattern 相匹配的主服务器。 pattern 参数是一个 Glob 风格的模式。 重置操作清楚主服务器目前的所有状态, 包括正在执行中的故障转移, 并移除目前已经发现和关联的, 主服务器的所有从服务器和 Sentinel ;
SENTINEL failover <master name> : 当主服务器失效时, 在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移。
客户端可以通过SENTINEL get-master-addr-by-name <master name>获取当前的主服务器IP地址和端口号,以及SENTINEL slaves <master name>获取所有的Slaves信息
3.双机热备配置
a.关闭redis-001与redis-002
b.在redis-001和redis-002配置sentinel.conf中加上以下配置信息:
sentinel monitor mymaster 192.168.231.130 6379 1
c.修改redis-002 sentinel.conf监听端口:
$ cd /usr/tools/redis-002/
$ vim sentinel.conf
...找到port 26379改为26380...
port 26380
d.分别启动redis-001(主)与redis-002(从),redis 服务和sentinel服务
$ cd /usr/tools/redis-002/
$ ./src/redis-server redis.conf
$ ./src/redis-sentinel sentinel.conf
$ cd /usr/tools/redis-001/
$ ./src/redis-server redis.conf
$ ./src/redis-sentinel sentinel.conf
此时在主从redis,sentinel控制台会出现以下信息:
14677:X 09 Oct 14:04:49.633 # Sentinel ID is 7b8fdc1e5e47426b0d62a3ddd22ede0fd712f452
14677:X 09 Oct 14:04:49.633 # +monitor master mymaster 192.168.231.130 6379 quorum 1
14677:X 09 Oct 14:04:49.634 * +slave slave 192.168.231.130:6380 192.168.231.130 6380 @ mymaster 192.168.231.130 6379
14677:X 09 Oct 14:05:53.727 * +sentinel sentinel 31e660153984b606951c564395bdc8e193943f0b 192.168.231.130 26380 @ mymaster 192.168.231.130 6379
e.测试结果:
连接主服务器sentinel,注意端口是sentinel.conf中配置的端口。
根据前面描述的sentinel命令查询主服务器信息:
192.168.231.130:26379> SENTINEL masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "192.168.231.130"
5) "port"
6) "6379"
7) "runid"
8) "fafb94fe9bff119e8a97f9183e3bcb5561933631"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "671"
19) "last-ping-reply"
20) "671"
21) "down-after-milliseconds"
22) "10000"
23) "info-refresh"
24) "4904"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "205675"
29) "config-epoch"
30) "0"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "1"
35) "quorum"
36) "1"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
192.168.231.130:26379>
查询从服务器信息:
192.168.231.130:26379> SENTINEL slaves mymaster
1) 1) "name"
2) "192.168.231.130:6380"
3) "ip"
4) "192.168.231.130"
5) "port"
6) "6380"
7) "runid"
8) "feabcfa65e69778e877ca0bd95adb9d642f6522f"
9) "flags"
10) "slave"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "928"
19) "last-ping-reply"
20) "928"
21) "down-after-milliseconds"
22) "10000"
23) "info-refresh"
24) "7332"
25) "role-reported"
26) "slave"
27) "role-reported-time"
28) "388802"
29) "master-link-down-time"
30) "0"
31) "master-link-status"
32) "ok"
33) "master-host"
34) "192.168.231.130"
35) "master-port"
36) "6379"
37) "slave-priority"
38) "100"
39) "slave-repl-offset"
40) "472844"
192.168.231.130:26379>
现在,我们来关闭端口为6379主redis-001服务器,看看会出现什么情况,此时redis-002控制台会出现以下信息:
14735:S 09 Oct 14:15:47.618 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:48.628 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:48.628 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:48.628 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:49.638 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:49.638 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:49.638 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:50.648 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:50.648 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:50.648 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:51.659 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:51.659 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:51.659 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:52.669 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:52.669 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:52.669 # Error condition on socket for SYNC: Connection refused
14735:M 09 Oct 14:15:53.459 * Discarding previously cached master state.
14735:M 09 Oct 14:15:53.459 * MASTER MODE enabled (user request from 'id=5 addr=192.168.231.130:53187 fd=7 name=sentinel-7b8fdc1e-cmd age=23 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0 omem=0 events=r cmd=exec')
14735:M 09 Oct 14:15:53.463 # CONFIG REWRITE executed with success.
从日志可以看出,服务器会经过多次连接主服务器失败后,判定主服务器故障,会对配置文件进行重写(CONFIG REWRITE executed with success),我们再去看看从服务器的配置文件redis.conf,会发现之前在末尾加上的slaveof 192.168.231.130 6379不见了,这就说明当sentinel监测到主服务器挂掉之后,自动将从服务器切换为主服务器。
我们再来看看主从服务器sentinel控制台输出了信息:
主sentinel:
14677:X 09 Oct 14:15:54.384 # +promoted-slave slave 192.168.231.130:6380 192.168.231.130 6380 @ mymaster 192.168.231.130 6379
14677:X 09 Oct 14:15:54.384 # +failover-state-reconf-slaves master mymaster 192.168.231.130 6379
14677:X 09 Oct 14:15:54.456 # +failover-end master mymaster 192.168.231.130 6379
14677:X 09 Oct 14:15:54.456 # +switch-master mymaster 192.168.231.130 6379 192.168.231.130 6380
14677:X 09 Oct 14:15:54.456 * +slave slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380
14677:X 09 Oct 14:16:04.479 # +sdown slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380
从sentinel:
14688:X 09 Oct 14:15:53.223 # +sdown master mymaster 192.168.231.130 6379
14688:X 09 Oct 14:15:53.223 # +odown master mymaster 192.168.231.130 6379 #quorum 1/1
14688:X 09 Oct 14:15:53.223 # Next failover delay: I will not start a failover before Sun Oct 9 14:21:53 2016
14688:X 09 Oct 14:15:54.461 # +config-update-from sentinel 7b8fdc1e5e47426b0d62a3ddd22ede0fd712f452 192.168.231.130 26379 @ mymaster 192.168.231.130 6379
14688:X 09 Oct 14:15:54.461 # +switch-master mymaster 192.168.231.130 6379 192.168.231.130 6380
14688:X 09 Oct 14:15:54.461 * +slave slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380
14688:X 09 Oct 14:16:04.483 # +sdown slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380
从上面日志信息可以看出,主从确实已经切换成功了,最后我们来看看实际情况是不是那样的,打开命令行执行查询主从信息命令,看看会出现什么结果:
192.168.231.130:26379> SENTINEL get-master-addr-by-name mymaster
1) "192.168.231.130"
2) "6380"
192.168.231.130:26379>
192.168.231.130:26379> SENTINEL masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "192.168.231.130"
5) "port"
6) "6380"
7) "runid"
8) "bb4fe3dece04db30c29f6650f1edd4d3689da751"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "14"
19) "last-ping-reply"
20) "14"
21) "down-after-milliseconds"
22) "10000"
23) "info-refresh"
24) "4648"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "847746"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "1"
35) "quorum"
36) "1"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
192.168.231.130:26379>
到这里基本已经部署完毕了,再去启动原先主服务器redis-001,会发现此时的redis-001变成了从服务器,接下来的内容由于与前面重复较多,我就不演示了。
注意事项
1.一步一步来,先配置主从复制,再配置主从切换
2.启动顺序不要弄错了,先启动主服务器的redis与sentinel,再启动从服务器redis与sentinel,如果遇到失败情况,由于sentinel启动后会自动修改和生成部分配置信息,为避免冲突浪费时间,建议直接删除配置文件,重新配置。
3.如果redis有密码的话,需要在主从服务器redis.conf中都加上:
masterauth <password>
以及在主从服务器sentinel.conf加上:
sentinel auth-pass mymaster <password>
两者密码一致。
4.daemonize yes,启用保护进程
protected-mode no,关闭保护模式
另附
具体程序代码修改部分,可以参考《JedisSentinelPool的相关配置与操作》。
来源:oschina
链接:https://my.oschina.net/u/2249566/blog/755797