Skip to content

Commit 3e317ff

Browse files
authored
Optimize dynamic config: integrate Zookeeper & Nacos, support interface-level dynamic config (#1430)
* integrate Zookeeper and Nacos as configuration centers * support dynamic config at the interface level * Optimize interface-level dynamic config * Modify dynamic config test * Add DynamicUrl * Optimize config update process * Modify config update process * Modify ApolloDynamicConfigManagerTest
1 parent 8b8fc7d commit 3e317ff

File tree

31 files changed

+1793
-40
lines changed

31 files changed

+1793
-40
lines changed

all/pom.xml

+12
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,16 @@
304304
<artifactId>sofa-rpc-config-apollo</artifactId>
305305
<version>${project.version}</version>
306306
</dependency>
307+
<dependency>
308+
<groupId>com.alipay.sofa</groupId>
309+
<artifactId>sofa-rpc-config-zk</artifactId>
310+
<version>${project.version}</version>
311+
</dependency>
312+
<dependency>
313+
<groupId>com.alipay.sofa</groupId>
314+
<artifactId>sofa-rpc-config-nacos</artifactId>
315+
<version>${project.version}</version>
316+
</dependency>
307317
<dependency>
308318
<groupId>com.alipay.sofa</groupId>
309319
<artifactId>bolt</artifactId>
@@ -553,6 +563,8 @@
553563
<include>com.alipay.sofa:sofa-rpc-tracer-opentracing-resteasy</include>
554564
<include>com.alipay.sofa:sofa-rpc-tracer-opentracing-triple</include>
555565
<include>com.alipay.sofa:sofa-rpc-config-apollo</include>
566+
<include>com.alipay.sofa:sofa-rpc-config-zk</include>
567+
<include>com.alipay.sofa:sofa-rpc-config-nacos</include>
556568
<include>com.alipay.sofa:sofa-rpc-doc-swagger</include>
557569
<!-- TODO -->
558570
</includes>

bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultConsumerBootstrap.java

+64-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.alipay.sofa.rpc.client.Cluster;
2121
import com.alipay.sofa.rpc.client.ClusterFactory;
2222
import com.alipay.sofa.rpc.client.ProviderGroup;
23+
import com.alipay.sofa.rpc.common.RpcConstants;
2324
import com.alipay.sofa.rpc.common.SofaConfigs;
2425
import com.alipay.sofa.rpc.common.SofaOptions;
2526
import com.alipay.sofa.rpc.common.utils.CommonUtils;
@@ -28,9 +29,12 @@
2829
import com.alipay.sofa.rpc.config.RegistryConfig;
2930
import com.alipay.sofa.rpc.context.RpcRuntimeContext;
3031
import com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException;
32+
import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent;
33+
import com.alipay.sofa.rpc.dynamic.ConfigChangeType;
3134
import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys;
3235
import com.alipay.sofa.rpc.dynamic.DynamicConfigManager;
3336
import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory;
37+
import com.alipay.sofa.rpc.dynamic.DynamicUrl;
3438
import com.alipay.sofa.rpc.ext.Extension;
3539
import com.alipay.sofa.rpc.invoke.Invoker;
3640
import com.alipay.sofa.rpc.listener.ConfigListener;
@@ -44,8 +48,10 @@
4448

4549
import java.util.ArrayList;
4650
import java.util.HashMap;
51+
import java.util.HashSet;
4752
import java.util.List;
4853
import java.util.Map;
54+
import java.util.Set;
4955
import java.util.concurrent.ConcurrentHashMap;
5056
import java.util.concurrent.ConcurrentMap;
5157
import java.util.concurrent.CountDownLatch;
@@ -54,6 +60,7 @@
5460
import java.util.concurrent.atomic.AtomicInteger;
5561

5662
import static com.alipay.sofa.rpc.common.RpcConstants.REGISTRY_PROTOCOL_DOMAIN;
63+
import static com.alipay.sofa.common.config.SofaConfigs.getOrDefault;
5764

5865
/**
5966
* Default consumer bootstrap.
@@ -146,7 +153,8 @@ public T refer() {
146153
// build cluster
147154
cluster = ClusterFactory.getCluster(this);
148155
// build listeners
149-
consumerConfig.setConfigListener(buildConfigListener(this));
156+
ConfigListener configListener = buildConfigListener(this);
157+
consumerConfig.setConfigListener(configListener);
150158
consumerConfig.setProviderInfoListener(buildProviderInfoListener(this));
151159
// init cluster
152160
cluster.init();
@@ -156,13 +164,25 @@ public T refer() {
156164
proxyIns = (T) ProxyFactory.buildProxy(consumerConfig.getProxy(), consumerConfig.getProxyClass(),
157165
proxyInvoker);
158166

159-
//动态配置
167+
//请求级别动态配置参数
160168
final String dynamicAlias = consumerConfig.getParameter(DynamicConfigKeys.DYNAMIC_ALIAS);
161169
if (StringUtils.isNotBlank(dynamicAlias)) {
162170
final DynamicConfigManager dynamicManager = DynamicConfigManagerFactory.getDynamicManager(
163-
consumerConfig.getAppName(), dynamicAlias);
171+
consumerConfig.getAppName(), dynamicAlias);
164172
dynamicManager.initServiceConfiguration(consumerConfig.getInterfaceId());
165173
}
174+
175+
//接口级别动态配置参数
176+
Boolean dynamicConfigRefreshEnable = getOrDefault(DynamicConfigKeys.DYNAMIC_REFRESH_ENABLE);
177+
String configCenterAddress = getOrDefault(DynamicConfigKeys.CONFIG_CENTER_ADDRESS);
178+
if (dynamicConfigRefreshEnable && StringUtils.isNotBlank(configCenterAddress)) {
179+
DynamicUrl dynamicUrl = new DynamicUrl(configCenterAddress);
180+
//启用接口级别动态配置
181+
final DynamicConfigManager dynamicManager = DynamicConfigManagerFactory.getDynamicManager(
182+
consumerConfig.getAppName(), dynamicUrl.getProtocol());
183+
dynamicManager.addListener(consumerConfig.getInterfaceId(), configListener);
184+
dynamicManager.initServiceConfiguration(consumerConfig.getInterfaceId(), configListener);
185+
}
166186
} catch (Exception e) {
167187
if (cluster != null) {
168188
cluster.destroy();
@@ -438,8 +458,47 @@ public void updateAllProviders(List<ProviderGroup> groups) {
438458
*/
439459
private class ConsumerAttributeListener implements ConfigListener {
440460

461+
// 可以动态配置的选项
462+
private final Set<String> supportDynamicConfigKeys = new HashSet<>();
463+
private final Map<String, String> newValueMap = new HashMap<>();
464+
465+
ConsumerAttributeListener() {
466+
supportDynamicConfigKeys.add(RpcConstants.CONFIG_KEY_TIMEOUT);
467+
supportDynamicConfigKeys.add(RpcConstants.CONFIG_KEY_RETRIES);
468+
supportDynamicConfigKeys.add(RpcConstants.CONFIG_KEY_LOADBALANCER);
469+
}
470+
471+
@Override
472+
public void process(ConfigChangedEvent event) {
473+
// 清除上次的动态配置值缓存
474+
consumerConfig.getDynamicConfigValueCache().clear();
475+
// 获取对应配置项的默认值
476+
for (String key : newValueMap.keySet()) {
477+
if (consumerConfig.getConfigValueCache().get(key) != null) {
478+
newValueMap.put(key, String.valueOf(consumerConfig.getConfigValueCache().get(key)));
479+
} else {
480+
newValueMap.put(key, null);
481+
}
482+
}
483+
if (!event.getChangeType().equals(ConfigChangeType.DELETED)) {
484+
// ADDED or MODIFIED
485+
Map<String, String> dynamicValueMap = event.getDynamicValueMap();
486+
for (String key : dynamicValueMap.keySet()) {
487+
String tempKey = key.lastIndexOf(".") == -1 ? key : key.substring(key.lastIndexOf(".") + 1);
488+
if (supportDynamicConfigKeys.contains(tempKey)) {
489+
String value = dynamicValueMap.get(key);
490+
if (StringUtils.isNotBlank(value)) {
491+
consumerConfig.getDynamicConfigValueCache().put(key, value);
492+
newValueMap.put(key, value);
493+
}
494+
}
495+
}
496+
}
497+
attrUpdated(newValueMap);
498+
}
499+
441500
@Override
442-
public void configChanged(Map newValue) {
501+
public void configChanged(Map newValueMap) {
443502

444503
}
445504

@@ -452,7 +511,7 @@ public synchronized void attrUpdated(Map newValueMap) {
452511
Map<String, String> oldValues = new HashMap<String, String>();
453512
boolean rerefer = false;
454513
try { // 检查是否有变化
455-
// 是否过滤map?
514+
// 是否过滤map?
456515
for (Map.Entry<String, String> entry : newValues.entrySet()) {
457516
String newValue = entry.getValue();
458517
String oldValue = consumerConfig.queryAttribute(entry.getKey());

config/config-apollo/src/main/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManager.java

+108-8
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,30 @@
1616
*/
1717
package com.alipay.sofa.rpc.dynamic.apollo;
1818

19+
import com.alipay.sofa.common.config.SofaConfigs;
1920
import com.alipay.sofa.rpc.auth.AuthRuleGroup;
21+
import com.alipay.sofa.rpc.common.utils.StringUtils;
22+
import com.alipay.sofa.rpc.dynamic.ConfigChangeType;
23+
import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent;
2024
import com.alipay.sofa.rpc.dynamic.DynamicConfigKeyHelper;
25+
import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys;
2126
import com.alipay.sofa.rpc.dynamic.DynamicConfigManager;
2227
import com.alipay.sofa.rpc.dynamic.DynamicHelper;
2328
import com.alipay.sofa.rpc.ext.Extension;
29+
import com.alipay.sofa.rpc.listener.ConfigListener;
30+
import com.alipay.sofa.rpc.log.Logger;
31+
import com.alipay.sofa.rpc.log.LoggerFactory;
2432
import com.ctrip.framework.apollo.Config;
33+
import com.ctrip.framework.apollo.ConfigChangeListener;
2534
import com.ctrip.framework.apollo.ConfigService;
35+
import com.ctrip.framework.apollo.enums.PropertyChangeType;
36+
import com.ctrip.framework.apollo.model.ConfigChange;
37+
38+
import java.util.Collections;
39+
import java.util.Set;
40+
import java.util.concurrent.ConcurrentHashMap;
41+
import java.util.concurrent.ConcurrentMap;
42+
import java.util.concurrent.CopyOnWriteArraySet;
2643

2744
/**
2845
* @author bystander
@@ -34,41 +51,88 @@
3451
@Extension(value = "apollo", override = true)
3552
public class ApolloDynamicConfigManager extends DynamicConfigManager {
3653

37-
private Config config;
54+
private final static Logger LOGGER = LoggerFactory.getLogger(ApolloDynamicConfigManager.class);
55+
56+
private static final String APOLLO_APPID_KEY = "app.id";
57+
58+
private static final String APOLLO_ADDR_KEY = "apollo.meta";
59+
60+
private static final String APOLLO_CLUSTER_KEY = "apollo.cluster";
61+
62+
private static final String APOLLO_PARAM_APPID_KEY = "appId";
63+
64+
private static final String APOLLO_PARAM_CLUSTER_KEY = "cluster";
65+
66+
private static final String APOLLO_PARAM_NAMESPACE_KEY = "namespace";
67+
68+
private static final String APOLLO_PROTOCOL_PREFIX = "http://";
69+
70+
private final ConcurrentMap<String, ApolloListener> watchListenerMap = new ConcurrentHashMap<>();
71+
72+
private final Config config;
3873

3974
protected ApolloDynamicConfigManager(String appName) {
40-
super(appName);
41-
config = ConfigService.getAppConfig();
75+
super(appName, SofaConfigs.getOrCustomDefault(DynamicConfigKeys.CONFIG_CENTER_ADDRESS, ""));
76+
if (getDynamicUrl() != null) {
77+
if (StringUtils.isNotBlank(getDynamicUrl().getParam(APOLLO_PARAM_APPID_KEY))) {
78+
System.setProperty(APOLLO_APPID_KEY, getDynamicUrl().getParam(APOLLO_PARAM_APPID_KEY));
79+
}
80+
if (StringUtils.isNotBlank(getDynamicUrl().getAddress())) {
81+
System.setProperty(APOLLO_ADDR_KEY, APOLLO_PROTOCOL_PREFIX + getDynamicUrl().getAddress());
82+
}
83+
if (StringUtils.isNotBlank(getDynamicUrl().getParam(APOLLO_PARAM_CLUSTER_KEY))) {
84+
System.setProperty(APOLLO_CLUSTER_KEY, getDynamicUrl().getParam(APOLLO_PARAM_CLUSTER_KEY));
85+
}
86+
if (StringUtils.isNotBlank(getDynamicUrl().getParam(APOLLO_PARAM_NAMESPACE_KEY))) {
87+
config = ConfigService.getConfig(getDynamicUrl().getParam(APOLLO_PARAM_NAMESPACE_KEY));
88+
} else {
89+
config = ConfigService.getAppConfig();
90+
}
91+
} else {
92+
config = ConfigService.getAppConfig();
93+
}
4294
}
4395

4496
@Override
4597
public void initServiceConfiguration(String service) {
46-
//TODO not now
98+
// TODO 暂不支持
99+
}
100+
101+
@Override
102+
public void initServiceConfiguration(String service, ConfigListener listener) {
103+
try {
104+
String rawConfig = config.getProperty(service, "");
105+
if (StringUtils.isNotBlank(rawConfig)) {
106+
listener.process(new ConfigChangedEvent(service, rawConfig));
107+
}
108+
} catch (Exception e) {
109+
LOGGER.error("Init service configuration error", e);
110+
}
47111
}
48112

49113
@Override
50114
public String getProviderServiceProperty(String service, String key) {
51115
return config.getProperty(DynamicConfigKeyHelper.buildProviderServiceProKey(service, key),
52-
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
116+
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
53117
}
54118

55119
@Override
56120
public String getConsumerServiceProperty(String service, String key) {
57121
return config.getProperty(DynamicConfigKeyHelper.buildConsumerServiceProKey(service, key),
58-
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
122+
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
59123

60124
}
61125

62126
@Override
63127
public String getProviderMethodProperty(String service, String method, String key) {
64128
return config.getProperty(DynamicConfigKeyHelper.buildProviderMethodProKey(service, method, key),
65-
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
129+
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
66130
}
67131

68132
@Override
69133
public String getConsumerMethodProperty(String service, String method, String key) {
70134
return config.getProperty(DynamicConfigKeyHelper.buildConsumerMethodProKey(service, method, key),
71-
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
135+
DynamicHelper.DEFAULT_DYNAMIC_VALUE);
72136

73137
}
74138

@@ -77,4 +141,40 @@ public AuthRuleGroup getServiceAuthRule(String service) {
77141
//TODO 暂不支持
78142
return null;
79143
}
144+
145+
@Override
146+
public void addListener(String key, ConfigListener listener) {
147+
ApolloListener apolloListener = watchListenerMap.computeIfAbsent(key, k -> new ApolloListener());
148+
apolloListener.addListener(listener);
149+
config.addChangeListener(apolloListener, Collections.singleton(key));
150+
}
151+
152+
public static class ApolloListener implements ConfigChangeListener {
153+
154+
private final Set<ConfigListener> listeners = new CopyOnWriteArraySet<>();
155+
156+
@Override
157+
public void onChange(com.ctrip.framework.apollo.model.ConfigChangeEvent changeEvent) {
158+
for (String key : changeEvent.changedKeys()) {
159+
ConfigChange change = changeEvent.getChange(key);
160+
ConfigChangedEvent event =
161+
new ConfigChangedEvent(key, change.getNewValue(), getChangeType(change));
162+
listeners.forEach(listener -> listener.process(event));
163+
}
164+
}
165+
166+
private ConfigChangeType getChangeType(ConfigChange change) {
167+
if (change.getChangeType() == PropertyChangeType.DELETED) {
168+
return ConfigChangeType.DELETED;
169+
}
170+
if (change.getChangeType() == PropertyChangeType.ADDED) {
171+
return ConfigChangeType.ADDED;
172+
}
173+
return ConfigChangeType.MODIFIED;
174+
}
175+
176+
void addListener(ConfigListener configListener) {
177+
this.listeners.add(configListener);
178+
}
179+
}
80180
}

config/config-apollo/src/test/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManagerTest.java

+12-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717
package com.alipay.sofa.rpc.dynamic.apollo;
1818

19+
import com.alipay.sofa.rpc.dynamic.DynamicConfigManager;
20+
import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory;
1921
import com.alipay.sofa.rpc.dynamic.DynamicHelper;
2022
import com.alipay.sofa.rpc.log.Logger;
2123
import com.alipay.sofa.rpc.log.LoggerFactory;
@@ -24,10 +26,11 @@
2426

2527
public class ApolloDynamicConfigManagerTest {
2628

27-
private final static Logger logger = LoggerFactory
28-
.getLogger(ApolloDynamicConfigManagerTest.class);
29+
private final static Logger logger = LoggerFactory
30+
.getLogger(ApolloDynamicConfigManagerTest.class);
2931

30-
private ApolloDynamicConfigManager apolloDynamicConfigManager = new ApolloDynamicConfigManager("test");
32+
private DynamicConfigManager apolloDynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager("test",
33+
"apollo");
3134

3235
@Test
3336
public void getProviderServiceProperty() {
@@ -37,17 +40,19 @@ public void getProviderServiceProperty() {
3740

3841
@Test
3942
public void getConsumerServiceProperty() {
43+
String result = apolloDynamicConfigManager.getConsumerServiceProperty("serviceName", "timeout");
44+
Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result);
4045
}
4146

4247
@Test
4348
public void getProviderMethodProperty() {
49+
String result = apolloDynamicConfigManager.getProviderMethodProperty("serviceName", "methodName", "timeout");
50+
Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result);
4451
}
4552

4653
@Test
4754
public void getConsumerMethodProperty() {
48-
}
49-
50-
@Test
51-
public void getServiceAuthRule() {
55+
String result = apolloDynamicConfigManager.getConsumerMethodProperty("serviceName", "methodName", "timeout");
56+
Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result);
5257
}
5358
}

0 commit comments

Comments
 (0)