三千字介绍Redis主从+哨兵+集群

一、Redis持久化策略

1.RDB

每隔几分钟或者一段时间会将redis内存中的数据全量的写入到一个文件中去。

优点:

  1. 因为他是每隔一段时间的全量备份,代表了每个时间段的数据。所以适合做冷备份。
  2. RDB对redis的读写影响非常小,因为redis主进程只需要fork一个子进程进行磁盘IO操作就行了。
  3. 相对于AOF来说,恢复较快,因为一个RDB就是数据文件,而AOF存的是指令日志。

缺点:

  1. 因为是一段时间才备份,所以容易丢数据。
  2. 如果一次写入的文件大,会导致读写服务暂停几毫秒,甚至几秒。

2.AOF

会将每条写入指令都写入到linux os缓存中去,然后每秒钟会将linux os中的指令作为日志追加到AOF的文件里面。

当redis内存大小达到一定的量,会通过LRU(最近最少使用)淘汰机制淘汰掉数据,然后再重写一个新的AOF文件出来。这样也保证了AOF文件不会无限制的增大。

优点:

  1. 不易丢数据
  2. AOF日志文件是以append-only的模式写入,没有磁盘寻址的开销,写入性能高,文件也不易破损
  3. AOF文件过大的时候,后台重写操作,也不会影响客户端。再rewrite的时候,会对指令压缩,创建出一份需要恢复的最小日志出来,再创建新日志文件时,老的文件照常写入,当新文件准备好了,再交换新老日志文件就行了
  4. 日志文件的命令是可读的,可以作为误删的紧急恢复。停了服务,再把那条删除指令删除,再恢复就行了。

缺点:

  1. AOF日志文件占用的磁盘空间比较大
  2. 开启AOF后,写操作的QPS会下降
  3. 以前出过bug,恢复的数据和原来不一样,健壮性没有RDB高
  4. 恢复数据慢,且不适合做冷备(需要手动写脚本)

3.混合持久化(Redis 4.0)

开启混合持久化

aof-use-rdb-preamble yes

综合来说:

我们可以采用两种都用的的方案,RDB做冷备,为了保证数据不丢失,AOF做数据恢复的第一选择。

如何配置持久化?

  1. 找到/usr/local/package/redis-4.0.9/redis.conf

  2. RDB的配置

 //每隔60秒,如果有10000个key发生改变就持久化一次
    save 60 10000
  1. AOF的配置
    # redis默认关闭AOF机制,可以将no改成yes实现AOF持久化
    appendonly no
    # AOF文件
    appendfilename "appendonly.aof"
    # AOF持久化同步频率,always表示每个Redis写命令都要同步fsync写入到磁盘中,但是这种方式会严重降低redis的速度;everysec表示每秒执行一次同步fsync,显示的将多个写命令同步到磁盘中;no表示让操作系统来决定应该何时进行同步fsync,Linux系统往往可能30秒才会执行一次
    # appendfsync always
    appendfsync everysec
    # appendfsync no
    
    # 在日志进行BGREWRITEAOF时,如果设置为yes表示新写操作不进行同步fsync,只是暂存在缓冲区里,避免造成磁盘IO操作冲突,等重写完成后在写入。redis中默认为no  
    no-appendfsync-on-rewrite no   
    # 当前AOF文件大小是上次日志重写时的AOF文件大小两倍时,发生BGREWRITEAOF操作。  
    auto-aof-rewrite-percentage 100  
    #当前AOF文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEAOF。  
    auto-aof-rewrite-min-size 64mb  
    # Redis再恢复时,忽略最后一条可能存在问题的指令(因为最后一条指令可能存在问题,比如写一半时突然断电了)
    aof-load-truncated yes
    #Redis4.0新增RDB-AOF混合持久化格式,在开启了这个功能之后,AOF重写产生的文件将同时包含RDB格式的内容和AOF格式的内容,其中RDB格式的内容用于记录已有的数据,而AOF格式的内存则用于记录最近发生了变化的数据,这样Redis就可以同时兼有RDB持久化和AOF持久化的优点(既能够快速地生成重写文件,也能够在出现问题时,快速地载入数据)。
    aof-use-rdb-preamble no
  1. AOF rewrite过程

    1. redis fork一个子进程
    2. 子进程基于当前内存中的数据开始写入一个新的aof的文件
    3. 这时新的命令进来,会存在内存中,也会存在旧的aof文件中
    4. 当新的aof文件写好了,这个过程中的新的命令也会追加到aof里来
    5. 然后用新日志文件替换掉旧的日志文件

