1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00

feat: introduce a multi-shard emulated cluster

This commit is contained in:
Roman Gershman 2024-05-29 17:19:37 +03:00
parent b89997c5ba
commit 19e0721ab9
No known key found for this signature in database
GPG key ID: F25B77EAF8AEBA7A
2 changed files with 42 additions and 29 deletions

View file

@ -28,6 +28,7 @@ ABSL_FLAG(std::string, cluster_announce_ip, "", "ip that cluster commands announ
ABSL_FLAG(std::string, cluster_node_id, "", ABSL_FLAG(std::string, cluster_node_id, "",
"ID within a cluster, used for slot assignment. MUST be unique. If empty, uses master " "ID within a cluster, used for slot assignment. MUST be unique. If empty, uses master "
"replication ID (random string)"); "replication ID (random string)");
ABSL_FLAG(uint32_t, cluster_shard_factor, 1, "number of virtual shards per node");
ABSL_DECLARE_FLAG(int32_t, port); ABSL_DECLARE_FLAG(int32_t, port);
@ -78,38 +79,49 @@ ClusterConfig* ClusterFamily::cluster_config() {
return tl_cluster_config.get(); return tl_cluster_config.get();
} }
ClusterShardInfo ClusterFamily::GetEmulatedShardInfo(ConnectionContext* cntx) const { ClusterShardInfos ClusterFamily::GetEmulatedShardInfo(ConnectionContext* cntx) const {
ClusterShardInfo info{.slot_ranges = {{.start = 0, .end = kMaxSlotNum}}, unsigned factor = std::max(absl::GetFlag(FLAGS_cluster_shard_factor), 1u);
.master = {}, unsigned slots_per_shard = (kMaxSlotNum + 1) / factor;
.replicas = {}, SlotId next_slot = 0;
.migrations = {}}; ClusterShardInfos result;
optional<Replica::Info> replication_info = server_family_->GetReplicaInfo(); for (unsigned j = 0; j < factor; ++j) {
ServerState& etl = *ServerState::tlocal(); SlotId end_slot = (j + 1) == factor ? kMaxSlotNum : SlotId(next_slot + slots_per_shard - 1);
if (!replication_info.has_value()) {
DCHECK(etl.is_master);
std::string cluster_announce_ip = absl::GetFlag(FLAGS_cluster_announce_ip);
std::string preferred_endpoint =
cluster_announce_ip.empty() ? cntx->conn()->LocalBindAddress() : cluster_announce_ip;
info.master = {.id = id_, ClusterShardInfo info{.slot_ranges = {{.start = next_slot, .end = end_slot}},
.ip = preferred_endpoint, .master = {},
.port = static_cast<uint16_t>(absl::GetFlag(FLAGS_port))}; .replicas = {},
.migrations = {}};
for (const auto& replica : server_family_->GetDflyCmd()->GetReplicasRoleInfo()) { optional<Replica::Info> replication_info = server_family_->GetReplicaInfo();
info.replicas.push_back({.id = replica.id, ServerState& etl = *ServerState::tlocal();
.ip = replica.address, if (!replication_info.has_value()) {
.port = static_cast<uint16_t>(replica.listening_port)}); DCHECK(etl.is_master);
std::string cluster_announce_ip = absl::GetFlag(FLAGS_cluster_announce_ip);
std::string preferred_endpoint =
cluster_announce_ip.empty() ? cntx->conn()->LocalBindAddress() : cluster_announce_ip;
info.master = {.id = (j == 0) ? id_ : absl::StrCat("emulated", j),
.ip = preferred_endpoint,
// +j for py-cluster to work.
.port = static_cast<uint16_t>(absl::GetFlag(FLAGS_port))};
for (const auto& replica : server_family_->GetDflyCmd()->GetReplicasRoleInfo()) {
info.replicas.push_back({.id = replica.id,
.ip = replica.address,
.port = static_cast<uint16_t>(replica.listening_port)});
}
} else {
// TODO: We currently don't save the master's ID in the replica
info.master = {.id = "", .ip = replication_info->host, .port = replication_info->port};
info.replicas.push_back({.id = id_,
.ip = cntx->conn()->LocalBindAddress(),
.port = static_cast<uint16_t>(absl::GetFlag(FLAGS_port))});
} }
} else { next_slot = info.slot_ranges.front().end + 1;
// TODO: We currently don't save the master's ID in the replica result.push_back(info);
info.master = {.id = "", .ip = replication_info->host, .port = replication_info->port};
info.replicas.push_back({.id = id_,
.ip = cntx->conn()->LocalBindAddress(),
.port = static_cast<uint16_t>(absl::GetFlag(FLAGS_port))});
} }
return result;
return info;
} }
void ClusterFamily::ClusterHelp(ConnectionContext* cntx) { void ClusterFamily::ClusterHelp(ConnectionContext* cntx) {
@ -222,7 +234,7 @@ void ClusterSlotsImpl(const ClusterShardInfos& config, ConnectionContext* cntx)
void ClusterFamily::ClusterSlots(ConnectionContext* cntx) { void ClusterFamily::ClusterSlots(ConnectionContext* cntx) {
if (IsClusterEmulated()) { if (IsClusterEmulated()) {
return ClusterSlotsImpl({GetEmulatedShardInfo(cntx)}, cntx); return ClusterSlotsImpl(GetEmulatedShardInfo(cntx), cntx);
} else if (tl_cluster_config != nullptr) { } else if (tl_cluster_config != nullptr) {
return ClusterSlotsImpl(tl_cluster_config->GetConfig(), cntx); return ClusterSlotsImpl(tl_cluster_config->GetConfig(), cntx);
} else { } else {
@ -231,6 +243,7 @@ void ClusterFamily::ClusterSlots(ConnectionContext* cntx) {
} }
namespace { namespace {
void ClusterNodesImpl(const ClusterShardInfos& config, string_view my_id, ConnectionContext* cntx) { void ClusterNodesImpl(const ClusterShardInfos& config, string_view my_id, ConnectionContext* cntx) {
// For more details https://redis.io/commands/cluster-nodes/ // For more details https://redis.io/commands/cluster-nodes/

View file

@ -94,7 +94,7 @@ class ClusterFamily {
ABSL_GUARDED_BY(migration_mu_); ABSL_GUARDED_BY(migration_mu_);
private: private:
ClusterShardInfo GetEmulatedShardInfo(ConnectionContext* cntx) const; ClusterShardInfos GetEmulatedShardInfo(ConnectionContext* cntx) const;
mutable util::fb2::Mutex config_update_mu_; mutable util::fb2::Mutex config_update_mu_;