利用redis-sentinel+keepalived实现redis高可用

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

目标、需求:

为上层应用提供高可靠、低延迟、低(无限接近0)数据损失的Redis缓存服务

方案概述:

采用同一网络内的三台主机(可以是物理主机、虚拟机或docker容器),要求三台主机之间都能相互访问,每一台主机上都安装redis-server、redis-sentinel和keepalived。

redis-server负责提供Redis缓存服务,三台主机间的关系是master-slave-slave

redis-sentinel负责提供Redis高可用,三台主机间的关系与redis-server相同

keepalived负责提供VIP地址供上层应用使用,三台主机的关系是master-backup-backup,VIP始终在redis-server master上,保证对上层应用可写可读。

三台主机的冗余度是1,也就是说当有一台主机宕机时另外两台中至少有一台主机可以提供Redis缓存服务

方案原理:

redis-server提供单实例的Redis缓存服务,redis-sentinel能在一台主机挂掉时自动的将某一台可用主机上的redis-server由slave状态切换成master状态。

keepalived通过vrrp_script检测当前主机上的redis-server是否以master状态运行,如果当前主机上的redis-server正在以master状态运行,则将vrrp_instance标记为存活状态,并分配VIP;如果当前主机上的redis-server正在以slave状态运行,则将vrrp_instance标记为错误状态。当某台主机宕机后,其他两台主机上的keepalived会将VIP切换到新的master(当前主机上的redis-server正在以master状态运行)上。

由于keepalived的VIP切换有延迟(大约40ms),因此上层应用不能过分依赖Redis,例如大规模并发性的短时间内向Redis插入大量数据。

连接图

image

如图所示,有三台主机,分别标识为Redis1、Redis2、Redis3,它们的角色和配置等信息如下:

主机标识 Redis1 Redis2 Redis3
IP地址 192.168.1.241 192.168.1.242 192.168.1.243
预设配置 redis-server master          
keepalived master
redis-server slave          
keepalived backup
redis-server slave          
keepalived backup
  VIP    

 

配置步骤:

步骤概述

  1. 安装:安装redis-server、redis-sentinel、keepalived

  2. 配置:配置Redis1、Redis2、Redis3,主要是编辑各个服务的配置文件

  3. 启动:先启动redis-server、再启动redis-sentinel、最后自动keepalived

  4. 验证:模拟一台主机宕机,主机网络中断,redis-server、redis-sentinel、keepalived三个服务任何一个发生故障的情况。

(1)设定主机名(建议设定为fqdn格式)、同步时间、更改文件描述符最大打开数量、更改内核参数、配置编译环境、配置防火墙在此就不赘述了。

(2)安装redis-server和redis-sentinel

Redis的安装由于只是bin二进制可执行文件和data目录比较重要,因此简化安装如下    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# http://download.redis.io/redis-stable.tar.gz     
wget -c http: //download .redis.io /releases/redis-3 .0.7. tar .gz     
tar  zxf redis-3.0.7. tar .gz     
cd  redis-3.0.7     
make     
cd     
\ cp  redis-3.0.7 /src/redis-benchmark  /usr/local/sbin/     
\ cp  redis-3.0.7 /src/redis-check-aof  /usr/local/sbin/     
\ cp  redis-3.0.7 /src/redis-check-dump  /usr/local/sbin/     
\ cp  redis-3.0.7 /src/redis-cli  /usr/local/sbin/     
\ cp  redis-3.0.7 /src/redis-sentinel  /usr/local/sbin/     
\ cp  redis-3.0.7 /src/redis-server  /usr/local/sbin/     
mkdir  /etc/redis     
mkdir  -p  /data/redis-6379/

(3)安装keepalived

