Redis 一主三从 哨兵

http://blog.51cto.com/mxlmgl/2065789

redis-server说明

服务器A:192.168.1.131:8000(主)

服务器B:192.168.1.135:8000

服务器C:192.168.1.231:8000

服务器D:192.168.1.241:8000

redis-sentinel说明

服务器A:192.168.1.131:6800

服务器B:192.168.1.135:6800

服务器C:192.168.1.231:6800

服务器D:192.168.1.241:6800

2.搭建redis系统

yum  install  -y  gcc*  tcl

首先下载安装redis

cd /usr/local

wget http://download.redis.io/releases/redis-3.2.11.tar.gz

tar zxvf redis-3.2.11.tar.gz

mv redis-3.2.11  redis

cd redis

make && make install

如果编译安装过程中,出现报错:

zmalloc.h:51:31: error: jemalloc/jemalloc.h: No such file or directory

原因:一些编译依赖或原来编译遗留出现的问题

解决方案:make distclean 清理一下,然后再make

或者直接  make MALLOC=libc  && make install

[root@localhost redis]# cd src

[root@localhost src]#cp redis-server redis-cli redis-check-aof redis-check-rdb redis-sentinel redis-trib.rb /usr/local/bin/

[root@localhost src]# mkdir /etc/redis

[root@localhost src]# mkdir /var/redis

[root@localhost src]# mkdir  /var/redis/{log,run,redis}

[root@localhost src]cd ..

[root@localhost redis]#cp redis.conf /etc/redis/redis.conf

[root@localhost redis]#  vi/etc/redis/redis.conf

修改如下:

port  8000 #修改端口是安全的第一步

daemonize  yes   

bind 0.0.0.0

pidfile    /var/run/redis-8000.pid 

logfile  /var/redis/log/redis_8000.log

dir /var/redis/redis //工作目录,dump文件所在目录

slaveof  192.168.1.131  8000    #从redis比主redis多这一行

########################################################

redis默认的持久化方式是RDB,数据写入到dump文件中。如果要启用AOF持久化,就在redis.conf文件中配置如下:

appendonly yes         #启用AOF持久化方式

appendfilename "appendonly.aof"       #AOF文件的名称,默认为appendonly.aof

# appendfsync always        #每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用。

appendfsync everysec        #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,是受推荐的方式。

# appendfsync no         #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不被推荐。

########################################################

[root@localhost redis]#redis-server /etc/redis/redis.conf 

设置开机启动

[root@dev ~]# echo "/usr/local/bin/redis-server /etc/redis/redis.conf" >> /etc/rc.local

关闭redis服务

[root@dev ~]# redis-cli shutdown //默认是6379端口

如果端口变化可以指定端口

[root@dev ~]# redis-cli -p 8000 shutdown

########################################################

还可以通过如下方法,设置redis服务启动脚本及开机自启动

将redis解压包下utils下redis启动脚本redis_init_script拷贝至/etc/init.d/,并修改脚本名称(也可不修改)为redis

[root@dev ~]# cp /usr/local/src/redis-stable/utils/redis_init_script /etc/init.d/redis

[root@dev ~]# chmod +x /etc/init.d/redis

修改脚本pid及conf路径为实际路径

[root@dev ~]# vim /etc/init.d/redis

......

REDISPORT=6379

EXEC=/usr/local/bin/redis-server

CLIEXEC=/usr/local/bin/redis-cli

PIDFILE=/var/redis/run/redis_6379.pid

CONF="/etc/redis/redis.conf"

......

这样,就可以直接用下面的命令关闭和启动redis服务了

[root@dev ~]# /etc/init.d/redis stop

Stopping ...

Redis stopped

[root@dev ~]# lsof -i:6379

[root@dev ~]# /etc/init.d/redis start

Starting Redis server...

[root@dev ~]# lsof -i:6379

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

redis-ser 9372 root 4u IPv4 58648940 0t0 TCP localhost:6379 (LISTEN)

