转载

spring cloud consul微服务长轮询更新

在使用spring cloud体系进行微服务开发时,一般的服务注册和发现除了 eureka 之外,还可以采用consul, zookeeper来实现。本文描述使用组件 spring-cloud-consul 时,如果保证服务变更时的实时发现和处理.

一般来说,采用zookeeper这种服务端通过连接挂在临时节点,然后消费端通过监听节点来感知服务的变更,这种实现方式对于服务端的上下线感知是最快的。因为通过socket来维系服务的健康度,当服务不可用时,socket立马即会断开.(本文不考虑服务假死,socket仍可用的情况),而监听方马上通过变更来更新server list. 当下一个请求处理时,即会正确选择合适的服务方进行处理。而且当服务方上线时,也会立马进行感知加入到服务列表中。

对于consul来实现服务注册,有很多种方式,这里我们采用 TTL check,即设置 spring.cloud.consul.discovery.heartbeat.enabled=true的情况,在这种情况下 其 默认ttl值为30,默认汇报时间为18左右.

对于消费者,即discover方,目前spring cloud consul中,采用标准的 ribbon-loadbalancer 中的 ServerList.getUpdatedListOfServers 来完成实例的更新。相应的定时任务通过 ServerListUpdater.start (默认实现为 PollingServerListUpdater) 来开启,内部采用 scheduleWithFixedDelay(默认30秒周期) 来实现.

在 consul 层,实现方为 ConsulServerList#getServers,即通过调用ConsulClient#getHealthServices 来获取健康的服务列表,对应consul的api即 /health/service/:service 来完成.

在这种情况下,存在一个间隔期,即30秒周期。如果服务方变更了,discover并不能实时感知,还需要等待下一次轮询才能感知到,对于微服务来说,这即是一个服务不可用的场景.

在官方 consul 的 API中,是存在 阻塞式调用的,即响应并不会立即返回,直到有变化或wait时间到。即长轮询概念,可以采取类似长轮询的概念来达到数据第一时间感知。目前世面大部分的配置中心同样采取类似的技术。

在本服务实现中,PollingServerListUpdater 即可增强为 LongPollingServerListUpdater,即schedule时间调整为 1秒. 而 ConsulServerList 则变更为 LongPollingConsulServerList,其wait时间可以调整为 30秒. 这种情况下,即可保证discover一直在监听数据变化(1秒可以忽略不计). 而相应的api在不变的情况下,加入对 passing 的支持即可. 其参考代码如下:

val paramList = Lists.<UrlParameters>newArrayList();
paramList.add(new SingleUrlParameters("passing", "true"));
paramList.add(new SingleUrlParameters("index", String.valueOf(index)));
paramList.add(new SingleUrlParameters("wait", "30s"));

val res = rawClient.makeGetRequest("/v1/health/service/:service", paramList);

在以上的参考代码中,需要注意的是 index 值需要在响应中保留下来,即作为下一次的请求值,即只有 index 变更时才会通知,如果一直传初始值(如0),则马上即会有响应.

在目前最新的spring cloud consul中(V2.2.2.RELEASE)中,相应的ServerList实例默认由ConsulRibbonClientConfiguration来提供,其 ribbonServerList bean方法提供以client为分组的bean实例。因为其为 @ConditionalOnMissingBean, 因此可以在业务侧进行覆盖. 如下的参考代码所示

@RibbonClients(defaultConfiguration = BusinessRibbonConfig.class)
public class BusinessConfiguration {
    public static class BusinessRibbonConfig {
        @Bean
        @Primary
        public ServerList serverList(IClientConfig config, ConsulDiscoveryProperties properties, ConsulDiscoveryCacheClient cacheClient) {
            return //自行实现的serverList, 支持passing和wait,index支持
        }
    }
}
原文  https://www.iflym.com/index.php/code/202003190001.html
正文到此结束
Loading...