1
2
3
4
5
6
7
8
9
10
11
# http://www.keepalived.org/documentation.html     
wget -c http: //www .keepalived.org /software/keepalived-1 .2.19. tar .gz     
tar  zxf keepalived-1.2.19. tar .gz     
cd  keepalived-1.2.19     
. /configure  --prefix= /usr/local/keepalived     
make     
make  install     
cp  /usr/local/keepalived/sbin/keepalived  /usr/sbin/     
cp  /usr/local/keepalived/etc/sysconfig/keepalived  /etc/sysconfig/     
cp  /usr/local/keepalived/etc/rc .d /init .d /keepalived  /etc/init .d/     
mkdir  /etc/keepalived

keepalived的配置文件在后面添加

(4)Redis1上的redis-sentinel配置文件

1
2
3
4
5
6
7
8
cat  > /etc/redis/sentinel .conf<<eof    
port 26379     
dir  /tmp     
sentinel monitor mymaster 192.168.1.241 6379 2     
sentinel down-after-milliseconds mymaster 30000     
sentinel parallel-syncs mymaster 1     
sentinel failover-timeout mymaster 180000     
eof

Redis2和Redis3上的redis-sentinel配置文件与Redis1上的redis-sentinel配置文件内容相同。

(5)Redis1上的redis-server的配置文件

1
2
3
4
5
6
7
8
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
cat  /etc/redis/redis-6379 .conf <<eof     
# maxmemory 268435456     
maxmemory 256mb     
daemonize  yes     
pidfile  /data/redis-6379/redis-6379 .pid     
port 6379     
bind 0.0.0.0     
tcp-backlog 511     
timeout 0     
 
tcp-keepalive 0     
loglevel notice     
logfile  /data/redis-6379/redis .log     
databases 16     
save 900 1     
save 300 10     
save 60 10000     
stop-writes-on-bgsave-error  yes     
rdbcompression  yes     
rdbchecksum  yes     
dbfilename dumpredis-6379.rdb     
dir  /data/redis-6379     
slave-serve-stale-data  yes     
slave- read -only  yes     
repl-diskless- sync  no     
repl-diskless- sync -delay 5     
# repl-ping-slave-period 10     
# repl-timeout 60     
repl-disable-tcp-nodelay no     
# repl-backlog-size 1mb     
# repl-backlog-ttl 3600     
slave-priority 100     
# min-slaves-to-write 3     
# min-slaves-max-lag 10     
 
appendonly no     
appendfilename  "appendonly.aof"     
appendfsync everysec     
no-appendfsync-on-rewrite no     
auto-aof-rewrite-percentage 100     
auto-aof-rewrite-min-size 64mb     
aof-load-truncated  yes     
lua- time -limit 5000     
slowlog-log-slower-than 10000     
slowlog-max-len 128     
latency-monitor-threshold 0     
notify-keyspace-events  ""     
hash -max-ziplist-entries 512     
hash -max-ziplist-value 64     
list-max-ziplist-entries 512     
list-max-ziplist-value 64     
set -max-intset-entries 512     
zset-max-ziplist-entries 128     
zset-max-ziplist-value 64     
hll-sparse-max-bytes 3000     
activerehashing  yes     
client-output-buffer-limit normal 0 0 0     
client-output-buffer-limit slave 256mb 64mb 60     
client-output-buffer-limit pubsub 32mb 8mb 60     
hz 10     
aof-rewrite-incremental-fsync  yes     
eof

(6)Redis2与Redis3上的redis-server配置文件

1
2
3
4
5
6
7
8
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
cat  /etc/redis/redis-6379 .conf <<eof    
slaveof 192.168.1.241 6379     
# maxmemory 268435456     
maxmemory 256mb     
daemonize  yes     
pidfile  /data/redis-6379/redis-6379 .pid     
port 6379     
bind 0.0.0.0     
tcp-backlog 511     
timeout 0     
tcp-keepalive 0     
loglevel notice     
logfile  /data/redis-6379/redis .log     
databases 16     
save 900 1     
save 300 10     
save 60 10000     
stop-writes-on-bgsave-error  yes     
rdbcompression  yes     
rdbchecksum  yes     
dbfilename dumpredis-6379.rdb     
dir  /data/redis-6379     
slave-serve-stale-data  yes     
slave- read -only  yes     
repl-diskless- sync  no     
repl-diskless- sync -delay 5 
     