设置自启动

[root@dev ~]# chkconfig redis on

redis 服务不支持 chkconfig

这是因为没有在启动脚本/etc/init.d/redis里加入redis启动优先级信息,可添加如下红色字体的两行:

[root@dev ~]# vim /etc/init.d/redis 

#!/bin/sh

#

# chkconfig: 2345 90 10                                                     //注意:后面的英文空格

# description: Redis is a persistent key-value database          //注意:后面的英文空格

# Simple Redis init.d script conceived to work on Linux systems

# as it does use of the /proc filesystem.

REDISPORT=6379

EXEC=/usr/local/bin/redis-server

CLIEXEC=/usr/local/bin/redis-cli

PIDFILE=/var/redis/run/redis_6379.pid

CONF="/etc/redis/redis.conf"

.......

[root@dev ~]# chkconfig redis on

[root@dev ~]# chkconfig --list|grep redis

redis 0:关闭 1:关闭 2:启用 3:启用 4:启用 5:启用 6:关闭

########################################################

验证:

在A服务器(主)

[root@localhost ~]#   redis-cli -h 192.168.1.131 -p 8000 info replication

[root@localhost ~]#    redis-cli -h 192.168.1.131 -p 8000 info replication

# Replication

role:master

connected_slaves:3

slave0:ip=192.168.1.231,port=8000,state=online,offset=462,lag=0

slave1:ip=192.168.1.241,port=8000,state=online,offset=462,lag=1

slave2:ip=192.168.1.135,port=8000,state=online,offset=462,lag=1

master_repl_offset:462

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:461

#############################################################################

[root@localhost ~]#   redis-cli -h 192.168.1.131 -p 8000

[root@localhost ~]#   192.168.1.131:8000> get name thb      (主,1.131)

[root@localhost redis]# redis-cli -h 192.168.1.135 -p 8000      (从。1.135)

192.168.1.135:8000> get name

"thb"

192.168.1.135:8000>

############################################################################

配置哨兵sentinel

[root@localhost redis]#  cd /usr/local/redis

[root@localhost redis]#  mkdir /etc/sentinel

[root@localhost redis]#  cp -a sentinel.conf /etc/sentinel

[root@localhost redis]#   vi /etc/sentinel/sentinel.conf   (之前的都删掉,就保留下面的内容)

bind  0.0.0.0

daemonize yes

port  6800

logfile  /var/log/sentinel.log

pidfile  /var/run/sentinel.pid

sentinel monitor master8000 192.168.1.131 8000 2

#5秒内master6800没有响应,就认为SDOWN

sentinel down-after-milliseconds master8000 5000

sentinel failover-timeout  master8000 15000

[root@localhost redis]#  redis-sentinel  /etc/sentinel/sentinel.conf

[root@localhost redis]#echo "/usr/local/bin/redis-sentinel /etc/sentinel/sentinel.conf" >> /etc/rc.local

四个redis-sentinel服务启动完毕后,连接任意sentinel服务可以获知当前主redis服务信息

[root@localhost ~]# redis-cli -h 192.168.1.131 -p 6800 info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=master8000,status=ok,address=192.168.1.131:8000,slaves=3,sentinels=3

测试

1.把主redis停掉

[root@localhost ~]# redis-cli -h 192.168.1.131 -p 8000 shutdown

[root@localhost ~]# netstat -ntpl

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name

tcp        0      0 0.0.0.0:58566               0.0.0.0:*                   LISTEN      1235/rpc.statd

tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1213/rpcbind

tcp        0      0 0.0.0.0:6800                0.0.0.0:*                   LISTEN      1685/redis-sentinel

tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1447/sshd

tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      1290/cupsd

tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1526/master

tcp        0      0 :::111                      :::*                        LISTEN      1213/rpcbind

tcp        0      0 :::52913                    :::*                        LISTEN      1235/rpc.statd