注意:当使用shutdown命令关闭redis服务时,会自动备份一个快照

当RDB生成快照时,AOF不会rewrite。反之亦然。

redis如果遇到断电或机器故障问题时怎么办?

答:一般使用持久化加服务器文件(将文件备份到阿里云)备份的方案

二、Redis淘汰策略

LRU:(least recently used)最近最少使用

  1. 标准的LRU算法:

使用HashMap+双向链表
三千字介绍Redis主从+哨兵+集群

核心步骤:

  1. save操作时,在hashmap中找对应的key值,如果存在,更新他并移到队头,如果不存在,则构建新节点,并移到队头,如果队列满了,则移除队尾的节点,并在hashmap中移除该key
  2. get操作时,在hashmap中找到对应的节点,将他移到队头

redis里面没有使用双向链表的实现方式,而是使用了一个pool池.

  1. Redis的LRU实现

常用策略:allkeys-lru

Redis使用的是近似LRU算法

  • 给每个 key 增加一个额外 24bit 长度的小字段, 存储该 key 的最后一次访问时间戳
  • 当空间满时, 随机采样取出 5 个 key (数量可配置), 按时间戳淘汰掉最旧的 key
  • 循环第二步, 直到内存低于 maxmemory 值
  • 随机采样的范围取决于配置的策略是 volatile 还是 allkeys

Redis 3.0 开始, 增加了淘汰池进一步提升了近似 LRU 的效果:

  • 上一次随机采样后未淘汰的 key, 会放入 淘汰池 留待下一次循环,
  • 下一次随机采样的key会先和淘汰池中的key合并后, 再计算淘汰最旧的key

三、Redis主从架构

1.主从特性

  1. 采用异步的方式复制到slave节点,不过redis2.8之后,每个slave节点会周期性的确认自己每次复制的数据量
  2. 一个master可以配置多个slave
  3. slave node也可以连接其他的slave node
  4. slave复制时不影响master的工作
  5. slave复制时也不会影响slave的查询操作,他会用旧的数据提供服务。但是当复制完成,需要删除旧数据,加载新数据集时,会暂停服务。
  6. slave主要用来做横向扩容,做读写分离

2.主从复制步骤

  1. 当slave第一次连接时,master会生成一个全量RDB文件给他做恢复,并将这个过程中新的写入命令缓存在内存中,等slave把RDB文件读入之后发给他
  2. 当slave断开一段时间后重连,master会将缺失的数据发给他
  3. 平时情况下,master收到一个指令,都会马上复制给slave

3.断点续传
从redis2.8开始,就支持主从复制的断点续传
master中存了backlog,master和slave都会保存一个replica offset,还有一个master id。如果中途网络断了,slave会让master从上次的replica offset开始继续复制。

4.过期key处理
slave不会过期key,只会等master过期key之后或者根据,模LRU淘汰了key之后拟一个del命令发给slave

5.配置主从服务器

  1. 安装redis
  2. cp utils/redis_init_script /etc/init.d/redis_6379
  3. redis自启动 chkconfig redis_6379 on
  4. mkdir /etc/redis
  5. mkdir -p /var/redis/6379
  6. cp redis.conf /etc/redis/6379.conf
  7. 修改配置文件6379.conf
  • daemonize yes //让redis以daemon进程运行
  • dir /var/redis/6379
  • slaveof CentOS01 6379
  • slave 服务器的配置文件上配 masterauth 123456
  • master服务器的配置文件上配
    requirepass 123456
  • 每个6379.conf里都要将bind 127.0.0.1改成bind 自己本机的ip
  1. 让redis跟随系统启动自动启动

在redis_6379脚本中,最上面,加入两行注释

#chkconfig:   2345 90 10  
#description:  Redis is a persistent key-value database

然后执行
chkconfig redis_6379 on
8. 压测性能 ./redis-benchmark -c 50 -n 10000

复制原理图:
三千字介绍Redis主从+哨兵+集群

注意:主从架构建议必须开启master节点的持久化。

四、哨兵模式

1.概念介绍

介绍:

  1. 集群监控,监控master和slave是否正常
  2. 消息通知,如果某个redis实例故障了,负责发消息给管理员
  3. 故障转移,如果master节点挂掉了,会自动转移到slave上
  4. 配置中心,如果故障转移发生了,通知client新的master地址

2.故障转移

哨兵至少要3个实例
三千字介绍Redis主从+哨兵+集群

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,但是故障转移不会执行

