Kubernetes 场景下的 StarRocks 灾备体系:Cluster Snapshot 实践解析

在存算一体架构下,StarRocks 通过 Failover Group、Backup & Restore 以及 Insert Into Files 等机制,实现了集群级的灾备与数据的备份和恢复能力。伴随性能优化与功能演进的持续推进,StarRocks 不断强化系统的稳定性与可用性,以满足企业日益增长的实时分析与高可用需求。

在 3.5 版本 中,StarRocks 推出了全新的 Cluster Snapshot 快照恢复机制,进一步完善了数据安全与灾备体系。

Snapshot 提供了一种高效、低成本、自动化的数据保护方式,显著提升系统的可用性与容灾能力,弥补了此前存算分离架构在备份与恢复方面的空缺。

当系统发生故障、误操作或区域性宕机时,Snapshot 可在分钟级 完成快速恢复,最大限度减少数据丢失与业务中断风险。通过将完整集群状态进行快照化并备份至对象存储,Snapshot 简化了传统灾备方案的复杂流程,使灾难恢复更加高效与便捷。这一机制尤其适用于 金融、零售、SaaS 等对系统稳定性要求极高的关键业务场景。

在此基础上,本文结合 StarRocks 在 Kubernetes 环境中的实际部署实践,进一步介绍了存算分离架构下的灾备机制、恢复流程及快照策略,帮助用户在集群异常或故障场景中快速恢复系统状态,保障业务连续性与数据安全。

名词解释

Cluster Snapshot:

在存算分离架构下,StarRocks 3.5 新增支持集群级别的 Snapshot 功能,提供完整的集群快照能力。Snapshot 可自动创建,记录集群在某一时间点的完整状态(包括 catalog、database、table、user 等元数据),并存储于对象存储中,实现快速的原地或异地恢复。Snapshot不包含外部依赖对象,比如 catalog 依赖的外部配置文件、本地 UDF jar 包等。

Cluster Snapshot 包含两部分内容:Metadata Snapshot 和 Data Snapshot。

  • Metadata Snapshot

FE 定期通过 checkpoint 的方式生成的 image 文件为 **Metadata Snapshot。**image 文件中包含了集群的元数据信息,包括库表,用户,权限等相关内容。

  • Data Snapshot

在存算分离的架构中,数据会存储在对象存储上。而对象存储具有高可靠,接近无限容量等特性。所以在 Snapshot 产生的过程中,我们并不需要对数据进行拷贝,只需要保留 Metadata Snapshot 对应的那些数据版本即可。在恢复时可以将元数据与对应的数据版本进行映射。

在启用集群自动快照功能后,系统会按照设定周期(默认每 10 分钟)生成一份完整快照,并将 FE 的元数据 image 文件写入指定的对象存储路径。因为原始数据文件本身就已经保存在对象存储中,因此数据层面不会发生额外的数据搬迁,系统默认保留最近一次快照及其所依赖的数据版本。

如上图所示,针对每个 tablet 的数据导入都会产生一个对应版本的 rowset。对于已经包含在未删除的 metadata snapshot 的 tablets,涉及到因为 drop table/partition、delete、Compaction 等操作需要后期 GC 删除无用文件的 GC 任务会在下一个 metadata snapshot 生成之前被阻塞,从而确保当前快照所需的数据版本不会被清理。

**Automated cluster snapshot:**系统会根据设置的快照保留周期,自动创建和保存最新的集群状态快照,且只会保留一个最新可用快照。

Cluster **Restore:**当需要恢复时,用户只需在新集群或原集群中指定快照在对象存储上的路径与存储卷配置,即可将系统恢复至指定时间点状态。恢复过程将自动加载元数据并清理冗余数据,确保数据一致性和可用性。

设计 目标

StarRocks存算分离架构支持自动化快照功能,通过快照实现集群的本地或远程恢复。快照的存储位置与数据目录保持一致。利用快照保存最新 checkpoint 版本中的数据信息,支持恢复集群到最近一次快照状态;

在每次生成新的快照文件时,系统会自动创建对应的快照,并删除历史快照文件,仅保留最新版本。因此,每个集群中自动化快照始终只有一个。

