李虹霖

 

搭建redis-sentinel(哨兵机制)集群

redis怎么才能做到高可用
对于redis主从架构,slave可以对应多个本身可以保障高可用,但是对于一个master节点,如果宕机,整个缓存系统就无法进行写的操作,显然整个系统会无法做到高可用
sentinel哨兵可以监测master节点是否正常运行(会自动识别出所有的slave信息),如果出现宕机,则会在对应的slave节点中通过投票的方式来选取一个slave节点作为新的master节点,
旧的master节点恢复之后会被接管成为新的master节点的slave节点。同时sentinel哨兵节点本身也是集群的方式部署来保障自身的高可用,并且一个sentinel是可以同时监听多个master节点

对于sentinel哨兵节点的一些核心概念:


1、sdown和odown转换机制

sdown和odown两种失败状态

sdown是主观宕机,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机

odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机

sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机

sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机

2、哨兵集群的自动发现机制

哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每个哨兵都会往__sentinel__:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在

每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves对应的__sentinel__:hello channel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置

每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在

每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步

3、slave配置的自动纠正

哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据; 如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上

4、slave->master选举算法

如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来

会考虑slave的一些信息

(1)跟master断开连接的时长
(2)slave优先级
(3)复制offset
(4)run id

如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下来会对slave进行排序

(1)按照slave优先级进行排序,slave priority越低,优先级就越高
(2)如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高
(3)如果上面两个条件都相同,那么选择一个run id比较小的那个slave

5、quorum和majority

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个哨兵来做切换,这个哨兵还得得到majority哨兵的授权,才能正式执行切换

如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换

但是如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换

6、configuration epoch

哨兵会对一套redis master+slave进行监控,有相应的监控的配置

执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号

7、configuraiton传播

哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制

这里之前的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的

其他的哨兵都是根据版本号的大小来更新自己的master配置的

 

1redis安装

解压完成后可以看到INSTALL和README.md文件,查看以获取更多有用信息。

在README文件中可以获取到软件的安装步骤。以下安装步骤基于此。

#step1 进入文件夹,执行编译命令

[root@ redis-3.2.8]# make

#step2 为了后面开发测试的方便,把启动脚本,配置文件,日志文件统一放到redis目录下

[root@ redis-3.2.8]# mkdir /usr/local/redis
[root@ redis-3.2.8]# mkdir /usr/local/redis/logs
[root@ redis-3.2.8]# mkdir /usr/local/redis/bin
[root@ redis-3.2.8]# mkdir /usr/local/redis/conf
[root@ redis-3.2.8]# mkdir /etc/sentinel
[root@ redis-3.2.8]# mkdir -p /var/sentinel/26377
[root@ redis-3.2.8]# mkdir -p /var/sentinel/26378
[root@ redis-3.2.8]# mkdir -p /var/sentinel/26379 [root@ redis-3.2.8]# cp redis.conf sentinel.conf /usr/local/redis/conf/ [root@ src]# cp redis-server redis-sentinel redis-cli /usr/local/redis/bin/

#step3 开启Redis服务,检测其可用性

[root@ bin]# redis-server ../conf/redis.conf 

可以看到日志信息

其中有3个警告

第一个警告:The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

意思是:TCP  backlog设置值,511没有成功,因为 /proc/sys/net/core/somaxconn这个设置的是更小的128.

第二个警告: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.

意思是:overcommit_memory参数设置为0!在内存不足的情况下,后台程序save可能失败。建议在文件 /etc/sysctl.conf 中将overcommit_memory修改为1。

第三个警告:you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix thisissue 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 thesetting after a reboot. Redis must be restarted after THP is disabled.

意思是:你使用的是透明大页,可能导致redis延迟和内存使用问题。执行 echo never > /sys/kernel/mm/transparent_hugepage/enabled 修复该问题。

临时解决方法:

  echo 511 > /proc/sys/net/core/somaxconn

  echo "vm.overcommit_memory=1" > /etc/sysctl.conf

  echo never > /sys/kernel/mm/transparent_hugepage/enabled。

永久解决方法:

