先学习:Redis架构简介-CSDN博客

Redis压测

Redis一般应用于高并发的场景,所以一定要对Redis的性能做压测。

Redis提供了压测脚本redis-benchmark,可以对Redis进行快速的基准测试。

# 20个线程,100W个请求,测试redis的set指令(写数据)
redis-benchmark -a 123qweasd -t set -n 1000000 -c 20

...

Summary:

throughput summary: 116536.53 requests per second ##平均每秒11w次写

latency summary (msec):

avg min p50 p95 p99 max

0.111 0.032 0.111 0.167 0.215 3.199

Redis数据持久化

持久化配置

Redis持久化相关的配置,可以分为几个策略:

  • 无持久化:不保证数据安全,只将Redis当做缓存用
  • RDB(RedisDatabase):按照一定的时间间隔缓存Redis所有的数据快照
  • AOF(Append Only File):记录Redis收到的每一次写操作,在之前的基础上进行追加新的操作
  • RDB+AOF:

RDB特点

  • RDB文件紧凑,适合定期备份,非常适合灾难恢复
  • 备份的是当前时间的内存的全部数据集。
  • 主线程启动一个子线程进行RDB备份
  • 数据备份时,需要将内存的数据克隆一份,如果数据量比较大,fork的子线程虽然不会阻塞redis主线程,但是会占用CPU, 容易造成Redis短暂的服务停用。
  • 不能进行实时备份,丢失数据风险

AOF特点

  • Redis默认1s进行一次AOF写入,数据更安全
  • 以日志的形式记录每一次写操作,追加文件而不允许写文件
  • AOF出现数据记录不完整的情况,可以使用redis-check-aof工具恢复
  • AOF文件通常比RDB文件更大
  • 写操作频繁的情况下,AOF的备份性能比RDB更慢

[root@192-168-65-214 appendonlydir]# redis-check-aof --fix appendonly.aof.1.incr.aof

混合持久策略(RDB+ AOF):

redis.conf配置文件中做配置

# Redis can create append-only base files in either RDB or AOF formats. Using

# the RDB format is always faster and more efficient, and disabling it is only

# supported for backward compatibility purposes.

aof-use-rdb-preamble yes

RDB

文件名默认dump.rdb。

RDB同步(何时触发RDB备份)

1.手动触发

  • save命令:备份期间阻塞主线程
  • bgsave命令:fork出一个子线程执行持久化,主线程在fork子线程的过程有短暂的阻塞,但是会占用更多的cpu和内存 

2. 自动触发

  • 达到配置文件的配置要求。 配置文件中,save m n : 在m秒有n个键发生改变,自动触发持久化,如果设置多个,只要满足其中一个条件就会触发。配置文件中可以修改。
  • flushall : 用于清空redis所有的数据库,flushdb清空redis所在数据库(默认0号数据库),会清空RDB文件,同时也会生成dump.rdb, 内容为空。
  • 主从同步(看Redis版本):全量同步时自动触发bgsave命令,生成rdb发送给从节点。

配置文件(备份策略)

# Save the DB to disk.

# save <seconds> <changes> [<seconds> <changes> ...]

# save ""

# Unless specified otherwise, by default Redis will save the DB:

# * After 3600 seconds (an hour) if at least 1 change was performed

# * After 300 seconds (5 minutes) if at least 100 changes were performed

# * After 60 seconds if at least 10000 changes were performed

# You can set these explicitly by uncommenting the following line.

# save 3600 1 300 100 60 10000  -- 备份策略

  • rdbcompression 是否启用RDB压缩,默认yes。 如果不想消耗CPU进行压缩,可以设置为no
  • stop-writes-on-bgsave-error 默认yes;如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制这种不一致, 在快照写入失败时,也能确保redis继续接受新的写入请求。
  • rdbchecksum 默认yes。在存储快照后,还可以让redis使用CRC64算法来进行数据校样做会增加大约10%的性能消耗。如果希望获得最大的性能提升,可以关闭此功能。

