Skip to content

Commit 57fb7a1

Browse files
committed
ApiBoot RateLimiter集成Nacos Config分布式配置中心
1 parent 452a62c commit 57fb7a1

File tree

8 files changed

+421
-30
lines changed

8 files changed

+421
-30
lines changed

api-boot-project/api-boot-plugins/api-boot-plugin-rate-limiter/src/main/java/org/minbox/framework/api/boot/plugin/rate/limiter/ApiBootRateLimiter.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,4 @@ public interface ApiBootRateLimiter {
3737
* @return true : allow access to
3838
*/
3939
boolean tryAcquire(Double QPS, String requestUri);
40-
41-
class Response {
42-
private final boolean allowed;
43-
private final long tokensRemaining;
44-
45-
public Response(boolean allowed, long tokensRemaining) {
46-
this.allowed = allowed;
47-
this.tokensRemaining = tokensRemaining;
48-
}
49-
50-
public boolean isAllowed() {
51-
return allowed;
52-
}
53-
54-
@Override
55-
public String toString() {
56-
return "Response{" +
57-
"allowed=" + allowed +
58-
", tokensRemaining=" + tokensRemaining +
59-
'}';
60-
}
61-
}
6240
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright [2019] [恒宇少年 - 于起宇]
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.minbox.framework.api.boot.plugin.rate.limiter.centre;
19+
20+
import org.minbox.framework.api.boot.common.exception.ApiBootException;
21+
22+
/**
23+
* ApiBoot RateLimiter Distributed Configuration Center
24+
*
25+
* @author:恒宇少年 - 于起宇
26+
* <p>
27+
* DateTime:2019-05-06 17:58
28+
* Blog:http://blog.yuqiyu.com
29+
* WebSite:http://www.jianshu.com/u/092df3f77bca
30+
* Gitee:https://gitee.com/hengboy
31+
* GitHub:https://github.com/hengboy
32+
*/
33+
public interface RateLimiterConfigCentre {
34+
/**
35+
* Getting QPS from Configuration Center
36+
*
37+
* @param configKey config key
38+
* @return QPS value
39+
* @throws ApiBootException ApiBoot Exception
40+
*/
41+
Long getQps(String configKey) throws ApiBootException;
42+
43+
/**
44+
* QPS Setting to Configuration Center
45+
*
46+
* @param configKey config key
47+
* @param QPS QPS value
48+
* @throws ApiBootException ApiBoot Exception
49+
*/
50+
void setQps(String configKey, Long QPS) throws ApiBootException;
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright [2019] [恒宇少年 - 于起宇]
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.minbox.framework.api.boot.plugin.rate.limiter.centre.support;
19+
20+
import org.minbox.framework.api.boot.common.exception.ApiBootException;
21+
import org.minbox.framework.api.boot.plugin.rate.limiter.centre.RateLimiterConfigCentre;
22+
import org.springframework.util.StringUtils;
23+
24+
import java.io.IOException;
25+
import java.io.StringReader;
26+
import java.util.Enumeration;
27+
import java.util.Properties;
28+
29+
/**
30+
* @author:恒宇少年 - 于起宇
31+
* <p>
32+
* DateTime:2019-05-06 18:02
33+
* Blog:http://blog.yuqiyu.com
34+
* WebSite:http://www.jianshu.com/u/092df3f77bca
35+
* Gitee:https://gitee.com/hengboy
36+
* GitHub:https://github.com/hengboy
37+
*/
38+
public abstract class AbstractRateLimiterConfigCentre implements RateLimiterConfigCentre {
39+
40+
/**
41+
* data-id
42+
*/
43+
public static final String DATA_ID = "apiboot-rate-limiter-config";
44+
/**
45+
* default qps
46+
*/
47+
public static final Long DEFAULT_QPS = 0L;
48+
/**
49+
* config properties key and value split
50+
*/
51+
public static final String PROPERTIES_KEY_VALUE_SPLIT = "=";
52+
53+
/**
54+
* data convert to properties
55+
*
56+
* @param content config data content
57+
* @return Properties
58+
*/
59+
protected Properties toProperties(String content) throws ApiBootException {
60+
try {
61+
Properties properties = new Properties();
62+
if (!StringUtils.isEmpty(content)) {
63+
properties.load(new StringReader(content));
64+
}
65+
return properties;
66+
} catch (IOException e) {
67+
throw new ApiBootException(e.getMessage(), e);
68+
}
69+
}
70+
71+
/**
72+
* properties convert to string
73+
*
74+
* @param properties config properties
75+
* @return config string
76+
* @throws ApiBootException ApiBoot Exception
77+
*/
78+
protected String fromProperties(Properties properties) throws ApiBootException {
79+
Enumeration enumeration = properties.propertyNames();
80+
StringBuffer buffer = new StringBuffer();
81+
while (enumeration.hasMoreElements()) {
82+
String propertyKey = String.valueOf(enumeration.nextElement());
83+
String propertyValue = properties.getProperty(propertyKey);
84+
buffer.append(propertyKey);
85+
buffer.append(PROPERTIES_KEY_VALUE_SPLIT);
86+
buffer.append(propertyValue);
87+
buffer.append("\n");
88+
}
89+
return buffer.toString();
90+
}
91+
92+
/**
93+
* format property key
94+
*
95+
* @param requestUri request uri
96+
* @return property key
97+
*/
98+
protected String formatPropertyKey(String requestUri) {
99+
return requestUri.replaceAll("/", ".");
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright [2019] [恒宇少年 - 于起宇]
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.minbox.framework.api.boot.plugin.rate.limiter.centre.support;
19+
20+
import org.minbox.framework.api.boot.common.exception.ApiBootException;
21+
22+
/**
23+
* Apollo Config Support
24+
*
25+
* @author:恒宇少年 - 于起宇
26+
* <p>
27+
* DateTime:2019-05-06 21:52
28+
* Blog:http://blog.yuqiyu.com
29+
* WebSite:http://www.jianshu.com/u/092df3f77bca
30+
* Gitee:https://gitee.com/hengboy
31+
* GitHub:https://github.com/hengboy
32+
*/
33+
public class ApolloRateLimiterConfigCentre extends AbstractRateLimiterConfigCentre {
34+
35+
@Override
36+
public Long getQps(String configKey) throws ApiBootException {
37+
return 0L;
38+
}
39+
40+
@Override
41+
public void setQps(String configKey, Long QPS) throws ApiBootException {
42+
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright [2019] [恒宇少年 - 于起宇]
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.minbox.framework.api.boot.plugin.rate.limiter.centre.support;
19+
20+
import com.alibaba.nacos.api.common.Constants;
21+
import com.alibaba.nacos.api.config.ConfigService;
22+
import com.alibaba.nacos.api.exception.NacosException;
23+
import com.alibaba.nacos.client.config.listener.impl.PropertiesListener;
24+
import com.alibaba.nacos.spring.util.NacosUtils;
25+
import org.minbox.framework.api.boot.common.exception.ApiBootException;
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
import org.springframework.util.Assert;
29+
import org.springframework.util.StringUtils;
30+
31+
import java.util.Properties;
32+
33+
/**
34+
* Nacos Config Support
35+
*
36+
* @author:恒宇少年 - 于起宇
37+
* <p>
38+
* DateTime:2019-05-06 18:02
39+
* Blog:http://blog.yuqiyu.com
40+
* WebSite:http://www.jianshu.com/u/092df3f77bca
41+
* Gitee:https://gitee.com/hengboy
42+
* GitHub:https://github.com/hengboy
43+
*/
44+
public class NacosRateLimiterConfigCentre extends AbstractRateLimiterConfigCentre {
45+
/**
46+
* logger instance
47+
*/
48+
static Logger logger = LoggerFactory.getLogger(NacosRateLimiterConfigCentre.class);
49+
/**
50+
* Nacos Config Service
51+
*/
52+
private ConfigService configService;
53+
/**
54+
* rate limiter config properties
55+
*/
56+
private Properties configProperties;
57+
58+
public NacosRateLimiterConfigCentre(ConfigService configService) {
59+
this.configService = configService;
60+
61+
// check configService not null
62+
Assert.notNull(configService, "ConfigService is required.");
63+
64+
// load config data from nacos
65+
String configData = loadConfigData();
66+
67+
// convert config data to properties
68+
this.configProperties = toProperties(configData);
69+
logger.info("ApiBoot RateLimiter nacos config properties load complete.");
70+
71+
// Enable monitoring of receiving configuration changes
72+
addConfigChangeListener();
73+
}
74+
75+
/**
76+
* get QPS config from nacos
77+
* for example properties:
78+
* 1. /user/list -> .user.list: 5
79+
* 2. /user/detail -> .user.detail: 10
80+
*
81+
* @param configKey config key
82+
* @return qps
83+
* @throws ApiBootException
84+
*/
85+
@Override
86+
public Long getQps(String configKey) throws ApiBootException {
87+
try {
88+
String propertyKey = formatPropertyKey(configKey);
89+
String qps = this.configProperties.getProperty(propertyKey);
90+
if (!StringUtils.isEmpty(qps)) {
91+
return Long.valueOf(qps);
92+
}
93+
} catch (Exception e) {
94+
logger.error(e.getMessage(), e);
95+
}
96+
return DEFAULT_QPS;
97+
}
98+
99+
/**
100+
* set qps config to nacos
101+
*
102+
* @param configKey config key
103+
* @param QPS QPS value
104+
* @throws ApiBootException
105+
*/
106+
@Override
107+
public void setQps(String configKey, Long QPS) throws ApiBootException {
108+
try {
109+
String propertyKey = formatPropertyKey(configKey);
110+
// update local cache config
111+
this.configProperties.setProperty(propertyKey, String.valueOf(QPS));
112+
// convert properties to string
113+
String configData = fromProperties(this.configProperties);
114+
if (!StringUtils.isEmpty(configData)) {
115+
// execute publish config
116+
this.configService.publishConfig(DATA_ID, Constants.DEFAULT_GROUP, configData);
117+
logger.info("ApiBoot RateLimiter nacos config publish successfully.");
118+
}
119+
} catch (Exception e) {
120+
throw new ApiBootException(e.getMessage(), e);
121+
}
122+
}
123+
124+
/**
125+
* load rate limiter config data
126+
*
127+
* @return config data
128+
* @throws ApiBootException ApiBoot Exception
129+
*/
130+
protected String loadConfigData() throws ApiBootException {
131+
try {
132+
return configService.getConfig(DATA_ID, Constants.DEFAULT_GROUP, NacosUtils.DEFAULT_TIMEOUT);
133+
} catch (NacosException e) {
134+
logger.error(e.getMessage(), e);
135+
}
136+
throw new ApiBootException("Load ApiBoot RateLimiter config data fail.");
137+
}
138+
139+
/**
140+
* add config change listener
141+
* If you modify the configuration through the nacos configuration center,
142+
* listen to the changes and update the content Properties.
143+
*/
144+
protected void addConfigChangeListener() throws ApiBootException {
145+
try {
146+
configService.addListener(DATA_ID, Constants.DEFAULT_GROUP, new PropertiesListener() {
147+
/**
148+
* Update local properties
149+
* @param properties Changed configuration properties
150+
*/
151+
@Override
152+
public void innerReceive(Properties properties) {
153+
configProperties = properties;
154+
logger.info("Update local current RateLimiter configuration is complete,content:{}", properties.toString());
155+
}
156+
});
157+
} catch (Exception e) {
158+
logger.error("Configuration change listener failed to open.", e);
159+
}
160+
}
161+
}

0 commit comments

Comments
 (0)