vim /etc/sysctl.conf
net.core.somaxconn = 512
vm.overcommit_memory = 1
sysctl -p  #-p 从指定的文件加载系统参数,如不指定即从/etc/sysctl.conf中加载

[root@centos224]# vi /etc/rc.local
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi

Redis server使用默认端口6379启动成功。

#step4 修改配置文件,使其以后台服务方式运行。

复制代码
#what?局域网内本机IP。
#我是部署到同一机器上所以IP都一样,端口不同
bind 127.0.0.1
#修改默认端口,避免被恶意脚本扫描。
port 9999
loglevel debug
logfile /usr/local/redis/logs/redis.log.9999
#为服务设置安全密码
requirepass redispass
#以守护进程方式运行 daemonize yes
复制代码

#step5 重新启动redis。

[root@ bin]# redis-cli -p 9999 -a redispass shutdown
我使用脚本启动方式
  启动脚本 redis_init_script 位于位于Redis的 /utils/ 目录下,redis_init_script脚本代码如下:
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
 
#redis服务器监听的端口
REDISPORT=9999
 
#服务端所处位置
EXEC=/usr/local/bin/redis-server
 
#客户端位置
CLIEXEC=/usr/local/bin/redis-cli
 
#redis的PID文件位置,需要修改
PIDFILE=/var/run/redis_${REDISPORT}.pid
 
#redis的配置文件位置,需将${REDISPORT}修改为文件名
CONF="/etc/redis/${REDISPORT}.conf"
 
case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

可以根据你自己端口进行修改

mkdir /etc/redis
cp redis.conf /etc/redis/9999.conf
将启动脚本复制到/etc/init.d目录下,本例将启动脚本命名为redisd(通常都以d结尾表示是后台自启动服务)。
cp redis_init_script /etc/init.d/redis_9999
./redis_9999 start

2开启主从复制(master-slave)

主从模式的两个重要目的,提升系统可靠性和读写分离提升性能。

这里通过修改端口的方式,再启动端口为9997和9998的服务作为备(从)机。

备机启动需要修改配置文件部分属性(在9999配置的基础上)。

复制代码
port 9997
logfile /usr/local/redis/logs/redis.log.9997
#指定master ip port
slaveof 127.0.0.1 9999
#认证master时需要的密码。必须和master配置的requirepass 保持一致
masterauth redispass
requirepass redispass protected-mode no
复制代码

从机9998配置同理

port 9998
logfile /usr/local/redis/logs/redis.log.9998
slaveof 127.0.0.1 9999
masterauth redispass
requirepass redispass protected-mode no

开启从机服务

[root@ bin]# ./redis_9997 start
[root@ bin]# ./redis_9998 start

查看slave 9998日志(省略部分信息),可以看出,slave在启动时成功连接master,并接收到了104字节的同步数据。

6472:S 30 Mar 11:18:17.206 * Connecting to MASTER 127.0.0.1:9999
6472:S 30 Mar 11:18:17.206 * MASTER <-> SLAVE sync started
6472:S 30 Mar 11:18:17.223 * MASTER <-> SLAVE sync: receiving 104 bytes from master
6472:S 30 Mar 11:18:17.223 * MASTER <-> SLAVE sync: Finished with success

redis做一个基准的压测

你如果要对自己刚刚搭建好的redis做一个基准的压测,测一下你的redis的性能和QPS(query per second)

redis自己提供的redis-benchmark压测工具,是最快捷最方便的,当然啦,这个工具比较简单,用一些简单的操作和场景去压测

1、对redis读写分离架构进行压测,单实例写QPS+单实例读QPS

redis-3.2.8/src

./redis-benchmark -h 127.0.0.1

-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)

根据你自己的高峰期的访问量,在高峰期,瞬时最大用户量会达到10万+,-c 100000,-n 10000000,-d 500

1、QPS,自己不同公司,不同服务器,自己去测试,跟生产环境还有区别

生产环境,大量的网络请求的调用,网络本身就有开销,你的redis的吞吐量就不一定那么高了

QPS的两个杀手:一个是复杂操作,lrange,挺多的; value很大,2 byte,我之前用redis做大规模的缓存

