当前位置:网站首页>从-99打造Sentinel高可用集群限流中间件
从-99打造Sentinel高可用集群限流中间件
2022-08-04 14:54:00 【InfoQ】
- 集群 server 自动选举
- 自动故障转移
- Sentinel-Dashboard持久化到Apollo
集群限流
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({EnableClusterImportSelector.class})
@Documented
public @interface SentinelCluster {
}
public class EnableClusterImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{ClusterConfiguration.class.getName()};
}
}
SentinelCluster
ClusterConfiguration
@Slf4j
public class ClusterConfiguration implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
private Environment environment;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ClusterManager.class);
beanDefinitionBuilder.addConstructorArgValue(this.environment);
registry.registerBeanDefinition("clusterManager", beanDefinitionBuilder.getBeanDefinition());
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
ClusterManager
ApolloDataSource
Apollo
@Slf4j
public class ClusterManager {
private Environment environment;
private String namespace;
private static final String CLUSTER_SERVER_KEY = "sentinel.cluster.server"; //服务集群配置
private static final String DEFAULT_RULE_VALUE = "[]"; //集群默认规则
private static final String FLOW_RULE_KEY = "sentinel.flow.rules"; //限流规则
private static final String DEGRADE_RULE_KEY = "sentinel.degrade.rules"; //降级规则
private static final String PARAM_FLOW_RULE_KEY = "sentinel.param.rules"; //热点限流规则
private static final String CLUSTER_CLIENT_CONFIG_KEY = "sentinel.client.config"; //客户端配置
public ClusterManager(Environment environment) {
this.environment = environment;
this.namespace = "YourNamespace";
init();
}
private void init() {
initClientConfig();
initClientServerAssign();
registerRuleSupplier();
initServerTransportConfig();
initState();
}
private void initClientConfig() {
ReadableDataSource<String, ClusterClientConfig> clientConfigDs = new ApolloDataSource<>(
namespace,
CLUSTER_CLIENT_CONFIG_KEY,
DEFAULT_SERVER_VALUE,
source -> JacksonUtil.from(source, ClusterClientConfig.class)
);
ClusterClientConfigManager.registerClientConfigProperty(clientConfigDs.getProperty());
}
private void initClientServerAssign() {
ReadableDataSource<String, ClusterClientAssignConfig> clientAssignDs = new ApolloDataSource<>(
namespace,
CLUSTER_SERVER_KEY,
DEFAULT_SERVER_VALUE,
new ServerAssignConverter(environment)
);
ClusterClientConfigManager.registerServerAssignProperty(clientAssignDs.getProperty());
}
private void registerRuleSupplier() {
ClusterFlowRuleManager.setPropertySupplier(ns -> {
ReadableDataSource<String, List<FlowRule>> ds = new ApolloDataSource<>(
namespace,
FLOW_RULE_KEY,
DEFAULT_RULE_VALUE,
source -> JacksonUtil.fromList(source, FlowRule.class));
return ds.getProperty();
});
ClusterParamFlowRuleManager.setPropertySupplier(ns -> {
ReadableDataSource<String, List<ParamFlowRule>> ds = new ApolloDataSource<>(
namespace,
PARAM_FLOW_RULE_KEY,
DEFAULT_RULE_VALUE,
source -> JacksonUtil.fromList(source, ParamFlowRule.class)
);
return ds.getProperty();
});
}
private void initServerTransportConfig() {
ReadableDataSource<String, ServerTransportConfig> serverTransportDs = new ApolloDataSource<>(
namespace,
CLUSTER_SERVER_KEY,
DEFAULT_SERVER_VALUE,
new ServerTransportConverter(environment)
);
ClusterServerConfigManager.registerServerTransportProperty(serverTransportDs.getProperty());
}
private void initState() {
ReadableDataSource<String, Integer> clusterModeDs = new ApolloDataSource<>(
namespace,
CLUSTER_SERVER_KEY,
DEFAULT_SERVER_VALUE,
new ServerStateConverter(environment)
);
ClusterStateManager.registerProperty(clusterModeDs.getProperty());
}
}
自动选举&故障转移
CacheRefreshedEvent

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.test.config.SentinelEurekaEventListener
SentinelCluster
@Configuration
@Slf4j
@ConditionalOnBean(annotation = SentinelCluster.class)
public class SentinelEurekaEventListener implements ApplicationListener<CacheRefreshedEvent> {
@Resource
private DiscoveryClient discoveryClient;
@Resource
private Environment environment;
@Resource
private ApolloManager apolloManager;
@Override
public void onApplicationEvent(EurekaClientLocalCacheRefreshedEvent event) {
if (!leaderAlive(loadEureka(), loadApollo())) {
boolean tryLockResult = redis.lock; //redis或者其他加分布式锁
if (tryLockResult) {
try {
flush();
} catch (Exception e) {
} finally {
unlock();
}
}
}
}
private boolean leaderAlive(List<ClusterGroup> eurekaList, ClusterGroup server) {
if (Objects.isNull(server)) {
return false;
}
for (ClusterGroup clusterGroup : eurekaList) {
if (clusterGroup.getMachineId().equals(server.getMachineId())) {
return true;
}
}
return false;
}
}

Dashboard持久化改造

