2024-05-08 19:10:15 +08:00
|
|
|
|
package com.sf.vertx.handle;
|
|
|
|
|
|
2024-05-09 18:01:15 +08:00
|
|
|
|
import java.time.Duration;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import java.util.ArrayList;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import java.util.Arrays;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson2.JSON;
|
|
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
|
|
import com.alibaba.fastjson2.TypeReference;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import com.hazelcast.config.Config;
|
|
|
|
|
import com.hazelcast.config.JoinConfig;
|
|
|
|
|
import com.hazelcast.config.NetworkConfig;
|
|
|
|
|
import com.hazelcast.config.TcpIpConfig;
|
2024-05-31 09:56:02 +08:00
|
|
|
|
import com.sf.vertx.api.pojo.ApiConfig;
|
|
|
|
|
import com.sf.vertx.api.pojo.AppConfig;
|
|
|
|
|
import com.sf.vertx.api.pojo.DataSecurity;
|
|
|
|
|
import com.sf.vertx.api.pojo.Node;
|
|
|
|
|
import com.sf.vertx.api.pojo.RouteContent;
|
|
|
|
|
import com.sf.vertx.api.pojo.SacService;
|
|
|
|
|
import com.sf.vertx.api.pojo.Strategy;
|
|
|
|
|
import com.sf.vertx.api.pojo.VertxConfig;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import com.sf.vertx.arithmetic.roundRobin.SacLoadBalancing;
|
|
|
|
|
import com.sf.vertx.constans.RedisKeyConfig;
|
2024-05-31 09:56:02 +08:00
|
|
|
|
import com.sf.vertx.enums.GatewayServiceType;
|
2024-05-31 16:15:08 +08:00
|
|
|
|
import com.sf.vertx.httpproxy.HttpProxy;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import com.sf.vertx.init.SacVertxConfig;
|
|
|
|
|
import com.sf.vertx.pojo.ClusterEventMsg;
|
2024-06-03 14:02:35 +08:00
|
|
|
|
import com.sf.vertx.pojo.SacCircuitBreaker;
|
2024-05-09 18:01:15 +08:00
|
|
|
|
import com.sf.vertx.pojo.SacCurrentLimiting;
|
2024-05-31 09:56:02 +08:00
|
|
|
|
import com.sf.vertx.security.MainSecurity;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import com.sf.vertx.utils.ProxyTool;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.collection.ConcurrentHashSet;
|
2024-05-09 18:01:15 +08:00
|
|
|
|
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
|
|
|
|
|
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import io.vertx.circuitbreaker.CircuitBreaker;
|
|
|
|
|
import io.vertx.circuitbreaker.CircuitBreakerOptions;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import io.vertx.core.Future;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import io.vertx.core.Vertx;
|
|
|
|
|
import io.vertx.core.VertxOptions;
|
2024-05-31 09:56:02 +08:00
|
|
|
|
import io.vertx.core.http.HttpClient;
|
|
|
|
|
import io.vertx.core.http.HttpServer;
|
|
|
|
|
import io.vertx.core.http.HttpServerOptions;
|
2024-05-14 13:44:21 +08:00
|
|
|
|
import io.vertx.core.net.JksOptions;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import io.vertx.core.spi.cluster.ClusterManager;
|
2024-05-11 14:57:45 +08:00
|
|
|
|
import io.vertx.ext.web.Route;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import io.vertx.ext.web.Router;
|
|
|
|
|
import io.vertx.ext.web.client.WebClient;
|
2024-05-31 09:56:02 +08:00
|
|
|
|
import io.vertx.ext.web.handler.CorsHandler;
|
|
|
|
|
import io.vertx.ext.web.handler.HttpException;
|
|
|
|
|
import io.vertx.httpproxy.ProxyContext;
|
|
|
|
|
import io.vertx.httpproxy.ProxyInterceptor;
|
|
|
|
|
import io.vertx.httpproxy.ProxyResponse;
|
2024-05-11 13:16:10 +08:00
|
|
|
|
import io.vertx.spi.cluster.hazelcast.HazelcastClusterManager;
|
2024-05-08 19:10:15 +08:00
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* vertx配置维护
|
2024-05-21 14:17:59 +08:00
|
|
|
|
*
|
2024-05-08 19:10:15 +08:00
|
|
|
|
* @author xy
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
@Slf4j
|
2024-05-10 10:28:52 +08:00
|
|
|
|
public class AppConfigHandler {
|
2024-05-31 09:56:02 +08:00
|
|
|
|
private static VertxConfig VERTX_CONFIG = new VertxConfig();
|
|
|
|
|
public static Vertx VERTX;
|
|
|
|
|
private static SacVertxConfig sacVertxConfig;
|
|
|
|
|
private static RedisTemplate<String, String> redisTemplate;
|
|
|
|
|
private static final ConcurrentHashMap<String, AppConfig> CACHE_APP_CONFIG_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// global api config appCode - RateLimiterRegistry
|
|
|
|
|
private static final ConcurrentHashMap<String, SacCurrentLimiting> GLOBAL_API_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// global app config appCode - Strategy
|
|
|
|
|
private static final ConcurrentHashMap<String, SacCurrentLimiting> GLOBAL_APP_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// appCode:apiCode:SacLoadBalancing
|
|
|
|
|
private static ConcurrentHashMap<String, SacLoadBalancing> LOADBALANCING_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// appCode:apiCode - ApiConfig
|
|
|
|
|
private static ConcurrentHashMap<String, ApiConfig> APICODE_CONFIG_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// apiCode限流配置 appCode:apiCode - RateLimiterRegistry
|
|
|
|
|
private static ConcurrentHashMap<String, SacCurrentLimiting> APICODE_CONFIG_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// 服务类型, apiCode限流配置 appCode:apiCode - 服务类型,SAC=SAC规范服务,OPEN=开放服务
|
|
|
|
|
private static ConcurrentHashMap<String, String> APICODE_CONFIG_SERVICE_TYPE_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
// 负载均衡路由类型 appCode:apiCode - routerType
|
|
|
|
|
// 执行流程 routerType= <br/>
|
|
|
|
|
// 1、serviceNodel="NORMAL", serviceNodel="ROUTE" and RouteType = "WEIGHT_ROUTE"
|
|
|
|
|
// <br/>
|
|
|
|
|
// return LOADBALANCING_MAP
|
|
|
|
|
// 2、serviceNodel="ROUTE", RouteType = "HEADER_ROUTE" <br/>
|
|
|
|
|
// return APICODE_CONFIG_ROUTERCONENT_MAP
|
|
|
|
|
private static ConcurrentHashMap<String, Integer> APICODE_CONFIG_ROUTERTYPE_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
private static ConcurrentHashMap<String, List<RouteContent>> APICODE_CONFIG_HEADER_ROUTERCONENT_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
// apiCode熔断配置 appCode:apiCode - CircuitBreaker
|
2024-06-03 14:02:35 +08:00
|
|
|
|
private static ConcurrentHashMap<String, SacCircuitBreaker> APICODE_CONFIG_CIRCUIT_BREAKER_MAP = new ConcurrentHashMap<>();
|
2024-05-31 09:56:02 +08:00
|
|
|
|
|
|
|
|
|
// apicode uri = * - appConfig
|
|
|
|
|
private static ConcurrentHashMap<String, AppConfig> APICODE_APPCONFIG_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
// 禁用appCode
|
|
|
|
|
private static ConcurrentHashSet<String> DISABLED_APPCODE = new ConcurrentHashSet<String>();
|
|
|
|
|
|
|
|
|
|
public static AppConfig getAppConfigByDomain(String domain) {
|
|
|
|
|
return APICODE_APPCONFIG_MAP.get(domain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Integer routerType(String key) {
|
|
|
|
|
return APICODE_CONFIG_ROUTERTYPE_MAP.get(key) != null ? APICODE_CONFIG_ROUTERTYPE_MAP.get(key) : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static List<RouteContent> routerHeaderConentList(String key) {
|
|
|
|
|
return APICODE_CONFIG_HEADER_ROUTERCONENT_MAP.get(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Boolean isServiceTypeOpen(String key) {
|
|
|
|
|
return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null
|
2024-06-03 14:02:35 +08:00
|
|
|
|
&& StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), GatewayServiceType.OPEN.getCode());
|
2024-05-31 09:56:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Boolean isServiceTypeSac(String key) {
|
|
|
|
|
return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null
|
2024-06-03 14:02:35 +08:00
|
|
|
|
&& StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), GatewayServiceType.SAC.getCode());
|
2024-05-31 09:56:02 +08:00
|
|
|
|
}
|
2024-06-03 14:02:35 +08:00
|
|
|
|
|
2024-05-31 09:56:02 +08:00
|
|
|
|
public static String getServiceType(String key) {
|
|
|
|
|
return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String sacResponseHeaderKey() {
|
|
|
|
|
return sacVertxConfig.getSacResponseHeaderKey();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String rpcUri() {
|
|
|
|
|
return sacVertxConfig.getRpcUri();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void removeDisabledAppcode(String appCode) {
|
|
|
|
|
DISABLED_APPCODE.remove(appCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void addDisabledAppcode(String appCode) {
|
|
|
|
|
DISABLED_APPCODE.add(appCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isDisabledAppcode(String appCode) {
|
|
|
|
|
return DISABLED_APPCODE.contains(appCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static SacCurrentLimiting getGlobalAppCurrentLimitingConfig(String appCode) {
|
|
|
|
|
return GLOBAL_APP_CURRENT_LIMITING_MAP.get(appCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static AppConfig getAppConfig(String appCode) {
|
|
|
|
|
return CACHE_APP_CONFIG_MAP.get(appCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void init(RedisTemplate<String, String> _redisTemplate, SacVertxConfig _sacVertxConfig) {
|
|
|
|
|
redisTemplate = _redisTemplate;
|
|
|
|
|
sacVertxConfig = _sacVertxConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isDataSecurity(String appCode) {
|
|
|
|
|
return CACHE_APP_CONFIG_MAP.get(appCode) != null && CACHE_APP_CONFIG_MAP.get(appCode).getDataSecurity() != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isApiCodeCircuitBreaker(String key) {
|
|
|
|
|
return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key) != null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-03 14:02:35 +08:00
|
|
|
|
public static SacCircuitBreaker getApiCodeCircuitBreaker(String key) {
|
2024-05-31 09:56:02 +08:00
|
|
|
|
return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* 优先apicode配置限流、无法找到匹配全局限流
|
|
|
|
|
*
|
|
|
|
|
* @param appCode
|
|
|
|
|
* @param apiCode
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static SacCurrentLimiting getApiCurrentLimiting(String appCode, String apiCode) {
|
|
|
|
|
String key = appCode + ":" + apiCode;
|
|
|
|
|
SacCurrentLimiting sacCurrentLimiting = APICODE_CONFIG_CURRENT_LIMITING_MAP.get(key) != null
|
|
|
|
|
? APICODE_CONFIG_CURRENT_LIMITING_MAP.get(key)
|
|
|
|
|
: null;
|
|
|
|
|
sacCurrentLimiting = sacCurrentLimiting != null ? sacCurrentLimiting
|
|
|
|
|
: (GLOBAL_API_CURRENT_LIMITING_MAP.get(appCode) != null ? GLOBAL_API_CURRENT_LIMITING_MAP.get(appCode)
|
|
|
|
|
: null);
|
|
|
|
|
return sacCurrentLimiting;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static VertxConfig getVertxConfig() {
|
|
|
|
|
return VERTX_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String getAppCodeHeaderKey() {
|
|
|
|
|
return VERTX_CONFIG.getAppCodeHeaderKey();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String getApiCodeHeaderKey() {
|
|
|
|
|
return VERTX_CONFIG.getApiCodeHeaderKey();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static SacLoadBalancing getLoadBalancing(String key) {
|
|
|
|
|
return LOADBALANCING_MAP.get(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ApiConfig getApicodeConfig(String key) {
|
|
|
|
|
return APICODE_CONFIG_MAP.get(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Long getApicodeConfigTimeOut(String key) {
|
|
|
|
|
return APICODE_CONFIG_MAP.get(key) != null ? APICODE_CONFIG_MAP.get(key).getTimeout() : 3000L;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static RateLimiterRegistry createRateLimiter(Strategy strategy) {
|
|
|
|
|
RateLimiterConfig config = RateLimiterConfig.custom()
|
|
|
|
|
.limitRefreshPeriod(Duration.ofSeconds(strategy.getTimeWindow()))
|
|
|
|
|
.limitForPeriod(strategy.getThreshold()).timeoutDuration(Duration.ofMillis(0)).build();
|
|
|
|
|
RateLimiterRegistry registry = RateLimiterRegistry.of(config);
|
|
|
|
|
return registry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void initRateLimiter(String appCode, Strategy strategy,
|
|
|
|
|
ConcurrentHashMap<String, SacCurrentLimiting> map) {
|
|
|
|
|
RateLimiterRegistry registry = createRateLimiter(strategy);
|
|
|
|
|
SacCurrentLimiting sacCurrentLimiting = new SacCurrentLimiting();
|
|
|
|
|
sacCurrentLimiting.setStrategy(strategy);
|
|
|
|
|
sacCurrentLimiting.setRegistry(registry);
|
|
|
|
|
map.put(appCode, sacCurrentLimiting);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* 从redis加载数据
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public static void initAllAppConfig() {
|
|
|
|
|
Set<String> set = redisTemplate.opsForZSet().range(RedisKeyConfig.APP_CONFIG_SET_KEY, 0, -1);
|
|
|
|
|
for (String appCode : set) {
|
|
|
|
|
AppConfigHandler.initAppConfig(appCode, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* 加载vertx配置
|
|
|
|
|
*/
|
|
|
|
|
public static void initVertxConfig() {
|
|
|
|
|
String vertxConfigKey = RedisKeyConfig.VERTX_CONFIG_STRING_KEY;
|
|
|
|
|
String vertxConfigValue = redisTemplate.opsForValue().get(vertxConfigKey);
|
|
|
|
|
if (StringUtils.isNotBlank(vertxConfigValue)) {
|
|
|
|
|
VERTX_CONFIG = JSONObject.parseObject(vertxConfigValue, VertxConfig.class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void delAppConfigCache(String appCode) {
|
|
|
|
|
AppConfig appConfig = CACHE_APP_CONFIG_MAP.get(appCode);
|
|
|
|
|
if (appConfig != null) {
|
|
|
|
|
// app、api默认限流
|
|
|
|
|
GLOBAL_API_CURRENT_LIMITING_MAP.remove(appCode);
|
|
|
|
|
GLOBAL_APP_CURRENT_LIMITING_MAP.remove(appCode);
|
|
|
|
|
for (SacService sacService : appConfig.getService()) {
|
|
|
|
|
if (sacService.getApiConfig() != null && sacService.getApiConfig().size() > 0) {
|
|
|
|
|
for (ApiConfig apiConfig : sacService.getApiConfig()) {
|
|
|
|
|
String key = appCode + ":" + apiConfig.getApiCode();
|
|
|
|
|
APICODE_CONFIG_MAP.remove(key);
|
|
|
|
|
LOADBALANCING_MAP.remove(key);
|
|
|
|
|
APICODE_CONFIG_SERVICE_TYPE_MAP.remove(key);
|
|
|
|
|
APICODE_CONFIG_CURRENT_LIMITING_MAP.remove(key);
|
|
|
|
|
APICODE_APPCONFIG_MAP.remove(apiConfig.getApiCode());
|
|
|
|
|
String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER";
|
2024-06-03 14:02:35 +08:00
|
|
|
|
SacCircuitBreaker sacCircuitBreaker = APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key);
|
|
|
|
|
if (sacCircuitBreaker != null) {
|
|
|
|
|
if(sacCircuitBreaker.getCircuitBreaker() != null) {
|
|
|
|
|
sacCircuitBreaker.getCircuitBreaker().close();
|
|
|
|
|
}
|
2024-05-31 09:56:02 +08:00
|
|
|
|
APICODE_CONFIG_CIRCUIT_BREAKER_MAP.remove(keyCircuitBreaker);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 应用配置
|
|
|
|
|
CACHE_APP_CONFIG_MAP.remove(appCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void initAppConfig(String appCode, boolean isDelLocalCache) {
|
|
|
|
|
// 是否需要先删除
|
|
|
|
|
if (isDelLocalCache) {
|
|
|
|
|
delAppConfigCache(appCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String appCodeKey = RedisKeyConfig.APP_CONFIG_PREFIX_KEY + ":" + appCode;
|
|
|
|
|
String appCodeValue = redisTemplate.opsForValue().get(appCodeKey);
|
|
|
|
|
if (StringUtils.isNotBlank(appCodeValue)) {
|
|
|
|
|
AppConfig appConfig = JSON.parseObject(appCodeValue, new TypeReference<AppConfig>() {
|
|
|
|
|
});
|
|
|
|
|
CACHE_APP_CONFIG_MAP.put(appCode, appConfig);
|
|
|
|
|
|
|
|
|
|
// app、api默认限流
|
|
|
|
|
if (appConfig.getApiCurrentLimitingConfig() != null) {
|
|
|
|
|
initRateLimiter(appCode, appConfig.getApiCurrentLimitingConfig(), GLOBAL_API_CURRENT_LIMITING_MAP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (appConfig.getAppCurrentLimitingConfig() != null) {
|
|
|
|
|
initRateLimiter(appCode, appConfig.getAppCurrentLimitingConfig(), GLOBAL_APP_CURRENT_LIMITING_MAP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// app router负载均衡
|
|
|
|
|
List<RouteContent> routeContentList = null;
|
|
|
|
|
for (SacService sacService : appConfig.getService()) {
|
|
|
|
|
int routerType = 1;
|
|
|
|
|
List<Node> nodeList = new ArrayList<>();
|
|
|
|
|
// 获取service模式
|
|
|
|
|
if (StringUtils.equals(sacService.getServiceModel(), "NORMAL")) {
|
|
|
|
|
Node node = new Node();
|
|
|
|
|
node.setIp(sacService.getServerAddress().getHost());
|
|
|
|
|
node.setPort(sacService.getServerAddress().getPort());
|
|
|
|
|
node.setWeight(0);
|
|
|
|
|
node.setProtocol(sacService.getServerAddress().getProtocol());
|
|
|
|
|
nodeList.add(node);
|
|
|
|
|
} else if (StringUtils.equals(sacService.getServiceModel(), "ROUTE")) {
|
|
|
|
|
if (sacService.getRouteConfig() != null
|
|
|
|
|
&& StringUtils.equals(sacService.getRouteConfig().getRouteType(), "WEIGHT_ROUTE")) {
|
|
|
|
|
for (RouteContent routeContent : sacService.getRouteConfig().getRouteContent()) {
|
|
|
|
|
Node node = new Node();
|
|
|
|
|
node.setIp(routeContent.getServerAddress().getHost());
|
|
|
|
|
node.setPort(routeContent.getServerAddress().getPort());
|
|
|
|
|
node.setWeight(routeContent.getWeight() != null && routeContent.getWeight() > 0
|
|
|
|
|
? routeContent.getWeight()
|
|
|
|
|
: 1);
|
|
|
|
|
node.setProtocol(routeContent.getServerAddress().getProtocol());
|
|
|
|
|
nodeList.add(node);
|
|
|
|
|
}
|
|
|
|
|
} else if (sacService.getRouteConfig() != null
|
|
|
|
|
&& StringUtils.equals(sacService.getRouteConfig().getRouteType(), "HEADER_ROUTE")) {
|
|
|
|
|
routerType = 2;
|
|
|
|
|
routeContentList = sacService.getRouteConfig().getRouteContent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化apiConfig
|
|
|
|
|
if (sacService.getApiConfig() != null && sacService.getApiConfig().size() > 0) {
|
|
|
|
|
for (ApiConfig apiConfig : sacService.getApiConfig()) {
|
|
|
|
|
String key = appCode + ":" + apiConfig.getApiCode();
|
|
|
|
|
APICODE_CONFIG_MAP.put(key, apiConfig);
|
|
|
|
|
if (sacService.getServiceType() != null) {
|
|
|
|
|
APICODE_CONFIG_SERVICE_TYPE_MAP.put(key, sacService.getServiceType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OPEN模式, 域名映射
|
2024-06-03 14:02:35 +08:00
|
|
|
|
if (isServiceTypeOpen(key)) {
|
2024-05-31 09:56:02 +08:00
|
|
|
|
APICODE_APPCONFIG_MAP.put(apiConfig.getApiCode(), appConfig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 负载均衡模式
|
|
|
|
|
APICODE_CONFIG_ROUTERTYPE_MAP.put(key, routerType);
|
|
|
|
|
switch (routerType) {
|
|
|
|
|
case 1:
|
|
|
|
|
if (nodeList.size() > 0) {
|
|
|
|
|
// 初始化负载均衡算法
|
|
|
|
|
SacLoadBalancing sacLoadBalancing = ProxyTool.roundRobin(nodeList);
|
|
|
|
|
LOADBALANCING_MAP.put(key, sacLoadBalancing);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
APICODE_CONFIG_HEADER_ROUTERCONENT_MAP.put(key, routeContentList);
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (apiConfig.getStrategy() != null && apiConfig.getStrategy().size() > 0) {
|
|
|
|
|
for (Strategy strategy : apiConfig.getStrategy()) {
|
|
|
|
|
if (StringUtils.equals(strategy.getType(), "CURRENT_LIMITING")) {
|
|
|
|
|
RateLimiterRegistry registry = createRateLimiter(strategy);
|
|
|
|
|
SacCurrentLimiting sacCurrentLimiting = new SacCurrentLimiting();
|
|
|
|
|
sacCurrentLimiting.setStrategy(strategy);
|
|
|
|
|
sacCurrentLimiting.setRegistry(registry);
|
|
|
|
|
APICODE_CONFIG_CURRENT_LIMITING_MAP.put(key, sacCurrentLimiting);
|
|
|
|
|
} else if (StringUtils.equals(strategy.getType(), "CIRCUIT_BREAKER")) {
|
|
|
|
|
String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER";
|
2024-05-08 19:10:15 +08:00
|
|
|
|
// interfaceBreaker = CircuitBreaker.create("interfaceBreaker", VERTX,
|
|
|
|
|
// new CircuitBreakerOptions().setMaxFailures(3).setMaxRetries(5).setTimeout(2000)
|
|
|
|
|
// .setFallbackOnFailure(true)
|
|
|
|
|
// ).openHandler(v -> {
|
|
|
|
|
// log.info("Circuit opened");
|
|
|
|
|
// }).closeHandler(v -> {
|
|
|
|
|
// log.info("Circuit closed");
|
|
|
|
|
// });//.retryPolicy(retryCount -> retryCount * 100L);
|
|
|
|
|
|
2024-05-31 09:56:02 +08:00
|
|
|
|
// apiCode熔断
|
|
|
|
|
CircuitBreaker circuitBreaker = CircuitBreaker
|
|
|
|
|
.create(keyCircuitBreaker + "-circuit-breaker", VERTX,
|
|
|
|
|
new CircuitBreakerOptions().setMaxFailures(strategy.getThreshold()) // 最大失败数
|
|
|
|
|
.setFailuresRollingWindow(strategy.getTimeWindow() * 1000) // 毫秒
|
|
|
|
|
// .setTimeout(apiConfig.getTimeout()) // 超时时间,不要开启,
|
|
|
|
|
// 配置会设置接口超时, 这个参数有bug,半开超时会卡死
|
|
|
|
|
.setFallbackOnFailure(true) // 失败后是否调用回退函数(fallback)
|
|
|
|
|
.setResetTimeout(strategy.getRecovery_interval() * 1000) // 在开启状态下,尝试重试之前所需时间
|
|
|
|
|
).openHandler(v -> {
|
|
|
|
|
log.info(keyCircuitBreaker + " Circuit open");
|
|
|
|
|
}).halfOpenHandler(v -> {
|
2024-06-03 14:02:35 +08:00
|
|
|
|
log.info(keyCircuitBreaker + " Circuit halfOpen");
|
2024-05-31 09:56:02 +08:00
|
|
|
|
}).closeHandler(v -> {
|
2024-06-03 14:02:35 +08:00
|
|
|
|
log.info(keyCircuitBreaker + " Circuit close");
|
2024-05-31 09:56:02 +08:00
|
|
|
|
});
|
2024-06-03 14:02:35 +08:00
|
|
|
|
SacCircuitBreaker sacCircuitBreaker = new SacCircuitBreaker();
|
|
|
|
|
sacCircuitBreaker.setCircuitBreaker(circuitBreaker);
|
|
|
|
|
sacCircuitBreaker.setStrategy(strategy);
|
|
|
|
|
APICODE_CONFIG_CIRCUIT_BREAKER_MAP.put(key, sacCircuitBreaker);
|
2024-05-31 09:56:02 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void createVertx() {
|
|
|
|
|
// TODO 编解码线程池,后面优化协程等方式
|
|
|
|
|
VertxOptions vertxOptions = new VertxOptions();
|
|
|
|
|
loadVertxOptions(vertxOptions);
|
|
|
|
|
VERTX = Vertx.vertx(vertxOptions);
|
|
|
|
|
createVertxRouter();
|
|
|
|
|
consumerClusterEventMsg();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Config hazelcastConfig(SacVertxConfig sacVertxConfig) {
|
|
|
|
|
// 集群
|
|
|
|
|
Config hazelcastConfig = new Config();
|
|
|
|
|
hazelcastConfig.setClusterName(sacVertxConfig.getClusterName()); // 集群名字
|
|
|
|
|
NetworkConfig networkConfig = new NetworkConfig();
|
|
|
|
|
networkConfig.setPort(sacVertxConfig.getNetworkPort());
|
|
|
|
|
networkConfig.setPortAutoIncrement(sacVertxConfig.isPortAutoIncrement());
|
|
|
|
|
|
|
|
|
|
JoinConfig join = new JoinConfig();
|
|
|
|
|
TcpIpConfig tcpIpConfig = new TcpIpConfig();
|
|
|
|
|
tcpIpConfig.setEnabled(true);
|
|
|
|
|
String[] clusterIps = sacVertxConfig.getClusterIp().split(",");
|
|
|
|
|
List<String> members = Arrays.asList(clusterIps);
|
|
|
|
|
tcpIpConfig.setMembers(members);
|
|
|
|
|
join.setTcpIpConfig(tcpIpConfig);
|
|
|
|
|
networkConfig.setJoin(join);
|
|
|
|
|
hazelcastConfig.setNetworkConfig(networkConfig);
|
|
|
|
|
|
|
|
|
|
// TODO 还有问题,不会使用
|
2024-05-11 16:40:25 +08:00
|
|
|
|
// ManagementCenterConfig managementCenterConfig = new ManagementCenterConfig();
|
|
|
|
|
// Set<String> interfaces = new HashSet<>();
|
|
|
|
|
// interfaces.add("http://192.168.1.68:8080/mancenter");
|
|
|
|
|
// managementCenterConfig.setTrustedInterfaces(interfaces);
|
|
|
|
|
// hazelcastConfig.setManagementCenterConfig(managementCenterConfig);
|
2024-05-31 09:56:02 +08:00
|
|
|
|
return hazelcastConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void createHazelcastClusterVertx() {
|
|
|
|
|
Config hazelcastConfig = hazelcastConfig(sacVertxConfig);
|
|
|
|
|
ClusterManager hazelcastClusterManager = new HazelcastClusterManager(hazelcastConfig);
|
|
|
|
|
// TODO 编解码线程池,后面优化协程等方式
|
|
|
|
|
VertxOptions vertxOptions = new VertxOptions();
|
|
|
|
|
loadVertxOptions(vertxOptions);
|
|
|
|
|
vertxOptions.setClusterManager(hazelcastClusterManager);
|
|
|
|
|
Vertx.clusteredVertx(vertxOptions, res -> {
|
|
|
|
|
if (res.succeeded()) {
|
|
|
|
|
VERTX = res.result();
|
|
|
|
|
log.info("hazelcastClusterManager create success");
|
|
|
|
|
createVertxRouter();
|
|
|
|
|
consumerClusterEventMsg();
|
|
|
|
|
} else {
|
|
|
|
|
res.cause().printStackTrace();
|
|
|
|
|
log.info("hazelcastClusterManager create failure");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void consumerClusterEventMsg() {
|
|
|
|
|
// 订阅消息
|
|
|
|
|
VERTX.eventBus().consumer("sac_cluster_event", message -> {
|
|
|
|
|
if (message.body() != null) {
|
|
|
|
|
ClusterEventMsg msg = JSONObject.parseObject(message.body().toString(), ClusterEventMsg.class);
|
|
|
|
|
log.info("Received message: {}", msg);
|
|
|
|
|
// message.reply("我是返回数据===" + message.body());
|
|
|
|
|
if (msg.getType() == 1) {
|
|
|
|
|
if (msg.getOperation() == 1) {
|
|
|
|
|
// 初始化AppConfig本地缓存
|
|
|
|
|
AppConfigHandler.initAppConfig(msg.getAppCode(), true);
|
|
|
|
|
} else if (msg.getOperation() == 3) {
|
|
|
|
|
// 删除本地缓存
|
|
|
|
|
delAppConfigCache(msg.getAppCode());
|
|
|
|
|
} else if (msg.getOperation() == 4) {
|
|
|
|
|
// 禁用app
|
|
|
|
|
addDisabledAppcode(msg.getAppCode());
|
|
|
|
|
} else if (msg.getOperation() == 5) {
|
|
|
|
|
// 启用app
|
|
|
|
|
removeDisabledAppcode(msg.getAppCode());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* 发布消息,订阅消息
|
|
|
|
|
*
|
|
|
|
|
* @param msg
|
|
|
|
|
*/
|
|
|
|
|
public static void publishClusterEventMsg(ClusterEventMsg msg) {
|
|
|
|
|
VERTX.eventBus().publish("sac_cluster_event", JSONObject.toJSONString(msg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void createVertxRouter() {
|
|
|
|
|
// consul初始化
|
|
|
|
|
// ConsulHandler.init(vertx);
|
|
|
|
|
|
|
|
|
|
// 从redis同步app配置
|
|
|
|
|
initAllAppConfig();
|
|
|
|
|
|
|
|
|
|
VertxConfig vertxConfig = AppConfigHandler.getVertxConfig();
|
|
|
|
|
// 创建HTTP监听
|
|
|
|
|
// 所有ip都能访问
|
|
|
|
|
HttpServerOptions httpServerOptions = new HttpServerOptions().setHost("0.0.0.0");
|
|
|
|
|
if (sacVertxConfig.isSSLs()) {
|
|
|
|
|
httpServerOptions.setSsl(true)
|
|
|
|
|
.setKeyStoreOptions(new JksOptions().setPassword("changeit").setPath("keystore.jks"));
|
|
|
|
|
}
|
|
|
|
|
HttpServer server = VERTX.createHttpServer(httpServerOptions);
|
|
|
|
|
Router mainHttpRouter = Router.router(VERTX);
|
|
|
|
|
Integer serverPort = vertxConfig.getPort() == null ? sacVertxConfig.getPort() : vertxConfig.getPort();
|
|
|
|
|
log.info("serverPort:{}", serverPort);
|
|
|
|
|
server.requestHandler(mainHttpRouter).listen(serverPort, h -> {
|
|
|
|
|
if (h.succeeded()) {
|
|
|
|
|
log.info("HTTP端口监听成功:{}", serverPort);
|
|
|
|
|
} else {
|
|
|
|
|
log.error("HTTP端口监听失败:{}", serverPort);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
HttpClient proxyClient = VERTX.createHttpClient();
|
|
|
|
|
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
|
|
|
|
proxy.originSelector(request -> Future.succeededFuture(ProxyTool.resolveOriginAddress(request)));
|
|
|
|
|
proxy.addInterceptor(new ProxyInterceptor() {
|
|
|
|
|
@Override
|
|
|
|
|
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
|
|
|
|
// if(StringUtils.equals(sacAppHeaderKey, "dsafdsfadafhappC")) {
|
|
|
|
|
// // 会跳转到 RestfulFailureHandlerImpl
|
|
|
|
|
// throw new HttpException(10003);
|
|
|
|
|
// }
|
|
|
|
|
return context.sendRequest();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Future<Void> handleProxyResponse(ProxyContext context) {
|
|
|
|
|
// 调试代码,获取reponse body
|
|
|
|
|
// Filter filter = new Filter();
|
|
|
|
|
// ProxyResponse proxyResponse = context.response();
|
|
|
|
|
// Body body = proxyResponse.getBody();
|
|
|
|
|
// proxyResponse.setBody(Body.body(filter.init(context.request().getURI(), body.stream(), false)));
|
|
|
|
|
// 继续拦截链
|
|
|
|
|
return context.sendResponse();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
WebClient mainWebClient = WebClient.create(VERTX);
|
|
|
|
|
String rateLimitModel = vertxConfig.getRateLimitModel();
|
|
|
|
|
Route routeSac = mainHttpRouter.post(rpcUri());
|
|
|
|
|
routeSac.handler(CorsHandler.create().addRelativeOrigin(".*"))
|
|
|
|
|
.handler(ParameterCheckHandler.create(GatewayServiceType.SAC))
|
2024-06-03 14:02:35 +08:00
|
|
|
|
.handler(AppRateLimitHandler.create(rateLimitModel))
|
|
|
|
|
.handler(ApiRateLimitHandler.create(rateLimitModel))
|
|
|
|
|
.handler(BodyPreCheckHandler.create())
|
|
|
|
|
.handler(BodyHandler.create().setHandleFileUploads(false))
|
|
|
|
|
.handler(BodyPostAnalysisHandler.create())
|
|
|
|
|
.handler(BodyPostCheckHandler.create())
|
|
|
|
|
.handler(SacRouteRequestHandler.create(mainWebClient))
|
|
|
|
|
.handler(ProxyHandler.create(mainWebClient, proxy))
|
2024-05-31 09:56:02 +08:00
|
|
|
|
.failureHandler(RestfulFailureHandler.create());
|
|
|
|
|
|
|
|
|
|
Route routeOpen = mainHttpRouter.route();
|
|
|
|
|
routeOpen.handler(CorsHandler.create().addRelativeOrigin(".*"))
|
|
|
|
|
.handler(ParameterCheckHandler.create(GatewayServiceType.OPEN))
|
2024-06-03 14:02:35 +08:00
|
|
|
|
.handler(AppRateLimitHandler.create(rateLimitModel))
|
|
|
|
|
.handler(ApiRateLimitHandler.create(rateLimitModel))
|
|
|
|
|
.handler(BodyPreCheckHandler.create())
|
|
|
|
|
.handler(BodyHandler.create().setHandleFileUploads(false))
|
|
|
|
|
.handler(BodyPostCheckHandler.create())
|
|
|
|
|
.handler(SacRouteRequestHandler.create(mainWebClient))
|
|
|
|
|
.handler(ProxyHandler.create(mainWebClient, proxy))
|
|
|
|
|
.failureHandler(RestfulFailureHandler.create());
|
2024-05-31 09:56:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void loadVertxOptions(VertxOptions vertxOptions) {
|
|
|
|
|
long blockedThreadCheckInterval = VERTX_CONFIG.getVertxOptionsConfig() == null ? -1
|
|
|
|
|
: VERTX_CONFIG.getVertxOptionsConfig().getBlockedThreadCheckInterval();
|
|
|
|
|
int workerPoolSize = VERTX_CONFIG == null || VERTX_CONFIG.getVertxOptionsConfig() == null ? -1
|
|
|
|
|
: VERTX_CONFIG.getVertxOptionsConfig().getWorkerPoolSize();
|
|
|
|
|
if (workerPoolSize != -1) {
|
|
|
|
|
vertxOptions.setWorkerPoolSize(workerPoolSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
2024-06-03 14:02:35 +08:00
|
|
|
|
// blockedThreadCheckInterval = 1000000L;
|
2024-05-31 09:56:02 +08:00
|
|
|
|
if (blockedThreadCheckInterval != -1) {
|
|
|
|
|
vertxOptions.setBlockedThreadCheckInterval(blockedThreadCheckInterval); // 不打印Thread blocked 阻塞日志
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String bodyEncrypt(String body, String appCode) {
|
|
|
|
|
DataSecurity dataSecurity = getAppConfig(appCode).getDataSecurity();
|
|
|
|
|
switch (dataSecurity.getAlgorithm()) {
|
|
|
|
|
case "AES":
|
|
|
|
|
return MainSecurity.aesEncrypt(body, dataSecurity.getPrivateKey());
|
|
|
|
|
case "RSA":
|
|
|
|
|
return MainSecurity.rsaEncrypt(body, dataSecurity.getPublicKey());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
log.info(" appCode:{}, encrypt key config is error.", appCode);
|
|
|
|
|
throw new HttpException(10011);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String bodyDecrypt(String body, String appCode) {
|
|
|
|
|
DataSecurity dataSecurity = getAppConfig(appCode).getDataSecurity();
|
|
|
|
|
switch (dataSecurity.getAlgorithm()) {
|
|
|
|
|
case "AES":
|
|
|
|
|
return MainSecurity.aesDecrypt(body, dataSecurity.getPrivateKey());
|
|
|
|
|
case "RSA":
|
|
|
|
|
return MainSecurity.rsaDecrypt(body, dataSecurity.getPrivateKey());
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
log.info(" appCode:{}, decrypt key config is error.", appCode);
|
|
|
|
|
throw new HttpException(10011);
|
|
|
|
|
}
|
2024-05-21 14:17:59 +08:00
|
|
|
|
|
2024-05-08 19:10:15 +08:00
|
|
|
|
}
|