做商品详情页的cache,可能是需要把大串数据,拼接在一起,作为一个json串,大小可能都几k,几个byte

2、水平扩容redis读节点,提升度吞吐量

就按照上一节课讲解的,再在其他服务器上搭建redis从节点,单个从节点读请QPS在5万左右,两个redis从节点,所有的读请求打到两台机器上去,承载整个集群读QPS在10万+

3 sentinel模式故障自动迁移

Master-slave主从复制避免了数据丢失带来的灾难性后果。

但是单点故障仍然存在,在运行期间master宕机需要停机手动切换。

Sentinel很好的解决了这个问题,当Master-slave模式中的Master宕机后,能够自主切换,选择另一个可靠的redis-server充当master角色,使系统仍正常运行。

一般来说sentinel server需要大于等于3个。

这里通过修改端口的方式开启3个sentinel server。修改配置文件sentinel.conf部分属性

复制代码
#服务运行端口号
port 26379
sentinel monitor mumaster 1270.0.0.1 9999 2 #mymaster为指定的master服务器起一个别名 #master IP和端口号 #2的含义:当开启的sentinel server认为当前master主观下线的(+sdown)数量达到2时,则sentinel server认为当前master客观下线(+odown)系统开始自动迁移。2的计算(建议):
#sentinel server数量的大多数,至少为count(sentinel server)/2 向上取整。2>3/2(主观下线与客观下线?) #master别名和认证密码。这就提醒了用户,在master-slave系统中,各服务的认证密码应该保持一致。 sentinel auth-pass mymaster redispass #以守护进程方式运行 daemonize yes logfile /usr/local/redis/logs/sentinel.log.26379 protected-mode no sentinel down-after-milliseconds mymaster 6000 sentinel failover-timeout mymaster 18000
复制代码

(多开服务只需要在以上配置基础上修改端口号,其它保持不变 port 26378/port 26377)

开启Sentinel服务

redis-sentinel /etc/sentinel/26377.conf
redis-sentinel /etc/sentinel/26378.conf
redis-sentinel /etc/sentinel/26379.conf

启动之后可以看到日志信息,每个哨兵都能去监控到对应的redis master,并能够自动发现对应的slave,哨兵之间,互相会自动进行发现,用的就是之前说的pub/sub,消息发布和订阅channel消息系统和机制

检查哨兵状态
redis-cli -h 127.0.0.1 -p 26377 -a "redispass"

sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster

SENTINEL get-master-addr-by-name mymaster

哨兵节点相关配置

 

1、哨兵节点的增加和删除

增加sentinal,会自动发现

删除sentinal的步骤

(1)停止sentinal进程
(2)SENTINEL RESET *,在所有sentinal上执行,清理所有的master状态
(3)SENTINEL MASTER mastername,在所有sentinal上执行,查看所有sentinal对数量是否达成了一致

2、slave的永久下线

让master摘除某个已经下线的slave:SENTINEL RESET mastername,在所有的哨兵上面执行

3、slave切换为Master的优先级

slave->master选举优先级:slave-priority,值越小优先级越高

4、基于哨兵集群架构下的安全认证

每个slave都有可能切换成master,所以每个实例都要配置两个指令

master上启用安全认证,requirepass
master连接口令,masterauth

sentinal,sentinel auth-pass <master-group-name> <pass>

 

5、容灾演练

通过哨兵看一下当前的master:SENTINEL get-master-addr-by-name mymaster

把master节点kill -9掉,pid文件也删除掉

查看sentinal的日志,是否出现+sdown字样,识别出了master的宕机问题; 然后出现+odown字样,就是指定的quorum哨兵数量,都认为master宕机了

(1)三个哨兵进程都认为master是sdown了
(2)超过quorum指定的哨兵进程都认为sdown之后,就变为odown
(3)哨兵1是被选举为要执行后续的主备切换的那个哨兵
(4)哨兵1去新的master(slave)获取了一个新的config version
(5)尝试执行failover
(6)投票选举出一个slave区切换成master,每隔哨兵都会执行一次投票
(7)让salve,slaveof noone,不让它去做任何节点的slave了; 把slave提拔成master; 旧的master认为不再是master了
(8)哨兵就自动认为之前的master变成slave,将投票出的slave变成master 
(9)哨兵去探查了一下之前的master(变成来salve)的状态,认为它sdown了 

 