FlowControllerV2
DynamicRuleProvider
Controller
flowRuleApolloProvider
flowRuleApolloPublisher
@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {
private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
@Autowired
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
@Autowired
@Qualifier("flowRuleApolloProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleApolloPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
}
@Component("flowRuleApolloProvider")
public class FlowRuleApolloProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
@Autowired
private ApolloManager apolloManager;
@Autowired
private Converter<String, List<FlowRuleEntity>> converter;
@Override
public List<FlowRuleEntity> getRules(String appName) {
String rules = apolloManager.loadNamespaceRuleList(appName, ApolloManager.FLOW_RULES_KEY);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("flowRuleApolloPublisher")
public class FlowRuleApolloPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ApolloManager apolloManager;
@Autowired
private Converter<List<FlowRuleEntity>, String> converter;
@Override
public void publish(String app, List<FlowRuleEntity> rules) {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
apolloManager.writeAndPublish(app, ApolloManager.FLOW_RULES_KEY, converter.convert(rules));
}
}
ApolloManager
open-api
@Component
public class ApolloManager {
private static final String APOLLO_USERNAME = "apollo";
public static final String FLOW_RULES_KEY = "sentinel.flow.rules";
public static final String DEGRADE_RULES_KEY = "sentinel.degrade.rules";
public static final String PARAM_FLOW_RULES_KEY = "sentinel.param.rules";
public static final String APP_NAME = "YourAppName";
@Value("${apollo.portal.url}")
private String portalUrl;
@Value("${apollo.portal.token}")
private String portalToken;
private String apolloEnv;
private String apolloCluster = "default";
private ApolloOpenApiClient client;
@PostConstruct
public void init() {
this.client = ApolloOpenApiClient.newBuilder()
.withPortalUrl(portalUrl)
.withToken(portalToken)
.build();
this.apolloEnv = "default";
}
public String loadNamespaceRuleList(String appName, String ruleKey) {
OpenNamespaceDTO openNamespaceDTO = client.getNamespace(APP_NAME, apolloEnv, apolloCluster, "default");
return openNamespaceDTO
.getItems()
.stream()
.filter(p -> p.getKey().equals(ruleKey))
.map(OpenItemDTO::getValue)
.findFirst()
.orElse("");
}
public void writeAndPublish(String appName, String ruleKey, String value) {
OpenItemDTO openItemDTO = new OpenItemDTO();
openItemDTO.setKey(ruleKey);
openItemDTO.setValue(value);
openItemDTO.setComment("Add Sentinel Config");
openItemDTO.setDataChangeCreatedBy(APOLLO_USERNAME);
openItemDTO.setDataChangeLastModifiedBy(APOLLO_USERNAME);
client.createOrUpdateItem(APP_NAME, apolloEnv, apolloCluster, "default", openItemDTO);
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
namespaceReleaseDTO.setEmergencyPublish(true);
namespaceReleaseDTO.setReleasedBy(APOLLO_USERNAME);
namespaceReleaseDTO.setReleaseTitle("Add Sentinel Config Release");
client.publishNamespace(APP_NAME, apolloEnv, apolloCluster, "default", namespaceReleaseDTO);
}
}
flowId
边栏推荐
- Phasecraft连下两城,助力英国量子技术商业化加速!
- [Problem solving] QT update component appears "To continue this operation, at least one valid and enabled repository is required"
- word2003按空格键为什么会出现小数点
- Go 语言快速入门指南: 变量和常量
- License server system does not support this version of this feature
- IP第十七天笔记
- 【历史上的今天】8 月 4 日:第一位图灵奖女性得主;NVIDIA 收购 MediaQ;首届网络安全挑战大赛完成
- Compound Refractive Lenses for X-ray Focusing
- C# 局部函数与事件
- FRED Application: Capillary Electrophoresis System
猜你喜欢
Hangzhou Electric School Competition (Counter Attack Index)
Go 语言快速入门指南: 变量和常量
利用决策树找出最优特征组合
快解析结合千方百剂
16、学习MySQL 正则表达式
1403. Minimum Subsequence in Non-Increasing Order
本周讨论用户体验:Daedalus 的 Nemo 加入 Ambire,探索加密海洋
Zheng Qing freshmen school competition and middle-aged engineering selection competition
X-ray grazing incidence focusing mirror
leetcode:255 验证前序遍历序列二叉搜索树
随机推荐
leetcode:253. 至少需要多少间会议室
【问题解决】QT更新组件出现 “要继续此操作,至少需要一个有效且已启用的储存库”
手搓一个“七夕限定”,用3D Engine 5分钟实现烟花绽放效果
基本介绍PLSQL
C# BBcode 转 Markdown
我爱七夕哈哈哈
IP第十八天笔记
Sum of four squares, laser bombs
【历史上的今天】8 月 4 日:第一位图灵奖女性得主;NVIDIA 收购 MediaQ;首届网络安全挑战大赛完成
FRED Application: Capillary Electrophoresis System
分布式链路追踪Jaeger + 微服务Pig在Rainbond上的实践分享
数据链路层-------以太网协议
C# 将dll打包到程序中
SQL语句的写法:Update、Case、 Select 一起的用法
Roslyn 通过 nuget 统一管理信息
7 天能找到 Go 工作吗?学学 Go 数组和指针试试
leetcode: 253. How many meeting rooms are required at least
Notes for xpath getting node with namespace
16、学习MySQL 正则表达式
Makefile 语法及使用笔记