# repl-ping-slave-period 10     
# repl-timeout 60     
repl-disable-tcp-nodelay no     
# repl-backlog-size 1mb     
# repl-backlog-ttl 3600     
slave-priority 100     
# min-slaves-to-write 3     
# min-slaves-max-lag 10     
appendonly no     
appendfilename  "appendonly.aof"     
appendfsync everysec     
no-appendfsync-on-rewrite no     
auto-aof-rewrite-percentage 100     
auto-aof-rewrite-min-size 64mb     
aof-load-truncated  yes     
lua- time -limit 5000     
slowlog-log-slower-than 10000     
slowlog-max-len 128     
latency-monitor-threshold 0     
notify-keyspace-events  ""     
hash -max-ziplist-entries 512     
hash -max-ziplist-value 64     
list-max-ziplist-entries 512     
list-max-ziplist-value 64     
set -max-intset-entries 512     
zset-max-ziplist-entries 128     
zset-max-ziplist-value 64     
hll-sparse-max-bytes 3000     
activerehashing  yes     
client-output-buffer-limit normal 0 0 0     
client-output-buffer-limit slave 256mb 64mb 60     
client-output-buffer-limit pubsub 32mb 8mb 60     
hz 10     
aof-rewrite-incremental-fsync  yes     
eof

(7)Redis1上的keepalived配置文件(vim /etc/keepalived/keepalived.conf)

关于keepalived的配置文件

keepalived的配置文件默认是没有的,当然sample&example文件还是有的,通常在PREFIX/etc/sample目录下。

keepalived master和backup(backups)之间不同的是:

1.优先级的不同,master的优先级priority的数字要高一些

2.global_defs段的router_id都不一样,实际中可以用任意名字区分也可以用主机名区分

3.backup的配置文件中还有一个nopreempt字段,意思是设置为非抢占模式,作用是让master优先获取到VIP,并保证VIP是在原先的master上。

1
2
3
4
5
6
7
8
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
43
! Configuration File  for  keepalived     
global_defs {     
    notification_email {     
      root@localhost     
    }     
    notification_email_from keepalived@localhost     
    smtp_server 127.0.0.1     
    smtp_connect_timeout 10     
    router_id keepalivedha_1     
}     
vrrp_script chk_http_port {     
     script  "redis-cli info | grep role:master >/dev/null 2>&1"     
     interval 1     
     timeout 2     
     fall 2     
     rise 1     
}     
vrrp_sync_group VG_1 {     
     group {     
         VI_1     
     }     
}     
vrrp_instance VI_1 {     
     state BACKUP     
     interface eth1     
     #use_vmac keepalived     
     #vmac_xmit_base     
     mcast_src_ip 192.168.1.241     
     smtp_alert     
     virtual_router_id 20    
     priority 100     
     advert_int 1     
     authentication {     
         auth_type PASS     
         auth_pass password     
     }     
     virtual_ipaddress {     
         192.168.1.245     
     }     
     track_script {     
         chk_http_port     
     }     
}

(8)Redis2上的keepalived配置文件

1
2
3
4
5
6
7
8
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
43
44
! Configuration File  for  keepalived    
global_defs {     
    notification_email {     
      root@localhost     
    }     
    notification_email_from keepalived@localhost    
    smtp_server 127.0.0.1     
    smtp_connect_timeout 10     
    router_id keepalivedha_2     
}     
vrrp_script chk_http_port {     
     script  "redis-cli info | grep role:master >/dev/null 2>&1"     
     interval 1     
     timeout 2     
     fall 2     
     rise 1     
}     
vrrp_sync_group VG_1 {     
     group {     
         VI_1     
     }     
}     
vrrp_instance VI_1 {     
     state BACKUP     
     interface eth2     
     #use_vmac keepalived     
     #vmac_xmit_base     
     mcast_src_ip 192.168.1.242     
     smtp_alert     
     virtual_router_id 20    
     priority 99     
     advert_int 1     
     authentication {     
         auth_type PASS     
         auth_pass password     
     }     
     virtual_ipaddress {     
         192.168.1.245     
     }     
     track_script {     
         chk_http_port     
     }     
     nopreempt     
}

