Redis再深入一点之高可用持久化及性能管理,必看!!!
Posted 28线不知名云架构师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis再深入一点之高可用持久化及性能管理,必看!!!相关的知识,希望对你有一定的参考价值。
一、Redis高可用
- 在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。
- 但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等
主要运用的高可用技术:
- 持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
- 主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
- 哨兵:在主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
- 集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案
二、Redis持久化
redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化,这是相对memcache来说的一个大的优势。redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。
2.1、RDB持久化
RDB就是Snapshot存储,是默认的持久化方式。按照一定的策略周期性的将数据保存到磁盘。对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期。Redis支持将当前数据的快照存成一个数据文件实现持久化。而一个持续写入的数据库如何生成快照呢。Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件。
Client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主线程中保存快照的,由于redis是用一个主线程来处理所有 client的请求,这种方式会阻塞所有client请求,所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不 是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能。
Redis的RDB文件不会坏掉,因为其写操作是在一个新进程中进行的。当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件。这样在任何时候出现故障,Redis的RDB文件都总是可用的。并且Redis的RDB文件也是Redis主从同步内部实现中的一环
2.1.1、主从同步
第一次Slave向Master同步的实现是:
Slave向Master发出同步请求,Master先dump出rdb文件,然后将rdb文件全量传输给slave,然后Master把缓存的命令转发给Slave,初次同步完成。
第二次以及以后的同步实现是:
Master将变量的快照直接实时依次发送给各个Slave。但不管什么原因导致Slave和Master断开重连都会重复以上两个步骤的过程。
Redis的主从复制是建立在内存快照的持久化基础上的,只要有Slave就一定会有内存快照发生。
2.1.2、工作原理
-
Redis调用fork(),产生一个子进程。
-
父进程继续处理client请求,子进程把内存数据写到一个临时的RDB文件。由于os的写时复制机制(copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数据是fork时刻整个数据库的一个快照。
-
当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出
2.1.3、优点
-
RDB文件是一个很简洁的单文件,它保存了某个时间点的Redis数据,很适合用于做备份。你可以设定一个时间点对RDB文件进行归档,这样就能在需要的时候很轻易的把数据恢复到不同的版本。
-
RDB很适合用于灾备。单文件很方便就能传输到远程的服务器上。
-
RDB的性能很好,需要进行持久化时,主进程会fork一个子进程出来,然后把持久化的工作交给子进程,自己不会有相关的I/O操作。
-
比起AOF,在数据量比较大的情况下,RDB的启动速度更快。
2.1.4、缺点
-
RDB容易造成数据的丢失。假设每5分钟保存一次快照,如果Redis因为某些原因不能正常工作,那么从上次产生快照到Redis出现问题这段时间的数据就会丢失了。
-
RDB使用
fork()
产生子进程进行数据的持久化,如果数据比较大的话可能就会花费点时间,造成Redis停止服务几毫秒。如果数据量很大且CPU性能不是很好的时候,停止服务的时间甚至会到1秒
2.1.5、触发条件
手动触发(save和bgsave,生产环境不使用)
- save命令和bgsave命令都可以生成RDB文件。
- save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求。
- bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求。
- bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用。
- 往往生产环境仍然不允许轻易使用
自动触发
- 在自动触发RDB持久化时,Redis也会选择bgsave而不是save来进行持久化。
- 自动触发最常见的情况是在配置文件中通过save m n,指定当m秒内发生n次变化时,会触发bgsave。
vim /etc/redis/6379.conf
以下三个save条件满足任意一个时,都会引起bgsave的调用
219 save 900 1 ##当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
220 save 300 10 ##当时间到300秒时, 如果redis数据发生了至少10次变化, 则执行bgsave
221 save 60 10000 :当时间到60秒时,如果redis数据发生了至少10000次变化, 则执行bgsave
242 rdbcompression yes ##是否开启RDB文件压缩
254 dbfilename dump.rdb ##指定RDB文件名
264 dir /var/lib/redis/6379 ##指定RDB文件和AOF文件所在目录
其他自动触发机制
- 在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点
- 执行shutdown命令时,自动执行rdb持久化
2.1.6、执行流程
- Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof的子进程,如果在执行则bgsave命令直接返回bgsave/bgrewriteaof
- 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令
- 父进程fork后,bgsave命令返回”Background saving started" 信息并不再阻塞父进程,并可以响应其他命令
- 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
- 子进程发送信号给父进程表示完成,父进程更新统计信息
2.1.7、启动时加载
- RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令
- 优先级:AOF>RDB,因此当AOF开启时,默认先载入AOF文件,仅当AOF关闭,才会载入RDB文件
- Redis载入RDB文件时(即启动过程中),会对RDB 文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败
2.2、AOF持久化
快照并不是很可靠。如果服务器突然Crash了,那么最新的数据就会丢失。而AOF文件则提供了一种更为可靠的持久化方式。每当Redis接受到会修改数据集的命令时,就会把命令追加到AOF文件里,当你重启Redis时,AOF里的命令会被重新执行一次,重建数据
2.2.1、原理
-
redis调用fork ,现在有父子两个进程
-
子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
-
父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题
-
当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件
-
现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加
2.2.2、优点
-
比RDB可靠。你可以制定不同的fsync策略:不进行fsync、每秒fsync一次和每次查询进行fsync。默认是每秒fsync一次。这意味着你最多丢失一秒钟的数据。
-
AOF日志文件是一个纯追加的文件。就算服务器突然Crash,也不会出现日志的定位或者损坏问题。甚至如果因为某些原因(例如磁盘满了)命令只写了一半到日志文件里,我们也可以用
redis-check-aof
这个工具很简单的进行修复。 -
当AOF文件太大时,Redis会自动在后台进行重写。重写很安全,因为重写是在一个新的文件上进行,同时Redis会继续往旧的文件追加数据。新文件上会写入能重建当前数据集的最小操作命令的集合。当新文件重写完,Redis会把新旧文件进行切换,然后开始把数据写到新文件上。
-
AOF把操作命令以简单易懂的格式一条接一条的保存在文件里,很容易导出来用于恢复数据。例如我们不小心用
FLUSHALL
命令把所有数据刷掉了,只要文件没有被重写,我们可以把服务停掉,把最后那条命令删掉,然后重启服务,这样就能把被刷掉的数据恢复回来。
2.2.3、缺点
-
在相同的数据集下,AOF文件的大小一般会比RDB文件大。
-
在某些fsync策略下,AOF的速度会比RDB慢。通常fsync设置为每秒一次就能获得比较高的性能,而在禁止fsync的情况下速度可以达到RDB的水平。
-
在过去曾经发现一些很罕见的BUG导致使用AOF重建的数据跟原数据不一致的问题。
2.2.4、开启AOF
Redis服务器默认开启RDB,关闭AOF
要开启AOF,需要在配置文件中配置
vim /etc/redis/6379.conf
700 appendonly yes ##修改成yes,开启AOF
704 appendfilename "appendonly.aof" ##指定A0F文件名称
796 aof-load-truncated yes ##是否忽略最后一条可能存在问题的指令
/etc/ init.d/redis_ 6379 restart ##重启redis
2.2.5、执行流程
由于需要记录Redis的每条写命令,因此A0F不需要触发,下面介绍AOF的执行流程。
AOF的执行流程包括:
- 命令追加(append)
将Redis的写命令追加到缓冲区aof_buf; (为了尽量不因为持久化而影响redis性能) - 文件写入(write)和文件同步(sync)
根据不同的同步策略将aof_buf中的内容同步到硬盘,所以Redis系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性
AOF缓存区的同步文件策略存在三种同步方式,它们分别是
vim /etc/redis/6379.conf
729 appendfsync always
##命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到A0F文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。
729 appendfsync no
命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
729 appendfsync everysec(默认配置)
命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。
3.文件重写(rewrite)
定期重写AOF文件,达到压缩的目的
2.2.6、文件重写的触发分类
文件重写的触发,分为手动触发和自动触发
- 手动触发
直接调用bgrewriteaof命令;通过fork子进程进行具体的工作,且只有在fork时阻塞。 - 自动触发
通过设置auto-aof-rewrite-min-size选项和auto-aof-rewrite-percentage选项来自动执行BGREWRITEA0F,且两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作
vim /etc/ redis/ 6379. conf
AOF同步的策略
729 # appendfsync always
730 appendfsync everysec
731 # appendfsync no
771 auto-aof-rewrite-percentage 100 ##当前AOF文件大小(即aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生BGREWRITEAOF操作
772 auto-aof-rewrite -min-size 64mb ##当前A0F文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEA0F
2.2.7、启动时加载
- 当AOF开启时,Redis启动时会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会载入RDB文件恢复数据。
- 当AOF开启,但AOF文件不存在时,即使RDB文件存在也不会加载。
- Redis载入AOF文件时,会对AOF文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败。但如果是AOF文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且aof-load-truncated参数开启,则日志中会输出警告,Redis忽略掉AOF文件的尾部,启动成功。
- aof-load-t runcated参数默认是开启的
三、Redis性能管理
3.1、查看Redis内存使用
127.0.0.1:6379> info memory
3.2、内存碎片率
1、操作系统分配的内存值used_memory_rss除以Redis使用的内存值used_memory计算得出内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)
2、跟踪内存碎片率对理解Redis实例的资源性能是非常重要的:
- 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低
- 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150号,其中50号是内存碎片率。需要在redis-cli工具上输入shutdown save命令,并重启Redis服务器。
- 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少Redis内存占用
3.3、内存使用率
1、redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换。
2、避免内存交换发生的方法:
- 针对缓存数据大小选择安装 Redis 实例
- 尽可能的使用Hash数据结构存储
- 设置key的过期时间
3.4、内回收key
- 保证合理分配redis有限的内存资源。
- 当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除。
配置文件中修改 maxmemory-policy 属性值:
vim /etc/redis/6379.conf
598 maxmemory-policy noenviction
volatile-lru ##使用LRU算法从已设置过期时间的数据集合中淘汰数据
volatile-ttl ##从已设置过期时间的数据集合中挑选即将过期的数据淘汰
volatile-random ##从已设置过期时间的数据集合中随机挑选数据淘汰
allkeys-lru ##使用LRU算法从所有数据集合中淘汰数据
allkeys-random ##从数据集合中任意选择数据淘汰
以上是关于Redis再深入一点之高可用持久化及性能管理,必看!!!的主要内容,如果未能解决你的问题,请参考以下文章