一、Redis高可用
在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。
但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等。
在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和 Cluster集群,,作用如下:
持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
哨兵:在主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
Cluster集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
二、持久化
持久化是redis当中一个非常重要的功能,因为redis是一个基于内存的数据库,如果没有持久化,一旦关机或者重启,之前所有的数据都会丢失,这对一个数据库来说是非常致命的,持久化就是为解决这个问题而诞生了
1.redis持久化方式
1.1 RDB(Redis DataBase)方式
RDB 是 Redis 默认的持久化方式,通过定期将内存中的数据以二进制的形式保存到磁盘上的RDB文件中,实现数据的持久化。这个过程可以通过Redis服务器自动触发(例如通过save配置指令设置触发条件),也可以手动执行(通过bgrewriteaof命令)。
RDB 文件是经过压缩的二进制文件,便于备份和恢复,同时加载速度快,但可能会丢失最后一次触发快照后到Redis宕机之间这段时间的数据。
1.2 AOF (Append Only File) 持久化
AOF 持久化则是将每一次对Redis服务器的写操作以Redis协议的格式追加到一个单独的日志文件(也就是AOF文件)中。相比RDB,AOF提供了更高的数据安全性,因为它的持久化粒度更细,理论上可以达到每一笔写操作都不会丢失的程度。
AOF 文件随着时间推移会不断增大,Redis 提供了AOF重写机制(bgrewriteaof命令触发),用来压缩AOF文件,去掉无效的命令和合并连续的写操作。
AOF模式可以配置不同的同步策略,包括“每条命令都同步”、“每秒同步一次”和“在写入后至少等待指定数量的写操作再同步”。
2.持久化过程
AOF 持久化则是将每一次对Redis服务器的写操作以Redis协议的格式追加到一个单独的日志文件(也就是AOF文件)中。相比RDB,AOF提供了更高的数据安全性,因为它的持久化粒度更细,理论上可以达到每一笔写操作都不会丢失的程度。
AOF 文件随着时间推移会不断增大,Redis 提供了AOF重写机制(bgrewriteaof命令触发),用来压缩AOF文件,去掉无效的命令和合并连续的写操作。
AOF模式可以配置不同的同步策略,包括“每条命令都同步”、“每秒同步一次”和“在写入后至少等待指定数量的写操作再同步”。
1.RDB持久化过程
1.1 触发RDB持久化
RDB持久化可以通过配置文件中的save指令自动触发,例如当满足一定条件(如过去5分钟内有10个key发生变化)时,Redis会自动执行一次快照操作。也可以通过手动执行SAVE或BGSAVE命令触发。SAVE命令会阻塞Redis服务器直到RDB文件创建完成,而BGSAVE命令会在后台异步执行持久化操作。
1. 2 父进程fork子进程
触发RDB持久化后,父进程会fork一个子进程,这个过程中父进程是阻塞的,不能接受其它的客户端命令
1.3 fork子进程完成
子进程负责将内存中的数据以二进制格式写入到RDB文件中,而主进程继续处理客户端请求。
1.4 子进程生成RDB文件
子进程将数据库中的数据转换为一系列序列化格式的键值对,然后写入磁盘文件。写入完成后,原来的RDB文件(如果存在)会被新的RDB文件替换。
1.5 子进程向父进程发送信号
子进程发送信号给父进程表示完成,父进程更新统计信息
2.AOF持久化过程
AOF持久化过程主要包括三个方面,命令追加、文件写入与文件同步、文件重写。
2.1 命令追加
每次客户端发送的写命令在Redis服务器中执行完成后,都会被以Redis协议格式追加到AOF缓冲区,而后统一写入到磁盘当中。主要是为了防止每次写命令都直接继续如磁盘,导致磁盘IO负载过高。造成瓶颈
2.2 文件写入与文件同步
启用AOF持久化后,Redis会将所有的写命令追加到AOF文件的末尾,可以配置不同的同步策略(always、everysec、no)来平衡数据安全性和性能。根据配置的同步策略,Redis会在命令执行完成后立即(always)、每秒(ecerysec)或在操作系统缓冲区满时(no)将命令刷入磁盘。
appendfsync always
设置为 always 表示每次Redis接收到写命令后,都会调用操作系统提供的 fsync() 或类似函数强制将AOF缓冲区的内容同步到磁盘中。这种方式能够确保每个写命令都立即被持久化,因此在Redis服务器崩溃的情况下,数据丢失的可能性最小。但是,频繁的同步操作会显著降低Redis的性能,因为它涉及到磁盘I/O操作,而磁盘I/O通常比内存操作要慢得多。
appendfsync everysec
这是Redis AOF的默认设置。在这种模式下,Redis会在每一秒结束时(大约每秒)将AOF缓冲区的内容同步到磁盘。这意味着在最坏情况下,如果Redis在同步后立即崩溃,可能会丢失这一秒内的写操作数据。然而,这种策略在保证数据相对安全的同时,也能保持较好的性能表现。
appendfsync no
当设置为 no 时,Redis不会主动调用同步操作,而是依赖操作系统的缓存策略来决定何时将AOF缓冲区内容刷到磁盘。这种配置下,Redis的写性能将会是最高的,因为它减少了与磁盘交互的频率。然而,这也意味着在服务器突然断电或无预警关机的情况下,可能丢失大量未写入磁盘的数据,因此数据安全性极低。
总结来说,appendfsync 的不同设置允许用户在数据安全性和性能之间进行权衡选择。在实际应用中,大多数场景推荐使用 appendfsync everysec 来达到较好的折衷效果。对于极度关注数据安全的应用,可以选择 appendfsync always,但在牺牲性能的前提下;而对于对性能要求极高且能接受一定数据丢失风险的应用,则可考虑 appendfsync no。
2.AOF重写
① 随着AOF文件的持续增长,Redis提供了AOF重写功能(可通过bgrewriteaof命令触发)来压缩AOF文件。
②Redis父进程首先判断当前是否存在正在执行bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在 bgsave命令则等bgsave执行完成后再执行。父进程执行fork操作创建子进程,这个过程中父进程是阻塞的。
③父进程fork后,bgrewriteaof命令返回信息并不再阻塞父进程。而后将所有的命令写入缓冲区,而后根据同步方式追加到AOF文件的末尾,同时命令也进入重写缓冲区
④ 子进程首先生成新的AOF文件,而后向父进程发送信号,更新统计信息
⑤重写缓冲区会遍历内存中的数据构建最小化且有效的命令集合,将这些命令写入新的AOF文件。
新的AOF文件创建完成后,Redis会原子地用新的AOF文件替换旧文件。
重写的作用
将过期的数据不再写入文件,最后一条错误语句不写入
无效的命令不在写入,比如创建set key value,在后面又执行了del key。这样创建又删除的操作将自动被忽略
将多条命令合并,比如将sadd key_set value1, sadd key_set value2, saddkey_set value3,合并成sadd key_set value1 value2 value3
三、开启持久化
1.开启RDB持久化
需要修改/etc/redis/6379.conf配置文件
#通过配置设置触发
save m n
#自动触发最常见的情况是在配置文件中通过save m n,指定当m秒内发生n次变化时,会触发bgsave。
vim /etc/redis/6379.conf
-----219行--以下三个save条件满足任意一个时,都会引起bgsave的调用
save 900 1 :当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
save 300 10 :当时间到300秒时, 如果redis数据发生了至少10次变化,则执行bgsave
save 60 10000 :当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave
-----242行--是否开启RDB文件压缩
rdbcompression yes
-----254行--指定RDB文件名
dbfilename dump.rdb
-----264行--指定RDB文件和AOF文件所在目录
dir /var/lib/redis/6379
2.开启AOF持久化
Redis服务器默认开启RDB,关闭AOF;要开启AOF,需要在配置文件中配置:
vim /etc/redis/6379.conf
--700行--修改,开启AOF
appendonly yes
--704行--指定A0F文件名称
appendfilename "appendonly.aof"
--796行--是否忽略最后一条可能存在问题的指令
aof-load-truncated yes
/etc/init.d/redis_6379 restart 重启服务
重启服务并查看端口是否开启
四、RDB与AOF的优缺点
1.RDB持久化方式的优点与缺点
1.1 优点
性能优异:RDB持久化在生成快照时会对主线程进行fork操作创建一个子进程,子进程完成数据持久化工作,不会阻塞主线程处理客户端请求,故对Redis服务性能影响较小。
数据恢复快:RDB文件是二进制格式的,紧凑且易于加载,Redis在重启时可以直接读取RDB文件恢复数据,速度较快。
易于备份与迁移:RDB文件可以方便地用于备份或迁移到其他Redis服务器,而且由于文件体积相对较小,传输和存储成本较低。
1.2 缺点
数据安全性略低:在发生故障时,最后一次持久化和故障之间的时间段内的数据可能丢失。如果RDB文件生成周期较长,潜在的数据丢失风险就越大。
资源消耗:虽然fork操作在现代操作系统中代价相对较小,但对于大容量数据的Redis实例,fork操作仍可能引起暂时的性能下降和较大的内存开销。
不适合大型在线更新场景:如果应用中有大量的写入操作,且需要非常严格的实时持久化保证,RDB可能不是最佳选择,因为RDB是以周期性快照方式进行持久化的。
2.AOF持久化方式的优点与缺点
2.1 优点
数据安全性高:AOF持久化以命令追加的方式记录,可以设置不同的同步策略(如appendfsync everysec),接近于实时持久化,大大降低了数据丢失的可能性。
容错性强:即便AOF文件损坏,Redis提供了redis-check-aof工具进行修复,可以从中找回大部分数据。
重写功能:缩小文件体积,减少磁盘的空间占用,优化存储效率,提示性能。
精确恢复:AOF记录了所有写操作,因此在Redis重启时可以按照写入命令的顺序逐条执行,精确恢复数据状态。
2.2 缺点
性能损耗:根据不同的同步策略,AOF可能需要频繁地将命令写入硬盘,尤其在always同步策略下,对性能影响较大。
文件体积增长较快:随着写操作的增多,AOF文件会逐渐变大,尽管Redis提供了AOF重写功能(bgrewriteaof)来压缩文件,但仍然需要一定的存储空间。
恢复速度相对较慢:AOF文件在Redis重启时需要逐条执行命令来恢复数据,相比于直接加载RDB文件,恢复速度较慢。
五、性能管理
1.内存碎片
内存碎片(Memory Fragmentation)是指在计算机内存管理中,由于分配和回收内存空间而导致的无法连续使用的内存区域。内存碎片分为两类:
内部碎片(Internal Fragmentation): 当内存分配器为一个程序分配内存时,分配的内存块可能会大于程序实际需要的空间。例如,分配器可能按照固定大小或者页大小分配内存,即使请求的内存小于分配单位大小,也会分配一个完整的单位。这部分分配给程序但未被使用的内存空间就是内部碎片。内部碎片不可用于分配给其他程序,即使它在物理上是可用的。
外部碎片(External Fragmentation): 随着程序的运行和内存的分配与回收,内存中可能会形成许多小的、不连续的空闲区域,虽然这些区域的总和足以满足一个大的内存请求,但由于它们彼此不连续,所以不能被分配给需要大块连续内存空间的程序。这些无法合并使用的空闲区域构成了外部碎片。
内存碎片的存在会降低内存利用率,尤其是在连续内存分配策略中,严重的内存碎片可能导致即使还有足够的内存总量,也无法分配给新的请求,这在资源有限的系统中尤为不利。现代内存管理系统通常会采用各种策略来减少或避免内存碎片,如动态内存分配算法、分页系统和垃圾回收机制等。
2.Redis内存碎片率
内存碎片率是衡量Redis内存利用率的一个关键指标,表示Redis在分配和回收内存过程中未使用的内存空间与已使用内存之间的比例。公式通常定义为 mem_fragmentation_ratio = used_memory_rss / used_memory,
其中
used_memory_rss 是Redis进程在操作系统层面所占用的实际物理内存大小。
used_memory 是Redis为了存储数据所分配的内存总量。
碎片率较高意味着Redis分配了大量的内存但并未完全有效利用,可能是由于Redis在分配内存时倾向于分配整块空间,当存储的数据大小变化时,原有的内存块未被完全填满,形成了碎片。长期的碎片积累可能导致Redis内存效率低下,甚至在达到最大内存限制(maxmemory 设置)时因内存不足引发 OOM 错误
跟踪内存碎片率对理解Redis实例的资源性能是非常重要的:
内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低,也说明 Redis 没有发生内存交换
内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。需要在redis-cli工具上输入shutdown save 命令,让 Redis 数据库执行保存操作并关闭 Redis 服务,再重启服务器。
内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少 Redis 内存占用。
3.Redis内存使用率
内存使用率是指Redis已经使用的内存占总内存(或分配给Redis的最大内存)的比例。虽然Redis本身并不直接显示内存使用率这个百分比,但我们可以通过计算得出大致的使用情况。例如,如果你知道Redis实例的最大可用内存(即maxmemory设定值),则内存使用率可近似表示为 used_memory / maxmemory * 100%
可以使用 info memor命令查看内存使用情况
六、Redis内部Key回收策略
为了管理内存资源并防止内存溢出,Redis提供了多种数据淘汰策略( eviction policies ),当内存达到maxmemory限制时,Redis会根据选择的策略自动删除部分Key以释放内存空间
开启key回收,取消配置文件(通常为/etc/redis/6379.conf)中598行的注释,开启key回收
volatile-lru:仅针对设置了过期时间(TTL)的Key,按照最近最少使用(LRU)算法剔除最久未访问的Key。
allkeys-lru:对所有Key均采用LRU算法剔除。
volatile-ttl:剔除即将过期的Key中,剩余生存时间(TTL)最短的Key。
noeviction:不主动删除任何Key,但在尝试写入新的数据时,如果内存已满,则拒绝执行会导致内存增长的命令。
volatile-random 和 allkeys-random:随机剔除具有过期时间或所有Key中的某个Key。
除了上述策略外,管理员还可以通过手动执行 DEL 或 KEYS 指令配合 UNLINK (非阻塞版本的删除指令)来删除特定Key,以减少内存占用。