故障恢复,再将旧的master重新启动,查看是否被哨兵自动切换成slave节点

查看到结果将9999 切换为slave节点

容灾演练日志
Sentinel ID is ea82430cf7f6d452eb22bbf29b92fcf001c734c8
3010:X 21 Nov 22:37:31.405 # +monitor master mymaster 127.0.0.1 9999 quorum 2
3010:X 21 Nov 23:01:12.589 # +sdown master mymaster 127.0.0.1 9999
3010:X 21 Nov 23:01:12.642 # +odown master mymaster 127.0.0.1 9999 #quorum 3/2           -- 进入ODOWN状态时。有三个哨兵认为master当机了
3010:X 21 Nov 23:01:12.642 # +new-epoch 7                                                -- 当前配置版本被更新时。
3010:X 21 Nov 23:01:12.642 # +try-failover master mymaster 127.0.0.1 9999                -- 尝试故障转移,正等待其他sentinel的选举。
3010:X 21 Nov 23:01:12.658 # +vote-for-leader ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7 -- 投票给领导
3010:X 21 Nov 23:01:12.668 # edace82644513417b676ee6eced3184771d6361d voted for ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7
3010:X 21 Nov 23:01:12.668 # 7e68a54266703cbf429f5c6512a50a39ab94b943 voted for ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7
3010:X 21 Nov 23:01:12.716 # +elected-leader master mymaster 127.0.0.1 9999              -- 被选举为去执行failover的时候。
3010:X 21 Nov 23:01:12.716 # +failover-state-select-slave master mymaster 127.0.0.1 9999 -- 开始要选择一个slave当选新master时。
3010:X 21 Nov 23:01:12.792 # +selected-slave slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 -- 找到了port:9998一个适合的slave来担当新master
                              -- 当把选择为新master的slave的身份进行切换的时候。
3010:X 21 Nov 23:01:12.792 * +failover-state-send-slaveof-noone slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 
                              -- 等待提升 9998 为新的master
3010:X 21 Nov 23:01:12.851 * +failover-state-wait-promotion slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999
3010:X 21 Nov 23:01:13.699 # +promoted-slave slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999        -- 提升 9998 master
3010:X 21 Nov 23:01:13.699 # +failover-state-reconf-slaves master mymaster 127.0.0.1 9999                         -- Failover状态变为reconf-slaves状态时
3010:X 21 Nov 23:01:13.749 * +slave-reconf-sent slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999     -- 重新配置 9997为slave
3010:X 21 Nov 23:01:14.770 # -odown master mymaster 127.0.0.1 9999                                                -- 离开ODOWN状态时。
                             -- inprog 9997 slave被重新配置为9998的master的slave,但数据复制还未发生时。
3010:X 21 Nov 23:01:14.770 * +slave-reconf-inprog slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999 
                             -- done   9997 slave被重新配置为9998的master的slave,并且数据复制已经与master同步时。
3010:X 21 Nov 23:01:14.770 * +slave-reconf-done slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999
3010:X 21 Nov 23:01:14.841 # +failover-end master mymaster 127.0.0.1 9999                                        -- 故障转移结束
3010:X 21 Nov 23:01:14.841 # +switch-master mymaster 127.0.0.1 9999 127.0.0.1 9998                               -- master由9999 替换为 9998
3010:X 21 Nov 23:01:14.841 * +slave slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9998                -- 检测到9997slave并添加进slave列表时
3010:X 21 Nov 23:01:14.842 * +slave slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998                -- 检测到9999slave
3010:X 21 Nov 23:01:44.849 # +sdown slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998                -- 进入SDOWN状态时;
3010:X 21 Nov 23:04:19.457 # -sdown slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998                -- 离开SDOWN状态时

 

posted on 2018-11-29 15:20  lol霖  阅读(1700)  评论(0编辑  收藏  举报

导航