Redis 主从复制全解析:从 PSYNC 协议到复制积压缓冲区的故障切换边界

Redis 主从复制全解析:从 PSYNC 协议到复制积压缓冲区的故障切换边界

1. 先从一个真实困惑说起:为什么主节点挂了,从节点还是旧数据

假设你负责一个电商秒杀系统,Redis 采用一主两从部署:主节点 M 处理所有写请求,从节点 S1、S2 通过复制保持数据一致。某个大促凌晨,M 所在机器宕机,Sentinel 在几秒内把 S1 提升为新主。运维在监控上看复制延迟只有 50ms,理论上最多丢 50ms 的数据。但业务核查时发现,某件商品的库存扣减记录丢失了近 3 秒的写入量------用户付款成功,库存却没扣。

问题不在于 Sentinel 切换慢,而在于主从复制从来不是「主节点写完,从节点立刻就有」的强一致模型。它是一套异步复制协议:主节点写入本地内存后立即返回客户端,再把写命令异步推给从节点。M 在宕机前那几秒产生的写命令,如果还没被 S1 收到,切换后就永久丢失了。而「那几秒」的边界,恰恰由一个容易被忽视的结构决定------复制积压缓冲区(repl_backlog)。

这篇文章不会一上来就丢出 PSYNC 的状态机,而是先把整个复制体系拆成几个角色和一条数据流,让你能用自己的话复述一遍,然后再逐个机制钻进去。目标很明确:读完你能回答三个问题------复制到底怎么同步的、backlog 到底决定了什么边界、故障切换时会丢多少数据。

2. 一句话模型与整体框架:谁在跟谁说话

先用一句普通中文记住核心模型:Redis 主从复制,就是从节点连上主节点后,先领一份全量数据快照,之后持续接收主节点推送的增量写命令,并用一个不断增长的偏移量来标记「我收到哪儿了」。

把整体拆成三部分,先看它们怎样串起来:

text 复制代码
     写命令                     传播写命令
客户端 ----> [主节点 Master] -----------------> [从节点 Replica 1]
                 |  |                                 ^
                 |  |  传播写命令                     |
                 |  +-------------------------> [从节点 Replica 2]
                 |
                 |  维护: runid / master_repl_offset
                 |  维护: repl_backlog (环形缓冲)
                 |  维护: 每个从节点的 ack 偏移量

角色:
  Master  : 接受写、生成复制流、记录 backlog
  Replica : 发起 PSYNC、接收 RDB 或增量流、周期性上报 ack offset
  Sentinel/Cluster : 观测主从状态,在故障时执行切换

三个角色分工如下:

角色 核心职责 关键状态
主节点 Master 执行写命令、生成复制流、维护 backlog runid、master_repl_offset、repl_backlog
从节点 Replica 连接主节点、接收数据、上报确认偏移 master_link_status、slave_repl_offset
哨兵/集群 Sentinel/Cluster 监控、判定客观下线、执行故障切换 主观下线、客观下线、quorum、epoch

一个请求/数据的完整流转顺序是:客户端写主节点 → 主节点执行并追加到 backlog → 主节点把命令异步推给所有从节点 → 从节点执行并更新自己的偏移量 → 从节点周期性向主节点上报 ack 偏移量。任何环节中断,复制就可能退化为全量重同步。下一节开始,我们按这个顺序逐个拆解。

3. 复制偏移量:复制世界里的「打卡进度」

3.1 偏移量到底标记了什么

复制偏移量(replication offset)是最容易理解、也最容易被忽视的概念。可以先把它理解成一条不断增长的字节流上的「打卡点」:主节点每产生一个字节的复制流,就把它自己的偏移量加一;从节点每接收并应用一个字节,就把自己的偏移量加一。两者之差,就是通常说的复制延迟(以字节计,不直接等于时间)。

一个最小数字例子:

text 复制代码
时刻 T1: 主节点执行 SET k1 v1,复制流增加 30 字节
         master_repl_offset = 1000
         replica_repl_offset = 1000   (从节点已跟上,差值为 0)

时刻 T2: 主节点连续执行 5 条写命令,复制流增加 200 字节
         master_repl_offset = 1200
         replica_repl_offset = 1000   (从节点还没收到,差值 200)

