1. 从"容器一重启数据就没了"说起:K8s 为什么必须有一套持久化存储机制
我最早接触 Kubernetes 时,踩过最深的一个坑就是:明明在容器里写好了业务数据,结果 Pod 一重启,或者节点一维护,数据全没了。当时第一反应是"是不是我代码写错了",排查了半天才发现,问题根本不在业务层,而是我对 K8s 存储模型的理解太想当然了。
K8s 里的 Pod 设计哲学是"临时、可替换、可水平扩展"。一个 Pod 里的容器崩了,Kubelet 会把它重新拉起来;Pod 本身被驱逐了,ReplicaSet 会在另一个节点上创建一个全新的 Pod。这种设计保证了业务的高可用和弹性伸缩,但代价就是:如果你把数据写在容器可写层里,那么随着容器或 Pod 的消亡,数据也跟着烟消云散。这对无状态应用(比如纯计算任务、静态页面服务)没啥影响,但对数据库、消息队列、文件存储这类有状态应用来说,就是致命问题。
所以 K8s 必须解决"如何在 Pod 生命周期之外保存数据"这件事。而它的答案,就是一套从底层存储资源到上层应用声明式使用的完整抽象体系:Volume、PV、PVC、StorageClass,再加上 CSI 插件机制。这套体系的核心目标可以概括成三句话:让应用声明"我要什么存储",让管理员提供"有哪些存储可用",让调度器决定"这个 Pod 该用哪个存储"。
很多人读 K8s 持久化存储相关的文档时,容易被一堆概念绕晕,感觉每个名词都在讲存储,但又不清楚它们之间的边界到底在哪。这篇文章我想换一个角度,不按官方文档的目录顺序讲,而是从一个真实应用从"无状态"改造成"有状态"的全过程来拆解,把每个组件在流程里承担的角色、它们之间的交互顺序、以及实际配置时最容易踩的坑,都一层层拨开来看。
不管你是刚入门 K8s 的运维新人,还是已经跑过一些业务 Pod、想系统地搞清楚存储选型和排障思路的开发者,这篇文章应该都能给你一条比较清晰的主线。我尽量多放一些可以直接抄走的配置示例和排障命令,少讲虚的。
2. 先看清三个核心角色的分工:Volume、PV、PVC、StorageClass 到底分别解决什么问题
2.1 最底层:Volume 是"挂在 Pod 里的目录",它不关心数据从哪来
K8s 里最基础的存储抽象是 Volume,它解决的核心问题就一个:怎样把一块存储挂载到 Pod 里的容器文件系统上。Volume 的生命周期和 Pod 是绑定的——Pod 存在,Volume 就在;Pod 被删除,Volume 跟着销毁(除非用的是持久化类型的 Volume)。这个设计有个好处:容器崩溃重启时,Volume 不会丢,因为 Volume 属于 Pod 层而不是容器层。
不同的 Volume 类型背后对应着不同的存储来源。比如 emptyDir 是节点本地的一个临时目录,hostPath 是直接挂节点上的某个路径,nfs 是挂一个外部 NFS 共享目录,cloudDisk 这类则是云厂商的块存储。Volume 本身只是一个"挂载动作 + 数据来源"的声明,它并不知道上层业务是什么,也不管数据要不要长期保存。如果哪天你听到别人说"K8s 持久化存储的核心是 Volume",这句话其实只说对了一半——Volume 只是载体,真正决定数据能否持久化的,是 Volume 背后的存储类型和生命周期策略。
2.2 中间层:PV 是"集群里的存储资源",PVC 是"应用的存储需求"
把 Volume 直接写进 Pod 配置是有问题的。比如你想在 Pod 里挂载一块云盘,那你得在 Pod 的 YAML 里写死云盘 ID、文件系统类型、挂载路径等一堆信息。如果团队里有多个人都要用存储,每个人都得自己去找存储、填参数,完全没法管理。更麻烦的是,换一套底层存储(比如从云盘换成 NFS),所有 Pod 配置都得改一遍。
为了解决这种耦合,K8s 引入了 PV(PersistentVolume,持久化存储卷)和 PVC(PersistentVolumeClaim,持久化存储声明)这两个抽象层。PV 是集群管理员预先准备好的存储资源对象,它描述的是"有一块 100Gi 的存储,访问模式是 ReadWriteOnce,后端对接的是某块云盘"。PVC 是用户提交的存储申请,描述的是"我要 50Gi 的存储,要求能读写"。
这两者的关系,可以直接理解成:PV 是"货架上已经摆好的商品",PVC 是"用户提交的采购单"。系统看到采购单后,会去找一个满足条件的商品,然后把它们绑定在一起。绑定完成后,应用在 Pod 里使用 PVC 时,根本不需要关心底层到底是 NFS、云盘还是本地盘。这就是解耦——存储的"供给方"和"需求方"各管各的,中间只通过资源规格和访问模式来匹配。
2.3 调度层:StorageClass 是"动态生产 PV 的工厂"
如果只有 PV 和 PVC,那管理员每次都得手动创建 PV,业务一多很快就变成运维噩梦。所以 K8s 又提供了 StorageClass 这个资源,它的作用可以概括为:定义一种"生产存储的模板"。你告诉 StorageClass"我要用哪类存储驱动、回收策略是什么、参数是什么",然后当用户创建 PVC 时,系统会自动调用这个模板,动态地创建一个 PV 并完成绑定。
这就有点像你不再需要亲自去商场挑成品货,而是告诉工厂"我需要 50Gi 的货,按这个规格生产",工厂自动把货造出来送到你手上。StorageClass 的出现,让"按需申请、即用即得"变成了现实,也解决了集群里存储资源规模化和自动化管理的问题。
为了更直观地说明 PV、PVC、StorageClass 各自关心的内容差异,我整理了一个对比表:
| 资源对象 | 核心职责 | 由谁创建 | 生命周期 | 典型字段 |
|---|---|---|---|---|
| Volume | 挂载动作与数据来源声明 | 应用开发者 | 与 Pod 绑定 | mountPath、volumeType |
| PV | 描述一块真实的存储资源 | 管理员(或 StorageClass 自动创建) | 独立于 Pod,可持久 | capacity、accessModes、storageClassName |
| PVC | 声明应用的存储需求 | 应用开发者 | 独立于 Pod,删除后释放 | resources.requests.storage、accessModes |
| StorageClass | 定义动态创建 PV 的模板 | 管理员 | 长期存在 | provisioner、reclaimPolicy、parameters |
这张表值得反复看,因为很多人搞混的概念其实就是这几个。尤其是 PV 和 PVC 的区别:PV 是"实际存在的存储资源",PVC 是"对资源的请求",它们之间通过 bind 来配对。StorageClass 则是"自动创建 PV 的机制",它不直接存储数据,只是存储资源的生产线。
2.4 控制器与 CSI:整个流程背后还有两个"看不见的手"
在 PV、PVC、StorageClass 之上,K8s 还有几个关键组件在默默工作。kube-controller-manager 里有个 PersistentVolumeController,它负责监听 PVC 和 PV 的变化,执行"找 PV、绑定 PVC、更新状态"这些动作。如果你创建了一个 PVC,会发现它先进入 Pending 状态,经过绑定后变成 Bound,这个状态的流转就是由控制器完成的。
另一个重要角色是 CSI(Container Storage Interface,容器存储接口)。它是 K8s 与具体存储系统(云盘、NFS、分布式存储等)之间的标准协议。每个云厂商或存储厂商都会实现一个 CSI 插件,K8s 通过调用 CSI 插件的标准接口,来完成"创建存储卷、挂载到节点、格式化、挂载进容器"等操作。CSI 插件的引入,让 K8s 核心代码不需要关心具体存储实现,也让我们可以在一个集群里同时使用不同厂商的存储,互不干扰。
如果你只记住一个关键点,那就是:PV/PVC/StorageClass 是"资源声明与调度"层面的事情,CSI 是"真正和存储硬件打交道"的层面。前者决定数据能不能持久保存,后者决定数据用什么方式保存。
3. 一次完整的持久化存储流程是怎么跑通的:从 PVC 创建到 Pod 挂载的逐步拆解
3.1 第一步:管理员先定义 StorageClass(或者确认已有可用的 StorageClass)
整个流程的起点,通常是管理员在集群里创建一个 StorageClass。以下是一个使用某云厂商 SSD 云盘的 StorageClass 示例:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-ssd provisioner: ebs.csi.aws.com # 这里以云厂商CSI驱动为例 parameters: type: gp3 fsType: ext4 encrypted: "true" reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true这个 YAML 里有几个值得注意的字段。provisioner 指定了由哪个 CSI 驱动来创建存储卷;parameters 是传给 CSI 驱动的参数,不同厂商有不同的可选值;reclaimPolicy 决定当 PVC 被删除时,底层 PV 怎么处理——Delete 表示删除 PV 并释放底层存储,Retain 表示保留底层数据供人工处理;volumeBindingMode 这里用了 WaitForFirstConsumer,意思是"等有 Pod 真正要用这个存储时,再创建 PV 并绑定",这能避免 PV 被创建在与 Pod 调度节点不同的可用区里,这个细节后面我会专门讲。
如果你使用的集群里已经有默认的 StorageClass,那这一步通常可以跳过。可以用下面的命令确认:
kubectl get storageclass kubectl get storageclass -o yaml # 查看默认StorageClass的详细信息如果发现某个 StorageClass 的 annotations 里有storageclass.kubernetes.io/is-default-class: "true",那它就就是集群默认使用的存储类,后面创建 PVC 时如果不指定 storageClassName,就会自动用它。
3.2 第二步:应用方创建 PVC,系统自动寻找或动态创建匹配的 PV
接下来,应用开发者创建一个 PVC:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name:>kubectl get pvc>apiVersion: apps/v1 kind: Deployment metadata: name: web-app spec: replicas: 3 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: app image: nginx:1.25 volumeMounts: - name: app-data mountPath: /data volumes: - name: app-data persistentVolumeClaim: claimName:>apiVersion: v1 kind: PersistentVolume metadata: name: manual-pv-01 spec: capacity: storage: 100Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain csi: driver: ebs.csi.aws.com volumeHandle: vol-xxxxxx这种做法的最大问题是流程冗长。应用要存储,得先提工单,管理员去申请云盘、创建 PV、等 PVC 绑定,然后应用才能调度。一旦云盘数量多了,还要做各种命名、打标签、记录归属关系,纯人工管理,出错概率高。更麻烦的是,如果业务方申请的是 50Gi,而管理员创建的是 100Gi 的 PV,这块多出来的容量就被这个 PVC 独占,其他业务想用也用不上,存储利用率偏低。
动态 StorageClass 解决的正是这些问题。PVC 创建后,系统自动调用 CSI 插件创建匹配规格的存储卷,秒级完成绑定;存储资源按需创建,用多少申请多少;容量不够时,只要 StorageClass 的 allowVolumeExpansion 为 true,还可以在线扩容 PVC。整个流程不仅快,而且把"人肉运维"降到了最低。
4.2 动态创建的内部逻辑:PVC -> StorageClass -> Provisioner -> 新 PV
StorageClass 动态创建的完整链路是这样的:
- 用户提交 PVC,指定 storageClassName。
- PersistentVolumeController 发现该 PVC 没有绑定 PV,且对应的 StorageClass 存在。
- 控制器调用 StorageClass 里定义的 provisioner 对应的 CSI Provisioner 组件。
- CSI Provisioner 与底层存储系统交互,创建一块新存储卷,并获取到 volumeHandle。
- 控制器根据返回的信息生成一个 PV 对象。
- PV 与 PVC 完成绑定,PVC 状态从 Pending 变为 Bound。
这条链路上任何一个环节出问题,PVC 都会一直 Pending。最常见的问题包括:CSI 驱动没安装或版本不匹配、底层云账号权限不足、StorageClass 参数写错。如果 PVC 卡在 Pending,第一件事是看事件:
kubectl describe pvc>apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: zone-aware-ssd provisioner: ebs.csi.aws.com parameters: type: gp3 volumeBindingMode: WaitForFirstConsumer在单可用区环境里,Immediate 和 WaitForFirstConsumer 差别不大;但如果是跨可用区的生产集群,建议一律加上 WaitForFirstConsumer。我曾经遇到过一个线上问题:某个 CronJob 用的是云盘 PV,PVC 创建后立刻绑定到可用区 A 的 PV,但 CronJob 的 Pod 调度到了可用区 B,结果 Pod 一直 ContainerCreating,报 volume 挂载超时。后来把 storageClass 改成 WaitForFirstConsumer,问题就再也没出现过。
5. 有状态应用场景下的存储选型:单节点读写、多节点共享、文件存储分别怎么选
5.1 快存储 vs 文件存储 vs 对象存储,别拿一种存储解决所有问题
K8s 支持很多存储类型,但粗略分三大类:
- 块存储(Block Storage):云盘、本地盘等。性能高,延迟低,但只能被一个节点读写(ReadWriteOnce),适合数据库、消息队列等对 IOPS 和延迟敏感的应用。典型代表:云厂商的云盘、分布式块存储。
- 文件存储(File Storage):NFS、GlusterFS、以及云厂商的文件存储服务等。支持多节点同时读写(ReadWriteMany),适合多个 Pod 共享同一份数据的场景,比如日志聚合目录、静态资源共享、CI 构建产物共享。性能通常低于块存储,但并发访问能力强。
- 对象存储(Object Storage):S3、OSS、MinIO 等。一般不走 K8s 的 PV/PVC 体系,而是通过 SDK 或 S3 兼容接口访问。适合海量非结构化数据、冷热分层存储,但在 K8s 里很少以 Volume 形式直接挂载给容器用(也有 CSI 驱动支持,但性能和体验不如前两者)。
选型的基本原则是:如果你的应用是单副本数据库、缓存、消息队列,优先用块存储;如果是多副本共享读写或者跨节点共享,优先用文件存储;如果是海量文件归档、备份、日志归档,优先用对象存储。没有一种存储能通吃所有场景,强行用一个必然会在性能或架构上出问题。
5.2 常见 CSI 驱动的选型对比
不同存储厂商提供不同的 CSI 驱动,K8s 只是通过统一接口对接它们。下面是一个实际项目中常见 CSI 驱动的简单对比:
| CSI 驱动 | 后端存储类型 | 典型访问模式 | 适用场景 | 备注 |
|---|---|---|---|---|
| 云厂商块存储 CSI | 云盘 | ReadWriteOnce | 数据库、有状态中间件 | 性能好,容量可在线扩容 |
| 云厂商文件存储 CSI | 文件存储/NFS | ReadWriteMany | 多 Pod 共享静态文件、日志 | 需注意挂载性能和并发上限 |
| NFS CSI / NFS 直挂 | NFS 服务器 | ReadWriteMany | 内网共享目录、测试环境 | 配置简单,但性能和可靠性依赖 NFS 服务端 |
如果你的集群不是云环境,而是一套自建机房,那 NFS 是最常见的多节点共享方案。但用 NFS 时要注意几个问题:NFS 服务端必须是高可用的,不能单点;NFS 挂载的 IO 性能会成为瓶颈;Pod 调度和挂载时要避免所有 Pod 都打到同一个 NFS 服务器。我自己维护过一套自建 K8s 集群,所有有状态应用都用 NFS 共享目录,前期很爽,后期发现日志目录和数据库目录混在一个 NFS 上,高峰期 IO 抢占严重。后来把数据库单独迁到了本地块存储,NFS 只保留多 Pod 共享的静态资源,性能问题才缓解。
5.3 StatefulSet 里的专用存储语义:volumeClaimTemplates 自动为每个副本生成独立 PVC
如果你部署的是有状态应用,比如一个三副本的 ZooKeeper 或 Kafka,不能简单地用 Deployment + 共享 PVC,因为每个副本应该是独立的、有标识的,数据也不能互相覆盖。这时应该用 StatefulSet,它有一个 Deployment 没有的特性:volumeClaimTemplates。
apiVersion: apps/v1 kind: StatefulSet metadata: name: zk spec: serviceName: zk-hs replicas: 3 selector: matchLabels: app: zk template: metadata: labels: app: zk spec: containers: - name: zk image: zookeeper:3.8 volumeMounts: - name: data mountPath: /data volumeClaimTemplates: - metadata: name: data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: fast-ssd resources: requests: storage: 20Gi当你 apply 这个 StatefulSet 后,系统会自动创建 3 个 PVC:>kubectl get pvc -A kubectl describe pvc <pvc-name> -n <namespace>
事件里如果出现waiting for a volume to be created, either by external provisioner or by storage class,说明 PVC 在等待 PV 创建;如果出现Failed to provision volume,说明 Provisioner 创建存储失败了。事件信息是最直接的线索,一定要先看。
第二步:检查 PV 状态
kubectl get pv kubectl describe pv <pv-name>看 PV 的状态是 Available、Bound、Released 还是 Failed。如果 PV 是 Failed,说明 CSI 创建存储卷时出错了;如果 PV 状态正常而 PVC 仍 Pending,可能是 PVC 与 PV 的容量或访问模式不匹配,或者节点调度问题导致绑定无法完成。
第三步:检查 StorageClass 和 CSI 插件状态
kubectl get storageclass kubectl get pods -n kube-system | grep csiCSI 控制器插件一般跑在 kube-system 命名空间下。看它是否 Running,日志里是否有报错。CSI 插件的日志往往是最底层的原因所在,比如云 API 鉴权失败、后端存储容量不足、卷被占用等。
第四步:检查 Pod 的事件
kubectl describe pod <pod-name> -n <namespace>如果 Pod 一直 ContainerCreating,事件里通常会有类似FailedMount的信息,比如Unable to attach or mount volumes: timed out waiting for the condition。这说明节点上的 Kubelet 在调用 CSI 挂载时超时了。常见原因包括:CSI Node 插件没跑在对应节点上、存储卷正在被其他节点挂载(ReadWriteOnce 被占用)、网络不通。
6.2 一个非常典型的坑:ReadWriteOnce 的 PV 被其他节点占用,导致 Pod 调度后挂载不上
有次我负责一套集群,某应用 Pod 一直 ContainerCreating,查看事件是Multi-Attach error for volume "pvc-xxxx",意思是这个 PV 已经被某个节点挂载了,当前 Pod 所在节点无法再次挂载。原因是这个存储的访问模式是 ReadWriteOnce,只允许被一个节点挂载。
这个现象经常出现在使用云盘的场景。比如一个 Deployment 有 3 个副本,它们都引用同一个 ReadWriteOnce 的 PVC。理论上这种配置就是不合理的,因为 ReadWriteOnce 只允许一个节点挂载,3 个副本分布在 3 个节点上,必然有两个挂载失败。正确做法是:要么把访问模式改成 ReadWriteMany(前提是底层存储支持),要么改用 StatefulSet 给每个副本独立的存储,要么直接用无状态应用,不要挂存储。
排这类问题时,先确认是不是"多个 Pod 共享一个 RWO 存储"的结构性问题。如果是,改配置比排查 CSI 更快。
6.3 另一个容易忽略的坑:PVC 删不掉,一直卡在 Terminating
删除 PVC 时,有时候 PVC 会一直处于 Terminating 状态,删不掉。最常见的原因是:还有 Pod 在引用这个 PVC。K8s 会阻止删除仍被使用的 PVC,保护数据安全。处理方式是把相关 Deployment、StatefulSet 或裸 Pod 先删掉,等 PVC 不再被引用后,它才会真正被删除。
如果确认已经没有 Pod 引用,但 PVC 仍 Terminating,可以看一下 PV 上的保护控制器,或者查看 PVC 的 finalizers:
kubectl get pvc <pvc-name> -o yaml | grep finalizers正常情况下,finalizer 是kubernetes.io/pvc-protection。如果 PVC 卡住很久,除了 finalizer 问题,也可能是底层 CSI 删除存储卷时卡住了,导致 PVC 无法被彻底清理。可以先检查 PV 是否已删除,如果 PV 已删除而 PVC 还在,多半是 finalizer 或 API 层面的问题,极端情况下可以通过编辑 PVC 移除 finalizer 来强制删除,但操作前必须确认底层数据已经不需要了。
6.4 扩容 PVC 时要确认底层存储是否支持在线扩容,不是改个配置就完事
PVC 扩容也是大家经常用到但容易出问题的操作。现在很多 StorageClass 配了allowVolumeExpansion: true,因此可以在线扩容 PVC。你只需要修改 PVC 里的 storage 大小:
kubectl edit pvc <pvc-name>把spec.resources.requests.storage从 50Gi 改成 80Gi,保存后系统会自动调用 CSI 驱动对底层存储卷扩容。但要注意:不是所有存储都支持在线扩容。如果你的 StorageClass 没开启 allowVolumeExpansion,或者 CSI 驱动不支持扩容操作,修改后 PVC 会一直停在 Pending 状态,并提示Waiting for user to (re-)start a pod to finish file system resize of volume on node之类的信息。另外,文件系统在线扩容是有条件的:如果你用的是 ext4,一般需要 Pod 重新挂载后才能完成文件系统扩容;xfs 则通常支持在线扩容。实操中,扩容后最好重启一下对应 Pod,确保新的容量真正生效。
7. 生产环境里的几条硬经验:从存储规划到备份,踩过坑才能总结出来
7.1 存储规划:明确容量配额、性能分层和命名规范
生产环境里,存储规划绝对不能等到业务上来才临时想。我的建议是三件事提前做:
第一,规划容量配额。不可能每个 PVC 都无限制申请,否则底层存储资源会很快耗尽。可以借助 K8s 的 ResourceQuota 来限制每个命名空间的存储总量,比如:
apiVersion: v1 kind: ResourceQuota metadata: name: storage-quota spec: hard: persistentvolumeclaims: "10" requests.storage: 500Gi这样每个命名空间最多能建 10 个 PVC,总容量不超过 500Gi。结合 LimitRange 还能约束单个 PVC 的最小和最大容量。别小看这些配额,等集群规模大了,没有配额就会有人建一堆 1Ti 的 PVC 把存储吃光。
第二,做性能分层。不同业务对存储性能的要求差异很大,数据库要高 IOPS,日志收集对性能要求一般但容量大,备份数据对性能和容量要求都不高。对应地,应该创建多个 StorageClass:fast-ssd给数据库、standard-sas给一般应用、archive给备份存储。不要让所有业务都往一个 StorageClass 里挤,否则性能和成本都会失控。
第三,制定命名规范。PVC 和 PV 的名字最好能体现业务归属。使用 StatefulSet 自动生成的 PVC 名字是>
微信小程序健身房预约系统:从选型到并发控制的实战解析
简介:围绕微信小程序健身房预约系统设计与实现的完整资料包,面向高校计算机相关专业学生以及需要开发预约类小程序的开发者,针对健身房排课、会员预约、课程管理效率低下的实际场景,提供一套从需求分析到功能落地的参考方案。资源…
数据库高可用核心要点:RTO/RPO、复制链路与自动切换实践
凌晨1点47分,告警电话把我叫醒。某业务系统的数据库主库宕了,应用侧写入超时,但等我登录管理端一看,高可用组件显示“一切正常”——因为它只做了TCP层面的健康检查,数据库进程还活着,只不过已经假死&#…
新电脑装Ubuntu全流程:驱动、软件与桌面美化避坑指南
1. 为什么我坚持在每台新电脑上装一遍 Ubuntu每次拿到一台新笔记本,不管是公司配的开发机还是自己攒的台式机,我第一件事就是抹掉预装系统,装一遍 Ubuntu。这个习惯坚持了七八年,踩过的坑能写满一个笔记本,但每次折腾完…
STM32C5 NPU实战:边缘AI MCU开发与CubeMX2迁移经验
/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …
Django电商订单分析系统:智能处理与可视化优化
1. 项目背景与核心价值电商行业每天产生海量订单数据,但大多数中小商家缺乏专业数据分析能力。这套基于Django的Python电商订单分析系统,正是为解决这个痛点而生。我在实际电商项目中发现,原始数据中藏着大量金矿——用户购买时段分布、热销商…
达梦数据库主备部署(同步归档模式)
前提“同步备库”一般用于对主库性能要求较高,想要避免因备库故障或异步恢复引发的Suspend 状态切换,但又希望备库的数据延迟不要太大的应用场景。在达梦数据库DM8中,“同步备库”可以通过“同步归档模式”实现。与实时归档相比,同…