(9)Redis3上的keepalived配置文件

1
2
3
4
5
6
7
8
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
43
44
! Configuration File  for  keepalived    
global_defs {     
    notification_email {     
      root@localhost     
    }     
    notification_email_from keepalived@localhost     
    smtp_server 127.0.0.1     
    smtp_connect_timeout 10     
    router_id keepalivedha_3    
}     
vrrp_script chk_http_port {     
     script  "redis-cli info | grep role:master >/dev/null 2>&1"     
     interval 1     
     timeout 2     
     fall 2     
     rise 1     
}     
vrrp_sync_group VG_1 {     
     group {     
         VI_1     
     }     
}     
vrrp_instance VI_1 {     
     state BACKUP     
     interface eth1     
     #use_vmac keepalived     
     #vmac_xmit_base     
     mcast_src_ip 192.168.1.243     
     smtp_alert     
     virtual_router_id 20    
     priority 98     
     advert_int 1     
     authentication {     
         auth_type PASS     
         auth_pass password     
     }     
     virtual_ipaddress {     
         192.168.1.245     
     }     
     track_script {     
         chk_http_port     
     }     
     nopreempt     
}

(10)启动redis-server

1
2
redis-server  /etc/redis/redis-6379 .conf
tail  /data/redis-6379/redis .log

(11)启动redis-sentinel

1
2
redis-sentinel  /etc/redis/redis-sentinel .conf
tail  /data/redis-6379/redis-sentinel .log

(12)启动keepalived

1
2
service keepalived start
tail  /var/log/messages

如果keepalived启动后日志如下图显示则表示启动成功。

image

image

测试

测试分两块内容,一是测试键值对的set与get,二是测试自增唯一id的是否可用。

(1)测试Redis键值对的set与get

先不模拟故障,先测试一下redis的set、get和复制情况

image

image

再测试一下模拟故障出现时redis的set、get和复制情况

停掉Redis1上的redis-server

image

Redis1上的VIP已经被移除

image

image

查看Redis2上的Redis状态和VIP状态

image

image

通过上图的***文字可以看出,VIP已经漂移到新的redis-server master了。

注意:VIP的漂移过程是需要时间的,时间大概需要10*4ms左右,如下图所示:

image

image

此时再次测试一下Redis的复制情况

image

由上图可见,Redis复制情况正常,上层应用依然可以使用Redis缓存服务。

(2)测试自增唯一id(autoincrementing unique identifier)

概念参考:http://redis-cookbook.readthedocs.org/en/latest/z.html

自增唯一id最常见的应用就是作为关系型数据库的主键,因为主键必须确保每个数据项都有唯一id。

它也可以在不支持自增唯一id的数据库中(比如MongoDB)用来替代唯一id(uniqueidentifier,通常是一个哈希值)

它也可以为用户提供更好的URL:比如将/topic/4e491e229f328b0cd900010d修改为/topic/10086。

一个自增唯一id对象最重要的是保证值的唯一性,要做到这一点,自增id的自增incr操作必须是一个原子操作,它应该能在一个原子时间内完成以下两件事:

增加id值,返回当前id值,并且它也没有减法decr和清零reset等操作,因为这些操作破坏了唯一性。

get操作一般只用于内部检查,比如观察值是否溢出,但在一般情况下,自增唯一id对象应该只有一个incr操作。

先测试一下主机健康状态下的自增唯一id