tcp        0      0 :::22                       :::*                        LISTEN      1447/sshd

tcp        0      0 ::1:631                     :::*                        LISTEN      1290/cupsd

tcp        0      0 ::1:25                      :::*                        LISTEN      1526/master

2.查看redis-sentinel的监控状态

[root@localhost ~]# redis-cli -h 192.168.1.131 -p 6800 info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=master8000,status=ok,address=192.168.1.231:8000,slaves=3,sentinels=6

发现231这台redis-server提升为主库。

在1.231 这台上查看

[root@session1 ~]# redis-cli -h 192.168.1.231 -p 8000 info replication

# Replication

role:master

connected_slaves:2

slave0:ip=192.168.1.241,port=8000,state=online,offset=36416,lag=1

slave1:ip=192.168.1.135,port=8000,state=online,offset=36558,lag=0

master_repl_offset:36842

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:36841

发现role已经是master了

至此,redis的高可用方案已经搭建完成。

六、客户端程序

客户端程序(如PHP程序)连接redis时需要ip和port,但redis-server进行故障转移时,主redis是变化的,所以ip地址也是变化的。客户端程序如何感知当前主redis的ip地址和端口呢?redis-sentinel提供了接口,请求任何一个sentinel,发送SENTINEL get-master-addr-by-name 就能得到当前主redis的ip和port。

[root@localhost ~]# redis-cli -h 192.168.1.131 -p 6800

192.168.1.131:6800> sentinel get-master-addr-by-name master8000

1) "192.168.1.231"

2) "8000"

192.168.1.131:6800>

获取当前主redis的ip和port

客户端每次连接redis前,先向sentinel发送请求,获得主redis的ip和port,然后用返回的ip和port连接redis。

这种方法的缺点是显而易见的,每次操作redis至少需要发送两次连接请求,第一次请求sentinel,第二次请求redis。

php请求sentinel程序代码可参见:https://github.com/huyanping/redis-sentinel

更好的办法是使用VIP,当然这对配置的环境有一定的要求,比如redis搭建在阿里云服务器上,可能不支持VIP。

VIP方案是,redis系统对外始终是同一ip地址,当redis进行故障转移时,需要做的是将VIP从之前的redis服务器漂移到现在新的主redis服务器上。

比如:当前redis系统中主redis的ip地址是192.168.56.101,那么VIP(192.168.56.250)指向192.168.56.101,客户端程序用VIP(192.168.56.250)地址连接redis,实际上连接的就是当前主redis,这样就避免了向sentinel发送请求。

当主redis宕机,进行故障转移时,192.168.56.102这台服务器上的redis提升为主,这时VIP(192.168.56.250)指向192.168.56.102,这样客户端程序不需要修改任何代码,连接的是192.168.56.102这台主redis。

                                         VIP指向192.168.1.131

                                  故障转移后,VIP漂移指向192.168.1.231

七、漂移VIP

那么现在的问题是,如何在进行redis故障转移时,将VIP漂移到新的主redis服务器上。

这里可以使用redis sentinel的一个参数client-reconfig-script,这个参数配置执行脚本,sentinel在做failover的时候会执行这个脚本,并且传递6个参数、 、 、 、 、 、,其中是新主redis的IP地址,可以在这个脚本里做VIP漂移操作。

sentinel client-reconfig-script master8000   /opt/notify_master6800.sh

修改三个服务器的redis-sentinel配置文件/etc/sentinel.conf,增加上面一行。然后在/opt/目录下创建notify_master6800.sh脚本文件,这个脚本做VIP漂移操作,内容如下:

#notify_master6800.sh脚本内容 

#!/bin/bash

MASTER_IP=$6  #第六个参数是新主redis的ip地址

LOCAL_IP='192.168.1.231'  #其他三个服务器上为192.168.1.131,192.168.56.135,192.168.1.241

VIP='192.168.1.251'

NETMASK='24'

INTERFACE='eth0'

