1. 安装
1 | wget http://download.redis.io/releases/redis-5.0.7.tar.gz |
2. Redis 部署方式
Redis 部署方式 redis 部署方式及常见特性- singleton 单点
- master-slave 主从
1 个 master, 多个 slaves
master 可以读和写, slaves 只能读不能写
master 挂掉之后, redis 不能提供写服务, 不影响从 slaves 上读取; slave 挂掉之后, 不影响 redis 服务, 可以重启 slave 节点, 之后会从 master 上同步数据过来
master 挂掉之后, slave 无法自动推举 master 节点. 如果 master 没有备份数据, 直接重启 master 将丢失所有 slaves 上的数据 - sentinel 哨兵
sentinel 模式建立在主从模式之上, 如果是单点 redis, sentinel 就没有意义
当 master 挂掉之后, 由 sentinel 选择一个 slave 作为 master, 并修改其他 slaves 的配置, 让他们指向新的 master. 挂掉的 master 重启后将作为 slave, 同步新的 master 上的数据
sentinel 是一个高可用的方案, 防止主从模式中 master 挂掉之后, 无法自动恢复的问题. sentinel 作为方案的一部分, 本身也需要集群, 防止单点故障.
一个 sentinel 或 sentinel 集群可以管理多个主从 redis.
客户端不直接连 redis, 而是由 sentinel 提供可用 master 的连接地址.
由于数据的保存还是依靠 master, 无法突破单台服务器内存大小的限制. - cluster 集群
cluster 多主多从, 多个 master 通过分片共同管理数据, 解决单台服务器容量问题.
master 挂掉后, 自动选择其 slave 节点作为 master.
容易增加或减少节点.
2.1. Redis 集群
Redis 集群教程2.1.1. Redis 集群中的数据分片
Redis 集群共有 16384 (2^14) 个哈希槽, 每个 key 通过 CRC16 校验后与 16384 取模来决定放在哪个槽.
集群中的每个节点负责一部分哈希槽.
这种结构很容易添加和删除节点.
比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.
2.1.2. 主从复制方式
复制- 完整同步
- 部分同步
- 命令传播
当 slave 连接 master 时, 发送 PSYNC $runId $offset 请求同步.
master 根据情况判断是完整同步还是部分同步.
$runId 是 slave 记录的 master 节点的 runId, 如果没有则说明 slave 是首次连接 master; 如果与 master 自己的 runId 不一致, 则说明 slave 断开后重新连接的不是之前的 master. 以上 2 中情况都需要完整同步.
$offset 是 slave 当前的命令偏移量. master 接收到的命令会在内存中保存到 replica backlog 中. 如果 slave 传过来的 offset 还在 backlog 范围内, 且 runId 一致, 则可以使用部分同步, 否则可能 slave 断开时间过长, 需要使用完整同步.
2.2. 主从复制方式
Redis的全量复制和部分复制3. Redis 持久化
持久化-
RDB
保存的是数据库的状态 -
AOF
Append Only File, 保存的是数据库执行过的命令同步(fsync)策略:
- always 每次都将 aof_buf 缓冲区同步到 AOF 文件
- everysec 每隔 1 秒将 aof_buf 缓冲区同步到 AOF 文件
- no 何时同步交由操作系统决定如果 AOF 文件过大, 会自动通过 REWRITEAOF 命令重写 AOF 文件
RDB 文件一般比 AOF 文件小, 所以一般执行速度会快于 AOF 文件
系统出现异常时, AOF 比 RDB 丢失数据更少
如果 Redis 同时配置了这两中备份方式, 启动时会优先选择加载 AOF 文件.
4. Redis 事务
关键字:
- WATCH 通过 CAS 监听多个 key 值是否变化, 如果变化则取消事务
- MULTI
- EXEC
- DISCARD
如果一个事务在入队过程中发生错误, 如命令不正确, 找不到等语法错误, Redis 将拒绝执行该事务.
如果一个事务在执行过程中发生错误, 事务将继续执行, 且不影响已经执行的命令, 即 Redis 不支持回滚.
5. Redis 内存清理
5.1. Redis 过期键删除策略
- 惰性删除
放任键过期不管, 但是每次从键空间中获取键时, 都检查取得的键是否过期, 如果过期就删除该键, 如果没有过期就返回该键. - 定期删除
每隔一段时间, 程序就对数据库进行一次检查, 删除里面的过期键.
Redis 会在规定时间内多次随机检查一部分键的过期时间, 如果过期则删除.
5.2. 最大内存策略
lru-cachemaxmemory 设置最大可用内存, 0 表示没有内存限制, redis就会一直向OS申请内存, 直到OS的所有内存都被使用完. 所以通常建议设置上redis的内存限制.
设置了maxmemory后, 当redis的内存达到内存限制后, 再向redis发送写指令, 会返回一个内存耗尽的错误. 错误通常会触发一个应用程序错误, 但是不会导致整台机器宕掉.
maxmemory-policy 设置内存回收策略
- noeviction: 返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令 (大部分的写入指令, 但DEL和几个例外)
- allkeys-lru: 尝试回收最少使用的键 (LRU) , 使得新添加的数据有空间存放.
- allkeys-random: 回收随机的键使得新添加的数据有空间存放.
- volatile-lru: 尝试回收最少使用的键 (LRU) , 但仅限于在过期集合的键,使得新添加的数据有空间存放.
- volatile-random: 回收随机的键使得新添加的数据有空间存放, 但仅限于在过期集合的键.
- volatile-ttl: 回收在过期集合的键, 并且优先回收存活时间 (TTL) 较短的键,使得新添加的数据有空间存放.
如果键分布比较均匀, 则使用 random 策略
如果需要保留热点访问数据, 则使用 lru 策略
如果需要根据键的过期时长回收, 则使用 ttl 策略
Redis 接收到写操作后, 先检查内存是否足够, 如果不够, 则执行回收策略释放内存.
随机从键空间中获取 maxmemory-samples 个键, 根据策略淘汰.
5.2.1. 近似 LRU
Redis的LRU算法并非完整的实现. 这意味着Redis并没办法选择最佳候选来进行回收, 也就是最久未被访问的键.
相反它会尝试运行一个近似LRU的算法, 通过对少量keys进行取样, 然后回收其中一个最好的key (被访问时间较早的) .
maxmemory-samples 设置随机采样的精度, 默认是 5, 值越大越接近真是的 LRU 算法, 但 CPU 消耗也越大, 执行效率越低.
5.3. Redis 一致性保证
什么时候 Redis 会出现丢失数据的情况?
- Redis 为了保证性能, 主从节点之间是异步复制, 当主节点异常挂掉之后切换从节点时可能会有部分数据丢失
- 集群模式中, 如果碰到网络分区的情况, 由于会同时存在 2 个 master 节点, 之后其中一个会被降为 slave, 从脑裂到恢复正常一段时间内的数据会丢失 通过以上配置, master 的副本数量不能少于 3 个, 且同步副本的延时不能超过 10 秒, 否则 master 将会拒绝写入请求, 减少数据同步后的数据丢失.
1
2min-replicas-to-write 3 # 最少连接到 master 的 slave 数量
min-replicas-max-lag 10 # master 和 slaves 之间同步的最大延迟