Redis 进阶一

破电脑

Redis进阶

Redis的持久化

在redis当中,提供了两种数据持久化的方式,分别为RDB以及AOF,且Redis默认开启的数据持久化方式为RDB方式

RDB持久化

Redis会定期保存数据快照至一个rbd文件中,并在启动时自动加载rdb文件,恢复之前保存的数据

手动修改

1
save [seconds] [changes] 

可通过SAVE或者BGSAVE命令手动触发RDB快照保存

在seconds秒内如果发生了changes次数据修改,则进行一次RDB快照保存

SAVE和BGSAVE区别

SAVEBGSAVE 两个命令都会调用 rdbSave 函数

SAVE 直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。

BGSAVE 则 fork 出一个子进程,子进程负责调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。 Redis 服务器在BGSAVE 执行期间仍然可以继续处理客户端的请求

RDB配置文件

1
2
3
4
save  900 1  
save 300 10
save 60 10000
save 5 1

redis的配置文件默认自带的存储机制。表示每隔多少秒,有多少个key发生变化就生成一份dump.rdb文件,作为redis的快照文件

例:save 60 10000 表示在60秒内,有10000个key发生变化,就会生成一份redis的快照

重新启动redis服务

1
2
3
ps -ef | grep redis  
bin/redis-cli -h 192.168.200.131 shutdown
bin/redis-server redis.conf

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
2
auto-aof-rewrite-percentage 100  
auto-aof-rewrite-min-size 64mb

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
2
3
4
5
如果key超时,删除key

如果一轮中删除的key的数量>W*25%,循环该过程

如果一轮中删除的key的数量≤W*25%,检查下一个expires[*],0-15循环
  • 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:任意选择数据淘汰

redis-policy策略

第二类:检测全库数据(所有数据集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
2
3
4
5
4小时27分15秒+11分36秒+2分16秒=4小时41分7秒=16867秒

1年=3652460*60=31536000秒

可用性=(31536000-16867)/31536000*100%=99.9465151%

业界可用性目标5个9,即99.999%,即服务器年宕机时长低于315秒,约5.25分钟

单点Redis可能出现的问题

机器故障

  • 问题

硬盘故障、系统崩溃

  • 实质

数据丢失,很可能对业务造成灾难性打击

容量瓶颈

  • 问题

内存不足

  • 本质

硬件条件跟不上

  • 解决思路

为了避免单点Redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份

主从复制

master 提供数据方,主服务器,主节点,主库主客户端

slave 接收数据方,从服务器,从节点,从库

主从复制

主从复制即将master中的数据即时、有效的复制到slave中

  • 特点

一个master可以拥有多个slave,一个slave只对应一个master

  • 职责

master

1
2
3
写数据
执行写操作时,将出现变化的数据自动同步到slave
读数据(可忽略)

slave

1
2
读数据
写数据(禁止)

主从复制概念

主从复制的作用

读写分离: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
2
master_link_down_since_seconds
masterhost & masterport
  • master系统信息
1
uslave_listening_port(多个)

master与slave断开连接 命令

断开slave与master的连接,slave断开连接后,不会删除已有数据,只是不再接受master发送的数据

1
slaveof no one

授权访问

  • master客户端发送命令设置密码
1
requirepass password
  • master配置文件设置密码
1
2
config set requirepass password
config get requirepass
  • 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
2
3
4
5
6
7
8
9
10
11
12
服务器运行ID(runid)

概念:服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id

组成:运行id由40位字符组成,是一个随机的十六进制字符
例如:fdc9ff13b9bbaab28db42b3d50f852bb5e3fcdce

作用:运行id被用于在服务器间进行传输,识别身份
如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于对方识别

实现方式:运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,
slave保存此ID,通过info Server命令,可以查看节点的runid
  • 主服务器的复制积压缓冲区
1
2
3
4
5
6
7
8
复制缓冲区

概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区
复制缓冲区默认数据存储空间大小是1M
当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列
作用:用于保存master收到的所有指令(仅影响数据变更的指令,例如set,select)

数据来源:当master接收到主客户端的指令时,除了将指令执行,会将该指令存储到缓冲区中
  • 主从服务器的复制偏移量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
偏移量

概念:一个数字,描述复制缓冲区中的指令字节位置

分类:

master复制偏移量:记录发送给所有slave的指令字节对应的位置(多个)
slave复制偏移量:记录slave接收master发送过来的指令字节对应的位置(一个)
作用:同步信息,比对master与slave的差异,当slave断线后,恢复数据使用

数据来源:

master端:发送一次记录一次
slave端:接收一次记录一次

字节值工作原理

  • 通过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
2
min-slaves-to-write 2
min-slaves-max-lag 8

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 国际 转载请保留原文链接及作者。