wKiom1bFYUyhvvAXAABD7HT-ts8276.png

发现各个redis-server中的自增唯一id是好用的。再测试一下某台主机故障状态下的自增唯一id。先根据ip addr找到VIP的主机位置,或者通过redis-cli info查看role找到redis-server master的主机,然后kill redis-server pid,再进行测试。

wKiom1bFYK2QVonMAAA5gRUmSQI600.png

wKioL1bFYlbxjmcaAABAoPWRlDQ544.png

由此发现redis-server中的自增唯一id仍然是好用的。

故障切换的步骤

如果一台主机宕机,则主机启动后,先启动redis-server、再启动redis-sentinel、最后自动keepalived。

如果多台主机宕机,则按照一台主机宕机的步骤做同样处理。

如果一台主机的中的某台服务停止,则直接启动该服务即可。

参考

Redis Documention http://redis.io/documentation

Redis High Availability http://redis.io/topics/sentinel

Redis Replication http://redis.io/topics/replication


后续

由于keepalived的应用场景有限,比如它的核心协议VRRP只能工作在局域网内,不能工作在局域网外(网间、广域网),而且在网络不受自己控制时基本不能用,除非设定好的VIP是供局域网使用。因此特别是在云计算环境中,使用云主机(例如阿里云ECS等)就不能用keepalived,因此只能寻找一个可替代keepalived的解决方案来替代它。Consul作为服务注册、服务发现的最佳选择,无疑可以很好的替代keepalived。第二种方案可以参考这篇文章《利用redis-sentinel+consul实现redis高可用》。

tag:Redis集群,Redis高可用,redis-sentinel,keepalived配置,Redis主从复制

--end--






本文转自 urey_pp 51CTO博客,原文链接:http://blog.51cto.com/dgd2010/1742766,如需转载请自行联系原作者




相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
NoSQL 关系型数据库 MySQL
Redis高可用之主从复制架构(第一部分)
Redis高可用之主从复制架构(第一部分)
|
3月前
|
机器学习/深度学习 NoSQL Redis
Redis高可用之集群架构(第三部分)
Redis高可用之集群架构(第三部分)
|
3月前
|
消息中间件 NoSQL Redis
Redis高可用之哨兵模式(第二部分)
Redis高可用之哨兵模式(第二部分)
|
3月前
|
存储 监控 NoSQL
|
2月前
|
存储 NoSQL Java
面试官:Redis如何保证高可用?
面试官:Redis如何保证高可用?
76 2
面试官:Redis如何保证高可用?
|
3月前
|
监控 NoSQL 程序员
Redis 高可用篇:你管这叫 Sentinel 哨兵集群原理
Redis 高可用篇:你管这叫 Sentinel 哨兵集群原理
77 5
|
3月前
|
存储 负载均衡 NoSQL
Redis 高可用篇:你管这叫主从架构数据同步原理?
Redis 高可用篇:你管这叫主从架构数据同步原理?
238 5
|
存储 缓存 负载均衡
分布式缓存Redis分区(分片)的高可用方案在大厂中的实践(下)
分布式缓存Redis分区(分片)的高可用方案在大厂中的实践
431 0
分布式缓存Redis分区(分片)的高可用方案在大厂中的实践(下)
|
缓存 监控 NoSQL
超全面Redis分布式高可用方案:哨兵机制
开发工作中对于分布式缓存高可用方案(搭建 Redis 缓存高可用方案),Redis 主从架构下是如何保证高可用的呢?
超全面Redis分布式高可用方案:哨兵机制
|
缓存 算法 NoSQL
分布式缓存Redis分区(分片)的高可用方案在大厂中的实践(中)
分片,Redis 数据的分布方式,分片就是将数据拆分到多个 Redis 实例,这样每个实例将只是所有键的一个子集。
125 0
分布式缓存Redis分区(分片)的高可用方案在大厂中的实践(中)

热门文章

最新文章