Skip to content

Commit f2684d6

Browse files
committed
[data_storage] separate TairMempool SSD storage type
1 parent 438e85f commit f2684d6

42 files changed

Lines changed: 709 additions & 52 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/BREAK_CHANGE.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,63 @@
22

33
本文档记录需要调用方、部署配置或持久化状态协同升级的不兼容变更。升级前必须按对应条目的前置条件处理,不能仅替换 KVCM 二进制。
44

5+
## TairMempool SSD 独立 Storage Type
6+
7+
Introduced by: PR #293
8+
9+
TairMempool DRAM 继续使用 `ST_TAIRMEMPOOL`/`pace`,LocalSSD 新增
10+
`ST_TAIRMEMPOOL_SSD`/`pace_ssd`。两者仍共享 `pace://` 数据面协议,但 KVCM 从此分别统计
11+
quota 和类型水位,使 DRAM 高水位能够触发到 SSD 的自动迁移。
12+
13+
### 不兼容内容
14+
15+
- Proto/领域枚举新增 `ST_TAIRMEMPOOL_SSD = 9`,配置 JSON 新增持久化类型字符串
16+
`"pace_ssd"`,写入策略新增 `CPS_ALWAYS_TAIR_MEMPOOL_SSD = 9`
17+
`CPS_PREFER_TAIR_MEMPOOL_SSD = 10`
18+
- 老 Worker Client 不认识 `pace_ssd`。Manager 把新 Storage 配置下发给老 Worker 后,老
19+
Client 会把它解析为 UNKNOWN,并可能以 `ER_INVALID_SDKBACKEND_CONFIG` 结束整个
20+
TransferClient 初始化,而不只是跳过 SSD backend。
21+
- 老 KVCM Server 不认识 Registry 中的 `"type":"pace_ssd"`。直接回滚旧二进制会导致该
22+
Storage backend 恢复失败,Registry recovery 无法完成并持续重试。
23+
- Storage 类型属于持久化 CacheLocation 和用量账本的一部分,不支持同名 Storage 从
24+
`pace` 原地改成 `pace_ssd`。服务端现在拒绝涉及 TairMempool DRAM/SSD 的原地类型变更;
25+
修改 timeout、domain 等同类型参数仍可使用 `update_storage`
26+
- 开源占位 backend 已按 `StorageConfig.type()` 返回类型。实际部署使用的 PACE backend 也
27+
必须返回配置中的类型,并在构造 URI 时固定使用 `pace` scheme;若仍硬编码
28+
`ST_TAIRMEMPOOL` 或使用 `ToString(GetType())` 构造 scheme,独立计量会静默失效或生成
29+
不兼容的 `pace_ssd://` URI。
30+
31+
### 启用前置条件和顺序
32+
33+
1. 先升级所有 Worker Client,使其能够解析类型 9、创建对应 TairMempool SDK,并继续识别
34+
`pace://` URI。在确认集群不存在老 Client 后再进入下一步。
35+
2. 升级全部 KVCM Server 和实际 PACE backend,确认 backend 的 `GetType()` 等于
36+
`StorageConfig.type()`,DRAM/SSD 生成的 URI scheme 均为 `pace`
37+
3. 为 SSD **新建不同名称**`pace_ssd` Storage。不要对已有 `pace` Storage 执行类型更新。
38+
`kvcm_ops``add_storage pace` 只接受 media type 0/2;`pace_ssd` 子命令固定使用 media
39+
type 5。`update_storage pace` 未指定 media type 时会读取并保留原 Storage 的 type/media,
40+
包括旧的 `ST_TAIRMEMPOOL + media_type=5`,不会在修改 timeout 时静默改变介质或类型。
41+
4. 在每个启用迁移的 Instance Group 中,为 `pace``pace_ssd` 分别配置正数
42+
`quota_config.capacity`。类型水位只遍历显式 quota;缺少源类型 quota 时迁移不会触发,
43+
缺少 SSD quota 时 SSD 没有独立水位和类型容量保护。
44+
5. 迁移规则继续以 DRAM Storage 为 `source_storage_name`、新 SSD Storage 为
45+
`target_storage_name`。SSD 只作迁移目标时无需加入 `storage_candidates`;直接写 SSD 时
46+
才加入候选并选用 SSD 专用 CachePreferStrategy。
47+
6. 用空 Instance Group 或测试 Instance 验证一次 DRAM 写入与 DRAM→SSD 迁移:新 Location
48+
分别记录 type 3/type 9,DRAM 用量下降、SSD 用量上升,且 Worker 能读写 `pace://` URI。
49+
50+
旧的 `ST_TAIRMEMPOOL + media_type=5` 配置仍可读取并继续按旧类型计量,但不能通过原地改类型
51+
获得独立水位。迁移方式是新建 `pace_ssd` Storage,将新迁移流量切到它;旧 Storage 必须保留
52+
到历史 Location 排空,避免 GC/读取找不到原 backend。
53+
54+
### 回滚说明
55+
56+
创建任何 `pace_ssd` Registry 配置前,可以直接回滚,因为新类型尚未进入持久化状态。创建后
57+
不能直接换回不认识类型 9 的旧 Server/Client。回滚前必须停止新写入和迁移,删除或排空所有
58+
type 9 CacheLocation,确认其物理数据已清理,再删除 `pace_ssd` Storage 与相关 quota/迁移配置;
59+
之后才能回滚二进制。仅把新 Storage 改名或原地改回 `pace` 不能修复已有 Location 的类型和
60+
用量,且服务端会拒绝这种类型更新。
61+
562
## Vineyard 事件上报升级为 EventReportBackend
663