差值 200 并不等于「丢了 200 字节的数据」,它只表示从节点暂时落后。只要主节点还活着,复制流会继续推送,从节点最终会追到 1200。真正危险的是主节点在这段落后期间宕机------从节点永远停在 1000,而主节点最后那 200 字节的写命令就可能丢失。

3.2 偏移量与故障切换的关系

故障切换时,Sentinel 或 Cluster 会优先选择偏移量最大的从节点作为新主,因为它「收到的最多」。这就解释了为什么复制延迟过大的从节点不应该被优先提升:它的数据更旧。

最容易误解的一点是:偏移量相等不代表数据完全一致。如果从节点在应用命令过程中出错,或者主节点曾发生过角色转换导致 runid 变化,偏移量相同也可能指向不同的数据历史。所以偏移量只能作为「量」的参考,判断一致性还要结合复制 ID(replid / runid)一起看。

4. PSYNC 协议:握手阶段决定了走哪条同步路径

4.1 为什么需要 PSYNC,而不是每次全量

如果每次从节点重连都要主节点做一次全量快照(RDB)并传输,那么网络抖动、从节点短暂重启都会引发巨额开销。为此 Redis 在 2.8 引入了 PSYNC(Partial SYNC,部分同步)协议:从节点在连接时告诉主节点「我曾经同步到哪个 runid 和哪个偏移量」,主节点据此判断能否只补发缺失的那一小段命令。

PSYNC 的核心交互可以概括成三个分支:

text 复制代码
从节点: PSYNC <replid> <offset>
主节点判断:
  分支 A: replid 匹配 且 offset 在 backlog 覆盖范围内
          -> +CONTINUE,只补发缺失命令  (部分重同步)
  分支 B: replid 不匹配,或第一次连接
          -> +FULLRESYNC <new_replid> <offset>,走全量  (全量重同步)
  分支 C: replid 匹配但 offset 太旧,已被 backlog 覆盖掉
          -> +FULLRESYNC,也只能走全量

第一次连接时,从节点发的是 PSYNC ? -1,问号表示「我不知道之前的 replid」,-1 表示「我不知道偏移量」。主节点一律回 +FULLRESYNC。

4.2 一次 PSYNC 完整握手示例

可以用 redis-cli 直连主节点,手工模拟一次握手来观察响应(这是调试复制时非常有用的手段):

bash 复制代码
# 目标: 观察主节点对一次 PSYNC 请求的响应分支
# 前置: 本机启动一个 Redis 实例,端口 6379

redis-cli -p 6379
# 先看看当前主节点的复制 ID 和偏移量
INFO replication

# 手工发送 PSYNC,用当前 replid 和当前 offset,模拟一次正常重连
PSYNC <当前replid> <当前offset>
# 预期: +CONTINUE,然后开始接收主节点后续推送的命令流

# 再试一个明显过旧的 offset(例如 1),模拟 backlog 已被覆盖
PSYNC <当前replid> 1
# 预期: +FULLRESYNC <replid> <offset>,随后主节点开始传输 RDB

关键点在于:+CONTINUE 和 +FULLRESYNC 是两条完全不同的路径。前者只补差量,代价很小;后者要 fork 子进程做 RDB 快照、传输全量数据、从节点清空并加载------在数据量大的实例上,这可能耗时几十秒甚至几分钟。所以工程上真正要争取的,是让重连尽量走 +CONTINUE。而这个「能不能补差量」的判据,就落在下一节的 backlog 上。

常见错误:手工执行 PSYNC 后如果直接退出了交互会话,主节点会保留一个未完成的从节点连接一段时间,可能污染 INFO replication 的从节点计数。调试完记得断开,或直接重启该实例。

5. repl_backlog:决定能不能「只补一点」的环形缓冲

5.1 backlog 是什么,为什么是环形的

复制积压缓冲区(replication backlog)是主节点上的一块内存区域,用来暂存最近推送过的复制流。当从节点断线重连并请求部分同步时,主节点就从 backlog 里找出从节点缺失的那一段补给它。可以把它理解成一个「最近 N 条命令的录音带」,只保留最近的一部分。