自动化快照由系统自动触发,用户可以通过 SQL 命令修改参数,以控制快照生成的周期。

限制:当前仅支持存算分离架构。

具体操作

由于篇幅所限,关于自动化集群快照的开启、关闭,以及集群快照与任务信息的查看等具体操作步骤,请参见官方文档,此处不再展开。

🔗:https://docs.mirrorship.cn/zh/docs/administration/cluster_snapshot/

Kubernetes 部署环境下的恢复流程

在 Kubernetes 部署环境中,为了能够让 operator 在 "disasterRecovery" 模式下优雅地完成调谐,引入了 disasterRecovery 和 disasterRecoveryStatus 配置项;

复制代码
spec:
  disasterRecovery:
    generation: 1
    enabled: true

status:
  disasterRecoveryStatus:
    phase: todo/doing/done
    reason: ""
    observedGeneration: 1
    startTimestamp: xxx
    endTimestamp: yyy       

配置项 "disasterRecovery" 的 "enabled" 必须为 true;

disasterRecoveryStatus.phase 表示灾难恢复的阶段,包括:todo待执行、doing执行中、done已完成,disasterRecoveryStatus的更新逻辑如下:

  1. 当 Operator 检测到首次进入灾备模式(disasterRecoveryStatus 为空)或 observedGeneration < generation 时,灾备模式进入 TODO 阶段。

  2. 在下发修改后的 StatefulSet 后,将 disasterRecoveryStatus.phase 更新为 doing 状态。该状态的持续时间取决于灾备操作的完成时间。

a. Operator 会定期检查 FE Pod 的状态:首先确认其所属的 generation;其次确认 Pod 是否处于 Ready 状态。

  1. 当 FE Pod 处于 Ready 状态后,将 disasterRecoveryStatus.phase 更新为 done 阶段。

  2. 随后,Operator 会根据 StarRocksCluster 的配置,正常启动集群。

如何在已运行的集群上执行灾备恢复

推荐在一个空的 StarRocks 集群上启用灾备。如果使用的是已有的 StarRocks 集群,在启用灾备之前需要清理 FE 组件的元数据 和 CN 组件的数据。

1.清理旧的元数据

a. 手动将 FE StatefulSet 的副本数设置为 0;

b. 删除对应的 FE 元数据 PVC。

  1. 清理旧的数据

a. 手动将 CN StatefulSet 的副本数设置为 0;

b. 删除对应的 CN Cache存储 PVC。

  1. 启动灾难恢复

4. 异常情况处理

a. CN 本地缓存清理

1). 在就地恢复(inplace recovery) 的场景下,本地 CN 节点可能仍然保留旧的缓存数据。 由于 ID 生成器被重置,相同的文件名可能对应不同的内容,从而导致缓存损坏。

2). 需要手动清理缓存:可以通过登录 Pod 清理缓存,或者强制删除 PV/PVC 卷,让 StatefulSet 为 CN 节点重新创建新的卷。

b. FE 节点就地恢复

1). 在某些情况下,现有 FE 节点可能已经形成一个高可用(HA)集群。在恢复后,fe-0 节 点会使 用新的元数据完成恢复,但 fe-1、fe-2 节点可能仍然保留旧的元数据,并继续形 成 一个 HA 集 群(其中可能有一个是 leader)。

2). 恢复完成后,可能会出现 fe-0 成为 leader(正确状态),而 fe-1/fe-2 形成另一个集群的 情 况。

3). 需要手动检查,并清理 fe-1、fe-2 的元数据目录,以确保能够从这种状态下恢复。

c. generation 字段可用于多次执行灾备。例如,如果上一次的灾备结果不符合预期,可以手动 修改相 关配置并提升 generation 的值,从而重新执行一次灾备。

d. 如果 FE 在生成快照时异常退出,S3 上可能会出现两个快照,此时需要使用较旧的快照进行 恢复。

