Skip to content

Commit 2576aed

Browse files
Mixficsolwuxianrong
andauthored
fix: add replication-id to implement master/slave Replication (OpenAtomFoundation#1951)
* Add replication-id to implement master/slave Replication --------- Co-authored-by: wuxianrong <wuxianrong@360.cn>
1 parent 67f851a commit 2576aed

11 files changed

Lines changed: 129 additions & 14 deletions

conf/pika.conf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,4 +413,8 @@ default-slot-num : 1024
413413

414414
# Rsync Rate limiting configuration
415415
throttle-bytes-per-second : 307200000
416-
max-rsync-parallel-num : 4
416+
max-rsync-parallel-num : 4
417+
418+
# The synchronization mode of Pika primary/secondary replication is determined by ReplicationID. ReplicationID in one replication_cluster are the same
419+
# replication-id :
420+

docs/ops/APIDifference.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,7 @@ slaveof命令允许通过指定write2file(binlog)的文件名称及同步位置
125125
类似于pkhscanrange, 逆序
126126

127127
### diskrecovery
128-
Pika 原创命令,功能为当磁盘意外写满后,RocksDB 会进入写保护状态,当我们将空间调整为充足空间时,这个命令可以将 RocksDB 的写保护状态解除,变为可以继续写的状态, 避免了 Pika 因为磁盘写满后需要重启才能恢复写的情况,执行成功时返回 OK,如果当前磁盘空间依然不足,执行这个命令返回`"The available disk capacity is insufficient`,该命令执行时不需要额外参数,只需要执行 diskrecovery 即可。
128+
Pika 原创命令,功能为当磁盘意外写满后,RocksDB 会进入写保护状态,当我们将空间调整为充足空间时,这个命令可以将 RocksDB 的写保护状态解除,变为可以继续写的状态, 避免了 Pika 因为磁盘写满后需要重启才能恢复写的情况,执行成功时返回 OK,如果当前磁盘空间依然不足,执行这个命令返回`"The available disk capacity is insufficient`,该命令执行时不需要额外参数,只需要执行 diskrecovery 即可。
129+
130+
### clearreplicationid
131+
Pika 原创命令,功能是清空 Pika 实例的 replicationid 的值并持久化到配置文件中

include/pika_admin.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ class ConfigCmd : public Cmd {
288288
void ConfigSet(std::string& ret);
289289
void ConfigRewrite(std::string& ret);
290290
void ConfigResetstat(std::string& ret);
291+
void ConfigRewriteReplicationID(std::string& ret);
291292
};
292293

293294
class MonitorCmd : public Cmd {
@@ -462,6 +463,18 @@ class DiskRecoveryCmd : public Cmd {
462463
std::map<std::string, uint64_t> background_errors_;
463464
};
464465

466+
class ClearReplicationIDCmd : public Cmd {
467+
public:
468+
ClearReplicationIDCmd(const std::string& name, int arity, uint16_t flag) : Cmd(name, arity, flag) {}
469+
void Do(std::shared_ptr<Slot> slot = nullptr) override;
470+
void Split(std::shared_ptr<Slot> slot, const HintKeys& hint_keys) override{};
471+
void Merge() override{};
472+
Cmd* Clone() override { return new ClearReplicationIDCmd(*this); }
473+
474+
private:
475+
void DoInitial() override;
476+
};
477+
465478
#ifdef WITH_COMMAND_DOCS
466479
class CommandCmd : public Cmd {
467480
public:

include/pika_command.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const std::string kCmdNameQuit = "quit";
5151
const std::string kCmdNameHello = "hello";
5252
const std::string kCmdNameCommand = "command";
5353
const std::string kCmdNameDiskRecovery = "diskrecovery";
54+
const std::string kCmdNameClearReplicationID = "clearreplicationid";
5455

5556
// Migrate slot
5657
const std::string kCmdNameSlotsMgrtSlot = "slotsmgrtslot";

include/pika_conf.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define kBinlogReadWinDefaultSize 9000
2323
#define kBinlogReadWinMaxSize 90000
2424
const uint32_t configRunIDSize = 40;
25+
const uint32_t configReplicationIDSize = 50;
2526

2627
// global class, class members well initialized
2728
class PikaConf : public pstd::BaseConf {
@@ -150,6 +151,10 @@ class PikaConf : public pstd::BaseConf {
150151
std::shared_lock l(rwlock_);
151152
return master_run_id_;
152153
}
154+
std::string replication_id() {
155+
std::shared_lock l(rwlock_);
156+
return replication_id_;
157+
}
153158
std::string requirepass() {
154159
std::shared_lock l(rwlock_);
155160
return requirepass_;
@@ -374,6 +379,11 @@ class PikaConf : public pstd::BaseConf {
374379
TryPushDiffCommands("master-run-id", value);
375380
master_run_id_ = value;
376381
}
382+
void SetReplicationID(const std::string& value) {
383+
std::lock_guard l(rwlock_);
384+
TryPushDiffCommands("replication-id", value);
385+
replication_id_ = value;
386+
}
377387
void SetSlavePriority(const int value) {
378388
std::lock_guard l(rwlock_);
379389
TryPushDiffCommands("slave-priority", std::to_string(value));
@@ -577,6 +587,7 @@ class PikaConf : public pstd::BaseConf {
577587

578588
int Load();
579589
int ConfigRewrite();
590+
int ConfigRewriteReplicationID();
580591

581592
private:
582593
pstd::Status InternalGetTargetDB(const std::string& db_name, uint32_t* target);
@@ -610,6 +621,7 @@ class PikaConf : public pstd::BaseConf {
610621
std::string server_id_;
611622
std::string run_id_;
612623
std::string master_run_id_;
624+
std::string replication_id_;
613625
std::string requirepass_;
614626
std::string masterauth_;
615627
std::string userpass_;

src/pika_admin.cc

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ void SlaveofCmd::Do(std::shared_ptr<Slot> slot) {
151151
return;
152152
}
153153

154+
/* The return value of the slaveof command OK does not really represent whether
155+
* the data synchronization was successful, but only changes the status of the
156+
* slaveof executor to slave */
157+
154158
bool sm_ret = g_pika_server->SetMaster(master_ip_, static_cast<int32_t>(master_port_));
155159

156160
if (sm_ret) {
@@ -1038,7 +1042,7 @@ void InfoCmd::InfoReplication(std::string& info) {
10381042
info.append("ERR: server role is error\r\n");
10391043
return;
10401044
}
1041-
1045+
tmp_stream << "ReplicationID: " << g_pika_conf->replication_id() << "\r\n";
10421046
std::string slaves_list_str;
10431047
switch (host_role) {
10441048
case PIKA_ROLE_SLAVE:
@@ -1324,6 +1328,8 @@ void ConfigCmd::Do(std::shared_ptr<Slot> slot) {
13241328
ConfigRewrite(config_ret);
13251329
} else if (strcasecmp(config_args_v_[0].data(), "resetstat") == 0) {
13261330
ConfigResetstat(config_ret);
1331+
} else if (strcasecmp(config_args_v_[0].data(), "rewritereplicationid") == 0) {
1332+
ConfigRewriteReplicationID(config_ret);
13271333
}
13281334
res_.AppendStringRaw(config_ret);
13291335
}
@@ -1849,6 +1855,12 @@ void ConfigCmd::ConfigGet(std::string& ret) {
18491855
EncodeNumber(&config_body, g_pika_conf->max_rsync_parallel_num());
18501856
}
18511857

1858+
if (pstd::stringmatch(pattern.data(), "replication-id", 1) != 0) {
1859+
elements += 2;
1860+
EncodeString(&config_body, "replication-id");
1861+
EncodeString(&config_body, g_pika_conf->replication_id());
1862+
}
1863+
18521864
std::stringstream resp;
18531865
resp << "*" << std::to_string(elements) << "\r\n" << config_body;
18541866
ret = resp.str();
@@ -2183,12 +2195,12 @@ void ConfigCmd::ConfigSet(std::string& ret) {
21832195
g_pika_conf->SetThrottleBytesPerSecond(static_cast<int>(ival));
21842196
ret = "+OK\r\n";
21852197
} else if (set_item == "max-rsync-parallel-num") {
2186-
if ((pstd::string2int(value.data(), value.size(), &ival) == 0) || ival > kMaxRsyncParallelNum) {
2187-
ret = "-ERR Invalid argument \'" + value + "\' for CONFIG SET 'max-rsync-parallel-num'\r\n";
2188-
return;
2189-
}
2190-
g_pika_conf->SetMaxRsyncParallelNum(static_cast<int>(ival));
2191-
ret = "+OK\r\n";
2198+
if ((pstd::string2int(value.data(), value.size(), &ival) == 0) || ival > kMaxRsyncParallelNum) {
2199+
ret = "-ERR Invalid argument \'" + value + "\' for CONFIG SET 'max-rsync-parallel-num'\r\n";
2200+
return;
2201+
}
2202+
g_pika_conf->SetMaxRsyncParallelNum(static_cast<int>(ival));
2203+
ret = "+OK\r\n";
21922204
} else {
21932205
ret = "-ERR Unsupported CONFIG parameter: " + set_item + "\r\n";
21942206
}
@@ -2202,6 +2214,14 @@ void ConfigCmd::ConfigRewrite(std::string& ret) {
22022214
}
22032215
}
22042216

2217+
void ConfigCmd::ConfigRewriteReplicationID(std::string &ret) {
2218+
if (g_pika_conf->ConfigRewriteReplicationID() != 0) {
2219+
ret = "+OK\r\n";
2220+
} else {
2221+
ret = "-ERR Rewire ReplicationID CONFIG fail\r\n";
2222+
}
2223+
}
2224+
22052225
void ConfigCmd::ConfigResetstat(std::string& ret) {
22062226
g_pika_server->ResetStat();
22072227
ret = "+OK\r\n";
@@ -2627,6 +2647,19 @@ void DiskRecoveryCmd::Do(std::shared_ptr<Slot> slot) {
26272647
res_.SetRes(CmdRes::kOk, "The disk error has been recovered");
26282648
}
26292649

2650+
void ClearReplicationIDCmd::DoInitial() {
2651+
if (!CheckArg(argv_.size())) {
2652+
res_.SetRes(CmdRes::kWrongNum, kCmdNameClearReplicationID);
2653+
return;
2654+
}
2655+
}
2656+
2657+
void ClearReplicationIDCmd::Do(std::shared_ptr<Slot> slot) {
2658+
g_pika_conf->SetReplicationID("");
2659+
g_pika_conf->ConfigRewriteReplicationID();
2660+
res_.SetRes(CmdRes::kOk, "ReplicationID is cleared");
2661+
}
2662+
26302663
#ifdef WITH_COMMAND_DOCS
26312664

26322665
bool CommandCmd::CommandFieldCompare::operator()(const std::string& a, const std::string& b) const {

src/pika_command.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ void InitCmdTable(CmdTable* cmd_table) {
9494
cmd_table->insert(std::pair<std::string, std::unique_ptr<Cmd>>(kCmdNameQuit, std::move(quitptr)));
9595
std::unique_ptr<Cmd> diskrecoveryptr = std::make_unique<DiskRecoveryCmd>(kCmdNameDiskRecovery, 1, kCmdFlagsRead | kCmdFlagsAdmin);
9696
cmd_table->insert(std::pair<std::string, std::unique_ptr<Cmd>>(kCmdNameDiskRecovery, std::move(diskrecoveryptr)));
97+
std::unique_ptr<Cmd> clearreplicationidptr = std::make_unique<ClearReplicationIDCmd>(kCmdNameClearReplicationID, 1, kCmdFlagsWrite | kCmdFlagsAdmin);
98+
cmd_table->insert(std::pair<std::string, std::unique_ptr<Cmd>>(kCmdNameClearReplicationID, std::move(clearreplicationidptr)));
9799

98100
#ifdef WITH_COMMAND_DOCS
99101
std::unique_ptr<Cmd> commandptr = std::make_unique<CommandCmd>(kCmdNameCommand, -1, kCmdFlagsRead | kCmdFlagsAdmin);

src/pika_conf.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ int PikaConf::Load() {
158158
} else if (run_id_.length() != configRunIDSize) {
159159
LOG(FATAL) << "run-id " << run_id_ << " is invalid, its string length should be " << configRunIDSize;
160160
}
161+
GetConfStr("replication-id", &replication_id_);
161162
GetConfStr("requirepass", &requirepass_);
162163
GetConfStr("masterauth", &masterauth_);
163164
GetConfStr("userpass", &userpass_);
@@ -642,6 +643,7 @@ int PikaConf::ConfigRewrite() {
642643
SetConfStr("write-binlog", write_binlog_ ? "yes" : "no");
643644
SetConfStr("run-id", run_id_);
644645
SetConfStr("master-run-id", master_run_id_);
646+
SetConfStr("replication-id", replication_id_);
645647
SetConfInt("max-cache-statistic-keys", max_cache_statistic_keys_);
646648
SetConfInt("small-compaction-threshold", small_compaction_threshold_);
647649
SetConfInt("max-client-response-size", static_cast<int32_t>(max_client_response_size_));
@@ -687,6 +689,29 @@ int PikaConf::ConfigRewrite() {
687689
return static_cast<int>(WriteBack());
688690
}
689691

692+
int PikaConf::ConfigRewriteReplicationID() {
693+
std::lock_guard l(rwlock_);
694+
SetConfStr("replication-id", replication_id_);
695+
if (!diff_commands_.empty()) {
696+
std::vector<pstd::BaseConf::Rep::ConfItem> filtered_items;
697+
for (const auto& diff_command : diff_commands_) {
698+
if (!diff_command.second.empty()) {
699+
pstd::BaseConf::Rep::ConfItem item(pstd::BaseConf::Rep::kConf, diff_command.first, diff_command.second);
700+
filtered_items.push_back(item);
701+
}
702+
}
703+
if (!filtered_items.empty()) {
704+
pstd::BaseConf::Rep::ConfItem comment_item(pstd::BaseConf::Rep::kComment, "# Generated by ReplicationID CONFIG REWRITE\n");
705+
PushConfItem(comment_item);
706+
for (const auto& item : filtered_items) {
707+
PushConfItem(item);
708+
}
709+
}
710+
diff_commands_.clear();
711+
}
712+
return static_cast<int>(WriteBack());
713+
}
714+
690715
rocksdb::CompressionType PikaConf::GetCompression(const std::string& value) {
691716
if (value == "snappy") {
692717
return rocksdb::CompressionType::kSnappyCompression;

src/pika_inner_message.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ message InnerResponse {
117117
required bool classic_mode = 1;
118118
repeated DBInfo dbs_info = 2;
119119
required string run_id = 3;
120+
optional string replication_id = 4;
120121
}
121122

122123
// master to slave

src/pika_repl_client_conn.cc

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,27 @@ void PikaReplClientConn::HandleMetaSyncResponse(void* arg) {
122122
return;
123123
}
124124

125-
if (meta_sync.run_id() == "" || g_pika_server->master_run_id() != meta_sync.run_id()) {
126-
LOG(INFO) << "Run id is not equal, need to do full sync, remote master run id: " << meta_sync.run_id()
127-
<< ", local run id: " << g_pika_server->master_run_id();
125+
// The relicationid obtained from the server is null
126+
if (meta_sync.replication_id() == "") {
127+
LOG(WARNING) << "Meta Sync Failed: the relicationid obtained from the server is null, keep sending MetaSync msg";
128+
return;
129+
}
130+
131+
// The Replicationids of both the primary and secondary Replicationid are not empty and are not equal
132+
if (g_pika_conf->replication_id() != meta_sync.replication_id() && g_pika_conf->replication_id() != "") {
133+
LOG(WARNING) << "Meta Sync Failed: replicationid on both sides of the connection are inconsistent";
134+
g_pika_server->SyncError();
135+
conn->NotifyClose();
136+
return;
137+
}
138+
139+
// First synchronization between the master and slave
140+
if (g_pika_conf->replication_id() != meta_sync.replication_id()) {
141+
LOG(INFO) << "New node is added to the cluster and requires full replication, remote replication id: " << meta_sync.replication_id()
142+
<< ", local replication id: " << g_pika_conf->replication_id();
128143
g_pika_server->force_full_sync_ = true;
129-
g_pika_server->set_master_run_id(meta_sync.run_id());
130-
g_pika_conf->SetMasterRunID(meta_sync.run_id());
144+
g_pika_conf->SetReplicationID(meta_sync.replication_id());
145+
g_pika_conf->ConfigRewriteReplicationID();
131146
}
132147

133148
g_pika_conf->SetWriteBinlog("yes");

0 commit comments

Comments
 (0)