它被实现成环形缓冲区(ring buffer):固定大小,写满后从头覆盖旧数据。这意味着 backlog 只能覆盖「最近一段时间」的命令,更早的会被挤掉。

概念 含义 典型配置
repl-backlog-size backlog 的字节容量 默认 1MB,生产常调大到 64MB 或更多
repl-backlog-ttl 最后一个从节点断开后,backlog 保留多久 默认 3600 秒
覆盖范围 backlog 能容纳的复制流秒数 取决于写入速率,写入越快覆盖时间越短

5.2 backlog 命中与未命中的边界

backlog 是否命中,决定了一次重连是全量还是增量。用数字说明:假设某实例写入速率是 2MB/s,backlog 配置为 64MB,那么 backlog 大约能覆盖 32 秒的复制流。

text 复制代码
场景一: 从节点断线 5 秒后重连
  缺失复制流约 10MB < 64MB -> backlog 命中 -> +CONTINUE -> 秒级恢复

场景二: 从节点断线 60 秒后重连
  缺失复制流约 120MB > 64MB -> backlog 未命中 -> +FULLRESYNC -> 全量传输

这就是 backlog 的核心价值:它把「网络抖动导致的短时断连」这种高频、低代价的场景,从全量重同步里救了出来。反过来,backlog 太小会让频繁抖动的集群不断触发全量同步;backlog 太大则白占内存。工程上的经验公式是:所需容量 ≈ 平均写入速率 × 可容忍的最长断线时间 × 安全系数。

最容易误解的是:调大 backlog 并不能减少故障切换时的数据丢失。它只影响「断线重连能否走增量」,而切换时数据丢多少,取决于从节点 ack 的偏移量和主节点实际写入偏移量的差,是另一回事。这两个概念经常被混为一谈。

6. 全量重同步:一次昂贵但必要的快照传输

6.1 全量同步的完整过程

当 PSYNC 判定无法部分同步时,主节点会触发全量重同步。整个过程按时间顺序如下:

text 复制代码
从节点                          主节点
  |                               |
  |--- PSYNC ? -1 --------------> |
  |                               | fork 子进程,生成 RDB 快照
  |<-- +FULLRESYNC <replid> <off> |
  |<-- RDB 文件数据 ------------  | 同时把 fork 之后的写命令
  |                               | 缓存到 repl_backlog / 客户端缓冲
  | 清空本地数据,加载 RDB        |
  |                               |
  |--- 加载完成 -----------------> |
  |<-- 补发 fork 期间的写命令 ---- |
  |<-- 持续增量复制流 ----------  |

注意两个细节:第一,主节点在 fork 生成 RDB 期间会继续接受写请求,这些新命令被缓存起来,等 RDB 传完后补发给从节点;第二,从节点加载 RDB 时会先清空自己的旧数据,所以全量同步期间从节点对外是不可用的(取决于配置,一般对外只读)。

6.2 fork 与 copy-on-write 的代价

全量同步的昂贵不只在于网络传输,更在于主节点的 fork 操作和随之而来的写时复制(copy-on-write)。fork 会短暂阻塞主线程;如果实例内存很大(比如 32GB),fork 的页表复制本身就可能造成几十到几百毫秒的卡顿。同时,fork 后主节点的写操作会触发物理页复制,内存可能膨胀到接近两倍。

下面这个最小可复现脚本用来观察全量同步时的内存与耗时变化:

bash 复制代码
#!/usr/bin/env bash
# 目标: 观察一次全量重同步期间主节点的内存峰值与从节点状态
# 前置: 已有一主一从,主节点端口 6379,从节点端口 6380

set -euo pipefail

# 在主节点写入约 200MB 数据,制造一定内存规模
redis-cli -p 6379 flushall
for i in $(seq 1 200); do
  redis-cli -p 6379 -x set "big:$i" < /dev/urandom | head -c 1048576 > /dev/null || true
done

# 打印从节点当前状态,应看到 master_link_status:down 之前是 up
redis-cli -p 6380 info replication | grep -E 'master_link_status|slave_repl_offset'

# 在从节点执行全量重同步,并计时
/usr/bin/time -v redis-cli -p 6380 replicaof 127.0.0.1 6379 2>&1 | tail -5

