Skip to content

Commit 05d6dd8

Browse files
authored
Merge pull request #1082 from weibocom/feat/gray_group
Feat/gray group
2 parents 7484dd8 + fd65e58 commit 05d6dd8

File tree

14 files changed

+331
-91
lines changed

14 files changed

+331
-91
lines changed

motan-core/src/main/java/com/weibo/api/motan/cluster/group/ClusterGroup.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ public interface ClusterGroup<T> extends Caller<T> {
1414
List<Cluster<T>> getSandboxClusters();
1515

1616
List<Cluster<T>> getBackupClusters();
17+
18+
List<Cluster<T>> getGreyClusters();
1719
}

motan-core/src/main/java/com/weibo/api/motan/cluster/group/DefaultClusterGroup.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.weibo.api.motan.rpc.Response;
1010
import com.weibo.api.motan.rpc.URL;
1111
import com.weibo.api.motan.switcher.Switcher;
12+
import com.weibo.api.motan.util.LoggerUtil;
1213
import com.weibo.api.motan.util.MathUtil;
1314
import com.weibo.api.motan.util.MotanSwitcherUtil;
1415

@@ -23,6 +24,7 @@ public class DefaultClusterGroup<T> implements ClusterGroup<T> {
2324
protected Cluster<T> masterCluster;
2425
protected List<Cluster<T>> backupClusters;
2526
protected List<Cluster<T>> sandboxClusters;
27+
protected List<Cluster<T>> greyClusters;
2628
protected AtomicInteger backupIndex;
2729

2830
static {
@@ -41,11 +43,17 @@ public DefaultClusterGroup(Cluster<T> masterCluster) {
4143
public Response call(Request request) {
4244
Cluster<T> cluster = masterCluster;
4345
if (selector != null) {
44-
cluster = selector.select(request);
46+
try {
47+
cluster = selector.select(request);
48+
} catch (Exception e) {
49+
LoggerUtil.warn("ClusterSelector select error, url:" + masterCluster.getUrl().toSimpleString(), e);
50+
}
4551
if (cluster == null) {
46-
throw new MotanServiceException("The ClusterSelector did not find an available Cluster");
52+
cluster = masterCluster;
53+
LoggerUtil.warn("ClusterSelector select null cluster, use master cluster instead. url:" + masterCluster.getUrl().toSimpleString());
4754
}
4855
}
56+
4957
try {
5058
return cluster.call(request);
5159
} catch (MotanServiceException e) {
@@ -63,7 +71,7 @@ public Response call(Request request) {
6371
@SuppressWarnings("unchecked")
6472
public void init() {
6573
// If there are no routable clusters, no selector is created.
66-
if (sandboxClusters != null) {
74+
if (sandboxClusters != null || greyClusters != null) {
6775
selector = ExtensionLoader.getExtensionLoader(ClusterSelector.class)
6876
.getExtension(masterCluster.getUrl().getParameter(URLParamType.clusterSelector.getName(),
6977
DEFAULT_CLUSTER_SELECTOR));
@@ -126,11 +134,20 @@ public void setSandboxClusters(List<Cluster<T>> sandboxClusters) {
126134
this.sandboxClusters = sandboxClusters;
127135
}
128136

137+
@Override
138+
public List<Cluster<T>> getGreyClusters() {
139+
return greyClusters;
140+
}
141+
142+
public void setGreyClusters(List<Cluster<T>> greyClusters) {
143+
this.greyClusters = greyClusters;
144+
}
145+
129146
@Override
130147
public String toString() {
131148
return "DefaultClusterGroup {masterCluster=" + clusterToString(masterCluster) + ", backupClusters="
132149
+ clustersToString(backupClusters)
133-
+ ", sandboxClusters=" + clustersToString(sandboxClusters) + "}";
150+
+ ", sandboxClusters=" + clustersToString(sandboxClusters) + ", greyClusters=" + clustersToString(greyClusters) + "}";
134151
}
135152

136153
private String clustersToString(List<Cluster<T>> clusters) {

motan-core/src/main/java/com/weibo/api/motan/cluster/group/DefaultClusterSelector.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,52 @@
11
package com.weibo.api.motan.cluster.group;
22

3-
import java.util.List;
4-
53
import com.weibo.api.motan.cluster.Cluster;
64
import com.weibo.api.motan.common.MotanConstants;
75
import com.weibo.api.motan.core.extension.SpiMeta;
86
import com.weibo.api.motan.exception.MotanFrameworkException;
97
import com.weibo.api.motan.rpc.Request;
108
import com.weibo.api.motan.util.CollectionUtil;
119

10+
import java.util.List;
11+
1212
@SpiMeta(name = "default")
13-
public class DefaultClusterSelector<T> implements ClusterSelector<T>{
13+
public class DefaultClusterSelector<T> implements ClusterSelector<T> {
1414
public static final String DEFAULT_ROUTE_GROUP_SANDBOX = "sandbox";
1515
protected ClusterGroup<T> clusterGroup;
1616
protected Cluster<T> defaultSandboxCluster; // Default sandbox cluster
17+
protected Cluster<T> defaultGreyCluster; // Default grey cluster
1718

1819
@Override
1920
public Cluster<T> select(Request request) {
20-
if (defaultSandboxCluster != null && !CollectionUtil.isEmpty(defaultSandboxCluster.getReferers())) {
21-
// Check the route group of the request
22-
String routeGroup = request.getAttachment(MotanConstants.ROUTE_GROUP_KEY);
23-
if (routeGroup != null) {
24-
routeGroup = routeGroup.trim();
25-
// If the route group is sandbox, directly return the default sandbox cluster
26-
if (DEFAULT_ROUTE_GROUP_SANDBOX.equals(routeGroup)) {
21+
String routeGroup = request.getAttachment(MotanConstants.ROUTE_GROUP_KEY);
22+
if (routeGroup != null) {
23+
String sandboxGroup = null;
24+
String greyGroup = null;
25+
if (defaultSandboxCluster != null && !CollectionUtil.isEmpty(defaultSandboxCluster.getReferers())) {
26+
sandboxGroup = defaultSandboxCluster.getUrl().getGroup();
27+
}
28+
if (defaultGreyCluster != null && !CollectionUtil.isEmpty(defaultGreyCluster.getReferers())) {
29+
greyGroup = defaultGreyCluster.getUrl().getGroup();
30+
}
31+
32+
// default sandbox value
33+
if (sandboxGroup != null && DEFAULT_ROUTE_GROUP_SANDBOX.equals(routeGroup.trim())) {
34+
return defaultSandboxCluster;
35+
}
36+
// Check the comma-separated group list
37+
String[] routeGroupList = routeGroup.split(",");
38+
for (String group : routeGroupList) {
39+
group = group.trim();
40+
if (sandboxGroup != null && sandboxGroup.equals(group)) {
2741
return defaultSandboxCluster;
2842
}
29-
30-
// Check the comma-separated group list
31-
String[] routeGroupList = routeGroup.split(",");
32-
String ownGroup = clusterGroup.getUrl().getGroup();
33-
for (String group : routeGroupList) {
34-
group = group.trim();
35-
if (group.equals(ownGroup)) {
36-
return defaultSandboxCluster;
37-
}
43+
if (greyGroup != null && greyGroup.equals(group)) {
44+
return defaultGreyCluster;
3845
}
3946
}
4047
}
48+
49+
// If no matching rule is found, return the master cluster
4150
return clusterGroup.getMasterCluster();
4251
}
4352

@@ -52,7 +61,13 @@ public void init(ClusterGroup<T> clusterGroup) {
5261
// Only save the first sandbox cluster as the default sandbox cluster
5362
this.defaultSandboxCluster = sandboxClusters.get(0);
5463
}
64+
List<Cluster<T>> greyClusters = clusterGroup.getGreyClusters();
65+
if (!CollectionUtil.isEmpty(greyClusters)) {
66+
// Only save the first grey cluster as the default grey cluster
67+
this.defaultGreyCluster = greyClusters.get(0);
68+
}
5569
}
70+
5671
@Override
5772
public void destroy() {
5873
}

motan-core/src/main/java/com/weibo/api/motan/common/URLParamType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ public enum URLParamType {
184184
dynamicMeta("dynamicMeta", true), // whether to enable dynamic meta
185185
clusterSelector("clusterSelector", "default"), // cluster selector for ClusterGroup
186186
sandboxGroups("sandboxGroups", ""),
187+
greyGroups("greyGroups", ""),
187188
backupGroups("backupGroups", ""),
188189
clusterEmptyNodeNotify("clusterEmptyNodeNotify", false), // whether to enable empty node notify to cluster
189190
;

motan-core/src/main/java/com/weibo/api/motan/config/AbstractInterfaceConfig.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ public class AbstractInterfaceConfig extends AbstractConfig {
139139
protected String sandboxGroups; // the group name of the sandbox
140140

141141
protected String backupGroups; // the group name of the backup
142+
protected String greyGroups; // the group name of the grey
143+
144+
public String getGreyGroups() {
145+
return greyGroups;
146+
}
147+
148+
public void setGreyGroups(String greyGroups) {
149+
this.greyGroups = greyGroups;
150+
}
142151

143152
public String getSandboxGroups() {
144153
return sandboxGroups;

motan-core/src/main/java/com/weibo/api/motan/config/RefererConfig.java

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,29 @@
4747
*/
4848

4949
public class RefererConfig<T> extends AbstractRefererConfig {
50-
private static final ConcurrentHashSet<String> NONE_SANDBOX_PROTOCOL_SET = new ConcurrentHashSet<>(); // The set of protocols that do not support sandbox grouping.
50+
private static final ConcurrentHashSet<String> NONE_EXTRA_GROUP_PROTOCOL_SET = new ConcurrentHashSet<>(); // The set of protocols that do not support sandbox/grey grouping.
51+
private static final ConcurrentHashSet<String> NONE_EXTRA_GROUP_REGISTRY_SET = new ConcurrentHashSet<>(); // The set of registries that do not support sandbox/grey grouping.
5152

5253
static {
53-
NONE_SANDBOX_PROTOCOL_SET.add(MotanConstants.PROTOCOL_INJVM);
54-
NONE_SANDBOX_PROTOCOL_SET.add("memcache");
55-
NONE_SANDBOX_PROTOCOL_SET.add("memcacheq");
56-
NONE_SANDBOX_PROTOCOL_SET.add("redis");
54+
NONE_EXTRA_GROUP_PROTOCOL_SET.add(MotanConstants.PROTOCOL_INJVM);
55+
NONE_EXTRA_GROUP_PROTOCOL_SET.add("memcache");
56+
NONE_EXTRA_GROUP_PROTOCOL_SET.add("memcacheq");
57+
NONE_EXTRA_GROUP_PROTOCOL_SET.add("redis");
58+
59+
NONE_EXTRA_GROUP_REGISTRY_SET.add("direct");
60+
NONE_EXTRA_GROUP_REGISTRY_SET.add("local");
61+
NONE_EXTRA_GROUP_REGISTRY_SET.add("weibomesh");
5762
}
5863

5964
private static final long serialVersionUID = -2299754608229467887L;
6065

6166
protected static final String MASTER_CLUSTER_KEY = "master-";
6267
protected static final String SANDBOX_CLUSTER_KEY = "sandbox-";
68+
protected static final String GREY_CLUSTER_KEY = "grey-";
6369
protected static final String BACKUP_CLUSTER_KEY = "backup-";
64-
protected static final String NONE_SANDBOX_STRING = "none";
70+
protected static final String NONE_GROUP_STRING = "none";
6571
public static String DEFAULT_SANDBOX_GROUPS = MotanGlobalConfigUtil.getConfig("DEFAULT_SANDBOX_GROUPS", ""); // 可以通过设置全局配置修改默认值
72+
public static String DEFAULT_GREY_GROUPS = MotanGlobalConfigUtil.getConfig("DEFAULT_GREY_GROUPS", ""); // 可以通过设置全局配置修改默认值
6673

6774

6875
private Class<T> interfaceClass;
@@ -191,16 +198,23 @@ private ClusterGroup<T> createClusterGroup(ConfigHandler configHandler, URL refU
191198
// create master cluster
192199
Cluster<T> masterCluster = createInnerCluster(configHandler, refUrl, MASTER_CLUSTER_KEY);
193200
DefaultClusterGroup<T> clusterGroup = new DefaultClusterGroup<T>(masterCluster);
194-
// try to create sandbox, backup clusters if not injvm protocol
195-
if (!NONE_SANDBOX_PROTOCOL_SET.contains(refUrl.getProtocol())) {
201+
// try to create sandbox, grey, backup clusters if needed
202+
if (needProcessExtraGroup(refUrl)) {
196203
try {
197204
String sandboxGroups = refUrl.getParameter(URLParamType.sandboxGroups.getName(), DEFAULT_SANDBOX_GROUPS);
198205
// set sandbox clusters
199-
if (StringUtils.isNotBlank(sandboxGroups) && !NONE_SANDBOX_STRING.equals(sandboxGroups)) {
206+
if (StringUtils.isNotBlank(sandboxGroups) && !NONE_GROUP_STRING.equals(sandboxGroups)) {
200207
clusterGroup.setSandboxClusters(createMultiClusters(refUrl, configHandler,
201208
sandboxGroups, SANDBOX_CLUSTER_KEY, false, true));
202209
LoggerUtil.info("init sandbox clusters success. master cluster url:" + refUrl.toSimpleString() + ", sandbox groups:" + sandboxGroups);
203210
}
211+
// set grey clusters
212+
String greyGroups = refUrl.getParameter(URLParamType.greyGroups.getName(), DEFAULT_GREY_GROUPS);
213+
if (StringUtils.isNotBlank(greyGroups) && !NONE_GROUP_STRING.equals(greyGroups)) {
214+
clusterGroup.setGreyClusters(createMultiClusters(refUrl, configHandler,
215+
greyGroups, GREY_CLUSTER_KEY, false, true));
216+
LoggerUtil.info("init grey clusters success. master cluster url:" + refUrl.toSimpleString() + ", grey groups:" + greyGroups);
217+
}
204218
// set backup clusters
205219
if (StringUtils.isNotBlank(refUrl.getParameter(URLParamType.backupGroups.getName()))) {
206220
clusterGroup.setBackupClusters(createMultiClusters(refUrl, configHandler,
@@ -216,6 +230,35 @@ private ClusterGroup<T> createClusterGroup(ConfigHandler configHandler, URL refU
216230
return clusterGroup;
217231
}
218232

233+
// Determine whether extra groups such as sandbox or grey group need to be processed.
234+
private boolean needProcessExtraGroup(URL refUrl) {
235+
// Special protocols such as injvm will not be processed.
236+
if (NONE_EXTRA_GROUP_PROTOCOL_SET.contains(refUrl.getProtocol())) {
237+
LoggerUtil.info("do not process extra groups due to protocol rules. url:" + refUrl.toSimpleString());
238+
return false;
239+
}
240+
// use directUrl not be processed.
241+
if (StringUtils.isNotBlank(directUrl)) {
242+
LoggerUtil.info("do not process extra groups due to directUrl rules. url:" + refUrl.toSimpleString());
243+
return false;
244+
}
245+
// will be proxied by mesh
246+
if (MeshProxyUtil.needProcess(refUrl, false)) {
247+
LoggerUtil.info("do not process extra groups due to mesh proxy rules. url:" + refUrl.toSimpleString());
248+
return false;
249+
}
250+
// Special registry such as direct will not be processed.
251+
if (registryUrls != null) {
252+
for (URL url : registryUrls) {
253+
if (NONE_EXTRA_GROUP_REGISTRY_SET.contains(url.getProtocol())) {
254+
LoggerUtil.info("do not process extra groups due to registry rules. url:" + refUrl.toSimpleString());
255+
return false;
256+
}
257+
}
258+
}
259+
return true;
260+
}
261+
219262
private List<Cluster<T>> createMultiClusters(URL baseUrl, ConfigHandler configHandler, String groupString,
220263
String prefixKey, boolean lazyInit, boolean emptyNodeNotify) {
221264
String baseGroup = baseUrl.getGroup();

motan-core/src/main/java/com/weibo/api/motan/util/MeshProxyUtil.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public class MeshProxyUtil {
6464
* @return 如果配置了环境变量则进行代理,否则原样返回
6565
*/
6666
public static List<URL> processMeshProxy(List<URL> originRegistryUrls, URL serviceUrl, boolean isServerEnd) {
67-
if (initChecked && needProcess(serviceUrl, isServerEnd)) {
67+
if (needProcess(serviceUrl, isServerEnd)) {
6868
try {
6969
List<URL> newRegistryUrls = new ArrayList<>(originRegistryUrls.size());
7070
for (URL url : originRegistryUrls) {
@@ -88,7 +88,10 @@ public static List<URL> processMeshProxy(List<URL> originRegistryUrls, URL servi
8888
return originRegistryUrls;
8989
}
9090

91-
private static boolean needProcess(URL serviceUrl, boolean isServerEnd) {
91+
public static boolean needProcess(URL serviceUrl, boolean isServerEnd) {
92+
if (!initChecked) {
93+
return false;
94+
}
9295
// check proxy mode
9396
String mode = proxyConfig.get(MODE_KEY);
9497
if (StringUtils.isBlank(mode)) {// 必须显示指定,不考虑提供默认值

motan-core/src/main/resources/META-INF/motan.xsd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,11 @@
323323
<xsd:documentation><![CDATA[ 沙箱环境使用的分组名 ]]></xsd:documentation>
324324
</xsd:annotation>
325325
</xsd:attribute>
326+
<xsd:attribute name="greyGroups" type="xsd:string" use="optional">
327+
<xsd:annotation>
328+
<xsd:documentation><![CDATA[ 灰度环境使用的分组名 ]]></xsd:documentation>
329+
</xsd:annotation>
330+
</xsd:attribute>
326331
<xsd:attribute name="backupGroups" type="xsd:string" use="optional">
327332
<xsd:annotation>
328333
<xsd:documentation><![CDATA[ 主分组异常时使用的后备分组名 ]]></xsd:documentation>

0 commit comments

Comments
 (0)