这一次需要更进一步,基于 Sentinel 实现内嵌式集群限流的高可用方案,并且包装成一个中间件 starter 提供给三方使用。
对于高可用,我们主要需要解决两个问题,这无论是使用内嵌或者独立模式都需要解决的问题,相比而言,内嵌式模式更简单一点。
- 集群 server 自动选举
- 自动故障转移
- Sentinel-Dashboard持久化到Apollo
集群限流
首先,考虑到大部分的服务可能都不需要集群限流这个功能,因此实现一个注解用于手动开启集群限流模式,只有开启注解的情况下,才去实例化集群限流的 Bean 和限流数据。
@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