Redis 进阶一
Redis进阶
Redis的持久化
在redis当中,提供了两种数据持久化的方式,分别为RDB以及AOF,且Redis默认开启的数据持久化方式为RDB方式
RDB持久化
Redis会定期保存数据快照至一个rbd文件中,并在启动时自动加载rdb文件,恢复之前保存的数据
手动修改
1 | save [seconds] [changes] |
可通过SAVE或者BGSAVE命令手动触发RDB快照保存
在seconds秒内如果发生了changes次数据修改,则进行一次RDB快照保存
SAVE和BGSAVE区别
SAVE
和 BGSAVE
两个命令都会调用 rdbSave 函数
SAVE
直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。
BGSAVE
则 fork 出一个子进程,子进程负责调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。 Redis 服务器在BGSAVE 执行期间仍然可以继续处理客户端的请求
RDB配置文件
1 | save 900 1 |
redis的配置文件默认自带的存储机制。表示每隔多少秒,有多少个key发生变化就生成一份dump.rdb文件,作为redis的快照文件
例:save 60 10000 表示在60秒内,有10000个key发生变化,就会生成一份redis的快照
重新启动redis服务
1 | ps -ef | grep redis |
AOF持久化
AOF持久方式时,Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时,会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新
开启AOF
AOF默认是关闭的,要开启,进行配置
1 | appendonly yes |
AOF配置
appendfsync no
:不进行fsync,将flush文件的时机交给OS决定,速度最快
appendfsync always
:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢
appendfsync everysec
:折中的做法,交由后台线程每秒fsync一次
AOF rewrite
可以重写AOF文件,只保留能够把数据恢复到最新状态的最小写操作集
AOF rewrite可以通过BGREWRITEAOF命令触发,也可以配置Redis定期自动进行
1 | auto-aof-rewrite-percentage 100 |
Redis在每次AOF rewrite时,会记录完成rewrite后的AOF日志大小,当AOF日志大小在该基础上增长了100%后,自动进行AOF rewrite
auto-aof-rewrite-min-size最开始的AOF文件必须要触发这个文件才触发,后面的每次重写就不会根据这个变量了。该变量仅初始化启动Redis有效
AOF优点
安全 启用appendfsync为always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据
AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复
AOF文件易读,可修改,在进行某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据
AOF的缺点
AOF文件比RDB文件更大
性能消耗比RDB高
数据恢复速度比RDB慢
制定合理的持久化策略:
AOF + fsync always的设置虽然能够绝对确保数据安全,但每个操作都会触发一次fsync,会对Redis的性能有比较明显的影响
AOF + fsync every second是比较好的折中方案,每秒fsync一次
AOF + fsync never会提供AOF持久化方案下的最优性能
使用RDB持久化通常会提供比使用AOF更高的性能,但需要注意RDB的策略配置
Redis事务
Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中
Redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令
Redis事务没有隔离级别的概念
批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到
Redis不保证原子性
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行
一个事务执行的阶段
第一阶段:开始事务
第二阶段:命令入队
第三阶段:执行事务
Redis事务相关命令
- MULTI
开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令队列
- EXEC
执行事务中的所有操作命令
- DISCARD
取消事务,放弃执行事务块中的所有命令
- WATCH
监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令
- UNWATCH
取消WATCH对所有key的监视
Redis不支持事务回滚
Redis之所以保持这样简易的事务,完全是为了保证高并发下的核心问题——性能
数据删除与淘汰策略
过期数据
Redis中的数据特征
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
TTL返回的值有三种情况:正数,-1,-2
正数
:代表该数据在内存中还能存活的时间
-1
:永久有效的数据
-2
:已经过期的数据 或被删除的数据 或 未定义的数据
删除策略就是针对已过期数据的处理策略
时效性数据的存储
过期数据是一块独立的存储空间,Hash结构,field是内存地址,value是过期时间,保存了所有key的过期描述,在最终进行过期处理的时候,对该空间的数据进行检测, 当时间到期之后通过field找到内存该地址处的数据,然后进行相关操作
数据删除策略
数据删除策略的目标
在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能的下降,甚至引发服务器宕机或 内存泄露
定时删除
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
优点
节约内存,到时就删除,快速释放掉不必要的内存占用
缺点
CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
总结
用处理器性能换取存储空间(拿时间换空间)
惰性删除
数据到达过期时间,不做处理。等下次访问该数据时,我们需要判断,如果未过期,返回数据,发现已过期,删除,返回不存在
优点
节约CPU性能,发现必须删除的时候才删除
缺点
内存压力很大,出现长期占用内存的数据
总结
用存储空间换取处理器性能(拿空间换时间)
定期删除
周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度
定期删除策略
Redis启动服务器初始化时,读取配置server.hz的值,默认为10
每秒钟执行server.hz次serverCron()——–>databasesCron()———>activeExpireCycle()
activeExpireCycle()对每个expires[*]逐一进行检测,每次执行耗时:250ms/server.hz
对某个expires[*]检测时,随机挑选W个key检测
1 | 如果key超时,删除key |
W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值参数current_db用于记录activeExpireCycle() 进入哪个expires[*] 执行
如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行
特点
CPU性能占用设置有峰值,检测频度可自定义设置
内存压力不是很大,长期占用内存的冷数据会被持续清理
总结
周期性抽查存储空间(随机抽查,重点抽查)
数据淘汰策略(逐出算法)
简单明了,内存不够了,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法
策略配置
- 最大可使用内存,即占用物理内存的比例,默认值为0,表示不限制。生产环境中根据需求设定,通常设置在50%以上
1 | maxmemory ?mb |
- 每次选取待删除数据的个数,采用随机获取数据的方式作为待检测删除数据
1 | maxmemory-samples count |
- 对数据进行删除的选择策略
1 | maxmemory-policy policy |
policy策略一共3类8种
第一类 检测易失数据(可能会过期的数据集server.db[i].expires ) 同一个库
volatile-lru
:挑选最近最少使用的数据淘汰 least recently used
volatile-lfu
:挑选最近使用次数最少的数据淘汰 least frequently used
volatile-ttl
:挑选将要过期的数据淘汰
volatile-random
:任意选择数据淘汰
第二类:检测全库数据(所有数据集server.db[i].dict )
allkeys-lru
:挑选最近最少使用的数据淘汰
allkeLyRs-lfu
:挑选最近使用次数最少的数据淘汰
allkeys-random
:任意选择数据淘汰,相当于随机
第三类:放弃数据驱逐
no-enviction(驱逐)
:禁止驱逐数据(redis4.0中默认策略),会引发OOM(Out Of Memory)
淘汰策略配置到这个属性上
1 | maxmemory-policy volatile-lru |
Redis的主从复制架构
当今互联网的三高架构
不是高血糖,高血压,和高血脂呦
高并发
应用要提供某一业务要能支持很多客户端同时访问的能力
高性能
性能带给我们最直观的感受就是:速度快,时间短
高可用
一年中应用服务正常运行的时间占全年时间的百分比
1 | 4小时27分15秒+11分36秒+2分16秒=4小时41分7秒=16867秒 |
业界可用性目标5个9,即99.999%,即服务器年宕机时长低于315秒,约5.25分钟
单点Redis可能出现的问题
机器故障
- 问题
硬盘故障、系统崩溃
- 实质
数据丢失,很可能对业务造成灾难性打击
容量瓶颈
- 问题
内存不足
- 本质
硬件条件跟不上
- 解决思路
为了避免单点Redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份
master
提供数据方,主服务器,主节点,主库主客户端
slave
接收数据方,从服务器,从节点,从库
主从复制
主从复制即将master中的数据即时、有效的复制到slave中
- 特点
一个master可以拥有多个slave,一个slave只对应一个master
- 职责
master
1 | 写数据 |
slave
1 | 读数据 |
主从复制的作用
读写分离
:master写、slave读,提高服务器的读写负载能力
负载均衡
:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数 量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
故障恢复
:当master出现问题时,由slave提供服务,实现快速的故障恢复
数据冗余
:实现数据热备份,是持久化之外的一种数据冗余方式
高可用基石
:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案
主从复制工作流程
建立连接阶段(即准备阶段)
数据同步阶段
命令传播阶段(反复同步)
阶段一:建立连接
当前状态:
slave:保存master的地址与端口
master:保存slave的端口
总体:之间创建了socket 连接
master与slave互联 命令
- 方式一:客户端发送命令
1 | slaveof masterip masterport |
- 方式二:启动服务器参数
1 | redis-server --slaveof masterip masterport |
- 方式三:服务器配置(主流方式)
1 | slaveof masterip masterport |
- slave系统信息
1 | master_link_down_since_seconds |
- master系统信息
1 | uslave_listening_port(多个) |
master与slave断开连接 命令
断开slave与master的连接,slave断开连接后,不会删除已有数据,只是不再接受master发送的数据
1 | slaveof no one |
授权访问
- master客户端发送命令设置密码
1 | requirepass password |
- master配置文件设置密码
1 | config set requirepass password |
- slave客户端发送命令设置密码
1 | auth password |
- slave配置文件设置密码
1 | masterauth password |
- slave启动服务器设置密码
1 | redis-server –a password |
阶段二:数据同步
当前状态:
slave:具有master端全部数据,包含RDB过程接收的数据
master:保存slave当前数据同步的位置
总体:之间完成了数据克隆
数据同步阶段master说明
如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行
复制缓冲区大小设定不合理,会导致数据溢出。如进行全量复制周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态。
1 | repl-backlog-size ?mb |
- master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执 行bgsave命令和创建复制缓冲区
数据同步阶段slave说明
- 为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务
1 | slave-serve-stale-data yes|no |
数据同步阶段,master发送给slave信息可以理解master是slave的一个客户端,主动向slave发送命令
多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果master带宽不足,因此数据同步需要根据业务需求,适量错峰
slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间的节点既是master,也是 slave。注意使用树状结构时,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟较大,数据一致性变差,应谨慎选择
小提示
设计Redis架构时,一开始就要想好了用几主几从,然后把他们启动其起来
阶段三:命令传播
当master数据库状态被修改后,导致主从服务器数据库状态不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播
master将接收到的数据变更命令发送给slave,slave接收命令后执行命令
部分复制
介绍一下三个核心要素
- 服务器的运行 id(run id)
1 | 服务器运行ID(runid) |
- 主服务器的复制积压缓冲区
1 | 复制缓冲区 |
- 主从服务器的复制偏移量
1 | 偏移量 |
字节值工作原理
通过offset区分不同的slave当前数据传播的差异
master记录已发送的信息对应的offset
slave记录已接收的信息对应的offset
三个阶段整体工作流程
心跳机制
进入命令传播阶段候,master与slave间需要进行信息交换,使用心跳机制进行维护,实现双方连接保持在线
master心跳任务
内部指令
:PING
周期
:由repl-ping-slave-period决定,默认10秒
作用
:判断slave是否在线
查询
:INFO replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常
slave心跳任务
内部指令
:REPLCONF ACK {offset}
周期
:1秒
作用1
:汇报slave自己的复制偏移量,获取最新的数据变更指令
作用2
:判断master是否在线
心跳阶段可能发生的问题
当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步
1 | min-slaves-to-write 2 |
slave数量少于2个,或者所有slave的延迟都大于等于8秒时,强制关闭master写功能,停止数据同步
slave数量由slave发送REPLCONF ACK命令做确认
slave延迟由slave发送REPLCONF ACK命令做确认
你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界
本文标题:Redis 进阶一
发布时间:2022年08月08日 - 01:08
最后更新:2022年08月08日 - 01:09
原始链接:https://codexiaobo.github.io/posts/1308773244/
许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。