目录
1.runtime和snapshot
1.1 rockDB的runtime和snapshot
在 RocksDB 中,runtime 表示 DB 正在运行的状态,包括系统资源使用情况、DB 内部数据结构的状态等等。在运行过程中,RocksDB 会不断更新 runtime,以反映最新的状态。
snapshot 通常用于读操作,它表示一个 DB 在某一时间点的一份快照,即一份只读的、不可变的 DB 数据。通过 snapshot,用户可以在不影响 DB 运行状态的情况下进行并行读取和操作。
需要注意的是,snapshot 并不是一个完全独立的副本,而是一个指向现有数据的引用。因此,在创建 snapshot 后修改 DB,将不会影响已经创建的 snapshot。另外,RocksDB 也支持快照恢复功能,即通过已有的 snapshot 快速恢复 DB 到指定时间点的状态。
可参考以下代码理解
// 打开或创建 DB
RocksDB db = RocksDB.open(options, "path/to/db");
// 写入一些数据
WriteOptions writeOptions = new WriteOptions();
db.put(writeOptions, "key1".getBytes(), "value1".getBytes());
db.put(writeOptions, "key2".getBytes(), "value2".getBytes());
// 创建一个 checkpoint
Checkpoint checkpoint = Checkpoint.create(db);
checkpoint.createCheckpoint("path/to/checkpoint");
// 关闭 snapshot 和 Checkpoint
checkpoint.close();
db.close();
// 恢复运行时状态
RocksDB dbRestart = RocksDB.open(options, "path/to/db");
Checkpoint checkpointRestart = Checkpoint.create(dbRestart);
checkpointRestore.restoreCheckpoint("path/to/checkpoint");
// 关闭 checkpointRestart
checkpointRestart.close();
dbRestart.close();
1.2 zeebe的runtime和snapshot
1.2.1 snapshot:
在leader节点上,partition的运行时状态会周期性的被存为snapshot文件;默认情况下,周期事件为5分钟(可配置 默认配置 DataCfg#snapshotPeriod
)
snapshot是所有运行中的event的投影,代表了当前进程的运行状态,其中包含了所有的active data,例如:已部署的流程、运行中的流程实例、还未执行完的jobs
当borker写了一个新的snapshot文件,新snapshot文件中最新写入的数据之前的所有数据,会被删除
1.2.2 runtime:
在leader节点上,partition当前的运行状态是被存储在 RocksDB的内存和磁盘上;复制到follower上的snapshot实际上是 RocksDB的snapshot
2. ZeebeDb 对象的创建
2.1 zeebeDbFactory 的初始化
broker启动时,初始化paritition时会创建 PartitionFactory,在其中会进行rocksDb的创建和初始化。
——> PartitionFactory#constructPartitions 中 会创建 StateController 对象,
——>PartitionFactory#createStateController 其中就包括了rocksDB的初始化。
zeebeDbFactory 对象传入到 StateControllerImpl 对象中,
——> StateControllerImpl#openDb 方法创建 ZeebeDb 对象
2.2 创建 zeebeDb 的时机
当partition的角色发生变化时,会调用 ZeebeDbPartitionTransitionStep#transitionTo
其中,ZeebeDbPartitionTransitionStep#transitionTo 会创建zeebeDB对象
3.创建snapshot(AsyncSnapshotDirector )
3.1 周期性创建
在 SnapshotDirectorPartitionTransitionStep#transitionTo 中 创建核心实例 AsyncSnapshotDirector
AsyncSnapshotDirector#scheduleSnapshotOnRate 提交任务
周期性创建snapshot ,默认的创建时间配置为 DataCfg#snapshotPeriod(默认5分钟)
3.2 手动触发snapshot:
BrokerAdminServiceEndpoint#BrokerAdminServiceEndpoint
// 主动创建snapshot
curl --location --request POST 'http://localhost:9600/actuator/partitions/takeSnapshot'
3.3 创建snapshot
AsyncSnapshotDirector#trySnapshot
——> AsyncSnapshotDirector#snapshot
调用rocksDB的api 创建snapshot文件
——>StateControllerImpl#takeTransientSnapshot
——>StateControllerImpl#takeTransientSnapshotInternal
——>StateControllerImpl#takeSnapshot
最终的方法为: ZeebeTransactionDb#createSnapshot
通过rocksDB中的CheckPoint机制实现了snapshot
——>AsyncSnapshotDirector#persistSnapshot
——>io.camunda.zeebe.snapshots.PersistableSnapshot#persist
——>io.camunda.zeebe.snapshots.impl.FileBasedTransientSnapshot#persistInternal
——>io.camunda.zeebe.snapshots.impl.FileBasedSnapshotStore#newSnapshot
——> io.camunda.zeebe.snapshots.impl.SnapshotChecksum#persist
持久化snapshot文件
指定partition的 snapshot 文件的地址:FileBasedSnapshotStoreFactory#createSnapshotStoreWithoutOpening
3.4 补充知识:rocksDB的checkpoint
RocksDB 的 checkpoint 是指将当前数据库状态保存到磁盘中以创建可读可恢复的快照。它可以在不停止 RocksDB 实例的情况下,将数据库的当前状态保存到磁盘上。
checkpoint 是一种轻量级操作,不需要暂停写操作和其他数据库访问操作就可以执行。它特别适合于大型数据库,因为在大型数据库中停止写操作,创建完整的快照和恢复操作可能需要很长时间。
在 RocksDB 中,使用 org.rocksdb.Checkpoint
类来完成 checkpoint 的创建和恢复。创建 checkpoint 的步骤如下:
-
创建一个 Checkpoint 对象:
Checkpoint checkpoint = Checkpoint.create(db);
,其中 db 是写入数据的 RocksDB 对象。 -
调用 Checkpoint 对象的
createCheckpoint()
方法来创建 checkpoint。此操作将 checkpoint 写入到文件系统中指定位置。例如:checkpoint.createCheckpoint("path/to/checkpoint");
-
关闭 Checkpoint 对象。
恢复 checkpoint 的步骤如下:
-
创建一个 RocksDB 对象,并使用
org.rocksdb.Checkpoint
创建 checkpoint 对象:RocksDB dbRestart = RocksDB.open(options, "path/to/db"); Checkpoint checkpointRestart = Checkpoint.create(dbRestart);
-
调用
checkpointRestore.restoreCheckpoint("path/to/checkpoint")
方法来从之前存储的 checkpoint 中恢复状态。 -
关闭 checkpointRestart 和恢复的 RocksDB 实例 dbRestart。
创建 checkpoint 时,除了将正在被写入磁盘的所有 SST 文件记录下来之外,也会将当前内存表中的所有数据保存下来。这是为了确保 checkpoint 是一个完整的数据快照,用户可以通过 checkpoint 来恢复整个数据库状态,而不仅仅是磁盘中的数据。
4.从snapshot恢复到运行时状态(runtime)
4.1加载snapshot文件
broker启动时,会加载snapshot文件
——>FileBasedSnapshotStore#onActorStarting
——>FileBasedSnapshotStore#loadLatestSnapshot
文件的操作,读取指定路径下的文件
加载的snapshot文件由 currentPersistedSnapshotRef
引用持有;
4.2 从snapshot恢复runtime
创建 zeebeDb 时,调用接口 ZeebeDbPartitionTransitionStep#recoverDb
(触发时机参考1.2节)
——> ZeebeDbPartitionTransitionStep#recoverDb
——>StateControllerImpl#recover
——>StateControllerImpl#recoverInternal
注意,方法中的 snapshot 是从变量 constructableSnapshotStore
中获取的,实际上就是上述加载的snapshot文件
4.3 从log恢复runtime
snapshot是周期性创建的,仅通过snapshot是无法恢复 在创建snapshot之后产生的事件,因此还需要从日志取出日志回放,完成整个运行状态的恢复。在启动 StreamProcessor
时会触发该动作。
——>StreamProcessor#onActorStarted
——>StreamProcessor#recoverFromSnapshot
——>ReplayStateMachine#startRecover
——>LogStreamBatchReader#seekToNextBatch
——>ReplayStateMachine#replayNextEvent