soul源码解读(十三)-- http服务探活

17 篇文章 0 订阅

http服务探活

官方文档写的是(官方文档地址):

  ip + port 检测
  在soul-admin 会有一个定时任务来扫描 配置的ip端口,如果发现下线,则会去除该 ip + port

  还有两个配置可以控制是否检测和检测间隔时间
  soul.upstream.check:true  默认为 ture,设置为false,不检测
  soul.upstream.scheduledTime:10  定时检测时间间隔,默认10秒

admin探活

我们找到 soul.upstream.check 配置的地方,发现是 UpstreamCheckService

// UpstreamCheckService.java
public void setup() {
    PluginDO pluginDO = pluginMapper.selectByName(PluginEnum.DIVIDE.getName());
    // 判断divide插件是否存在
    if (pluginDO != null) {
    	// 从数据库查询是否有http服务已注册
        List<SelectorDO> selectorDOList = selectorMapper.findByPluginId(pluginDO.getId());
		...
            if (CollectionUtils.isNotEmpty(divideUpstreams)) {
            	// 把http服务节点存到本地缓存,已selector的name为key
                UPSTREAM_MAP.put(selectorDO.getName(), divideUpstreams);
            }
    }
    if (check) {
    	// 如果设置了探活,就新建一个每10s执行一次任务的线程池去检测http服务是否存活
        new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), SoulThreadFactory.create("scheduled-upstream-task", false))
                .scheduleWithFixedDelay(this::scheduled, 10, scheduledTime, TimeUnit.SECONDS);
    }
}

scheduled会循环调用check()

// UpstreamCheckService.java
private void check(final String selectorName, final List<DivideUpstream> upstreamList) {
    List<DivideUpstream> successList = Lists.newArrayListWithCapacity(upstreamList.size());
    for (DivideUpstream divideUpstream : upstreamList) {
    	// 探活重点
        final boolean pass = UpstreamCheckUtils.checkUrl(divideUpstream.getUpstreamUrl());
    }
    ...
}
// 探活
public static boolean checkUrl(final String url) {
    ...
    if (checkIP(url)) {
        return isHostConnector(hostPort[0], Integer.parseInt(hostPort[1]));
    } else {
        return isHostReachable(url);
    }
}   

我们在上面的 setup() 打上断点,然后启动 admin
发现,断点确实走进来了,因为 http 服务没启动,所以本地缓存为空。

服务注册

启动 soul-examples-http 服务

断点到 check 里面,一会就发现本地缓存里面又启动的 http 服务节点了,然后我们去找更新缓存的地方。
找到了 submit() 

往上找,是 SoulClientRegisterServiceImpl#handlerSpringMvcSelector
继续往上是 SoulClientRegisterServiceImpl#registerSpringMvc
再往上就是一个接口

// SoulClientController.java
@PostMapping("/springmvc-register")
    public String registerSpringMvc(@RequestBody final SpringMvcRegisterDTO springMvcRegisterDTO) {
        return soulClientRegisterService.registerSpringMvc(springMvcRegisterDTO);
    }

看到这里,大家就知道了,http 服务在启动之后,会调用这个接口把自己注册到 admin。

我们继续去找 http 服务注册自己的入口。
发现 SpringCloudClientBeanPostProcessor#postProcessAfterInitialization
这个函数里面会在每个 bean 初始化之后,去判断这个 bean 是不是 http 服务

// SpringCloudClientBeanPostProcessor.java
Controller controller = AnnotationUtils.findAnnotation(bean.getClass(), Controller.class);
RestController restController = AnnotationUtils.findAnnotation(bean.getClass(), RestController.class);
RequestMapping requestMapping = AnnotationUtils.findAnnotation(bean.getClass(), RequestMapping.class);
if (controller != null || restController != null || requestMapping != null) {
    		...
            executorService.execute(() -> RegisterUtils.doRegister(buildJsonParams(clazzAnnotation, finalPrePath), url,
                    RpcTypeEnum.SPRING_CLOUD));
            return bean;
        }
        ...     

然后向 admin 注册,下面是注册的代码。

public static void doRegister(final String json, final String url, final RpcTypeEnum rpcTypeEnum) {

     String result = OkHttpTools.getInstance().post(url, json);
     if (AdminConstants.SUCCESS.equals(result)) {
         log.info("{} client register success: {} ", rpcTypeEnum.getName(), json);
     } 
      ... 

我们启动http服务后也可以看到以下日志

2021-01-29 01:16:49.503  INFO 14500 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils  : http client register success: {"appName":"http","context":"/http","path":"/http/order/path/**","pathDesc":"","rpcType":"http","host":"172.17.250.209","port":8189,"ruleName":"/http/order/path/**","enabled":true,"registerMetaData":false} 
2021-01-29 01:16:54.213  INFO 14500 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils  : http client register success: {"appName":"http","context":"/http","path":"/http/order/findById","pathDesc":"Find by id","rpcType":"http","host":"172.17.250.209","port":8189,"ruleName":"/http/order/findById","enabled":true,"registerMetaData":false} 

服务下线

接下来我们看下,如果 http 服务关闭了,admin 怎么感知
关闭 http 服务之后,等一会,admin 这边会再次走到 UpstreamCheckService#check 里
里面回去检查节点是否还活着,如果不存活,就从内存里删除。

if (successList.size() > 0) {
		...
        } else {
            UPSTREAM_MAP.remove(selectorName);
            updateSelectorHandler(selectorName, null);
        }

总结

soul 的 http 探活,就是 admin 在启动的时候会去数据库捞一遍数据,看有没有服务之前已经注册过,然后根据配置的检测开关, 开启一个每隔10s检测一次节点是否存活的线程池。

然后 http 服务启动后会主动把自己注册到 admin,admin 会把节点缓存起来,然后每隔10s检测是否存活。

服务下线后,admin 检测到下线状态,会从内存里删除这个节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值