复制代码
➜  disaster-recovery git:(master) ✗ s3cmd ls s3://ydx-starrocks-cluster-bucket/data/5b0125af-7ff6-45df-9b60-c896797458ba/meta/image/
DIR  s3://ydx-starrocks-cluster-bucket/data/5b0125af-7ff6-45df-9b60-c896797458ba/meta/image/automated_cluster_snapshot_1739446285344/
DIR  s3://ydx-starrocks-cluster-bucket/data/5b0125af-7ff6-45df-9b60-c896797458ba/meta/image/automated_cluster_snapshot_1739446405766/

Kubernetes 部署环境下的灾备恢复实践

为了让用户更简单方便地参考本文档,我们使用 kube-starrocks Helm Chart 来部署集群。请注意:

  1. 必须使用 v1.10.0 以上版本的 Operator 和 YAML Manifest;

  2. 我们在文档中使用 xxx 来替代敏感信息,请根据实际情况设置为合理的值。

创建可用的集群

首先,准备 ./starrocks-values.yaml 配置文件。

复制代码
operator:
  starrocksOperator:
    image:
      repository: starrocks/operator
      tag: v1.10.0
    imagePullPolicy: IfNotPresent
    replicaCount: 1
    resources:
      requests:
        cpu: 1m
        memory: 20Mi
starrocks:
  starrocksCluster:
    enabledBe: false
    enabledCn: true
  starrocksCnSpec:
    config: |
      sys_log_level = INFO
      # ports for admin, web, heartbeat service
      thrift_port = 9060
      webserver_port = 8040
      heartbeat_service_port = 9050
      brpc_port = 8060
    image:
      repository: starrocks/cn-ubuntu
      tag: 3.4.1
    replicas: 3
    resources:
      limits:
        cpu: 8
        memory: 8Gi
      requests:
        cpu: 1m
        memory: 10Mi
    storageSpec:
      name: cn
      logStorageSize: 1Gi
      storageSize: 10Gi
  starrocksFESpec:
    feEnvVars:
    - name: LOG_CONSOLE
      value: "1"
    config: |
      LOG_DIR = ${STARROCKS_HOME}/log
      DATE = "$(date +%Y%m%d-%H%M%S)"
      JAVA_OPTS="-Dlog4j2.formatMsgNoLookups=true -Xmx8192m -XX:+UseG1GC -Xlog:gc*:${LOG_DIR}/fe.gc.log.$DATE:time -XX:ErrorFile=${LOG_DIR}/hs_err_pid%p.log -Djava.security.policy=${STARROCKS_HOME}/conf/udf_security.policy"
      http_port = 8030
      rpc_port = 9020
      query_port = 9030
      edit_log_port = 9010
      mysql_service_nio_enabled = true
      sys_log_level = INFO
      run_mode = shared_data
      cloud_native_meta_port = 6090
      enable_load_volume_from_conf = true
      cloud_native_storage_type = S3
      aws_s3_path = xxx
      aws_s3_region = xxx
      aws_s3_endpoint = xxx
      aws_s3_access_key = xxx
      aws_s3_secret_key = xxx
      # we add this configuration because we want to get cluster snapshot quickly
      automated_cluster_snapshot_interval_seconds = 60
    replicas: 3
    image:
      repository: starrocks/fe-ubuntu
      tag: 3.4.1
    resources:
      limits:
        cpu: 2
        memory: 4Gi
      requests:
        cpu: 1m
        memory: 20Mi
    storageSpec:
      logStorageSize: 1Gi
      name: fe-storage
      storageSize: 10Gi

注意:我们将 automated_cluster_snapshot_interval_seconds 设置为按每分钟触发。

接下来,使用 Helm 创建集群。

复制代码
helm install -f ./starrocks-values.yaml starrocks starrocks-community/kube-starrocks --version 1.10.0

# make sure the cluster has been successfully deployed
kubectl get pods
NAME                  READY   STATUS    RESTARTS        AGE
kube-starrocks-cn-0   1/1     Running   0               23s
kube-starrocks-fe-0   1/1     Running   0               79s
kube-starrocks-fe-1   1/1     Running   0               79s
kube-starrocks-fe-2   1/1     Running   0               79s

建表与写入数据

连接 FE

复制代码
# enter FE pod
kubectl exec -it kube-starrocks-fe-0 bash

