HOME/Articles/

Redis原理

Article Outline

Redis 是 Nosql 单线程,但可处理10w/s的并发。使用JAVA对Redis进行操作 类似于 jdbc接口标准对mysql。jdbc对于mysql有多种实现类,常用druid;而JAVA对于Redis,常用Jedis 在Redis中,key即byte[] (String) Redis的数据结构(value): String, List, Set, orderset, Hash

Redis的使用

  • String
  1. 存储json类型对象
  2. 计数器
  3. 视频点赞
  • List(双向链表)
  1. 直接模拟 队列、堆、栈
  2. 朋友圈点赞
  • Hash(HashMap)
  1. 保存对象
  2. 分组

Redis的持久化方式

将内存中的数据异步写入到硬盘中,两种方式:RDB(默认) 和 AOF

  • RDB持久化原理 通过bgsave命令触发。父进程执行fork操作创建子进程,子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后堆原有文件进行原子替换(定时一次性将所有数据进行快照生成一份副本存储在硬盘中)

    • 优点:一个紧凑的二进制文件,Redis加载RDB恢复数据的速度远快于AOF
    • 缺点:每次生成RDB开销较大,非实时持久化
  • AOF持久化原理 开启后,Redis每执行一个修改数据的命令,都会把这个命令写入到AOF文件里

    • 优点:实时持久化
    • 缺点:AOF文件体积逐渐变大,需定期执行重写操作来降低文件体积,加载慢

Redis速度快的原因

Redis因为如下原因速度快:

  1. Redis是单线程,避免了线程之间的竞争
  2. Redis的操作是在内存中的,减少了磁盘I/O
  3. 多路复用模型,用了缓冲区的概念,selector模型来进行

Redis三种集群方式

主从复制

主从复制原理

  • 从服务器连接主服务器,发送SYNC命令
  • 主服务器接收到SYNC命令后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录之后执行的所有写命令
  • 主服务器BGSAVE执行完成后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令
  • 从服务器收到快照文件后丢弃所有旧数据,载入新收到的快照
  • 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令
  • 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
  • 主服务器每执行一个写命令就向从服务器发送相同的写命令,从服务器接收并执行收到的写命令

    主从复制优点

  • 支持主从复制,主机会自动将数据同步到从机,可进行读写分离
  • 为分载Master的读操作压力,Slave服务器可为客户端提供只读操作的服务,写服务仍由Master完成
  • Slave也可接收其他Slave的连接和同步请求,有效地分载Master的同步压力
  • Master Server是以非阻塞的方式为Slaves提供服务。因此,即使在Master-Slave同步期间,客户端仍可提交查询或修改请求
  • Slave Server是以非阻塞的方式完成数据同步。同步期间,对于客户端提交的查询请求会返回同步前的数据

    主从复制缺点

  • Redis不具备自动容错与恢复功能。主机从机的宕机都会导致前端部分读写请求失败,需等待机器重启或手动切换前端的IP才能恢复
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性
  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂

哨兵模式

当主服务器中断服务后,可将一个从服务器升级为主服务器继续提供服务。该过程需人工介入操作。为此, Redis 2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能 哨兵的作用是监控Redis系统的运行状况。它的功能包括如下两点:

  1. 监控主服务器和从服务器是否正常运行
  2. 主服务器出现故障时自动地将从服务器切换为主服务器

    工作方式

  • 每个Sentinel(哨兵)进程以 1次/秒 的频率向整个集群的Master主服务器,Slave从服务器及其他Sentinel进程发送一个PING命令
  • 若一个实例(instance)距离最后一次有效回复PING命令的时间超过down-after-milliseconds选项所指定的值,则这个实例会被Sentinel进程标记为 主观下线(SDOWN)
  • 若一个Master主服务器被标记为 主观下线,则正在监视这个Master主服务器的所有Sentinel进程要以 1次/秒 的频率确认Master主服务器确实进入了 主观下线
  • 当有足够数量的Sentinel进程(>= 配置文件指定的值)在指定的时间范围内确认Master主服务器进入了 主观下线,则Master主服务器会被标记为 客观下线(ODOWN)
  • 在一般情况下,每个Sentinel进程会以 1次/10秒 的频率向集群中的所有Master主服务器、Slave从服务器发送INFO命令
  • 当Master主服务器被Sentinel进程标记为 客观下线 时,Sentinel进程向下线的Master主服务器的所有Slave从服务器发送INFO命令的频率从 1次/10秒 改为 1次/秒
  • 若没有足够数量的Sentinel进程同意Master主服务器下线,Master主服务器的 客观下线 状态就会被移除;若Master主服务器重新向Sentinel进程发送PING命令返回有效回复,Master主服务器的 主观下线 状态就会被移除

    哨兵模式优点

  • 哨兵模式是基于主从模式的,具有所有主从模式的优点
  • 主从可自由切换,系统健壮性更好,可用性更高

    哨兵模式优点

  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂

Redis-Cluster集群

Redis的哨兵模式基本已实现高可用,读写分离。但这种模式下每台Redis服务器都存储相同的数据,浪费内存。因此,在Redis 3.0上加入了Cluster模式,实现Redis的分布式存储,在每个Redis节点上存储不同内容 Redis-Cluster采用无中心结构,特点如下:

  • 所有的Redis节点彼此相连(PING-PONG机制),内部使用二进制协议优化传输速度和带宽
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效
  • 客户端与Redis节点直连,无需中间代理层,客户端仅需连接集群中任意一个可用节点而无需连接集群所有节点

    工作方式

    在Redis的每个节点上,都具有如下结构:
  • 插槽(slot): 取值范围 [0 ~ 16383]
  • cluster: 可理解为一个集群管理的插件

当存取的key到达时,Redis会根据CRC16算法得出一个结果并对16384求余使其对应一个在 [0 ~ 16383]间的哈希槽,找到对应插槽的对应节点,直接自动跳转到对应节点上进行存取操作。
为保证高可用,Redis-Cluster集群引入了主从模式,主节点与从节点具有(1:N)的关系。当主节点宕机时,就会启用从节点。当其他主节点PING主节点A时,若超过半数的主节点与A通信超市,即可认为主节点A宕机。若主节点A和它的从节点A1都宕机了,那么该集群无法再提供服务

内存淘汰策略

Redis的内存淘汰策略是指Redis在用于缓存的内存不足时如何处理需要写入且需要申请额外空间的数据

  • noeviction: 当内存不足以容纳新写入数据时,新写入操作报错

  • allkeys-lru: 当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key

  • allkeys-random: 当内存不足以容纳新写入数据时,在键空间中,随机移除某个key

  • voliate-lru: 当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key

  • voliate-random: 当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key

  • voliate-ttl: 当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

缓存击穿

  • 原因: 请求数据时无法直接从缓存中获取,直接进入数据库查询
  • 解决方案: 对涉及到的查询数据只查询缓存,如果特殊则可进行数据库查询,也可以采用布隆过滤器查询

缓存雪崩

  • 原因: 一次性加入缓存的数据过多,导致内存过高,影响内存的使用导致服务宕机
  • 解决方案:
    1. 使用Redis集群
    2. 后端服务降级和限流:当一个接口请求次数过多会添加过多数据。因此可对服务限流,减少问题的出现