Skip to content

Commit d86d311

Browse files
committed
default_policy: Prefer local rack nodes
Until now, the default policy respected rack preference only when it came to replicas. Considering non-token-aware queries (e.g. unprepared statements), they would never prioritize the preferred rack. Now, local rack nodes are always preferred before other nodes, both in `pick()` and in `fallback()`. Tests and docs are adjusted for this behaviour. One new test is added for the case when no token is provided and a rack is preferred.
1 parent 81f3afb commit d86d311

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

docs/source/load-balancing/default-policy.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,16 @@ policy to prioritize nodes based on their location. It has three modes:
4444

4545
When a datacenter `"my_dc"` is preferred, the policy will treat nodes in `"my_dc"`
4646
as "local" nodes, and nodes in other datacenters as "remote" nodes. This affects
47-
the order in which nodes are returned by the policy when selecting replicas for
47+
the order in which nodes are returned by the policy when selecting nodes for
4848
read or write operations. If no datacenter is preferred, the policy will treat
4949
all nodes as local nodes.
5050

5151
`preferences` allow the load balancing policy to prioritize nodes based on their
5252
availability zones (racks) in the preferred datacenter, too. When a datacenter
5353
and a rack are preferred, the policy will first return replicas in the local rack
5454
in the preferred datacenter, and then the other replicas in the datacenter
55-
(followed by remote replicas).
55+
(followed by remote replicas). After replicas, the other node will be ordered
56+
similarly, too (local rack nodes, local datacenter nodes, remote nodes).
5657

5758
When datacenter failover is disabled (`permit_dc_failover` is set to
5859
false), the default policy will only include local nodes in load balancing

scylla/src/transport/load_balancing/default.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,22 @@ or refrain from preferring datacenters (which may ban all other datacenters, if
170170
// some alive local node.
171171
// If there was no preferred datacenter specified, all nodes are treated as local.
172172
let nodes = self.preferred_node_set(cluster);
173-
let picked = Self::pick_node(nodes, &self.pick_predicate);
174-
if let Some(alive_local) = picked {
173+
174+
if let ReplicaLocationPreference::DatacenterAndRack(dc, rack) = &self.preferences {
175+
// Try to pick some alive local rack random node.
176+
let rack_predicate = Self::make_rack_predicate(
177+
&self.pick_predicate,
178+
ReplicaLocationCriteria::DatacenterAndRack(dc, rack),
179+
);
180+
let local_rack_picked = Self::pick_node(nodes, rack_predicate);
181+
182+
if let Some(alive_local_rack) = local_rack_picked {
183+
return Some(alive_local_rack);
184+
}
185+
}
186+
187+
// Try to pick some alive local random node.
188+
if let Some(alive_local) = Self::pick_node(nodes, &self.pick_predicate) {
175189
return Some(alive_local);
176190
}
177191

@@ -276,6 +290,17 @@ or refrain from preferring datacenters (which may ban all other datacenters, if
276290

277291
// Get a list of all local alive nodes, and apply a round robin to it
278292
let local_nodes = self.preferred_node_set(cluster);
293+
294+
let maybe_local_rack_nodes =
295+
if let ReplicaLocationPreference::DatacenterAndRack(dc, rack) = &self.preferences {
296+
let rack_predicate = Self::make_rack_predicate(
297+
&self.pick_predicate,
298+
ReplicaLocationCriteria::DatacenterAndRack(dc, rack),
299+
);
300+
Either::Left(Self::round_robin_nodes(local_nodes, rack_predicate))
301+
} else {
302+
Either::Right(std::iter::empty::<NodeRef<'a>>())
303+
};
279304
let robined_local_nodes = Self::round_robin_nodes(local_nodes, Self::is_alive);
280305

281306
let all_nodes = cluster.replica_locator().unique_nodes_in_global_ring();
@@ -301,6 +326,7 @@ or refrain from preferring datacenters (which may ban all other datacenters, if
301326

302327
// Construct a fallback plan as a composition of replicas, local nodes and remote nodes.
303328
let plan = maybe_replicas
329+
.chain(maybe_local_rack_nodes)
304330
.chain(robined_local_nodes)
305331
.chain(maybe_remote_nodes)
306332
.chain(maybe_down_local_nodes)
@@ -1570,7 +1596,8 @@ mod tests {
15701596
expected_groups: ExpectedGroupsBuilder::new()
15711597
.deterministic([B]) // pick local rack replicas
15721598
.deterministic([C]) // fallback replicas
1573-
.group([A, G]) // local nodes
1599+
.group([A]) // local rack nodes
1600+
.group([G]) // local DC nodes
15741601
.build(),
15751602
},
15761603
// Keyspace SS with RF=2 with enabled rack-awareness and no local-rack replica
@@ -1595,7 +1622,34 @@ mod tests {
15951622
// r2 r1 r1 r1 r2 r1 r1
15961623
expected_groups: ExpectedGroupsBuilder::new()
15971624
.group([A]) // pick local DC
1598-
.group([C, G, B]) // local nodes
1625+
.group([G]) // local rack nodes
1626+
.group([C, B]) // local DC nodes
1627+
.build(),
1628+
},
1629+
// Keyspace NTS with RF=3 with enabled DC failover and rack-awareness, no token provided
1630+
Test {
1631+
policy: DefaultPolicy {
1632+
preferences: NodeLocationPreference::DatacenterAndRack(
1633+
"eu".to_owned(),
1634+
"r1".to_owned(),
1635+
),
1636+
is_token_aware: true,
1637+
permit_dc_failover: true,
1638+
..Default::default()
1639+
},
1640+
routing_info: RoutingInfo {
1641+
token: None,
1642+
keyspace: Some(KEYSPACE_NTS_RF_3),
1643+
consistency: Consistency::One,
1644+
..Default::default()
1645+
},
1646+
// going through the ring, we get order: F , A , C , D , G , B , E
1647+
// us eu eu us eu eu us
1648+
// r2 r1 r1 r1 r2 r1 r1
1649+
expected_groups: ExpectedGroupsBuilder::new()
1650+
.group([A, C, B]) // local rack nodes
1651+
.group([G]) // local DC nodes
1652+
.group([F, D, E]) // remote nodes
15991653
.build(),
16001654
},
16011655
];

0 commit comments

Comments
 (0)