# use mysql client to login
mysql -h 127.0.0.1 -P9030 -uroot
...
mysql>    

执行以下 SQL 语句:

复制代码
# create database and table
CREATE DATABASE IF NOT EXISTS quickstart;

USE quickstart;

-- create table
CREATE TABLE source_wiki_edit
(
    event_time      DATETIME,
    channel         VARCHAR(32)      DEFAULT '',
    user            VARCHAR(128)     DEFAULT '',
    is_anonymous    TINYINT          DEFAULT '0',
    is_minor        TINYINT          DEFAULT '0',
    is_new          TINYINT          DEFAULT '0',
    is_robot        TINYINT          DEFAULT '0',
    is_unpatrolled  TINYINT          DEFAULT '0',
    delta           INT              DEFAULT '0',
    added           INT              DEFAULT '0',
    deleted         INT              DEFAULT '0'
)
DUPLICATE KEY(
    event_time,
    channel,user,
    is_anonymous,
    is_minor,
    is_new,
    is_robot,
    is_unpatrolled
)
PARTITION BY RANGE(event_time)(
    PARTITION p06 VALUES LESS THAN ('2015-09-12 06:00:00'),
    PARTITION p12 VALUES LESS THAN ('2015-09-12 12:00:00'),
    PARTITION p18 VALUES LESS THAN ('2015-09-12 18:00:00'),
    PARTITION p24 VALUES LESS THAN ('2015-09-13 00:00:00')
)
DISTRIBUTED BY HASH(user);

-- insert data
INSERT INTO source_wiki_edit
VALUES
    ("2015-09-12 00:00:00","#en.wikipedia","AustinFF",0,0,0,0,0,21,5,0),
    ("2015-09-12 00:00:00","#ca.wikipedia","helloSR",0,1,0,1,0,3,23,0),
    ("2015-09-12 08:00:00","#ca.wikipedia","helloSR",0,1,0,1,0,3,23,0);

-- select data
mysql> select * from source_wiki_edit;
+---------------------+---------------+----------+--------------+----------+--------+----------+----------------+-------+-------+---------+
| event_time          | channel       | user     | is_anonymous | is_minor | is_new | is_robot | is_unpatrolled | delta | added | deleted |
+---------------------+---------------+----------+--------------+----------+--------+----------+----------------+-------+-------+---------+
| 2015-09-12 00:00:00 | #ca.wikipedia | helloSR  |            0 |        1 |      0 |        1 |              0 |     3 |    23 |       0 |
| 2015-09-12 00:00:00 | #en.wikipedia | AustinFF |            0 |        0 |      0 |        0 |              0 |    21 |     5 |       0 |
| 2015-09-12 08:00:00 | #ca.wikipedia | helloSR  |            0 |        1 |      0 |        1 |              0 |     3 |    23 |       0 |
+---------------------+---------------+----------+--------------+----------+--------+----------+----------------+-------+-------+---------+
3 rows in set (0.34 sec)

生成集群快照

启动备份:

复制代码
mysql> ADMIN SET AUTOMATED CLUSTER SNAPSHOT ON STORAGE VOLUME builtin_storage_volume;
Query OK, 0 rows affected (0.10 sec)

等待备份完成

复制代码
mysql> SELECT * FROM  INFORMATION_SCHEMA.CLUSTER_SNAPSHOT_JOBS;
+------------------------------------------+--------+---------------------+---------------------+-------------+-------------+---------------+
| SNAPSHOT_NAME                            | JOB_ID | CREATED_TIME        | FINISHED_TIME       | STATE       | DETAIL_INFO | ERROR_MESSAGE |
+------------------------------------------+--------+---------------------+---------------------+-------------+-------------+---------------+
| automated_cluster_snapshot_1739857978127 |  10136 | 2025-02-18 13:52:58 | 2025-02-18 13:54:17 | FINISHED    |             |               |
| automated_cluster_snapshot_1739858117584 |  10137 | 2025-02-18 13:55:17 | NULL                | SNAPSHOTING |             |               |
+------------------------------------------+--------+---------------------+---------------------+-------------+-------------+---------------+
2 rows in set (0.02 sec)