764
Introduced by: PR #249

docs/configuration.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ timeout,因此不会使用配置数组顺序作为隐式优先级。
206206
```TEXT
207207
{
208208
"storage_config": {
209-
"type": "file", # 后端类型,可选值file,pace,mooncake,hf3fs,vcns_hf3fs
209+
"type": "file", # 后端类型,可选值file,pace,pace_ssd,mooncake,hf3fs,vcns_hf3fs
210210
"global_unique_name": "nfs_01", # storage backend的名字,需要全局唯一
211211
"storage_spec": { # storage spec 需根据不同backend类型相应配置,TODO:具体每个type的spec配置文档
212212
"root_path": "/tmp/nfs/",
@@ -234,6 +234,10 @@ timeout,因此不会使用配置数组顺序作为隐式优先级。
234234
{
235235
"storage_type": "pace",
236236
"capacity": 10000000000
237+
},
238+
{
239+
"storage_type": "pace_ssd",
240+
"capacity": 10000000000
237241
}
238242
]
239243
},
@@ -256,6 +260,8 @@ timeout,因此不会使用配置数组顺序作为隐式优先级。
256260
# CPS_PREFER_TAIR_MEMPOOL = 6,
257261
# CPS_ALWAYS_VCNS_3FS = 7,
258262
# CPS_PREFER_VCNS_3FS = 8,
263+
# CPS_ALWAYS_TAIR_MEMPOOL_SSD = 9,
264+
# CPS_PREFER_TAIR_MEMPOOL_SSD = 10,
259265
# };
260266
"cache_prefer_strategy": 2,
261267
"meta_indexer_config": {
@@ -283,6 +289,28 @@ timeout,因此不会使用配置数组顺序作为隐式优先级。
283289
}
284290
```
285291

