Redis
通用命令
- keys 获取所有键
- dbsize 数据库key数量
- exists key 判断key是否存在
- del key[] 删除单个/多个key
- expire key seconds 设置key过期时间
- type key 查看key数据类型
基础数据结构
- string
- list
- hash
- set
- zset (有序)
keys
keys 为O(n) 命令, 一般不在生产环境使用。并且Redis为单线程架构, 所以会阻塞其它指令。
支持Pattern。
可在从节点使用。
dbsize
计算Key的总数。O(1)命令,内置计数器,所以不会影响生产环境。
exists
判断key是否存在。
del
删除key,可以多个
expire
为key设置过期时间。
使用ttl key 可以查看过期时间。
使用persist key 可以去除过期时间。
type
获取key类型。
持久化方式
快照:Redis RDB
日志:Redis AOF
RDB
主要的三种方式创建RDB文件
- save 同步
- bgsave 异步
- 自动
save 命令会阻塞其它指令。 生成临时文件, 执行完save指令后, 会将历史老文件替换成新文件。时间复杂度O(n)。不需要消耗额外的内存。
bgsave 异步, 通过linux fork来生成子进程,由于需要fork,所以需要消耗额外的内存。
时间换空间的思想。
配置自动生成RDB的策略。 可能会频繁备份, 对磁盘造成压力
save 900 1 #900s,1 changes
save 300 10
save 60 10000
dbfilename dump.rdb #rdb文件名
dir ./ #文件路径
stop-write-on-bgsave-error yes #bgsave报错,是否停止写入
rdbcompression yes #文件是否压缩
rdbchecksum yes #文件校验和检验
触发机制
- 全量复制
- debug reload
- shutdown
AOF
将所有操作日志记录下来,先将操作记录放入AOF BUFFER, 再写入AOF文件中,减少磁盘IO。
###RDB的问题
- 耗时,耗性能
- 不可控,会丢数据
###三种策略
- always 每一次都会fsync, 不丢失数据; IO开销大
- everysec 每秒都会fsync,可能会丢一秒的数据
- no OS决定fsync,不需要管理;不可控
###问题
- 日志文件会堆积,对磁盘造成压力。
- 命令写入,时间推移,并发量变大。 文件变大后,进行恢复会比较慢。
提供AOF重写来解决日志文件过大造成的问题。减少磁盘占用量, 加速AOF恢复速度。
AOF 重写的两种实现方式
- bgrewriteaof 命令 fork子进程来完成aof重写
- AOF 重写配置,自动重写
AOF重写配置:
- auto-aof-rewrite-min-size AOF文件重写需要的size
- auto-aof-rewrite-percentage AOF文件增长率
AOF统计:
-
aof_current_size 当前AOF文件大小
-
aof_base_size 上次启动和重写的文件大小
重写配置:
自动触发时机
aof_current_size > auto-aof-rewrite-min-size
(aof_current_size - aof_base_size)/aof_base_size > auto-aof-rewrite-percentage
配置:
appendonly yes
appendfilename “appenonly-${port}.aof”
appendsync everysec
dir ./
no-appendfsync-no-rewrite yes
同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。
RBD vs AOF
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
轻重 | 重 | 轻 |
RDB最佳策略
- “关闭”,但是关闭不了,主从复制是需要bgsave的。
- 集中管理,周期性数据备份,文件大小相对比较小。
- 主从。
AOF最佳策略
- “开”,持久化,缓存和存储。
- AOF重写集中管理。
- 使用everysec
最佳策略
- 小分片,maxmemory
- 缓存或存储,来配置不同策略
- 监控服务器状态
- 足够的内存空间,预留内存给fork等子进程使用
主从复制
配置主从复制
- 使用指令 slaveof
- 修改conf 文件
slaveof
slaveof 为异步命令。运行时间取决于数据量。 在使用了slaveof指令之后,会清除本地的数据,直接使用master的数据来覆盖本地数据。
取消复制
slaveof no one, 使用指令来取消复制。
在使用slaveof no one后,并不会清除本地已有的数据记录。
使用配置文件
slaveof ip port
slave-read-only yes
方式 | 指令 | 配置 |
---|---|---|
优点 | 无需重启 | 统一配置管理 |
缺点 | 不便于管理 | 需要重启 |
需要修改RDB文件名配置,防止同一个工作目录下, 两个server同时操作同一个RDB文件。
查看主从关系
使用指令 info replication 来查看状态信息。
slaveof 主从复制,slave节点通过master的rdb文件进行全量同步。就算关闭了master的自动bgsave功能, 还是会在复制时触发bgsave。
全量复制和部分复制
- run_id redis启动时会被赋有一个run id起到标志作用。 为了之后的全量复制。
- master/slave_repl_offset 写入数据时,会对offset进行改变。为了之后的部分复制。
全量复制的过程
- psync 使用run id 查看偏移量。
- 若没有run id, 则FULLRESYNC同步
- slave save master info
- master bgsave生成备份文件,write、send buffer to repl_back_buffer
- master send rdb
- master send buffer
- slave flush old data
- slave load rdb & buffer
全量复制的开销
- bgsave 的 处理时间
- RDB文件的网络传输时间
- slave节点的 flush all 时间
- slave节点加载rdb文件
- 可能的AOF重写
部分复制的过程
- slave connect to master lost
- master write and send buffer to repl_back_buffer
- slave connect to master
- slave psync
- master continue
- send particial data
开发和运维中的问题
- 读写分离:将读的流量分摊到从节点
- 主从配置不一致
- 规避全量复制
- 规避复制风暴
读写分离
可能遇到的问题
- 复制数据延迟
- 读到过期数据
- 从节点发生故障
主从配置不一致
- maxmemory不一致,可能会导致丢失数据
规避全量复制
可能产生全量复制的情况:
- 第一次全量复制, 无法避免。 方案: 小主节点, maxmemory, 低峰时处理。
- 节点运行的run id 发生变化, 可能是主节点重启后run id变化了。方案: 故障转移,例如sentinel 和 cluster。
- 复制缓冲区不足,将bgsave的过程中的操作,放入缓冲区。方案: 增大复制缓冲区 配置rel_backlog_size。
规避复制风暴
- 单节点复制风暴, 方案: 更换为拓扑模型来减轻master压力。
- 单机器复制风暴,方案:将master分布在不同的机器上。
主从复制高可用-Sentinel
Redis 提供 redis sentinel 的高可用的实现。
Redis Sentinel 的基本架构
- 多个sentinel节点发现并确认master出现问题。
- 选举出一个sentinel作为领导。
- 选择一个slave作为master。
- 通知其余的slave节点, 新的master信息。
- 通知client端,master的变化。
- 等待老的master节点复活,并将其变成新的slave节点。
Redis sentinel可以监控多套master-slave, 节省资源。
安装配置
- 配置开启主从节点
- 配置开启sentinel监控主节点。
sentinel 主要配置:
port ${port} 端口
dir "" 运行路径
logfile 日志文件
sentinel minitor mymaster 127.0.0.1 7000 2 配置redis master信息, 2的意思是sentinel数量,至少有2个sentinel发现master有问题,才发生故障转移
sentinel down-after-milliseconds mymaster 30000 如何判断是否有故障, 3w ms的响应
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
故障转移
三个定时任务
- 每10秒每个sentinel对master和slave进行info操作。 发现所有slave节点;确认主从关系。
- 每2秒每个sentinel通过master节点的channel交换信息(pub/sub 发布订阅的模式)。通过hello通道交互;交互对节点的”看法“和自身信息。
- 每1秒每个sentinel对其它sentinel和redis执行ping操作。
主观/客观下线
主观下线:
每个sentinel节点对于redis节点失败的”偏见“。
sentinel down-after-milliseconds mymaster 30000
如果超过30s, sentinel无法ping通节点,则会主观下线。
客观下线:
所有sentinel节点对于redis节点失败”达成共识“(超过quorum统一)
sentinel节点的数量最好是奇数, 符合投票选举。 quorum数量最好设置成 sentinel节点数量/2。
领导者选举
-
原因:只有一个sentinel节点来完成故障转移。
-
选举:通过sentinel is-master-down-by-addr命令都希望成为领导者
- 每个主观下线的sentinel节点向其他sentinel节点发送命令,要求将其成为领导者。
- 收到命令的sentinel节点,判断是否已经同意其它sentinel节点的命令, 若没有则会同意该请求,否则拒绝。
- 如果sentinel节点发现自己的票数已经超过sentinel集合的半数切超过quorum,则将会成为领导者。
- 如果此过程中有多个sentinel节点成为了领导者, 那么将等待一段时间重新进行选举。
故障转移
- 从slave节点中选出一个”合适的“节点做为新的master节点。
- 对上述slave节点,执行slaveof no one命令使其成为master节点。
- 对剩余的slave节点发送命令,让它们成为新master节点的slave节点, 复制规则和paralle-syncs参数有关。
- 更新对原来master节点配置为slave, 并保持关注,当其恢复后命令它去复制新的master节点。
选择”合适“的slave节点:
- 选择slave-priority 最高的节点, 如果存在则返回, 不存在则继续。
- 选择复制offset最大的slave节点(完整度最高的),如果存在则返回,不存在则继续。
- 选择runid最小的slave节点。
Redis Cluster
为什么需要cluster
- 并发量
- 数据量
- 网络流量
数据分布
全量数据过大, 需要对数据进行分区。
分区方式:
- 顺序分区(1-10, 11-20。。。。)
- 哈希分区(hash(key)%3) 哈希函数并取余
分布方式 | 特点 | 典型产品 |
---|---|---|
哈希分布 | 数据分散度高,键值分布业务无关,无法顺序访问,支持批量操作 | 一致性哈希Memache, RedisCluster, 其它缓存产品 |
顺序分布 | 数据分散度易倾斜,键值业务相关,可顺序访问,不支持批量操作 | BigTable, HBase |
哈希分布:
- 节点取余分区
- 一致性哈希分区
- 虚拟槽分区
持续更新中。。。