# 观察主节点内存与 fork 相关指标
redis-cli -p 6379 info memory | grep -E 'used_memory_human|mem_fragmentation_ratio'
redis-cli -p 6379 info stats | grep -E 'latest_fork_usec'
redis-cli -p 6379 info replication | grep -E 'master_repl_offset|repl_backlog'

运行后重点看三项:latest_fork_usec 反映 fork 耗时(持续偏大说明实例内存过重)、used_memory 在同步期间是否接近翻倍(说明 CoW 页复制严重)、从节点 master_link_status 从 down 变 up 的耗时(即全量同步总时长)。适用场景是容量评估与故障演练;边界在于该脚本会清空数据,绝不能在生产实例执行,应放在隔离的测试环境。

7. 故障切换:偏移量、backlog 与切换策略怎么共同决定丢多少数据

7.1 切换时数据丢失的定量理解

故障切换(failover)的数据丢失边界,可以用一个不等式表达:

text 复制代码
可能丢失的数据量 ≤ 主节点最后成功写入的偏移量 --- 被提升从节点最后 ack 的偏移量

这里的「被提升从节点」是 Sentinel/Cluster 选出的那个偏移量最大的从节点。也就是说,即使系统里有三个从节点,能保住的数据也只取决于最「新」的那一个。如果那个从节点本身落后主节点 2 秒,那这 2 秒就得丢。

影响因素 对丢数据的影响 可调手段
从节点复制延迟 延迟越大,丢失上限越高 网络优化、从节点算力、避免大 Key 阻塞
主节点写入速率 同样延迟下,速率越高丢得越多 业务层限流、写命令合并
backlog 大小 不影响切换丢失,只影响重连路径 主要作用是减少全量同步
min-replicas-to-write 强制至少有 N 个从节点 ack 才允许写 可显著降低丢失,但会牺牲可用性

7.2 用 min-replicas 把「异步」变成「有条件的半同步」

Redis 提供了一组配置,让主节点在从节点数量或延迟不满足条件时拒绝写入,从而给异步复制加一道「准同步」护栏:

conf 复制代码
# redis.conf 关键片段
# 至少有 2 个从节点的复制延迟不超过 10 秒,主节点才接受写
min-replicas-to-write 2
min-replicas-max-lag 10

含义是:如果当前健康从节点少于 2 个,或它们落后超过 10 秒,主节点直接对写命令返回错误。这能在一定程度上把「丢 10 秒数据」的概率压下去,代价是当从节点集体抖动时,主节点会拒绝写入,可用性下降。它不能保证零丢失,只是把丢失窗口约束住。

7.3 时序:一次完整切换里发生了什么

text 复制代码
时间轴  Sentinel 视角
  t0    Master 正常,Replica 持续 ack
  t1    Sentinel 主观下线 Master(ping 超时)
  t2    Sentinel 向其他 Sentinel 询问,达到 quorum -> 客观下线
  t3    选举 Leader Sentinel(基于 epoch 和 Raft 式投票)
  t4    Leader 从 Replica 中挑选 offset 最大、优先级最高者
  t5    向该 Replica 发送 REPLICAOF NO ONE,提升为新 Master
  t6    其余 Replica 转向新 Master 复制
  t7    旧 Master 恢复后,被降级为新 Master 的从节点

从 t1 到 t5 这段时间是数据丢失窗口:主节点若在 t0 之后、t1 之前仍接受了写入,这些写入只有那些已被从节点收到的部分能保住。所以工程上要监控的核心指标,是「从节点 ack 偏移量和主节点偏移量的差值」在故障窗口内的最大值。

8. Java 工程实践:用 Spring Boot 观察复制状态并做写保护

8.1 最小示例:读取复制状态

目标:在 Spring Boot 应用中通过 RedisConnection 读取主从复制信息,便于在健康检查里暴露复制延迟。前置环境:Spring Boot 3.x,spring-boot-starter-data-redis,本机一主一从。

java 复制代码
package com.example.replication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;

import java.util.Properties;