3.解决异步复制和脑裂导致的数据丢失

min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒

4.sdown和odown转换机制
sdown:主观宕机,即一个哨兵觉得master宕机了
odown:客观宕机,即quorum数量的哨兵觉得master宕机了

5.哨兵集群的自动发现机制

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

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

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

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

6.选举算法

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

会考虑slave的一些信息

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

7.部署哨兵

  1. 复制配置文件
    mkdir -p /var/sentinel/5000
    mkdir /etc/sentinel
    mkdir -p /var/log/sentinal/5000
    mv /usr/local/package/redis-4.0.9/sentinel.conf /etc/sentinel/5000.conf
  1. 修改配置文件
  port 5000
  bind  192.168.1.14
  sentinel monitor mymaster 192.168.1.12 6379 2
  dir /var/sentinel/5000
  sentinel parallel-syncs mymaster 1
  sentinel failover-timeout mymaster 60000
  sentinel down-after-milliseconds mymaster 30000
  sentinel auth-pass mymaster 123456
  daemonize yes
  logfile /var/log/sentinal/5000/sentinel.log

注意:sentinel monitor mymaster 192.168.1.12 6379 2 这行要放在使用mymaster的那些其他配置之前

  1. 启动哨兵

./redis-sentinel /etc/sentinel/5000.conf

五、redis集群

1.概念介绍

  1. 自动对数据进行分片,每个master上存放一部分数据
  2. 提供内置的高可用支持,部分master不可用了,还是可以继续工作的

2.部署选型
redis cluster VS replication + sentinel

当数据量少,主要承载的是高并发时,单机就足够了。一个master多个slave,在搭建一个sentinel集群来保证高可用性

redis cluster主要还是用来做海量数据的缓存。

3.分布式Hash算法

当需要把数据分到不同的几个机器存储时,就需要一个算法了。

  1. 方法一:取模
    对数据的hash值取模,比如有3台集器,那么就用hash%3,得到的就是0-2的三个数字,就可以确定将数据存在哪一台上面了

缺点:如果有一台机器挂掉了,那么数据会对2取模,那么得到的机器号就错乱了,导致大量数据不能从正确的机器上去取

  1. 方法二:一致性hash算法(圆环算法)

将3台机器放在一个圆环上,然后要缓存的数据经过计算也落在圆环的某一个点,然后顺时针去环上找离他最近的那个机器。

优点:当一台机器挂掉,不影响其他的机器上存的数据

缺点:具有热点问题,可能某一个机器会有大量数据,这就需要将每个机器都多设置几个虚拟节点,均匀分布在圆环上。

三千字介绍Redis主从+哨兵+集群

  1. 方法三:redis cluster的hash slot算法

redis cluster有固定的16384个slot,对每个key计算CRC16值,然后对16384取模,获取对应的slot,每个master都有部分的slot。这样的话如果增加一个master,就将其他master上的slot分点给她就行了。

4.部署redis集群

  1. 创建目录
  mkdir -p /etc/redis-cluster
  mkdir -p /var/log/redis
  mkdir /var/redis/7001
  mkdir /var/redis/7002
  1. 修改配置文件 7001.conf
  port 7001
  cluster-enabled yes
  cluster-config-file /etc/redis-cluster/node-7001.conf
  cluster-node-timeout 15000
  pidfile "/var/run/redis_7001.pid"
  dir "/var/redis/7001"
  logfile "/var/log/redis/7001.log"
  1. 修改配置文件
vi /usr/local/share/gems/gems/redis-3.2.1/lib/redis/client.rb

password=123456
  1. 执行
 echo never > /sys/kernel/mm/transparent_hugepage/enabled
  1. 启动脚本
   cd /etc/init.d/
   cp redis_6379 redis_7001
修改redis_7001配置

  REDISPORT=7001
  1. 安装ruby
   yum install -y ruby
    下载一个redis-3.2.1.gem,然后执行
    gem install redis
    
    cp /usr/local/package/redis-4.0.9/src/redis-trib.rb /usr/local/bin
    
    /usr/local/bin/redis-trib.rb create --replicas 1 192.168.1.12:7001 192.168.1.12:7002 192.168.1.13:7003 192.168.1.13:7004 192.168.1.14:7005 192.168.1.14:7006
  1. 检查节点状态
 ./redis-trib.rb check 192.168.1.12 7001
上一篇:【Java从0到架构师】Redis - 持久化(RBD、AOF)、高可用(主从复制、哨兵机制)


下一篇:Redis的过期键删除策略