Skip to content

Commit fc6d81c

Browse files
authored
fix hot node in weak read (#422)
1 parent 6c891a2 commit fc6d81c

File tree

1 file changed

+43
-19
lines changed

1 file changed

+43
-19
lines changed

src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.ArrayList;
2424
import java.util.Collections;
2525
import java.util.List;
26+
import java.util.concurrent.ThreadLocalRandom;
2627

2728
public class ObPartitionLocation {
2829
private ReplicaLocation leader;
@@ -90,10 +91,9 @@ public ReplicaLocation getReplica(ObReadConsistency consistencyLevel,
9091
}
9192

9293
private ReplicaLocation getReadReplicaNoLdc(ObRoutePolicy routePolicy) {
93-
for (ReplicaLocation r : replicas) {
94-
if (r.isValid() && !r.isLeader()) {
95-
return r;
96-
}
94+
ReplicaLocation follower = getRandomFollowerFromList(replicas);
95+
if (follower != null) {
96+
return follower;
9797
}
9898
if (routePolicy == ObRoutePolicy.FOLLOWER_ONLY) {
9999
throw new IllegalArgumentException("No follower replica found for route policy: "
@@ -107,25 +107,22 @@ private ReplicaLocation getReadReplicaByRoutePolicy(ObRoutePolicy routePolicy)
107107
// 路由策略优先:FOLLOWER_FIRST 优先选择 follower,FOLLOWER_ONLY 只能选择 follower
108108
// 在满足路由策略的前提下,按就近原则选择(同机房 -> 同 region -> 其他 region)
109109

110-
// 优先在同机房找 follower
111-
for (ReplicaLocation r : sameIdc) {
112-
if (r.isValid() && !r.isLeader()) {
113-
return r;
114-
}
110+
// 优先在同机房找 follower(随机选择以避免热点)
111+
ReplicaLocation follower = getRandomFollowerFromList(sameIdc);
112+
if (follower != null) {
113+
return follower;
115114
}
116115

117-
// 如果同机房没有 follower,在同 region 找 follower
118-
for (ReplicaLocation r : sameRegion) {
119-
if (r.isValid() && !r.isLeader()) {
120-
return r;
121-
}
116+
// 如果同机房没有 follower,在同 region 找 follower(随机选择以避免热点)
117+
follower = getRandomFollowerFromList(sameRegion);
118+
if (follower != null) {
119+
return follower;
122120
}
123121

124-
// 如果同 region 没有 follower,在其他 region 找 follower
125-
for (ReplicaLocation r : otherRegion) {
126-
if (r.isValid() && !r.isLeader()) {
127-
return r;
128-
}
122+
// 如果同 region 没有 follower,在其他 region 找 follower(随机选择以避免热点)
123+
follower = getRandomFollowerFromList(otherRegion);
124+
if (follower != null) {
125+
return follower;
129126
}
130127

131128
// 如果都没有找到 follower
@@ -139,6 +136,33 @@ private ReplicaLocation getReadReplicaByRoutePolicy(ObRoutePolicy routePolicy)
139136
return leader;
140137
}
141138

139+
/**
140+
* 从列表中随机选择一个有效的 follower,避免热点问题
141+
*
142+
* @param locations replica 列表
143+
* @return 随机选择的 follower,如果没有有效的 follower 则返回 null
144+
*/
145+
private ReplicaLocation getRandomFollowerFromList(List<ReplicaLocation> locations) {
146+
if (locations == null || locations.isEmpty()) {
147+
return null;
148+
}
149+
150+
// 收集所有有效的 follower
151+
List<ReplicaLocation> validFollowers = new ArrayList<>();
152+
for (ReplicaLocation r : locations) {
153+
if (r.isValid() && !r.isLeader()) {
154+
validFollowers.add(r);
155+
}
156+
}
157+
158+
if (validFollowers.isEmpty()) {
159+
return null;
160+
}
161+
162+
// 随机选择一个 follower
163+
return validFollowers.get(ThreadLocalRandom.current().nextInt(validFollowers.size()));
164+
}
165+
142166
/*
143167
* Classify Replica for weak read, according to Server LDC location.
144168
* Synchronized to avoid duplicate initialization.

0 commit comments

Comments
 (0)