292+
TairMempool DRAM 使用 `pace`(proto `ST_TAIRMEMPOOL`),LocalSSD 使用
293+
`pace_ssd`(proto `ST_TAIRMEMPOOL_SSD`,同时要求 `media_type=5`)。两类 storage
294+
仍使用 `pace://` 数据面 URI,但 quota、类型水位和迁移触发用量分别统计。旧的
295+
`ST_TAIRMEMPOOL + media_type=5` 配置仍可读取,迁移到新类型后才能获得独立 SSD 水位。
296+
297+
启用独立 SSD 类型时还需遵守以下配置约束:
298+
299+
- 使用 `kvcm_ops add_storage ... pace_ssd` 创建一个新的、全局唯一的 Storage;不要把已有
300+
`pace` Storage 原地更新为 `pace_ssd`。Storage 类型会写入 CacheLocation 和用量账本,
301+
服务端会拒绝同名 Storage 的类型变更。
302+
- Instance Group 的 `quota.quota_config` 必须同时为 `pace``pace_ssd` 配置正容量。
303+
类型水位只遍历这里显式出现的类型;缺少 `pace_ssd` 时不会形成 SSD 类型水位和容量上限,
304+
缺少迁移源 `pace` 时迁移规则不会触发。
305+
- SSD 仅作为迁移目标时,不要求放入 `storage_candidates`;迁移规则按
306+
`target_storage_name` 精确选择它。若需要把普通新写入直接落到 SSD,则必须把 SSD Storage
307+
放入 `storage_candidates`,并使用 `CPS_ALWAYS_TAIR_MEMPOOL_SSD`
308+
`CPS_PREFER_TAIR_MEMPOOL_SSD`
309+
- `pace``pace_ssd` 的数据面 URI scheme 都是 `pace://``pace_ssd` 只用于配置、计量
310+
和选择,不能生成 `pace_ssd://` URI。
311+
312+
详细升级顺序和回滚限制见 [Breaking Changes](BREAK_CHANGE.md#tairmempool-ssd-独立-storage-type)
313+
286314
## Logger Config
287315

288316
```TEXT

kv_cache_manager/client/src/internal/config/sdk_config.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ std::string MooncakeSdkConfig::ToString() const {
103103
return oss.str();
104104
}
105105

106-
TairMempoolSdkConfig::TairMempoolSdkConfig() { set_type(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL); }
106+
TairMempoolSdkConfig::TairMempoolSdkConfig(DataStorageType type) { set_type(type); }
107107

108108
bool TairMempoolSdkConfig::FromRapidValue(const rapidjson::Value &rapid_value) {
109109
return SdkBackendConfig::FromRapidValue(rapid_value);
@@ -146,7 +146,8 @@ bool SdkWrapperConfig::FromRapidValue(const rapidjson::Value &rapid_value) {
146146
sdk_backend_config = std::make_shared<MooncakeSdkConfig>();
147147
break;
148148
case DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL:
149-
sdk_backend_config = std::make_shared<TairMempoolSdkConfig>();
149+
case DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD:
150+
sdk_backend_config = std::make_shared<TairMempoolSdkConfig>(type);
150151
break;
151152
case DataStorageType::DATA_STORAGE_TYPE_NFS:
152153
sdk_backend_config = std::make_shared<NfsSdkConfig>();

kv_cache_manager/client/src/internal/config/sdk_config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class MooncakeSdkConfig : public SdkBackendConfig {
150150

151151
class TairMempoolSdkConfig : public SdkBackendConfig {
152152
public:
153-
TairMempoolSdkConfig();
153+
explicit TairMempoolSdkConfig(DataStorageType type = DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL);
154154
bool FromRapidValue(const rapidjson::Value &rapid_value) override;
155155
void ToRapidWriter(rapidjson::Writer<rapidjson::StringBuffer> &writer) const noexcept override;
156156

@@ -205,6 +205,8 @@ class SdkWrapperConfig : public Jsonizable {
205205
{DataStorageType::DATA_STORAGE_TYPE_HF3FS, std::make_shared<Hf3fsSdkConfig>()},
206206
{DataStorageType::DATA_STORAGE_TYPE_VCNS_HF3FS, std::make_shared<Hf3fsSdkConfig>()},
207207
{DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL, std::make_shared<TairMempoolSdkConfig>()},
208+
{DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD,
209+
std::make_shared<TairMempoolSdkConfig>(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD)},
208210
{DataStorageType::DATA_STORAGE_TYPE_NFS, std::make_shared<NfsSdkConfig>()}};
209211
SdkTimeoutConfig timeout_config_;
210212
};

kv_cache_manager/client/src/internal/config/test/client_config_test.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ TEST_F(ClientConfigTest, TestClientConfigTairMemPoolSuccess) {
5454
auto sdk_wrapper_config = client_config.sdk_wrapper_config();
5555
ASSERT_TRUE(sdk_wrapper_config);
5656
auto sdk_backend_configs_map = sdk_wrapper_config->sdk_backend_configs_map();
57-
// 默认就加了3个
58-
ASSERT_EQ(4, sdk_backend_configs_map.size());
57+
ASSERT_EQ(5, sdk_backend_configs_map.size());
5958
auto tair_mempool_config = sdk_backend_configs_map[DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL];
6059
ASSERT_TRUE(tair_mempool_config);
6160
ASSERT_EQ("logs/pace_client.log", tair_mempool_config->sdk_log_file_path());

kv_cache_manager/client/src/internal/config/test/sdk_config_test.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,37 @@ TEST_F(SdkBackendConfigTest, TestSdkWrapperConfigGetSdkConfig) {
107107
auto tair_config = sdk_wrapper_config.GetSdkBackendConfig(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL);
108108
ASSERT_NE(tair_config, nullptr);
109109

110+
auto tair_ssd_config = sdk_wrapper_config.GetSdkBackendConfig(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD);
111+
ASSERT_NE(tair_ssd_config, nullptr);
112+
EXPECT_EQ(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD, tair_ssd_config->type());
113+
110114
auto nfs_config = sdk_wrapper_config.GetSdkBackendConfig(DataStorageType::DATA_STORAGE_TYPE_NFS);
111115
ASSERT_NE(nfs_config, nullptr);
112116

113117
auto unknown_config = sdk_wrapper_config.GetSdkBackendConfig(DataStorageType::DATA_STORAGE_TYPE_UNKNOWN);
114118
ASSERT_EQ(unknown_config, nullptr);
115119
}
116120

121+
TEST_F(SdkBackendConfigTest, TestSdkWrapperConfigParsesTairMempoolSsd) {
122+
SdkWrapperConfig sdk_wrapper_config;
123+
ASSERT_TRUE(sdk_wrapper_config.FromJsonString(R"({
124+
"thread_num": 8,
125+
"queue_size": 2000,
126+
"sdk_backend_configs": [{
127+
"type": "pace_ssd",
128+
"sdk_log_file_path": "logs/pace_ssd_client.log",
129+
"sdk_log_level": "INFO",
130+
"spec_byte_sizes_per_block": {}
131+
}],
132+
"timeout_config": {"put_timeout_ms": 15000, "get_timeout_ms": 15000}
133+
})"));
134+
135+
const auto config = sdk_wrapper_config.GetSdkBackendConfig(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD);
136+
ASSERT_NE(nullptr, config);
137+
EXPECT_EQ(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD, config->type());
138+
EXPECT_EQ("logs/pace_ssd_client.log", config->sdk_log_file_path());
139+
}
140+
117141
TEST_F(SdkBackendConfigTest, TestDuplicatedSdkConfig) {
118142
SdkWrapperConfig sdk_wrapper_config;
119143
std::string file_content = getFileContent("sdk_wrapper_config_duplicated_sdk_config.json");

kv_cache_manager/client/src/internal/sdk/sdk_factory.cc

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,24 @@ std::shared_ptr<SdkInterface> SdkFactory::CreateSdk(const DataStorageType &type,
2626
KVCM_LOG_WARN("sdk_backend_config or storage_config is null");
2727
return nullptr;
2828
}
29+
auto sdk = CreateSdkInstance(type);
30+
if (!sdk) {
31+
KVCM_LOG_WARN("unsupported sdk type: %s", ToString(type).c_str());
32+
return nullptr;
33+
}
34+
auto ec = sdk->Init(sdk_backend_config, storage_config);
35+
if (ec != ER_OK) {
36+
KVCM_LOG_WARN("init sdk failed, type:%s, sdk backend config: %s, storage config: %s, errorcode: %d",
37+
ToString(type).c_str(),
38+
sdk_backend_config->ToJsonString().c_str(),
39+
storage_config->ToString().c_str(),
40+
ec);
41+
return nullptr;
42+
}
43+
return sdk;
44+
}
45+
46+
std::shared_ptr<SdkInterface> SdkFactory::CreateSdkInstance(const DataStorageType &type) {
2947
std::shared_ptr<SdkInterface> sdk;
3048
switch (type) {
3149
#ifdef ENABLE_HF3FS
@@ -43,30 +61,17 @@ std::shared_ptr<SdkInterface> SdkFactory::CreateSdk(const DataStorageType &type,
4361
#endif
4462
#ifdef ENABLE_TAIR_MEMPOOL
4563
case DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL:
64+
case DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD:
4665
sdk = std::make_shared<TairMempoolSdk>();
4766
break;
4867
#endif
4968
case DataStorageType::DATA_STORAGE_TYPE_NFS:
5069
sdk = std::make_shared<LocalFileSdk>();
5170
break;
5271
default:
53-
KVCM_LOG_WARN("unsupported sdk type: %s", ToString(type).c_str());
54-
return nullptr;
55-
}
56-
if (!sdk) {
57-
KVCM_LOG_WARN("create sdk failed, sdk is null, type:%s", ToString(type).c_str());
58-
return nullptr;
59-
}
60-
auto ec = sdk->Init(sdk_backend_config, storage_config);
61-
if (ec != ER_OK) {
62-
KVCM_LOG_WARN("init sdk failed, type:%s, sdk backend config: %s, storage config: %s, errorcode: %d",
63-
ToString(type).c_str(),
64-
sdk_backend_config->ToJsonString().c_str(),
65-
storage_config->ToString().c_str(),
66-
ec);
6772
return nullptr;
6873
}
6974
return sdk;
7075
}
7176

72-
} // namespace kv_cache_manager
77+
} // namespace kv_cache_manager

kv_cache_manager/client/src/internal/sdk/sdk_factory.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ class SdkFactory {
1212
static std::shared_ptr<SdkInterface> CreateSdk(const DataStorageType &type,
1313
const std::shared_ptr<SdkBackendConfig> &sdk_backend_config,
1414
const std::shared_ptr<StorageConfig> &storage_config);
15+
16+
private:
17+
static std::shared_ptr<SdkInterface> CreateSdkInstance(const DataStorageType &type);
1518
};
1619

17-
} // namespace kv_cache_manager
20+
} // namespace kv_cache_manager

kv_cache_manager/client/src/internal/sdk/test/BUILD

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ cc_test(
5757
],
5858
)
5959

60+
cc_test(
61+
name = "SdkFactoryTest",
62+
srcs = ["sdk_factory_test.cc"],
63+
copts = ["-fno-access-control"],
64+
deps = [
65+
"//kv_cache_manager/client/src/internal/sdk",
66+
"//kv_cache_manager/common:unittest",
67+
],
68+
)
69+
6070
cc_test(
6171
name = "hf3fs_sdk_test",
6272
srcs = select({
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <gtest/gtest.h>
2+
#include <typeinfo>
3+
4+
#include "kv_cache_manager/client/src/internal/sdk/sdk_factory.h"
5+
#include "kv_cache_manager/common/unittest.h"
6+
7+
using namespace kv_cache_manager;
8+
9+
TEST(SdkFactoryTest, TairMempoolDramAndSsdCreateSameSdkType) {
10+
#ifdef ENABLE_TAIR_MEMPOOL
11+
const auto dram_sdk = SdkFactory::CreateSdkInstance(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL);
12+
const auto ssd_sdk = SdkFactory::CreateSdkInstance(DataStorageType::DATA_STORAGE_TYPE_TAIR_MEMPOOL_SSD);
13+
14+
ASSERT_NE(nullptr, dram_sdk);
15+
ASSERT_NE(nullptr, ssd_sdk);
16+
EXPECT_EQ(SdkType::TAIR_MEMPOOL, dram_sdk->Type());
17+
EXPECT_EQ(SdkType::TAIR_MEMPOOL, ssd_sdk->Type());
18+
EXPECT_EQ(typeid(*dram_sdk), typeid(*ssd_sdk));
19+
#else
20+
GTEST_SKIP() << "TairMempool SDK is disabled";
21+
#endif
22+
}

0 commit comments

Comments
 (0)