mysql> SELECT * FROM  INFORMATION_SCHEMA.CLUSTER_SNAPSHOTS;
+------------------------------------------+---------------+---------------------+---------------+--------------------+------------+------------------------+---------------------------------------------------------------------------------------------------------------------------------+
| SNAPSHOT_NAME                            | SNAPSHOT_TYPE | CREATED_TIME        | FE_JOURNAL_ID | STARMGR_JOURNAL_ID | PROPERTIES | STORAGE_VOLUME         | STORAGE_PATH                                                                                                                    |
+------------------------------------------+---------------+---------------------+---------------+--------------------+------------+------------------------+---------------------------------------------------------------------------------------------------------------------------------+
| automated_cluster_snapshot_1739857978127 | AUTOMATED     | 2025-02-18 13:52:58 |           253 |                114 |            | builtin_storage_volume | s3://xxx/7351ce6a-f4a4-4937-a876-cb8801085aea/meta/image/automated_cluster_snapshot_1739857978127 |
+------------------------------------------+---------------+---------------------+---------------+--------------------+------------+------------------------+---------------------------------------------------------------------------------------------------------------------------------+

注意:由于我们设置了每分钟执行一次备份,下面使用的备份路径可能与上文不同。最终结果可以通过 S3 查看。

复制代码
s3cmd ls s3://xxx/data/7351ce6a-f4a4-4937-a876-cb8801085aea/meta/image/

sDIR  s3://xxx/data/7351ce6a-f4a4-4937-a876-cb8801085aea/meta/image/automated_cluster_snapshot_1739858235830/

删除已创建的集群

复制代码
# 卸载 StarRocks 集群
helm uninstall  starrocks

# 删除持久化的数据
kubectl get pvc | awk '{if (NR>1){print $1}}' | xargs kubectl delete pvc
persistentvolumeclaim "cn-data-kube-starrocks-cn-0" deleted
persistentvolumeclaim "cn-log-kube-starrocks-cn-0" deleted
persistentvolumeclaim "fe-storage-log-kube-starrocks-fe-0" deleted
persistentvolumeclaim "fe-storage-log-kube-starrocks-fe-1" deleted
persistentvolumeclaim "fe-storage-log-kube-starrocks-fe-2" deleted
persistentvolumeclaim "fe-storage-meta-kube-starrocks-fe-0" deleted
persistentvolumeclaim "fe-storage-meta-kube-starrocks-fe-1" deleted
persistentvolumeclaim "fe-storage-meta-kube-starrocks-fe-2" deleted

创建用于灾备的新集群

我们将复用之前的 starrocks-values.yaml 文件,因此请确保存储文件已妥善保存。接着,准备一个名为 cluster_snapshot.yaml的新文件,其中的内容就是我们在灾备中需要配置的内容。

复制代码
starrocks:
  starrocksCluster:
    disasterRecovery:
      enabled: true
      generation: 1    
  starrocksFESpec:
    # mount the cluster_snapshot.yaml
    configMaps:
    - name: cluster-snapshot
      mountPath: /opt/starrocks/fe/conf/cluster_snapshot.yaml
      subPath: cluster_snapshot.yaml
  configMaps:
  - name: cluster-snapshot
    data:
      cluster_snapshot.yaml: |
        # information about the cluster snapshot to be downloaded and restored
        cluster_snapshot:
            cluster_snapshot_path: s3://xxx/data/7351ce6a-f4a4-4937-a876-cb8801085aea/meta/image/automated_cluster_snapshot_1739858235830
            storage_volume_name: builtin_storage_volume

        # Operator will add the other FE followers automatically
        # just leave it blank
        frontends:[]

        # Operator will add the CN nodes automatically
        # just leave it blank
        compute_nodes:[]

        # used for restoring a cloned snapshot
        storage_volumes:
          - name: builtin_storage_volume
            type: S3
            location: s3://xxx/data
            comment: my s3 volume
            properties:
              - key: aws.s3.region
                value: xxx
              - key: aws.s3.endpoint
                value: xxx
              - key: aws.s3.access_key
                value: xxx
              - key: aws.s3.secret_key
                value: xxx

