redis怎么才能作到高可用
对于redis主从架构,slave能够对应多个自己能够保障高可用,可是对于一个master节点,若是宕机,整个缓存系统就没法进行写的操做,显然整个系统会没法作到高可用
sentinel哨兵能够监测master节点是否正常运行(会自动识别出全部的slave信息),若是出现宕机,则会在对应的slave节点中经过投票的方式来选取一个slave节点做为新的master节点,
旧的master节点恢复以后会被接管成为新的master节点的slave节点。同时sentinel哨兵节点自己也是集群的方式部署来保障自身的高可用,而且一个sentinel是能够同时监听多个master节点
对于sentinel哨兵节点的一些核心概念:redis
一、sdown和odown转换机制算法
sdown和odown两种失败状态json
sdown是主观宕机,就一个哨兵若是本身以为一个master宕机了,那么就是主观宕机vim
odown是客观宕机,若是quorum数量的哨兵都以为一个master宕机了,那么就是客观宕机centos
sdown达成的条件很简单,若是一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数以后,就主观认为master宕机缓存
sdown到odown转换的条件很简单,若是一个哨兵在指定时间内,收到了quorum指定数量的其余哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机安全
二、哨兵集群的自动发现机制服务器
哨兵互相之间的发现,是经过redis的pub/sub系统实现的,每一个哨兵都会往__sentinel__:hello这个channel里发送一个消息,这时候全部其余哨兵均可以消费到这个消息,并感知到其余的哨兵的存在网络
每隔两秒钟,每一个哨兵都会往本身监控的某个master+slaves对应的__sentinel__:hello channel里发送一个消息,内容是本身的host、ip和runid还有对这个master的监控配置架构
每一个哨兵也会去监听本身监控的每一个master+slaves对应的__sentinel__:hello channel,而后去感知到一样在监听这个master+slaves的其余哨兵的存在
每一个哨兵还会跟其余哨兵交换对master的监控配置,互相进行监控配置的同步
三、slave配置的自动纠正
哨兵会负责自动纠正slave的一些配置,好比slave若是要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据; 若是slave链接到了一个错误的master上,好比故障转移以后,那么哨兵会确保它们链接到正确的master上
四、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
五、quorum和majority
每次一个哨兵要作主备切换,首先须要quorum数量的哨兵认为odown,而后选举出一个哨兵来作切换,这个哨兵还得获得majority哨兵的受权,才能正式执行切换
若是quorum < majority,好比5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵受权就能够执行切换
可是若是quorum >= majority,那么必须quorum数量的哨兵都受权,好比5个哨兵,quorum是5,那么必须5个哨兵都赞成受权,才能执行切换
六、configuration epoch
哨兵会对一套redis master+slave进行监控,有相应的监控的配置
执行切换的那个哨兵,会从要切换到的新master(salve->master)那里获得一个configuration epoch,这就是一个version号,每次切换的version号都必须是惟一的
若是第一个选举出的哨兵切换失败了,那么其余哨兵,会等待failover-timeout时间,而后接替继续执行切换,此时会从新获取一个新的configuration epoch,做为新的version号
七、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压测工具,是最快捷最方便的,固然啦,这个工具比较简单,用一些简单的操做和场景去压测
一、对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
一、QPS,本身不一样公司,不一样服务器,本身去测试,跟生产环境还有区别
生产环境,大量的网络请求的调用,网络自己就有开销,你的redis的吞吐量就不必定那么高了
QPS的两个杀手:一个是复杂操做,lrange,挺多的; value很大,2 byte,我以前用redis作大规模的缓存
作商品详情页的cache,多是须要把大串数据,拼接在一块儿,做为一个json串,大小可能都几k,几个byte
二、水平扩容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
哨兵节点相关配置
一、哨兵节点的增长和删除
增长sentinal,会自动发现
删除sentinal的步骤
(1)中止sentinal进程
(2)SENTINEL RESET *,在全部sentinal上执行,清理全部的master状态
(3)SENTINEL MASTER mastername,在全部sentinal上执行,查看全部sentinal对数量是否达成了一致
二、slave的永久下线
让master摘除某个已经下线的slave:SENTINEL RESET mastername,在全部的哨兵上面执行
三、slave切换为Master的优先级
slave->master选举优先级:slave-priority,值越小优先级越高
四、基于哨兵集群架构下的安全认证
每一个slave都有可能切换成master,因此每一个实例都要配置两个指令
master上启用安全认证,requirepass
master链接口令,masterauth
sentinal,sentinel auth-pass <master-group-name> <pass>
五、容灾演练
经过哨兵看一下当前的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状态时