浅析Redis如何保证数据不丢失
目录
- 引言
- Redis面临的数据丢失风险
- 基础策略
- RDB机制
- AOF机制
- 配置建议
- 高级策略
- 主从架构实现多副本保存
- 哨兵系统实现故障转移
- 集群架构实现数据冗余
- 跨机房部署
- 其他运维措施
- 运维工具检测
- 定期备份数据
- 总结
引言
大家即使没用过Redis,也应该都听说过Redis的威名。
Redis是一种Nosql类型的数据存储,全称Remote Dictionary Server,也就是远程字典服务器,用过Dictionary的应该都知道它是一种键值对(Key-Value)的数据结构,所以Redis也称为KV存储。
Redis的用途十分广泛,包括帮助网页快速加载,管理登录状态,更新社交动态、游戏积分排名、电商抢购秒杀,等等,有点规模的应用后边都有它的身影。
Redis之所以这么流行,首先是因为它的处理速度特别快,它主要在内存中处理数据;其次它提供了多种数据结构,使用起来比较方便,而且这些数据结构的操作时间复杂度都很优秀;最后Redis会将数据保存到磁盘中,提供一定的持久性。
但是很多同学常常对Redis的数据安全有所担忧,大家经常问:Redis能保证数据不丢失吗?怎么做到的?本文会简单说说Redis的数据保护机制,它的好处和局限,以及我们应该怎样设置、有哪些高级技巧。
Redis面临的数据丢失风险
Redis中的数据是有可能丢失的。
首先,咱们搞清楚一个概念——数据持久性。简单来说,数据持久性就是确保你的数据在遇到各种意外情况时,比如断电、系统崩溃等,之后还能安然无恙的存在。就像是手机,即使没电了,充上电之后,里面的照片和信息都还在,没有丢失。
那么,Redis面临的数据丢失风险有哪些呢?
上文说到Redis主要在内存中操作数据,内存是一种临时存储,一旦断电(或者硬件故障、软件错误等),内存中的数据就会烟消云散。有的同学会说,数据不是会保存到硬盘吗?是的,但是还是可能会有一些数据来不及写入硬盘,这是Redis的持久化机制导致的,下边会进行详细说明。
而且,即使Redis将全部数据都及时保存到了硬盘,硬盘出现问题也可能会导致Redis的数据丢失。
另外有的同学会说,我只是在Redis中缓存数据,所有的数据在数据库中都有完整的记录。这个问题虽然有点超纲,但是这里还是简单交代下。这种情况下如果要恢复的数据量比较大,从数据库恢复数据的时间会比较长,这会延长故障的恢复时间。而且如果系统访问量比较大,还可能导致缓存穿透的问题,击垮数据库。
所以,尽管Redis给我们的应用带来了极速体验,但是如果不采取措施,数据丢失的风险是实实在在的。下面,我们将探讨Redis如何通过各种持久化策略来应对这些风险,尽量保证数据的安全。
基础策略
保证数据不丢失的基础策略就是使用Redis自带的持久化机制,Redis提供了两种主要的数据持久化方法:RDB(快照)和AOF(追加文件)。这两种方法各有千秋,让我们来详细了解一下。
RDB机制
RDB持久化是通过创建数据集的快照来工作的,在指定的时间间隔内,Redis会自动将内存中的数据集写入硬盘的一个文件(通常是dump.rdb)。这就像是给数据拍了一张快照,当需要的时候可以随时从这个快照恢复。
优点:
性能高:快照生成时,用到了写时拷贝技术,此时Redis主进程只负责写入数据,实际保存工作由子进程完成,因此对性能影响较小。
恢复快:与AOF相比,使用RDB文件恢复数据通常更快。
缺点:
数据可能丢失:如果Redis异常停止,那么最后一次快照之后的所有数据更改都会丢失。
大数据集恢复时间长:虽然比AOF快,但是如果数据集非常大,恢复过程仍然可能需要较长时间。
AOF机制
AOF持久化通过记录每个写操作到一个日志文件中,实现数据的持久化。这就像是把每次数据变动都先记录下来,然后再更新到内存中,需要恢复时,按照这个操作日志一步步来就行了。
需要注意AOF记录也很难做到每个写操作都先持久化到硬盘中,这是因为硬盘的读写速度一般都很慢,比内存操作低几个数量级,如果每次都先写到硬盘,Redis也做不到目前的低延迟高并发。所以写操作一般都是先缓存一段时间,然后再批量flush到硬盘。
优点:
数据安全性高:AOF持久化可以配置不同的同步频率,例如每秒同步,这样可以在保证性能的同时,减少数据丢失的风险。
可读的日志文件:AOF文件是一个纯文本文件,可以被人读懂,便于理解和问题排查。
缺点:
文件体积大:由于记录了所有写操作,AOF文件的体积通常会大于RDB文件。
恢复速度慢:与RDB相比,AOF在恢复大量数据时通常更慢,因为需要重新执行所有操作。
配置建议
RDB配置建议
大部分情况下都建议开启RDB,因为RDB需要的资源相对AOF小很多。如果对数据完整性的要求不高,或者能很快的从其它渠道恢复数据,一般只需要开启RDB就可够了。
合理设置快照间隔
Redis的RDB持久化允许我们配置多个不同的快照条件,以适应不同的数据更新频率和保证数据安全。我们可以在 redis.conf 配置文件中设置多个快照规则。以下是一个示例配置,展示了如何根据数据变化的频繁程度来设置快照的条件:
# 在900秒内如果至少有1个键被改变,则进行一次快照
save 900 1
# 在300秒内如果至少有10个键被改变,则进行一次快照
save 300 10
# 在60秒内如果至少有1000个键被改变,则进行一次快照
save 60 1000
这样的配置意味着:
如果数据变化不是很频繁,我们不需要那么频繁地进行快照保存,以避免不必要的性能开销。
当数据变化变得更加频繁时,我们通过更紧密的快照来减少数据丢失的风险。
动态调整快照规则
除了在配置文件中静态设置快照规则外,Redis还提供了命令让我们可以在运行时动态调整快照规则。使用CONFIG SET命令,我们可以根据应用的当前状态和需求,动态地调整快照条件:
# 动态设置快照规则
redis-cli CONFIG SET save "60 1000 300 10 900 1"
注意事项
性能考量:虽然频繁的快照可以减少数据丢失的风险,但也可能会对性能产生影响,特别是在数据集很大的情况下。因此,需要根据实际情况权衡快照频率和性能。
监控与调整:建议监控Redis的性能指标,并根据实际运行情况调整快照规则。随着业务的发展,可能需要定期回顾和调整这些设置。
AOF配置建议
当数据仅保存在Redis中,或对数据的丢失难以容忍时,建议开启AOF。
考虑到性能和数据安全,建议设置为每秒同步一次。这样既可以保证数据的及时性,又不会对性能影响太大。
以下是一个示例配置:
appendfsync everysec
定期重写AOF
随着时间的推移,AOF文件可能会变得很大,不仅会占用更多的磁盘空间,而且重启后或从故障恢复时处理的会比较慢。缓解这个问题,可以使用Redis提供的定期重写机制。
在AOF重写过程中,Redis会创建一个新的AOF文件,这个新文件仅包含重建当前数据集所需的最小命令集合。例如,如果一系列的INCR命令将某个键的值从0递增到了100,那么在重写后的AOF文件中可能只会记录一条SET命令来直接设置这个键为100,从而大大减小文件。
通过 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 参数可以配置自动重写的条件。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage:重写时机:当前AOF文件大小相对于上一次重写后的文件大小的增长百分比。例如,若设置为100,则表示每当AOF文件大小翻倍时,Redis将自动触发AOF重写。
auto-aof-rewrite-min-size:即使满足了增长百分比条件,Redis也不会立即进行重写,还需要AOF文件达到一个最小尺寸。只有当文件大小超过这个设定值时,才会真正触发重写。
通过以上配置,在保证Redis性能的同时,数据安全性也有了基础的保证。
高级策略
从对基础策略的分析中我们了解到即使采用AOF日志,因为写日志的延迟,数据仍存在丢失的可能性。而且即使数据都写入到了硬盘,也无法处理单机硬盘故障导致数据丢失的问题。
这一小节就让我们来看下处理这个问题的一些高级策略,包括主从架构、哨兵系统和集群架构。这些策略可以提高数据的安全性和可用性。
主从架构实现多副本保存
在Redis的主从架构中,数据会从一个主节点复制到一个或多个从节点。这样做的好处是,即使主节点出现问题,我们也可以从从节点中恢复数据,而且从节点可以继续提供查询服务。
工作原理:主节点负责处理所有的写操作,并将这些操作记录同步到从节点。从节点则可以处理读请求,分担主节点的读负载
优点:
数据冗余:通过在多个从节点上保存数据副本,提高了数据的可靠性。
读负载均衡:从节点可以处理读请求,帮助分担主节点的读负载。
配置示例:
# 从节点配置
slaveof <masterip> <masterport>
主节点无需特别配置,只需正常启动。从节点的配置文件中增加slaveof配置,masterip、masterport是主节点的IP和端口。
哨兵系统实现故障转移
哨兵系统(Sentinel)是一种用于监控Redis主从节点状态的系统,能够在主节点故障时自动进行故障转移。
工作原理:哨兵通过发送命令,检查主从节点的健康状态。如果主节点不可达,哨兵会自动将其中一个从节点提升为新的主节点,并更新其他从节点以指向新的主节点。
优点:
自动故障转移:提高了系统的可用性,当主节点出现故障时,能够快速恢复。
监控:哨兵还负责监控Redis节点的运行状态,提供了一定程度的自动管理。
配置示例:
# 哨兵配置文件 sentinel.conf
sentinel monitor mymaster <masterip> <masterport> 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel monitor mymaster:这条命令让哨兵监控一个名为 mymaster 的主节点,其IP和端口分别为 masterip 和 masterport 。数字2表示当至少有两个哨兵认为主节点不可达时,才会进行故障转移。这是为了避免因为网络闪断导致的误判。这也告诉我们如果需要更高的可用性,哨兵进程也要部署多个,一般3个或5个就够了。
sentinel down-after-milliseconds mymaster 5000:设置哨兵判断主节点为“下线”的时间。例如,这里设置为5000毫秒(5秒),如果哨兵在这段时间内无法达到主节点,则认为主节点下线。因为各种原因,哨兵可能会出现误判的问题,多等一会说不定又能访问主节点。
sentinel failover-timeout mymaster 60000:设置故障转移的超时时间,单位是毫秒。在这个例子中,设置为60000毫秒(60秒)。如果故障转移操作在这段时间内没有完成,则会被取消。
sentinel parallel-syncs mymaster 1:设置在故障转移后,同时可以有多少个从节点同时对新的主节点进行同步。这里设置为1,意味着一次只有一个从节点可以同步。在故障转移后,所有从服务器都需要与新的主服务器进行全量同步以保证数据一致性。由于全量同步会阻塞从节点,并且可能会消耗较大的网络带宽和CPU资源,所以通过限制并发同步的从节点数量,可以避免过多从节点同时进行同步带来的资源压力过大问题。
集群架构实现数据冗余
Redis集群通过分片的方式来存储数据,每个分片存储不同的数据。通过多个节点的协作,实现数据的冗余和分布式存储。
工作原理:Redis集群将所有的数据分为16384个哈希槽,每个节点负责一部分哈希槽。客户端根据特定的哈希规则,将数据存储到相应的节点上。
优点:
数据分片:实现了数据的自动分片,便于管理大规模数据。
高可用性:集群中的节点可以相互备份,即使部分节点失败,也不会影响整个集群的可用性。
配置示例: 配置Redis集群涉及到启动多个Redis实例,可使用redis-cli工具创建集群:
# 启动Redis实例(假设启动6个实例作为示例)
redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes-7000.conf --cluster-node-timeout 5000 --appendonly yes --appendfilename appendonly-7000.aof --dbfilename dump-7000.rdb --logfile 7000.log
# 重复上述命令,修改端口为7001-7005
# 使用redis-cli创建集群
redis-cli --cluster create <ip1>:7000 <ip2>:7001 <ip3>:7002 <ip4>:7003 <ip5>:7004 <ip6>:7005 --cluster-replicas 1
--cluster-enabled yes:启用Redis集群模式。
--cluster-config-file nodes-7000.conf:指定集群的配置文件。这个文件由Redis自动维护,记录了集群中所有节点的信息。
--cluster-node-timeout 5000:设置节点超时时间,单位是毫秒。如果一个节点在这段时间内没有响应,集群会认为该节点已经下线。
--appendonly yes:启用AOF持久化模式。在集群模式下,推荐使用AOF持久化来保证数据安全。
--appendfilename appendonly-7000.aof:指定AOF文件的名字。这里根据不同的端口号,为每个实例指定了不同的AOF文件名,以避免冲突。
--dbfilename dump-7000.rdb:指定RDB文件的名字。同样地,根据不同的端口号为每个实例指定了不同的RDB文件名。
--logfile 7000.log:指定日志文件的名字。这有助于在出现问题时进行故障排查。
通过主从架构、哨兵系统和集群架构,可以有效地实现数据的多副本保存、故障转移和数据冗余,提高系统的可靠性和可用性,基本上可以避免单机系统的数据丢失问题。
跨机房部署
服务器所在的机房也可能出现问题,比如光缆被挖断了、空调系统坏了、机房着火了等实际出现过的状况,为了解决这些问题,我们还可以通过跨机房的方法来提升Redis的数据可靠性和可用性。
- 在不同机房间部署主从复制架构。在一个数据中心内设置主节点,在另一个或多个数据中心设置从节点。
- Sentinel(哨兵)集群也应跨机房部署,以避免单点故障。
- 使用Redis Cluster进行跨机房部署,每个机房都可以有多个分片(shard),并且每个分片的主节点和从节点分别位于不同的地理位置,这样即使一个机房完全不可用,其他机房的副本仍然能够提供服务。
跨机房部署时需要自行解决网络的通信问题,让各个节点之间可以无障碍的相互访问,机房间最好使用低延迟、高带宽的专线连接,以加速数据同步过程并降低网络问题导致的数据不一致风险。
还有面试中经常提及的两地三中心的多活架构,也可以安排上。每个机房都部署一套完整的、独立处理读写请求的Redis集群,并通过分布式锁或者数据同步中间件等技术保证各个集群间数据的一致性。
- 分布式锁可以采用ZooKeeper、etcd、redis等,确保在多个数据中心进行同步更新时,只有一个数据中心的Redis集群在给定时间内对某个资源拥有写权限。
- 数据同步中间件主要用于实时或近实时地将一个数据中心的写入操作同步到另一个数据中心。可以使用消息队列、专业的数据同步工具(比如阿里巴巴开源的Canal)等。
- 多活架构还要设计数据分片策略、数据路由机制以及事务处理方式,比如根据地域或者一致性Hash分片来区分用户,然后使用客户端驱动路由或者网关路由来把用户导向不同的机房,最后使用分布式事务提交数据。
多活架构比较复杂,我也没有实际搞过,这里就不多说了。
其他运维措施
日常运维中的定期检查和文件备份,虽然平时看起来不起眼,但在关键时刻却能发挥巨大作用。
运维工具检测
就像我们用手表监测心率一样,使用专业的运维工具可以帮助我们实时监控Redis服务器的状态,包括性能指标、资源使用情况、可能的瓶颈等。
具体做法:
选择合适的工具:市面上有许多优秀的运维监控工具,如Prometheus结合Grafana、Zabbix等,可以根据自己的需求和环境选择。
定制监控项:根据你的具体需求,定制监控项。比如,内存使用率、磁盘使用率、命令执行延迟、连接数等,这些都是常见的监控指标。
设置告警:设置阈值,一旦监控到的数据超过这个阈值,就会触发告警。这就像是你的手表在你心率异常时提醒你,帮助你及时发现并处理问题。
定期备份数据
备份就是我们给文件买了一份保险,无论是误操作还是系统故障,都能够确保数据不会丢失,可以快速恢复到备份时的状态。
具体做法:
定期执行:设定一个合理的备份频率,比如每天凌晨进行一次。频率的选择取决于你的业务需求和数据变化的频繁程度。
自动化:利用crontab等工具自动化备份流程,让备份工作自动化进行,减少人为遗忘的风险。
远程存储:将备份文件存储在远程服务器或云存储服务上。这样做的好处是,即使本地发生灾难性事件,数据仍然是安全的。
通过实施这些常规措施,我们可以大大提高数据的安全性和系统的稳定性。
总结
说了这么多,让我们做一个总结。
如果你的业务对数据的完整性要求非常高,建议开启AOF持久化,并设置合理的fsync策略(如每秒同步一次)。同时,配合使用主从复制和哨兵系统,以确保数据的高可用性和安全性。
对于读写性能有极高要求的场景,可以考虑只使用RDB持久化或者RDB与AOF结合的方式(数据完整性要求高,AOF用于故障恢复,RDB用于重启加速)。同时,通过增加从节点和合理分配读写负载,可以进一步提升性能、提高数据安全性。
如果业务数据量巨大,单个Redis实例难以满足存储需求,那么Redis集群是一个不错的选择。它通过分片来实现数据的分布式存储,同时保持高可用性。
日常的监控和备份也要搞起来,如果服务和数据及其重要,跨机房部署可以提供极大的数据安全性和系统稳定性。至于传说中的多活架构,不到万不得已不要轻易尝试,极为复杂,成本很高。
最后不要忘了定期演练,搞了这么多的机制到底能不能发挥作用?有没有被不小心搞坏,定期演练可以提前发现问题,及时解决,避免更大的损失。