Redis开发与运维读书笔记
Redis开发与运维读书笔记
虽然一直使用redis,但是对redis缺少整体的一个学习,这两天趁着有时间就把这本书拿出来看了下,这本书应该来说是很有阅读空间的,读的过程做了些笔记,相当于备忘
单线程架构
redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务
为什么单线程还能这么快
-
纯内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100ns
-
非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多时间
-
单线程避免了线程切换和竞态产生的消耗
单线程问题:对于每个命令的执行时间有要求,如果某个命令执行过长,会造成其他命令的阻塞,所以Redis是面向快速执行场景的数据库。
redis数据结构
字符串
内部编码
-
int 8个字节的长整型
-
embstr:小于等于39个字节的字符串
-
raw:大于39个字节的字符串
redis会根据当前值得类型和长度决定使用哪种内部编码实现
使用场景
-
缓存功能 合理的健名设计,业务名:对象名:id:【属性】
-
计数
-
session共享
-
限速
哈希
内部编码
ziplist(压缩列表) 当哈希类型元素小于512 、同时所有值都小于64字节时,Redis会使用ziplist作为哈希的内部实现
hashtable(哈希表)
列表
列表中的元素是有序的 列表中的元素是可以重复的
内部编码
ziplist ziplist(压缩列表) 当列表元素小于512 、同时所有值都小于64字节时,Redis会使用ziplist作为列表的内部实现
linkedlist 当列表类型无法满足ziplist的条件时,redis会使用linkedlist作为表的内部实现
使用场景:消息队列 (lpush+brpop) 文章列表
集合 不允许重复元素 并行集合中的元素是无序的,无法通过索引下标获取元素,一个集合最多可以存储2*32-1个元素,集合支持多个结合取交集、并集、差集
内部编码
intset(整数集合) 当集合中的元素都是整数且元素个数小于512 redis使用inset来作为集合的内部实现
有序集合 元素不能重复且有序
内部编码
ziplist 有序集合个数小于128 同时元素的值都笑余4字节,redis会用ziplist来作为有序集合的内部实现
使用场景 添加用户赞数
skiplist
hashtable
使用场景:给用户添加标签、给标签添加用户、
持久化
RDB持久化:把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动车发
手动触发分别对应save和bgsave命令
save命令:阻塞当前redis服务器,直到RDB过程完成为止
bgsave命令:redis进程执行fork操作创建子进程,RDB持久化由子进程负责,完成后自动结束,阻塞只发生在fork阶段,一般时间很短
RDB优点:
-
RDB是一个紧凑压缩的二进制文件,非常适用于备份,全量复制等场景
-
redis加载RDB恢复数据远远快于AOF的方式
RDB缺点:
RDB方式数据没办法做到实时持久化/秒级持久化
存在老版本redis服务无法兼容新版RDB格式的问题
AOF(append only file):以独立日志的方式记录每次写命令,重启时在重新执行AOF文件中的命令达到恢复数据的目的
AOF工作流程操作:命令写入(append)、文件同步(sync)、文件重写(rewrite)、重启加载(load)
AOF命令写入的内容直接是文本协议格式
AOF缓冲区同步文件策略
-
always
-
everysec
-
no
redis复制
建立复制
配置复制的方式
-
在配置文件中加入slaveof{masterHost}{masterPort}随redis启动生效
-
在redis-server启动命令后加入slaveof{masterHost}{masterPort}随redis启动生效
-
直接使用命令slaveof{masterHost}{masterPort}随redis启动生效生效
断开复制:slaverof no one命令
断开复制流程:
断开与主节点复制关系
从节点晋升为主节点
传输延迟
repl-disable-tcp-nodelay参数用于控制是否关闭TCP_NODELAY
复制拓扑结构
-
一主一从
-
一主多从
-
树状主从
复制过程
-
保存主节点信息
-
主从建立socket链接
-
发送ping命令
-
权限验证
-
同步数据集 使用psync命令完成主从数据同步,同步过程分为全量复制和部分复制 全量复制:一般用于初次复制场景 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据给从节点
-
命令持续复制
复制风暴:
大量从节点对同一主节点或者对同一台机器的多个主节点短时间发起全量复制的过程。规避复制风暴的方式有如下几个:
单主节点复制风暴:减少主节点挂载的从节点数量,或者采用树状复制结构,加入中间层从节点来保护从节点
单机器复制风暴:把主节点尽量分散在多台机器上,避免在单台机器部署过多的主节点
redis内存消耗划分
自身内存、对象内存、缓冲内存、内存碎片
缓冲内存包括:客户端缓冲、复制积压缓冲区、AOF缓冲区
AOF缓冲区:用于在Redis重写期间保存最近的写入命令
复制积压缓冲区:Redis在2.8版本之后提供了一个可重用的固定大小缓冲区用于实现部分复制功能。
redis内存管理
限制内存目的:
-
用于缓存场景,当超出内存上限时使用LRU等删除策略释放内存空间
-
防止所用内存超过物理内存空间
内存回收策略
惰性删除:用于客户端读取带有超时属性的健,如果已经超过健设置的过期时间,会执行删除操作并返回空,这种方式存储内存泄漏的问题
定式任务删除:Redis内部维护一个定时任务,默认每秒运行10次,定时任务删除过期健逻辑采用了自适应算法,根据健的过期比例、使用快慢两种速率模式回收健
内存溢出控制策略:redis所用内存达到maxmemory上限时会触发相应的溢出控制策略
-
noevicition:默认策略,不会删除任何数据,拒绝所有写入策略,只响应读操作
-
volatile-lru:根据LRU算法删除设置了超时属性(expire)的健,直到腾出足够空间为止,如果没有可删除的健对象,回退noeviction策略
-
allkey-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止
-
allkeys-random:随机删除所有键,知道腾出足够空间为止
-
volatile-random:随机删除过期键,知道腾出足够空间为止
-
vloatile-ttl:根据键值对象的ttl属性,删除最近将要过期的数据,如果没有,回退noevicition策略
redis内存优化
redis存储的所有值对象在内部定义为redisObject结构体
type字段:表示当前对象使用的数据类型
enoding:表示redis内部编码类型
lru字段:记录对象最后一次被访问的时间
refcount字段:记录当前对象被引用的次数,用于通过引用次数回收内存
*ptr字段:与对象的数据内容相关,如果是整数,直接存储数据;否则表示指向数据的指针。
优化建议:
缩减键和值的长度,在完整面熟业务的情况下,键值越短越好,value长度:把业务对象序列化成二进制数组放入redis。
使用共享对象池
字符串优化:
尽量减少字符串频繁修改操作如append、setrange,改为直接使用set修改字符串,降低预分配带来的内存浪费和内存碎化
字符串重构,像json这样的数据可以使用hash结构,
字符串结构:redis自己实现了字符串结构,内部简单动态字符串
特点:
O(1)时间复杂度获取:字符串长度、已用长度、未用长度
可用于保存字节数组,支撑安全的二进制数据存储
内部实现空间预分配机制,降低内存再分配次数
惰性删除机制,字符串缩减后的空间不释放,作为预分配空间保留
编码优化
编码类型转换在redis写入数据时自动完成,这个转换过程是不可逆,转换规则只能从小内存编码向大内存编码转换
控制键的数量
redis sentinel
主从复制优点:
从节点可以扩展主节点的读能力
从节点作为主节点的备份,一旦主节点出现故障不可达的情况,从节点可以作为后备份顶上来,,并且保证数据尽量不丢失(主从复制是最终一致性)
缺点:
一旦主节点出现故障,需要手动将一个从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令其他从节点去复制新的主节点,整个过程需要人工干预
主节点的写能力受到单机限制
主节点的存储能力受到单机限制
当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用
Redis Sentinel功能:
监控:Sentinel节点会定期检测Redis数据节点、其余Sentinel节点是否可达
通知:Sentinel节点会定期检测Redis数据节点、其余Sentinel节点是否可达
通知:Sentinel节点会将故障转移的结果通知给应用发方
主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系
配置提供者:在Redis Sentinel结构中,客户端在初始化的时候链接的是Sentinel节点集合,从中获取主节点信息
实现原理
三个定时任务
每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的拓扑结构
每隔2秒,每个Sentinel节点向Redis数据节点的_sentinel_:hello频道上发送改Sentinel节点对于主节点的判断以及当前Sentinel节点的信息,同时每个Sentinel节点也会订阅该频道来了解其他Sentinel节点以及他们对主节点的判断,这个定时任务完成两个工作
发现新的sentinel节点
Sentinel节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据
每隔1秒,每个Sentiinel节点会向主节点、从节点、其余sentinel节点发送一天ping命令做一次心态检测,来确定这些节点是否可达
客观下线主观下线
领导者sentinel节点选举
Redis使用Raft算法实现领导者选举,过程如下
每个在线的Sentinel节点都有资格成为领导者,当它确认主观节点主观下线时候,会想其他Sentinel节点发送Sentinel is-master-down-by-addr命令,要求将自己设置为领导者
收到命令的Sentinel节点,如果没有同意过其他Sentinel节点的sentinel-is-master-down-by-addr命令,将同意该请求,否则拒绝
如果该Sentinel节点发现自己的票数已经大于等于max(quorum,num(sentinels)/2+1),那么它将成为领导者
如果此过程没有选举出其他领导者,将进入下一次选举
故障转移具体步骤
-
在从节点列表中选出一个节点作为新的主节点,选择方法如下
-
过滤"不健康"(主观下线、断线)\5秒内没有回复过Sentinel节点ping响应、与主节点失联超过down-afte-milliseconds*10秒
-
选择slave-priority(从节点优先级)最高的从节点列表,如果存在则返回,不存在则继续
-
选择复制偏移量最大的从节点(复制的最完整),如果存在则返回,不存在则继续
-
选择runid最小的从节点
-
-
Sentinel领导者会对一地不选出来的从节点执行slaveof no one命令让其成为主节点
-
Sentinel领导者节点会向剩余的从节点发送命令,让他们成为新主节点的从节点,复制规则和parallel-syncs参数有关
-
Sentinel节点集合会将原来的主节点更新为从节点,并保持对其关注,当其恢复后命令它去复制新的主节点