一、redis 使用
1、安装单机版redis
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -xzvf tcl8.6.1-src.tar.gz
cd /usr/local/tcl8.6.1/unix/
./configure
make && make install
使用redis-3.2.8.tar.gz(截止2017年4月的最新稳定版)
tar -zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make && make test && make install
2、redis的生产环境启动方案
如果一般的学习课程,你就随便用redis-server启动一下redis,做一些实验,这样的话,没什么意义
要把redis作为一个系统的daemon进程去运行的,每次系统启动,redis进程一起启动
(1)redis utils目录下,有个redis_init_script脚本
(2)将redis_init_script脚本拷贝到linux的/etc/init.d目录中,将redis_init_script重命名为redis_6379,6379是我们希望这个redis实例监听的端口号
(3)修改redis_6379脚本的第6行的REDISPORT,设置为相同的端口号(默认就是6379)
(4)创建两个目录:/etc/redis(存放redis的配置文件),/var/redis/6379(存放redis的持久化文件)
(5)修改redis配置文件(默认在根目录下,redis.conf),拷贝到/etc/redis目录中,修改名称为6379.conf
(6)修改redis.conf中的部分配置为生产环境
daemonize yes 让redis以daemon进程运行
pidfile /var/run/redis_6379.pid 设置redis的pid文件位置
port 6379 设置redis的监听端口号
dir /var/redis/6379 设置持久化文件的存储位置
(7)启动redis,执行cd /etc/init.d, chmod 777 redis_6379,./redis_6379 start
(8)确认redis进程是否启动,ps -ef | grep redis
(9)让redis跟随系统启动自动启动
在redis_6379脚本中,最上面,加入两行注释
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
chkconfig redis_6379 on
3、redis cli的使用
redis-cli SHUTDOWN,连接本机的6379端口停止redis进程
redis-cli -h 127.0.0.1 -p 6379 SHUTDOWN,制定要连接的ip和端口号
redis-cli PING,ping redis的端口,看是否正常
redis-cli,进入交互式命令行
SET k1 v1
GET k1
redis的技术,包括4块
redis各种数据结构和命令的使用,包括java api的使用
redis一些特殊的解决方案的使用,pub/sub消息系统,分布式锁,输入的自动完成,等等
redis日常的管理相关的命令
redis企业级的集群部署和架构
我们这套课程,实际上是针对企业级的大型缓存架构,用得项目,真实的大型电商网站的详情页系统(缓存)
我们首先讲解的第一块,其实就是企业级的大型缓存架构中的,redis集群架构(海量数据、高并发、高可用),最最流行,最最常用的分布式缓存系统
后面我们做商品详情页系统的业务开发的时候,当然也会去用redis的一些命令
redis基础知识:教程,书籍,视频
redis持久化、主从架构、复制原理、集群架构、数据分布式存储原理、哨兵原理、高可用架构
网上一些redis的教程,持久化,集群,哨兵,也讲了,都是泛泛而讲,简单带你搭建一下
我会深入集群架构的底层原理,哨兵的底层原理,用一线的经验,告诉你,redis的大规模的架构师如何去支撑海量数据、高并发、高可用的
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
二、redis的持久化,RDB,AOF,区别,各自的特点是什么,适合什么场景
1、RDB和AOF两种持久化机制的介绍
AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集
如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制
通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说云服务
如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启动redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务
如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整
2、RDB持久化机制的优点
(1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说Amazon的S3云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定 好的备份策略来定期备份redis中的数据
(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
(3)相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速
3、RDB持久化机制的缺点
(1)如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据
(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒
4、AOF持久化机制的优点
(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
(2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将
该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
5、AOF持久化机制的缺点
(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的
(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。
6、RDB和AOF到底该如何选择
(1)不要仅仅使用RDB,因为那样会导致你丢失很多数据
(2)也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
三、如何配置RDB持久化机制 、RDB持久化机制的工作流程 、基于RDB持久化机制的数据恢复实验
1、如何配置RDB持久化机制
redis.conf文件,也就是/etc/redis/6379.conf,去配置持久化
save 60 1000
每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting,快照
也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成
save可以设置多个,就是多个snapshotting检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件
2、RDB持久化机制的工作流程
(1)redis根据配置自己尝试去生成rdb快照文件
(2)fork一个子进程出来
(3)子进程尝试将数据dump到临时的rdb快照文件中
(4)完成rdb快照文件的生成之后,就替换之前的旧的快照文件
dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照
3、基于RDB持久化机制的数据恢复实验
(1)在redis中保存几条数据,立即停掉redis进程,然后重启redis,看看刚才插入的数据还在不在
数据还在,为什么?
带出来一个知识点,通过redis-cli SHUTDOWN这种方式去停掉redis,其实是一种安全退出的模式,redis在退出的时候会将内存中的数据立即生成一份完整的rdb快照
/var/redis/6379/dump.rdb
(2)在redis中再保存几条新的数据,用kill -9粗暴杀死redis进程,模拟redis故障异常退出,导致内存数据丢失的场景
这次就发现,redis进程异常被杀掉,数据没有进dump文件,几条最新的数据就丢失了
(2)手动设置一个save检查点,save 5 1
(3)写入几条数据,等待5秒钟,会发现自动进行了一次dump rdb快照,在dump.rdb中发现了数据
(4)异常停掉redis进程,再重新启动redis,看刚才插入的数据还在
rdb的手动配置检查点,以及rdb快照的生成,包括数据的丢失和恢复,全都演示过了
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
四、AOF持久化的配置、AOF持久化的数据恢复实验、AOF rewrite、AOF破损文件的修复、AOF和RDB同时工作
1、AOF持久化的配置
AOF持久化,默认是关闭的,默认是打开RDB持久化
appendonly yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓
打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写入os cache的,然后每隔一定时间再fsync一下
而且即使AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为aof数据比较完整
可以配置AOF的fsync策略,有三种策略可以选择,一种是每次写入一条数据就执行一次fsync; 一种是每隔一秒执行一次fsync; 一种是不主动执行fsync
always: 每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢,那就只能这样了
mysql -> 内存策略,大量磁盘,QPS到多少,一两k。QPS,每秒钟的请求数量
redis -> 内存,磁盘持久化,QPS到多少,单机,一般来说,上万QPS没问题
everysec: 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万的
no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了
2、AOF持久化的数据恢复实验
(1)先仅仅打开RDB,写入一些数据,然后kill -9杀掉redis进程,接着重启redis,发现数据没了,因为RDB快照还没生成
(2)打开AOF的开关,启用AOF持久化
(3)写入一些数据,观察AOF文件中的日志内容
其实你在appendonly.aof文件中,可以看到刚写的日志,它们其实就是先写入os cache的,然后1秒后才fsync到磁盘中,只有fsync到磁盘中了,才是安全的,要不然光是在os cache中,机器只要重启,就什么都没了
(4)kill -9杀掉redis进程,重新启动redis进程,发现数据被恢复回来了,就是从AOF文件中恢复回来的
redis进程启动的时候,直接就会从appendonly.aof中加载所有的日志,把内存中的数据恢复回来
3、AOF rewrite
redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉
redis中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在redis内存中
所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,到很大很大
所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致
redis 2.4之前,还需要手动,开发一些脚本,crontab,通过BGREWRITEAOF命令去执行AOF rewrite,但是redis 2.4之后,会自动进行rewrite操作
在redis.conf中,可以配置rewrite策略
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
比如说上一次AOF rewrite之后,是128mb
然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite
但是此时还要去跟min-size,64mb去比较,256mb > 64mb,才会去触发rewrite
(1)redis fork一个子进程
(2)子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
(3)redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
(4)子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
(5)用新的日志文件替换掉旧的日志文件
4、AOF破损文件的修复
如果redis在append数据到AOF文件时,机器宕机了,可能会导致AOF文件破损
用redis-check-aof --fix命令来修复破损的AOF文件
5、AOF和RDB同时工作
(1)如果RDB在执行snapshotting操作,那么redis不会执行AOF rewrite; 如果redis再执行AOF rewrite,那么就不会执行RDB snapshotting
(2)如果RDB在执行snapshotting,此时用户执行BGREWRITEAOF命令,那么等RDB快照生成之后,才会去执行AOF rewrite
(3)同时有RDB snapshot文件和AOF日志文件,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整
6、最后一个小实验,让大家对redis的数据恢复有更加深刻的体会
(1)在有rdb的dump和aof的appendonly的同时,rdb里也有部分数据,aof里也有部分数据,这个时候其实会发现,rdb的数据不会恢复到内存中
(2)我们模拟让aof破损,然后fix,有一条数据会被fix删除
(3)再次用fix得aof文件去重启redis,发现数据只剩下一条了
数据恢复完全是依赖于底层的磁盘的持久化的,主要rdb和aof上都没有数据,那就没了
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
五、
1、企业级的持久化的配置策略
在企业中,RDB的生成策略,用默认的也差不多
save 60 10000:如果你希望尽可能确保说,RDB最多丢1分钟的数据,那么尽量就是每隔1分钟都生成一个快照,低峰期,数据量很少,也没必要
10000->生成RDB,1000->RDB,这个根据你自己的应用和业务的数据量,你自己去决定
AOF一定要打开,fsync,everysec
auto-aof-rewrite-percentage 100: 就是当前AOF大小膨胀到超过上次100%,上次的两倍
auto-aof-rewrite-min-size 64mb: 根据你的数据量来定,16mb,32mb
2、企业级的数据备份方案
RDB非常适合做冷备,每次生成之后,就不会再有修改了
数据备份方案
(1)写crontab定时调度脚本去做数据备份
(2)每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
(3)每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份
(4)每次copy备份的时候,都把太旧的备份给删了
(5)每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去
/usr/local/redis
每小时copy一次备份,删除48小时前的数据
crontab -e
0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh
redis_rdb_copy_hourly.sh
#!/bin/sh
cur_date=`date +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=`date -d -48hour +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$del_date
每天copy一次备份
crontab -e
0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh
redis_rdb_copy_daily.sh
#!/bin/sh
cur_date=`date +%Y%m%d`
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=`date -d -1month +%Y%m%d`
rm -rf /usr/local/redis/snapshotting/$del_date
每天一次将所有数据上传一次到远程的云服务器上去
3、数据恢复方案
(1)如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据
不演示了,在AOF数据恢复那一块,演示了,fsync everysec,最多就丢一秒的数
(2)如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复
AOF没有破损,也是可以直接基于AOF恢复的
AOF append-only,顺序写入,如果AOF文件破损,那么用redis-check-aof fix
(3)如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复
(4) 假如有人不小心就把hadoop中存储的大量的数据文件对应的目录,rm -rf一下/var/redis/6379下的文件给删除了, 那么找到RDB最新的一份备份,小时级的备份可以了,小时级的肯定是最新的,copy到redis里面去,就可以恢复到某一个小时的数据
4、容灾演练
(1)如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据
(2)如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复
AOF没有破损,也是可以直接基于AOF恢复的
(3)如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复
(4)如果当前机器上的所有RDB文件全部损坏,那么从远程的云服务上拉取最新的RDB快照回来恢复数据
(5)如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
六、 如果redis单机要支撑超过10万+的并发,那应该怎么做? redis replication -> 主从架构 -> 读写分离 -> 水平扩容支撑读高并发
2、redis replication的核心机制
(1)redis采用异步方式复制数据到slave节点,不过redis 2.8开始,slave node会周期性地确认自己每次复制的数据量
(2)一个master node是可以配置多个slave node的
(3)slave node也可以连接其他的slave node
(4)slave node做复制的时候,是不会block master node的正常工作的
(5)slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了
(6)slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量
slave,高可用性,有很大的关系
3、master持久化对于主从架构的安全保障的意义
如果采用了主从架构,那么建议必须开启master node的持久化!
不建议用slave node作为master node的数据热备,因为那样的话,如果你关掉master的持久化,可能在master宕机重启的时候数据是空的,然后可能一经过复制,salve node数据也丢了
master -> RDB和AOF都关闭了 -> 全部在内存中
master宕机,重启,是没有本地数据可以恢复的,然后就会直接认为自己IDE数据是空的
master就会将空的数据集同步到slave上去,所有slave的数据全部清空
100%的数据丢失
master节点,必须要使用持久化机制
第二个,master的各种备份方案,要不要做,万一说本地的所有文件丢失了; 从备份中挑选一份rdb去恢复master; 这样才能确保master启动的时候,是有数据的
即使采用了后续讲解的高可用机制,slave node可以自动接管master node,但是也可能sentinal还没有检测到master failure,master node就自动重启了,还是可能导致上面的所有slave node数据清空故障
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
七、主从架构的核心原理
1、主从架构的核心原理
当启动一个slave node的时候,它会发送一个PSYNC命令给master node
如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次full resynchronization
开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。
slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。
2、主从复制的断点续传
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制
但是如果没有找到对应的offset,那么就会执行一次resynchronization
3、无磁盘化复制
master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了
repl-diskless-sync
repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接过来
4、过期key处理
slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
八、复制的完整流程
1、复制的完整流程
(1)slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始
master host和ip是从哪儿来的,redis.conf里面的slaveof配置的
(2)slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
(3)slave node发送ping命令给master node
(4)口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
(5)master node第一次执行全量复制,将所有数据发给slave node
(6)master node后续持续将写命令,异步复制给slave node
2、数据同步相关的核心机制
指的就是第一次slave连接msater的时候,执行的全量复制,那个过程里面你的一些细节的机制
(1)master和slave都会维护一个offset
master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况
(2)backlog
master node有一个backlog,默认是1MB大小
master node给slave node复制数据时,也会将数据在backlog中同步写一份
backlog主要是用来做全量复制中断候的增量复制的
(3)master run id
info server,可以看到master run id
如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制
如果需要不更改run id重启redis,可以使用redis-cli debug reload命令
4)psync
从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制
3、全量复制
(1)master执行bgsave,在本地生成一份rdb快照文件
(2)master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
(3)对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
(4)master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
(5)client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
(6)slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
(7)如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间
如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟
4、增量复制
(1)如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
(2)master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
(3)msater就是根据slave发送的psync中的offset来从backlog中获取数据的
5、heartbeat
主从节点互相都会发送heartbeat信息
master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat
6、异步复制
master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
九、搭建redis单机一主一从
一主一从,往主节点去写,在从节点去读,可以读到,主从架构就搭建成功了
1、启用复制,部署slave node
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -xzvf tcl8.6.1-src.tar.gz
cd /usr/local/tcl8.6.1/unix/
./configure
make && make install
使用redis-3.2.8.tar.gz(截止2017年4月的最新稳定版)
tar -zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make && make test && make install
(1)redis utils目录下,有个redis_init_script脚本
(2)将redis_init_script脚本拷贝到linux的/etc/init.d目录中,将redis_init_script重命名为redis_6379,6379是我们希望这个redis实例监听的端口号
(3)修改redis_6379脚本的第6行的REDISPORT,设置为相同的端口号(默认就是6379)
(4)创建两个目录:/etc/redis(存放redis的配置文件),/var/redis/6379(存放redis的持久化文件)
(5)修改redis配置文件(默认在根目录下,redis.conf),拷贝到/etc/redis目录中,修改名称为6379.conf
(6)修改redis.conf中的部分配置为生产环境
daemonize yes 让redis以daemon进程运行
pidfile /var/run/redis_6379.pid 设置redis的pid文件位置
port 6379 设置redis的监听端口号
dir /var/redis/6379 设置持久化文件的存储位置
(7)让redis跟随系统启动自动启动
在redis_6379脚本中,最上面,加入两行注释
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
chkconfig redis_6379 on
在slave node上配置:slaveof 192.168.1.1 6379,即可
也可以使用slaveof命令
2、强制读写分离
基于主从复制架构,实现读写分离
redis slave node只读,默认开启,slave-read-only
开启了只读的redis slave node,会拒绝所有的写操作,这样可以强制搭建成读写分离的架构
3、集群安全认证
master上启用安全认证,requirepass
master连接口令,masterauth
4、读写分离架构的测试
先启动主节点,eshop-cache01上的redis实例
再启动从节点,eshop-cache02上的redis实例
刚才我调试了一下,redis slave node一直说没法连接到主节点的6379的端口
在搭建生产环境的集群的时候,不要忘记修改一个配置,bind
bind 127.0.0.1 -> 本地的开发调试的模式,就只能127.0.0.1本地才能访问到6379的端口
每个redis.conf中的bind 127.0.0.1 -> bind自己的ip地址
在每个节点上都: iptables -A INPUT -ptcp --dport 6379 -j ACCEPT
redis-cli -h ipaddr
info replication
在主上写,在从上读
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十、对单机redis 一主一从压测
redis自己提供的redis-benchmark压测工具,是最快捷最方便的,当然啦,这个工具比较简单,用一些简单的操作和场景去压测
1、对redis读写分离架构进行压测,单实例写QPS+单实例读QPS
redis-3.2.8/src
./redis-benchmark -h 192.168.31.187
-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 50
各种基准测试,直接出来
1核1G,虚拟机
====== PING_INLINE ======
100000 requests completed in 1.28 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.78% <= 1 milliseconds
99.93% <= 2 milliseconds
99.97% <= 3 milliseconds
100.00% <= 3 milliseconds
78308.54 requests per second
====== PING_BULK ======
100000 requests completed in 1.30 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.87% <= 1 milliseconds
100.00% <= 1 milliseconds
76804.91 requests per second
====== SET ======
100000 requests completed in 2.50 seconds
50 parallel clients
3 bytes payload
keep alive: 1
5.95% <= 1 milliseconds
99.63% <= 2 milliseconds
99.93% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
40032.03 requests per second
====== GET ======
100000 requests completed in 1.30 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.73% <= 1 milliseconds
100.00% <= 2 milliseconds
100.00% <= 2 milliseconds
76628.35 requests per second
====== INCR ======
100000 requests completed in 1.90 seconds
50 parallel clients
3 bytes payload
keep alive: 1
80.92% <= 1 milliseconds
99.81% <= 2 milliseconds
99.95% <= 3 milliseconds
99.96% <= 4 milliseconds
99.97% <= 5 milliseconds
100.00% <= 6 milliseconds
52548.61 requests per second
====== LPUSH ======
100000 requests completed in 2.58 seconds
50 parallel clients
3 bytes payload
keep alive: 1
3.76% <= 1 milliseconds
99.61% <= 2 milliseconds
99.93% <= 3 milliseconds
100.00% <= 3 milliseconds
38684.72 requests per second
====== RPUSH ======
100000 requests completed in 2.47 seconds
50 parallel clients
3 bytes payload
keep alive: 1
6.87% <= 1 milliseconds
99.69% <= 2 milliseconds
99.87% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
40469.45 requests per second
====== LPOP ======
100000 requests completed in 2.26 seconds
50 parallel clients
3 bytes payload
keep alive: 1
28.39% <= 1 milliseconds
99.83% <= 2 milliseconds
100.00% <= 2 milliseconds
44306.60 requests per second
====== RPOP ======
100000 requests completed in 2.18 seconds
50 parallel clients
3 bytes payload
keep alive: 1
36.08% <= 1 milliseconds
99.75% <= 2 milliseconds
100.00% <= 2 milliseconds
45871.56 requests per second
====== SADD ======
100000 requests completed in 1.23 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.94% <= 1 milliseconds
100.00% <= 2 milliseconds
100.00% <= 2 milliseconds
81168.83 requests per second
====== SPOP ======
100000 requests completed in 1.28 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.80% <= 1 milliseconds
99.96% <= 2 milliseconds
99.96% <= 3 milliseconds
99.97% <= 5 milliseconds
100.00% <= 5 milliseconds
78369.91 requests per second
====== LPUSH (needed to benchmark LRANGE) ======
100000 requests completed in 2.47 seconds
50 parallel clients
3 bytes payload
keep alive: 1
15.29% <= 1 milliseconds
99.64% <= 2 milliseconds
99.94% <= 3 milliseconds
100.00% <= 3 milliseconds
40420.37 requests per second
====== LRANGE_100 (first 100 elements) ======
100000 requests completed in 3.69 seconds
50 parallel clients
3 bytes payload
keep alive: 1
30.86% <= 1 milliseconds
96.99% <= 2 milliseconds
99.94% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
27085.59 requests per second
====== LRANGE_300 (first 300 elements) ======
100000 requests completed in 10.22 seconds
50 parallel clients
3 bytes payload
keep alive: 1
0.03% <= 1 milliseconds
5.90% <= 2 milliseconds
90.68% <= 3 milliseconds
95.46% <= 4 milliseconds
97.67% <= 5 milliseconds
99.12% <= 6 milliseconds
99.98% <= 7 milliseconds
100.00% <= 7 milliseconds
9784.74 requests per second
====== LRANGE_500 (first 450 elements) ======
100000 requests completed in 14.71 seconds
50 parallel clients
3 bytes payload
keep alive: 1
0.00% <= 1 milliseconds
0.07% <= 2 milliseconds
1.59% <= 3 milliseconds
89.26% <= 4 milliseconds
97.90% <= 5 milliseconds
99.24% <= 6 milliseconds
99.73% <= 7 milliseconds
99.89% <= 8 milliseconds
99.96% <= 9 milliseconds
99.99% <= 10 milliseconds
100.00% <= 10 milliseconds
6799.48 requests per second
====== LRANGE_600 (first 600 elements) ======
100000 requests completed in 18.56 seconds
50 parallel clients
3 bytes payload
keep alive: 1
0.00% <= 2 milliseconds
0.23% <= 3 milliseconds
1.75% <= 4 milliseconds
91.17% <= 5 milliseconds
98.16% <= 6 milliseconds
99.04% <= 7 milliseconds
99.83% <= 8 milliseconds
99.95% <= 9 milliseconds
99.98% <= 10 milliseconds
100.00% <= 10 milliseconds
5387.35 requests per second
====== MSET (10 keys) ======
100000 requests completed in 4.02 seconds
50 parallel clients
3 bytes payload
keep alive: 1
0.01% <= 1 milliseconds
53.22% <= 2 milliseconds
99.12% <= 3 milliseconds
99.55% <= 4 milliseconds
99.70% <= 5 milliseconds
99.90% <= 6 milliseconds
99.95% <= 7 milliseconds
100.00% <= 8 milliseconds
24869.44 requests per second
我们这个读写分离这一块的第一讲
大部分情况下来说,看你的服务器的机器性能和配置,机器越牛逼,配置越高
单机上十几万,单机上二十万
很多公司里,给一些低配置的服务器,操作复杂度
大公司里,都是公司会提供统一的云平台,比如京东、腾讯、BAT、其他的一些、小米、美团
虚拟机,低配
搭建一些集群,专门为某个项目,搭建的专用集群,4核4G内存,比较复杂的操作,数据比较大
几万,单机做到,差不多了
redis提供的高并发,至少到上万,没问题
几万~十几万/二十万不等
QPS,自己不同公司,不同服务器,自己去测试,跟生产环境还有区别
生产环境,大量的网络请求的调用,网络本身就有开销,你的redis的吞吐量就不一定那么高了
QPS的两个杀手:一个是复杂操作,lrange,挺多的; value很大,2 byte,我之前用redis做大规模的缓存
做商品详情页的cache,可能是需要把大串数据,拼接在一起,作为一个json串,大小可能都几k,几个byte
2、水平扩容redis读节点,提升度吞吐量
就按照上一节课讲解的,再在其他服务器上搭建redis从节点,单个从节点读请QPS在5万左右,两个redis从节点,所有的读请求打到两台机器上去,承载整个集群读QPS在10万+
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十一、哨兵的介绍
sentinal,中文名是哨兵
哨兵是redis集群架构中非常重要的一个组件,主要功能如下
(1)集群监控,负责监控redis master和slave进程是否正常工作
(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移,如果master node挂掉了,会自动转移到slave node上
(4)配置中心,如果故障转移发生了,通知client客户端新的master地址
哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作
(1)故障转移时,判断一个master node是宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题
(2)即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了
目前采用的是sentinal 2版本,sentinal 2相对于sentinal 1来说,重写了很多代码,主要是让故障转移的机制和算法变得更加健壮和简单
2、哨兵的核心知识
(1)哨兵至少需要3个实例,来保证自己的健壮性
(2)哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
(3)对于哨兵 + redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
3、为什么redis哨兵集群只有2个节点无法正常工作?
哨兵集群必须部署2个以上节点
如果哨兵集群仅仅部署了个2个哨兵实例,quorum=1
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
Configuration: quorum = 1
master宕机,s1和s2中只要有1个哨兵认为master宕机就可以还行切换,同时s1和s2中会选举出一个哨兵来执行故障转移
同时这个时候,需要majority,也就是大多数哨兵都是运行的,2个哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2个哨兵都运行着,就可以允许执行故障转移
但是如果整个M1和S1运行的机器宕机了,那么哨兵只有1个了,此时就没有majority来允许执行故障转移,虽然另外一台机器还有一个R1,但是故障转移不会执行
4、经典的3节点哨兵集群
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
Configuration: quorum = 2,majority
如果M1所在机器宕机了,那么三个哨兵还剩下2个,S2和S3可以一致认为master宕机,然后选举出一个来执行故障转移
同时3个哨兵的majority是2,所以还剩下的2个哨兵运行着,就可以允许执行故障转移
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十二、哨兵主备切换的数据丢失问题:异步复制、集群脑裂
1、两种数据丢失的情况
主备切换的过程,可能会导致数据丢失
(1)异步复制导致的数据丢失
因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了
(2)脑裂导致的数据丢失
脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着
此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master
这个时候,集群里就会有两个master,也就是所谓的脑裂
此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了
因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
2、解决异步复制和脑裂导致的数据丢失
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失
(1)减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十三、redis哨兵的多个核心底层原理的深入解析(包含slave选举算法)
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配置的
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十四、在项目中以经典的3节点方式部署哨兵集群
1、哨兵的配置文件
sentinel.conf
最小的配置
每一个哨兵都可以去监控多个maser-slaves的主从架构
因为可能你的公司里,为不同的项目,部署了多个master-slaves的redis主从集群
相同的一套哨兵集群,就可以去监控不同的多个redis主从集群
你自己给每个redis主从集群分配一个逻辑的名称
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
sentinel monitor mymaster 127.0.0.1 6379
类似这种配置,来指定对一个master的监控,给监控的master指定的一个名称,因为后面分布式集群架构里会讲解,可以配置多个master做数据拆分
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
上面的三个配置,都是针对某个监控的master配置的,给其指定上面分配的名称即可
上面这段配置,就监控了两个master node
这是最小的哨兵配置,如果发生了master-slave故障转移,或者新的哨兵进程加入哨兵集群,那么哨兵会自动更新自己的配置文件
sentinel monitor master-group-name hostname port quorum
quorum的解释如下:
(1)至少多少个哨兵要一致同意,master进程挂掉了,或者slave进程挂掉了,或者要启动一个故障转移操作
(2)quorum是用来识别故障的,真正执行故障转移的时候,还是要在哨兵集群执行选举,选举一个哨兵进程出来执行故障转移操作
(3)假设有5个哨兵,quorum设置了2,那么如果5个哨兵中的2个都认为master挂掉了; 2个哨兵中的一个就会做一个选举,选举一个哨兵出来,执行故障转移; 如果5个哨兵中有3个哨兵都是运行的,那么故障转移就会被允许执行
down-after-milliseconds,超过多少毫秒跟一个redis实例断了连接,哨兵就可能认为这个redis实例挂了
parallel-syncs,新的master别切换之后,同时有多少个slave被切换到去连接新master,重新做同步,数字越低,花费的时间越多
假设你的redis是1个master,4个slave
然后master宕机了,4个slave中有1个切换成了master,剩下3个slave就要挂到新的master上面去
这个时候,如果parallel-syncs是1,那么3个slave,一个一个地挂接到新的master上面去,1个挂接完,而且从新的master sync完数据之后,再挂接下一个
如果parallel-syncs是3,那么一次性就会把所有slave挂接到新的master上去
failover-timeout,执行故障转移的timeout超时时长
2、在eshop-cache03上再部署一个redis
只要安装redis就可以了,不需要去部署redis实例的启动
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -xzvf tcl8.6.1-src.tar.gz
cd /usr/local/tcl8.6.1/unix/
./configure
make && make install
使用redis-3.2.8.tar.gz(截止2017年4月的最新稳定版)
tar -zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make && make test
make install
2、正式的配置
哨兵默认用26379端口,默认不能跟其他机器在指定端口连通,只能在本地访问
mkdir /etc/sentinal
mkdir -p /var/sentinal/5000
/etc/sentinel/5000.conf
port 5000
bind 192.168.31.187
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
port 5000
bind 192.168.31.19
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
port 5000
bind 192.168.31.227
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
3、启动哨兵进程
在eshop-cache01、eshop-cache02、eshop-cache03三台机器上,分别启动三个哨兵进程,组成一个集群,观察一下日志的输出
redis-sentinel /etc/sentinal/5000.conf
redis-server /etc/sentinal/5000.conf --sentinel
日志里会显示出来,每个哨兵都能去监控到对应的redis master,并能够自动发现对应的slave
哨兵之间,互相会自动进行发现,用的就是之前说的pub/sub,消息发布和订阅channel消息系统和机制
4、检查哨兵状态
redis-cli -h 192.168.31.187 -p 5000
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
SENTINEL get-master-addr-by-name mymaster
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十五、对项目中的哨兵节点进行管理以及高可用redis集群的容灾演练
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)哨兵就自动认为之前的187:6379变成了slave了,19:6379变成了master了
(9)哨兵去探查了一下187:6379这个salve的状态,认为它sdown了
所有哨兵选举出了一个,来执行主备切换操作
如果哨兵的majority都存活着,那么就会执行主备切换操作
再通过哨兵看一下master:SENTINEL get-master-addr-by-name mymaster
尝试连接一下新的master
故障恢复,再将旧的master重新启动,查看是否被哨兵自动切换成slave节点
(1)手动杀掉master
(2)哨兵能否执行主备切换,将slave切换为master
(3)哨兵完成主备切换后,新的master能否使用
(4)故障恢复,将旧的master重新启动
(5)哨兵能否自动将旧的master变为slave,挂接到新的master上面去,而且也是可以使用的
6、哨兵的生产环境部署
daemonize yes
logfile /var/log/sentinal/5000
mkdir -p /var/log/sentinal/5000
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十六、redis如何在保持读写分离+高可用的架构下,还能横向扩容支撑1T+海量数据
1、单机redis在海量数据面前的瓶颈
2、怎么才能够突破单机瓶颈,让redis支撑海量数据?
3、redis的集群架构
redis cluster
支撑N个redis master node,每个master node都可以挂载多个slave node
读写分离的架构,对于每个master来说,写就写到master,然后读就从mater对应的slave去读
高可用,因为每个master都有salve节点,那么如果mater挂掉,redis cluster这套机制,就会自动将某个slave切换成master
redis cluster(多master + 读写分离 + 高可用)
我们只要基于redis cluster去搭建redis集群即可,不需要手工去搭建replication复制+主从架构+读写分离+哨兵集群+高可用
4、redis cluster vs. replication + sentinal
如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个G,单机足够了
replication,一个mater,多个slave,要几个slave跟你的要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证redis主从架构的高可用性,就可以了
redis cluster,主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
十七、数据分布算法:hash+一致性hash+redis cluster的hash slot
讲解分布式数据存储的核心算法,数据分布的算法
hash算法 -> 一致性hash算法(memcached) -> redis cluster,hash slot算法
用不同的算法,就决定了在多个master节点的时候,数据如何分布到这些节点上去,解决这个问题
1、redis cluster介绍
redis cluster
(1)自动将数据进行分片,每个master上放一部分数据
(2)提供内置的高可用支持,部分master不可用时,还是可以继续工作的
在redis cluster架构下,每个redis要放开两个端口号,比如一个是6379,另外一个就是加10000的端口号,比如16379
16379端口号是用来进行节点间通信的,也就是cluster bus的东西,集群总线。cluster bus的通信,用来进行故障检测,配置更新,故障转移授权
cluster bus用了另外一种二进制的协议,主要用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间
2、最老土的hash算法和弊端(大量缓存重建)
3、一致性hash算法(自动缓存迁移)+虚拟节点(自动负载均衡)
4、redis cluster的hash slot算法
redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot
redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot
hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去
移动hash slot的成本是非常低的
客户端的api,可以对指定的数据,让他们走同一个hash slot,通过hash tag来实现