• 理解Redis事务机制
  • 掌握Redis持久化机制
  • 理解Redis高可用 — 主从复制、哨兵模式
  • 理解Redis高可扩 — Redis Cluster数据分片
  • 掌握Redis过期删除策略
  • 掌握Redis内存淘汰策略

    什么是Redis?

    Redis是一个基于内存的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件

  • 基于内存存储,读写性能高

  • 适合存储热点数据(热点商品、资讯、新闻)
  • 企业应用广泛

    使用Redis能做什么

  • 数据缓存 ★

  • 消息队列
  • 注册中心
  • 发布订阅

Redis的数据类型
字符串(string):普通字符串,常用
哈希(hash):适合存储对象
列表(list):按照插入顺序排序,可以有重复元素
集合(set):无序集合,没有重复元素
有序集合(sorted set / zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素

1 事务机制

Redis事务是基于队列实现的,创建一个事务队列,然后将事务操作都放入队列中,最后依次执行。
#开启事务
multi

添加命令
sadd user:1001:follow 1002
sadd user:1002:follow 1001
sadd user:1001:fans 1002
sadd user:1002:fans 1002

执行事务
exec

取消事务
discard

Redis事务处理机制
Redis对于命令执行错误处理,有两种解决方式:

  • 语法错误(编译)

整个事务队列中,存在一条正确指令,两条语法错误指令, 当执行exec后,会直接返回 错误,正确的命令也不会执行。

  • 执行错误(运行)

在执行时出现了错误,因此只会错误的命令不执行, 而正确的命令仍然能够正常执行。

2 持久化机制

Redis提供了两种持久化机制:RDBAOF
RDB(Redis DataBase)是Redis默认存储方式。其基于快照思想,当符合一定条件(手动或自动触发)时,Redis会将这一刻的内存数据进行快照并保存在磁盘上,产生一个经过压缩的二进制文件,文件后缀名.rdb。

触发条件

符合配置文件中的快照规则

在redis.conf文件中配置了一些默认触发机制。

save “” # 不使用RDB存储 不能主从

记忆
save 3600 1 #表示1小时内至少1个键被更改则进行快照。
save 300 100 #表示5分钟(300秒)内至少100个键被更改则进行快照。
save 60 10000 #表示1分钟内至少10000个键被更改则进行快照。

手动执行save或bgsave命令

  1. redis客户端执行savebgsave命令,手动触发RDB快照。

进入客户端
bin/redis-cli

执行save命令(同步执行)
save

执行bgsave命令(异步子线程执行)
bgsave

那么这两个命令都会触发快照的话,他们两个又有什么区别呢?

  • save:同步处理,阻塞Redis服务进程,服务器不会处理任何命令,直到RDB文件保存完毕。
  • bgsave:会fork一个和主线程一致的子线程负责操作RDB文件,不会阻塞Redis服务进程,操作RDB文件的同时仍然可以处理命令。

Redis默认使用的是 bgsave 来保存快照数据。

2.2.3 执行过程

1)Redis服务进程判断,当前是否有子线程在执行save或bgsave。
2)如果有,则直接返回,不做任何处理。
3)如果没有,则以阻塞式创建子线程,在创建子线程期间,Redis不处理任何命令。
4)创建完子线程后,取消阻塞,Redis服务继续响应其他命令。
5)同时基于子线程操作RDB文件,将此刻数据保存到磁盘。

2.2.4 优缺点

优点:

  • 基于二进制文件完成数据备份,占用空间少,便于文件传输。
  • 能够自定义规则,根据Redis繁忙状态进行数据备份。

缺点:

  • 无法保证数据完整性,会丢失最后一次快照后的所有数据。
  • bgsave执行每次执行都会阻塞Redis服务进程创建子线程,频繁执行影响系统吞吐率。

    2.3 AOF

    2.3.1 概述

    RDB方式会出现数据丢失的问题,对于这个问题,可以通过Redis中另外一种持久化方式解决:AOF
    AOF(append only file)是Redis提供了另外一种持久化机制。与RDB记录数据不同,当开启AOF持久化后,Redis会将客户端发送的所有更改数据的命令,记录到磁盘中的AOF文件。 这样的话,当Redis重启后,通过读取AOF文件,按顺序获取到记录的数据修改命令,即可完成数据恢复。

基础使用

AOF方式需要手动开启,修改redis.conf
对于AOF的触发方式有三种:alwayseverysecno。 默认使用everysec。可以通过redis.conf中appendfsync属性进行配置。
开启AOF后,重启Redis,进入Redis客户端并执行多条写命令,这些命令会被保存到appendonly.aof文件中
此时查看redis/data目录,会新产生一个appendonly.aof文件。 查看文件内容。通过文件查看,可以看到,在aof文件中,记录了对redis操作的所有写命令,读命令并不会记录。

1)客户端向Redis发送写命令。
2)Redis将接收到的写命令保存到缓冲文件aof_buf的末尾这个过程是命令追加。
3)redis将缓冲区文件内容写入到AOF文件,这个过程是文件写入
4)redis根据策略将AOF文件保存到磁盘,这个过程是文件同步。
5)何时将AOF文件同步到磁盘的策略依据就是redis.conf文件中appendfsync属性值:alwayseverysecno

  • always:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,并将AOF文件同步到磁盘。该方式效率最低,安全性最高。
  • everysec:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中。 并且每隔一秒会由子线程将AOF文件同步到磁盘。该方式兼备了效率与安全,即使出现宕机重启,也只会丢失不超过两秒的数据。
  • no:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,但并不对AOF文件进行同步磁盘。 同步操作交由操作系统完成(每30秒一次),该方式最快,但最不安全。

AOF重写优化