@SpringBootApplication
public class ReplicationProbeApplication {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx =
                     SpringApplication.run(ReplicationProbeApplication.class, args)) {

            RedisConnectionFactory factory = ctx.getBean(RedisConnectionFactory.class);
            try (RedisConnection conn = factory.getConnection()) {
                Properties info = conn.info("replication");
                String role = info.getProperty("role");
                String offset = info.getProperty("master_repl_offset");
                String linkStatus = info.getProperty("master_link_status");
                String slaveOffset = info.getProperty("slave_repl_offset");

                System.out.println("role=" + role + ", master_offset=" + offset
                        + ", link=" + linkStatus + ", slave_offset=" + slaveOffset);

                if ("slave".equals(role)) {
                    long master = Long.parseLong(offset);
                    long slave = Long.parseLong(slaveOffset);
                    long lag = master - slave;
                    System.out.println("复制延迟字节数=" + lag);
                    if (lag > 20 * 1024 * 1024) {
                        System.err.println("警告: 复制延迟超过 20MB,故障切换可能丢失较多数据");
                    }
                }
            }
        }
    }
}

关键步骤:conn.info("replication") 返回的 Properties 里,master_repl_offset 是主节点偏移量,slave_repl_offset 是从节点已应用偏移量。预期输出类似 role=slave, master_offset=1200, link=up, slave_offset=1000,并打印延迟字节数。适用场景是健康检查与告警;容易改错的地方是:从节点上 master_repl_offset 字段在部分版本里也可能是主节点的偏移快照,务必以 INFO replication 实际输出为准,不要想当然按字段名解析。

8.2 结合 Redisson 的分布式锁与复制延迟

目标:演示在复制延迟存在时,分布式锁可能出现的边界问题。前置:Redisson 客户端连接一主两从。

java 复制代码
package com.example.replication;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import java.util.concurrent.TimeUnit;

public class LockWithReplicationRisk {

    public static void main(String[] args) throws InterruptedException {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient client = Redisson.create(config);

        RLock lock = client.getLock("order:lock:1001");
        try {
            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (!locked) {
                System.out.println("未获取到锁,放弃处理");
                return;
            }
            System.out.println("获取锁成功,处理订单扣减");
            // 模拟业务处理
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("加锁过程被中断");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
            client.shutdown();
        }
    }
}

这段代码本身正确,但要理解它在主从复制下的边界:Redisson 的锁依赖主节点写入。如果主节点在锁写入后、同步到从节点前宕机,而故障切换又选了一个没有这条锁记录的从节点,那么新主上锁就不存在,第二个线程可能同时拿到锁。缓解手段是:对强一致要求的场景,用 Redlock 或基于 min-replicas-to-write 的写保护,或改用带共识的协调服务如 etcd、ZooKeeper。这里的关键结论是:基于单主异步复制的 Redis 锁,天然存在故障切换时的互斥失效窗口,不能用于对正确性要求极高的资金类互斥。 适用场景是并发度控制、幂等辅助;不适用场景是严格串行的资金操作。

9. Sentinel 与 Cluster 下的复制边界对比

很多团队把 Sentinel 和 Cluster 的复制行为混为一谈,其实两者在「一个分片内的复制」上是同一套 PSYNC + backlog 机制,差别在故障切换的触发和范围。

维度 Sentinel 模式 Cluster 模式
复制单位 整个主节点 每个分片的主节点
切换触发 Sentinel 集群判定客观下线 分片内节点投票 + 集群总线
切换范围 全局,所有从节点跟随 仅该分片,其他分片不受影响
数据丢失边界 提升偏移最大的从节点 同样,但只影响该分片的数据
backlog 角色 断线重连走增量 同左,且分片间独立
常见风险 脑裂、切换期间写丢失 分片倾斜、跨分片事务不可用

结论化的选择:当数据量不大、需要全局原子操作(如 KEYS、事务、Lua 跨 Key)时选 Sentinel;当数据量大、需要水平扩展且能接受分片语义时选 Cluster。两者都不能消除异步复制的丢失窗口,只能通过 min-replicas 和合理的从节点布局来收窄它。

10. 常见误区与实际表现

误区 实际表现 正确理解
「主从复制是强一致」 切换后数据回退 异步复制,只保证最终一致
「调大 backlog 能防丢数据」 切换照样丢 backlog 只影响重连是否增量
「偏移量相同就数据一致」 极端情况下不一致 还需核对 replid 与历史
「从节点越多越安全」 切换只认最新的那个 关键是最大偏移从节点的状态
「Sentinel 切换是瞬时的」 秒级到十几秒 主观下线 + 投票需要时间