RDB日志恢复

恢复指令:redis-check-rdb,因为rdb文件是二进制文件,所以不太容易篡改。

AOF

配置文件

# The base name of the append only file.

# Append-only file names are created by Redis following a specific pattern.

# The file name's prefix is based on the 'appendfilename' configuration

# parameter, followed by additional information about the sequence and type.

# For example, if appendfilename is set to appendonly.aof, the following file

# names could be derived:

# - appendonly.aof.1.base.rdb    as a base file. -- rdb文件是二进制数据文件

# - appendonly.aof.1.incr.aof,  appendonly.aof.2.incr.aof    as incremental files. -- incr.aof是增量的操作日志

# - appendonly.aof.manifest as a manifest file. -- manifest文件信息元数据

appendfilename "appendonly.aof"

现在的AOF已经具备了RDB+AOF的功能。并且,拆分增量文件的方式,也能够进一步控制aof文件的大小。 虽然AOF具备了RDB的功能,但是因为AOF数据通常在不断变化,还是建议定期做RDB的备份。

配置:

  • appendonly 是否开启aof。 默认是不开启的。
  • appendSync同步方式, 默认1s同步一次
  • appenddirname AOF文件目录
  • auto-aof-rewrite-percentage, auto-aof-rewrite-min-size 文件触发重写策略。 默认每个文件64M,写到100%, 进行一次重写。
  • no-appendfsync-on-rewrite  aof重写期间是否同步

AOF文件内容

appendonly.aof.1.incr.aof增量文件。里面其实就是按照Redis的协议记录了每一次操作。

127.0.0.1:6379> keys *

(empty array)

127.0.0.1:6379> set k1 v1

OK

127.0.0.1:6379> set k2 v2

OK