AOF会将对Redis操作的所有写命令都记录下来,随着服务器的运行,AOF文件内保存的内容会越来越多。这样就会造成两个比较严重的问题:占用大量存储空间数据还原花费的时间多
为了解决AOF文件巨大的问题,Redis提供了AOF文件重写功能。 当AOF文件体积超过阈值时,则会触发AOF文件重写,Redis会开启子线程创建一个新的AOF文件替代现有AOF文件。 新的AOF文件不会包含任何浪费空间的冗余命令,只存在恢复当前Redis状态的最小命令集合。

对于重写阈值的配置,可以通过修改redis.conf进行配置。
#当前aof文件大小超过上一次aof文件大小的百分之多少时进行重写。如果之前没有重写过,以
启动时aof文件大小为准
auto-aof-rewrite-percentage 100

限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
除了让Redis自动执行重写外,也可以手动让其进行执行:bgrewriteaof

2.4 RDB与AOF对比

  1. RDB默认开启,AOF需手动开启。
  2. RDB性能优于AOF。
  3. AOF安全性优于RDB。
  4. AOF优先级高于RDB。
  5. RDB存储某个时刻的数据快照,AOF存储命令。
  6. RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF默认使用everysec,每秒保存一次,最多丢失两秒以内的数据。

3 高可用-主从复制

具体步骤:
1、Slave服务启动,主动连接Master,并发送SYNC命令,请求初始化同步;
2、Master收到SYNC后,执行BGSAVE命令生成RDB文件,并缓存该时间段内的写命令;
3、Master完成RDB文件后,将其发送给所有Slave服务器;
4、Slave服务器接收到RDB文件后,删除内存中旧的缓存数据,并装载RDB文件;
5、Master在发送完RDB后,即刻向所有Slave服务器发送缓存中的写命令;
主从复制的作用:

  • 读写分离:主写从读,提高服务器的读写负载能力
  • 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
  • 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
  • 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
  • 高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案

    3.5.2 集群节点哨兵模式

    3.5.2.1 哨兵模式介绍

  • Redis提供了哨兵的命令,是一个独立的进程

  • 原理 哨兵通过发送命令给多个节点,等待Redis服务器响应,从而监控运行的多个Redis实例的运行情况
  • 当哨兵监测到master宕机,会自动将slave切换成master,通过通知其他的从服务器,修改配置文件切换主机

Sentinel三大工作任务

  • 监控(Monitoring)
    • Sentinel 会不断地检查你的主服务器和从服务器是否运作正常
  • 提醒(Notification)
    • 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知
  • 自动故障迁移(Automatic failover)

    • 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器
    • 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器

      3.5.2.2 客观下线和主观下线

  • 主观下线(Subjectively Down, 简称 SDOWN)

    • 哨兵进程会使用 PING 命令检测它自己和主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库或从库对 PING 命令的响应超时了,那么,哨兵就会先把它标记为“主观下线”
    • 一个服务器没有在 down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线
    • 如果检测的是从库,那么,哨兵简单地把它标记为“主观下线”就行了,因为从库的下线影响一般不太大,集群的对外服务不会间断。
    • 如果检测的是主库,那么,哨兵还不能简单地把它标记为“主观下线”,开启主从切换。因为很有可能存在这么一个情况:那就是哨兵误判了,其实主库并没有故障。可是,一旦启动了主从切换,后续的选主和通知操作都会带来额外的计算和通信开销。

我们要知道啥叫误判。很简单,就是主库实际并没有下线,但是哨兵误以为它下线了。误判一般会发生在集群网络压力较大、网络拥塞,或者是主库本身压力较大的情况下。

  • 客观下线(Objectively Down, 简称 ODOWN)
    • 指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断
    • 一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线
    • 客观下线条件只适用于主服务器
  • 仲裁 qurum
    • Sentinel 在给定的时间范围内, 从其他 Sentinel 那里接收到了【足够数量】的主服务器下线报告, 那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线
    • 这个【足够数量】就是配置文件里面的值,一般是Sentinel个数的一半加1,比如3个Sentinel则就设置为2
    • down-after-milliseconds 是一个哨兵在超过规定时间依旧没有得到响应后,会自己认为主机不可用
    • 当拥有认为主观下线的哨兵达到sentinel monitor所配置的数量时,就会发起一次投票,进行failover

4.2 分片集群原理

Redis原理:

  • 数据切片和实例的对应分布关系
    • Redis Cluster 方案:无中心化
      • 采用哈希槽(Hash Slot)来处理数据和实例之间的映射关系
      • 一个切片集群共有 16384 个哈希槽,只给Master分配
      • 具体的映射过程
        1. 根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;
        2. 再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽
    • 哈希槽映射到具体的 Redis 实例上
      • 用 cluster create 命令创建集群,Redis 会自动把这些槽平均分布在集群实例上
      • 也可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数注意:需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作
  • 客户端如何定位数据
    • Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散
    • 客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端
    • 客户端会把哈希槽信息缓存在本地。当请求键值对时,会先计算键所对应的哈希槽
    • 但集群中,实例和哈希槽的对应关系并不是一成不变的
      • 实例新增或删除
      • 负载均衡
    • 实例之间可以通过相互传递消息,获得最新的哈希槽分配信息,但客户端是无法主动感知这些变化
  • 重定向机制
    • 如果实例上没有该键值对映射的哈希槽,就会返回 MOVED 命令
      • 客户端会更新本地缓存
    • 迁移部分完成情况下,返回ASK
      • 表明 Slot 数据还在迁移中
      • ASK 命令把客户端所请求数据的最新实例地址返回给客户端
      • 并不会更新客户端缓存的哈希槽分配信息