部署集群的命令与第一次不同,这里我们需要同时指定两个 YAML 文件,其中 cluster_snapshot.yaml 是专门用于本次灾备的配置文件。

复制代码
helm install -f ./starrocks-values.yaml -f cluster_snapshot.yaml starrocks starrocks-community/kube-starrocks --version 1.10.0

灾难恢复的详细流程如下:

  1. Operator 会启动一个 FE Pod,并启用灾难恢复。

    ignore the operator pod

    kubectl get pods
    NAME READY STATUS RESTARTS AGE
    kube-starrocks-fe-0 1/1 Running 0 4m37s

此时,当我们检查 StarRocksCluster 的状态时,显示结果如下:

复制代码
kubectl get src kube-starrocks -oyaml | less

status:
  phase: running
  disasterRecoveryStatus:
    observedGeneration: 1
    phase: doing
    reason: disaster recovery is in progress
    startTimestamp: "1739860263"
  1. 灾难恢复完成后,Operator 会自动启动其他 Pods。

    kubectl get pods
    NAME READY STATUS RESTARTS AGE
    kube-starrocks-cn-0 1/1 Running 0 7m54s
    kube-starrocks-fe-0 1/1 Running 0 7m1s
    kube-starrocks-fe-1 1/1 Running 0 7m54s
    kube-starrocks-fe-2 1/1 Running 0 7m54s

集群状态显示如下:

复制代码
kubectl get src kube-starrocks -oyaml | less

status:
  phase: running
  disasterRecoveryStatus:
    endTimestamp: "1739861262"
    observedGeneration: 1
    phase: done
    reason: disaster recovery is done
    startTimestamp: "1739860263"

验证灾备是否成功

检查数据恢复是否完成。

复制代码
# enter the pod
kubectl exec -it kube-starrocks-fe-0 bash

# connect mysql
mysql -h 127.0.0.1 -P9030 -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 0
Server version: 8.0.33 branch-3.4-12d148f

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

# get the data
mysql> USE quickstart;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from source_wiki_edit;
+---------------------+---------------+----------+--------------+----------+--------+----------+----------------+-------+-------+---------+
| event_time          | channel       | user     | is_anonymous | is_minor | is_new | is_robot | is_unpatrolled | delta | added | deleted |
+---------------------+---------------+----------+--------------+----------+--------+----------+----------------+-------+-------+---------+
| 2015-09-12 08:00:00 | #ca.wikipedia | helloSR  |            0 |        1 |      0 |        1 |              0 |     3 |    23 |       0 |
| 2015-09-12 00:00:00 | #ca.wikipedia | helloSR  |            0 |        1 |      0 |        1 |              0 |     3 |    23 |       0 |
| 2015-09-12 00:00:00 | #en.wikipedia | AustinFF |            0 |        0 |      0 |        0 |              0 |    21 |     5 |       0 |
+---------------------+---------------+----------+--------------+----------+--------+----------+----------------+-------+-------+---------+
3 rows in set (2.00 sec)
相关推荐
thinktik6 小时前
AWS EKS 计算资源自动扩缩之Fargate[AWS 海外区]
后端·kubernetes·aws
回忆是昨天里的海9 小时前
k8s部署容器化应用-nginx2
云原生·容器·kubernetes
小任今晚几点睡13 小时前
kubernets简介和部署
kubernetes·k8s·kubernets in docker
一念一花一世界14 小时前
Arbess从入门到实战(16) - 使用Arbess+Gitee实现K8s自动化部署
ci/cd·云原生·容器·kubernetes·tiklab
ajax_beijing16 小时前
修改k8s的镜像源为国内镜像源
云原生·容器·kubernetes
A-刘晨阳16 小时前
K8S 二进制集群搭建(一主两从)
linux·运维·云原生·容器·kubernetes
thinktik18 小时前
AWS EKS 计算资源自动扩缩之Karpenter[AWS 海外区]
后端·kubernetes·aws
回忆是昨天里的海1 天前
k8s集群-节点间通信之安装kube-flannel插件
java·docker·kubernetes