11. 生产实践建议与排障清单

11.1 监控指标

  • master_repl_offset 与从节点 slave_repl_offset 的差值,按实例和时间趋势告警。
  • master_link_status 必须持续为 up,出现 down 立即排查。
  • latest_fork_usec 持续超过 100ms 说明实例内存过重,考虑调整持久化与内存结构。
  • repl_backlog_size 与历史最大断线时长的乘积,用于校验 backlog 是否够大。

11.2 排障清单

  1. 从节点 master_link_status 为 down:检查网络连通、主节点是否设置了 requirepass、密码配置是否一致。
  2. 频繁全量重同步:检查 backlog 是否过小、从节点是否频繁重启、网络是否存在周期性抖动。
  3. 切换后大量数据回退:核对被提升从节点的 ack 偏移量、切换窗口内主节点的写入量。
  4. 复制延迟持续增长:排查大 Key、慢命令、从节点磁盘或内存瓶颈。

12. 面试与复盘问题

  • 为什么 Redis 需要复制积压缓冲区,它和全量重同步是什么关系?
  • PSYNC 的三种响应分支分别对应什么条件?
  • 故障切换时的数据丢失上限由哪两个偏移量决定?
  • min-replicas-to-write 能否保证零丢失?它的代价是什么?
  • 单主异步复制下的分布式锁,在什么条件下会失去互斥性?
  • Sentinel 与 Cluster 的切换范围差异,对业务一致性有什么影响?

13. 总结:用一张决策清单收束

text 复制代码
需要判断一次复制行为会走哪条路:
  1) 从节点首次连接?          -> 全量重同步
  2) replid 不匹配?           -> 全量重同步
  3) 缺失偏移在 backlog 内?   -> 部分重同步 (+CONTINUE)
  4) 缺失偏移超出 backlog?    -> 全量重同步

需要评估故障切换会丢多少数据:
  1) 被提升从节点的最后 ack 偏移
  2) 主节点最后成功写入的偏移
  两者之差即为丢失上限;backlog 大小不直接参与该计算。

需要降低丢失窗口:
  1) 减小复制延迟(网络、从节点算力、避免大 Key)
  2) 配置 min-replicas-to-write 与 min-replicas-max-lag
  3) 对强一致场景,改用带共识的组件或让写等待至少一个从节点确认

回到开头的秒杀事故:如果当时配置了 min-replicas-to-write 1 且从节点延迟小于 1 秒,那么主节点在从节点跟不上时会拒绝写入,虽然会损失部分可用性,但能把这 3 秒的库存丢失压到很小。Redis 主从复制的所有配置,本质上都是在「可用性」和「一致性」之间调参,而 PSYNC、backlog、偏移量这三个概念,就是调节这个旋钮时你必须看懂的刻度盘。

14. 参考资料

相关推荐
Alice-YUE1 小时前
提示词工程:工业级 Prompt 写法与分层组装
java·开发语言·大模型·prompt·提示词工程·system prompt
夜雪一千1 小时前
MySQL 中什么是条件注释
数据库·mysql
泡茶喝茶写代码1 小时前
A股量化数据工程:从 REST 接口到策略信号(第 4 篇):行业与概念板块树构建
java·python·股票数据api·股票数据·股票数据api接口·股票api数据接口·股票量化数据api
可乐鸡翅yeah_1 小时前
AES‑128 加密 M3U8,IV 初始化向量新手容易踩坑
前端·网络·数据库·ffmpeg·音视频·m3u8在线
弹简特1 小时前
【Java项目-企悦抽】17-抽奖模块02-抽奖接口实现
java·开发语言·状态模式·springboot
吴声子夜歌1 小时前
Nginx应用与运维——Nginx编译及部署(部署)
java·运维·nginx
IvorySQL1 小时前
PostgreSQL 日报| relchecks 溢出导致表无法删除(9 月 28 日)
数据库·人工智能·ai·postgresql·区块链
hweiyu002 小时前
Redis命令:HPEXPIREAT
redis·缓存
帷幕落秋2 小时前
Redis主从复制
运维·数据库