if [ ${MASTER_IP} = ${LOCAL_IP} ];then

    /sbin/ip  addr  add ${VIP}/${NETMASK}  dev ${INTERFACE}  #将VIP绑定到该服务器上

    /sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}

    exit 0

else

   /sbin/ip  addr del  ${VIP}/${NETMASK}  dev ${INTERFACE}   #将VIP从该服务器上删除

   exit 0

fi

exit 1  #如果返回1,sentinel会一直执行这个脚本

现在当前主redis是192.168.1.231,需要手动绑定VIP到该服务器上。

/sbin/ip  addr add 192.168.1.251/24 dev eth0 

/sbin/arping -q   -c 3 -A 192.168.1.251 -I eth0

然后,去另一个服务器上通过VIP地址连接redis-server和redis-sentinel。

[root@localhost opt]# ifconfig

eth0      Link encap:Ethernet  HWaddr 00:0C:29:34:43:27

inet addr:192.168.1.131 Bcast:192.168.1.255  Mask:255.255.255.0

inet6 addr: fe80::20c:29ff:fe34:4327/64 Scope:Link

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:3830849 errors:0 dropped:0 overruns:0 frame:0

TX packets:3406249 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:444297730 (423.7 MiB)  TX bytes:416136987 (396.8 MiB)

[root@localhost opt]# redis-cli -h 192.168.1.251 -p 8000 info replication

# Replication

role:master

connected_slaves:3

slave0:ip=192.168.1.241,port=8000,state=online,offset=18468111,lag=1

slave1:ip=192.168.1.135,port=8000,state=online,offset=18468111,lag=0

slave2:ip=192.168.1.131,port=8000,state=online,offset=18468111,lag=0

master_repl_offset:18468111

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:17419536

[root@localhost opt]# redis-cli -h 192.168.1.251 -p 6800 info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=master8000,status=ok,address=192.168.1.231:8000,slaves=3,sentinels=4

                                                      通过VIP连接redis

从上面也可以看出当前主redis是192.168.1.231。

下面关闭这台redis服务,看看VIP是否漂移到另一台服务器上。

[root@session1 opt]# redis-cli -h 192.168.1.231 -p 8000 shutdown

[root@session1 opt]# redis-cli -h 192.168.1.231 -p 6800 info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=master8000,status=ok,address=192.168.1.135:8000,slaves=3,sentinels=4

[root@localhost opt]# redis-cli -h 192.168.1.251 -p 6800 info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=master8000,status=ok,address=192.168.1.135:8000,slaves=3,sentinels=4

通过访问VIP连接redis,发现VIP确实指向了192.168.1.135。

这里要注意脚本里的ip和网卡名称(eth)不能错,要不飘移不成功。

八、总结

通过上面的操作,使用redis主从 + 哨兵(sentinel)+ 漂移VIP的方案搭建了一个redis高可用系统,但这个系统保证的是单个redis实例的高可用,所以适合业务比较小的应用。如果业务比较大,并发量比较高,建议搭建redis集群,比如官方redis cluster,还有开源的codings集群。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 前言 Redis是一个高性能的key-value数据库,现时越来越多企业与应用使用Redis作为缓存服务器。楼主是...
    liangzzz阅读 4,245评论 9 152
  • NOSQL类型简介键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,volde...
    MicoCube阅读 3,956评论 2 27
  • 1 Redis介绍1.1 什么是NoSql为了解决高并发、高可扩展、高可用、大数据存储问题而产生的数据库解决方...
    克鲁德李阅读 5,265评论 0 36
  • 在cross validated上发现了类似的问题,boostrap的bias多是拿来估计variance,并且有...
    张10_阅读 364评论 0 1
  • 娃奶奶是地地道道的农村人,勤劳能干的农村妇女。 她带我家娃有半年多了。白天我上班,中午回来一次看看宝宝,喂个奶就直...
    郭小果子阅读 1,129评论 1 1