这组指令的文件示例:

    AOF同步过程

    1. 所有的命令追加到AOF缓冲区
    2. AOF缓冲区根据对应的同步策略(配置参数appendfSync)向硬盘进行同步操作

    同步策略:

    • 同步:每次修改同步
    • 异步:每秒同步
    • 不同步:由操作系统决定同步时机

    AOF重写过程

            Redis会定期对AOF中的操作进行优化重写,让AOF中的操作更加精简,在Redis7的AOF文件中,会生成base rdb和incr.aof文件。

      AOF日志恢复

      修复的过程实际上就是将aof文件(appendonly.aof.1.incr.aof日志文件)的最后那一条不完整的指令删除掉。使用redis-check-aof工具恢复.

      主从复制Replica机制

      配置方式

      配从不配主原则

      REPLICAOF host port|NO ONE : 一般配置到redis.conf中。

      SLAVEOF host port|NO ONE: 在运行期间修改slave节点的信息。如果该服务已经是某个主库的从库了,那么就会停止和原master的同步关系。

      -- 查看主从状态
      127.0.0.1:6379> info replication

      默认情况下,从库是只读的,不允许写入数据。因为数据只能从master往数据,就会造成数据不一致。但是从库没有禁止CONFIG、DEBUG等管理指令,这些指令如果和主节点不一致,还是容易造成数据不一致。

      replica-read-only yes  -- redis.conf中的配置

      rename-command CONFIG "" 。 -- redis.conf中增加这个配置,屏蔽掉slave上的CONFIG指令。

      复制时机

      主从复制。当Master数据有变化时,自动将新的数据异步同步到其他slave中。

      主从复制过程

      哨兵机制Sentinel机制

      配置方式

      sentinel.conf

      如何发现Master宕机

      • S_DOWN(主观下线):通过心跳检测,一个Sentinel节点认为 Redis Master节点宕机了。
      • O_DOWN(客观下线): 当一个Sentinel认为Redis Master宕机了,Redis的Sentinel就会互相进行沟通,当超过quorum(Sentinel集群的半数)个Sentinel节点都认为master已经出现S_DOWN后,就会将master标记为O_DOWN。

      切换新Master过程

      <1> master变成O_DOWN后,Sentinel集群Leader的节点负责协调整个故障切换过程。

      <2>Sentinel会在剩余健康的Slave节点中选举出一个节点作为新的Master。选举采用采用的Raft算法, 选举的规则如下:

      • 首先检查是否有提前配置的优先节点:各个服务节点的redis.conf中的replica-priority配置最低的从节点。这个配置的默认值是100。
      • 如果配置都一样,检查复制偏移量offset最大的从节点。也就是找同步数据最快的slave节点。因为他的数据相对更全。
      • 如果offset还是一样,最后按照slave的RunID字典顺序最小的节点。

      <3>切换新的主节点。 Sentinel Leader给新的mater节点执行 slave of no one操作,将他提升为master节点。 然后给其他slave发送slave of 指令。让其他slave成为新Master的slave。

      <4>如果旧的master恢复了,Sentinel Leader会让旧的master降级为slave,并从新的master上同步数据,恢复工作。

      集群Cluster机制

      配置方式

      cluster-enabled yes   -- 开启集群模式

      cluster-config-file nodes-6379.conf  -- 指定一个给集群进行修改的配置问文件

      将多个独立的Redis服务整合成一个统一的集群:

      --cluster create表示创建集群。 
      --cluster-replicas 表示为每个master创建一个slave节点。
      接下来,Redis会自动分配主从关系,形成Redis集群。
      
      [root@192-168-65-214 cluster]# redis-cli -a 123qweasd --cluster create --cluster-replicas 1 192.168.65.214:6381 192.168.65.214:6382 192.168.65.214:6383
      192.168.65.214:6384 192.168.65.214:6385 192.168.65.214:6386

      Redis在分配主从关系时,会优先将主节点和从节点分配在不同的机器上。

      集群模式下的问题

      1. 批量指令原子性问题

      127.0.0.1:6381> mset k1 v1 k2 v2 k3 v3

      (error) CROSSSLOT Keys in request don't hash to the same slot

      不同的key对应到不同的槽位,分不到了不同的服务器,就出现分布式事务问题。

      解决方案:

      127.0.0.1:6381> CLUSTER KEYSLOT k1

      (integer) 12706

      127.0.0.1:6381> CLUSTER KEYSLOT roy{k1}

      (integer) 12706

      127.0.0.1:6381> CLUSTER KEYSLOT roy:k1

      (integer) 12349

      -- 使用相同的hash tag,能保证这些数据都是保存在同一个节点上的。

      -- 如果key中有{},  只根据{}中的内容计算槽位。

      127.0.0.1:6381> mset user_{1}_name roy user_{1}_id 1 user_{1}_password 123

      -> Redirected to slot [9842] located at 192.168.65.214:6382

      OK

      2. 数据倾斜

      大量的数据被存储到集群中的某个热点Redis节点上

      解决方案:

      1. 调整key的结构,尤其是那些访问频繁的热点key,让数据能够尽量平均的分配到各个slot上。
      2. 调整slot的分布,将那些数据量多,访问频繁的热点slot进行重新调配,让他们尽量平均的分配到不同的Redis节点上。

      集群通信协议

      Redis集群之间通过gossip协议进行频繁的通信,用于传递消息和更新节点状态。gossip协议包含多种消息,包括ping,pong,meet,fail等等。

      gossip集群是去中心化的,各个节点彼此之间通过gossip协议互相通信,保证集群内部各个节点最终能够达成统一。

      Redis集群中,每个节点都有一个专门用于节点之间进行gossip通信的端口,就是自己提供服务的端口+10000.因此,在部署Redis集群时,要注意防火墙配置,不要把这个端口屏蔽。

      集群选举Master

              当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master 可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:

      1》slave发现自己的master变为FAIL

      2》将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST信息(currentEpoch代表选举周期)

      3》其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个 epoch只发送一次ack(master应该根据特定的决定响应结果)

      4》尝试Failover的slave收集master返回的FAILOVER_AUTH_ACK

      5》slave收到超过半数master的ack后变成新Master

      6》slave广播Pong消息通知其他集群节点

          

      注意:slave节点并不是在master节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,确保mater FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票.

      Redis数据不一致

      Redis Cluster在设计上优先考虑一致性,但在特定场景下确实可能存在数据不一致的情况。

      数据不一致原因

      1. 脑裂问题(网络分区)

      当集群出现网络分区时,可能会出现多个主节点都认为自己是某个槽位的主节点。

      示例场景:

      • 节点A、B、C在一个分区,节点D、E在另一个分区

      • 如果多数节点(A、B、C)认为主节点D失效,它们会选举新的主节点

      • 此时两个分区D和E都可能接受写操作,导致数据不一致

      2. 异步复制导致的数据丢失

      # 写操作流程:
      1. 客户端向主节点写入数据
      2. 主节点返回成功
      3. 主节点异步复制到从节点 ← 此步骤延迟或失败可能导致数据丢失

      3. 故障转移期间的写丢失

      主节点故障后,从节点提升为主节点期间,可能丢失未复制的写操作。

      4. 持久化失败导致数据不一致

              持久化失败是导致数据不一致的原因,但往往与其他问题(如主从复制延迟或脑裂)共同作用导致数据不一致。

      1. 数据在内存中:当Redis实例(尤其是主节点)因故障(如断电、进程异常退出)重启时,内存中的数据会丢失。如果故障前没能成功将数据持久化到磁盘,那么这部分数据就彻底丢失了,从而造成数据不一致。
      2. 复制依赖持久化:在主从复制中,一个从节点如果要与主节点保持同步,在全量同步时,主节点会生成RDB快照(这本身是一个持久化过程)并发送给从节点。如果这个过程中断或失败,也会导致从节点数据不一致。

      解决方案

      1. 避免脑裂问题

      1.1 多数派原则与故障检测
      # 节点通过Gossip协议通信
      # 需要大多数节点确认才会进行故障转移
      CLUSTER NODES  # 查看节点状态和纪元
      1.2 合理集群规模
      # 建议至少3主3从,避免2主2从(容易因网络分区产生脑裂)
      # 节点数量最好是奇数,便于多数派决策

      2. 配置参数优化

      避免异步复制导致的数据丢失问题

      # 关键配置项
      min-replicas-to-write 1     # 至少1个从节点确认才接受写
      min-replicas-max-lag 10     # 从节点延迟不超过10秒
      cluster-node-timeout 15000  # 节点超时时间(毫秒)

      3. 应用层保护

      # 重要操作使用WAIT命令
      r.set('important_key', 'value')
      r.wait(1, 5000)  # 等待至少1个副本确认,超时5秒

      4. 监控告警

              对Redis集群的节点状态、主从复制延迟、网络延迟、持久化状态等关键指标进行监控,以便及时发现问题。

      # 关键监控指标
      redis-cli cluster info | grep cluster_state
      redis-cli info replication | grep connected_slaves

      手动恢复策略

      # 检查集群状态
      redis-cli --cluster check 192.168.1.101:7001
      
      # 修复槽位分配
      redis-cli --cluster fix 192.168.1.101:7001

      5. 持久化配置

      1. 启用合理的持久化机制
        1.  RDB自动生成策略

        2.  AOF同步策略appendfSync

        3. RDB和AOF结合:这样可以利用RDB进行快速备份和恢复,同时利用AOF来保证更高的数据安全性。

      2. 建立定期备份计划:定期备份你的Redis数据都是至关重要的。可以编写脚本,定期执行SAVE或BGSAVE命令(BGSAVE会在后台执行,不会阻塞服务器)来生成RDB文件的备份,并将备份文件传输到安全的地方(如不同的物理机或云存储)。

      Redis Cluster通过多数派决策、故障转移机制、复制机制、持久化等手段,在大多数情况下能保证数据一致性。但在网络分区、节点故障、运维误操作等极端情况下,仍可能出现数据不一致。

      Logo

      有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

      更多推荐