soul网关-10-divide插件的upstream探活

之前的笔记里面学习过普通springboot项目接入soul网关的时候,只要有@SoulSpringMvcClient注解的接口,就会被注册到soul-admin的divide插件的selector和rule里面去。soul网关不仅通过divide插件进行请求代理,还可以对业务的机器进行探活。

假如说网关没有探活功能,那么当用户的请求过来之后,会直接转发给相关业务方。这个时候假如业务方的机器因为请求压力太大挂掉了,但是网关还是把大量的请求直接传过来了,业务方的机器还是会因为有大量的请求一直起不来。或者是业务方的某一台机器有问题不能正常服务,如果网关直接转发用户请求,可能会把请求转到不能服务的那台机器上去了,这样的话对用户来说体验更好一点。所以,网关有必要对业务方的机器进行探活。

我们来学习一下soul网关是如何进行服务(upstream)探活的。

SelectorServiceImpl有一个属性是UpstreamCheckService类型的,我们先来看下UpstreamCheckService的几个属性:

  • Map<String, List<DivideUpstream>>类型的UPSTREAM_MAP属性,是把selectorName与服务节点列表的映射缓存在了内存中。直接读写这个内存中的变量,效率很高
  • boolean类型的check属性,表示是否需要进行探活。默认true
  • int类型的scheduledTime属性,表示每隔多少秒进行一下探活。默认10s
  • 还有一些操作数据库的mapper
public class UpstreamCheckService {

    private static final Map<String, List<DivideUpstream>> UPSTREAM_MAP = Maps.newConcurrentMap();

    @Value("${soul.upstream.check:true}")
    private boolean check;

    @Value("${soul.upstream.scheduledTime:10}")
    private int scheduledTime;

    private final SelectorMapper selectorMapper;

    private final ApplicationEventPublisher eventPublisher;

    private final PluginMapper pluginMapper;

    private final SelectorConditionMapper selectorConditionMapper;

    ……
    ……
    ……

UpstreamCheckService里面最关键的,就是public void setup()方法,该方法上面有一个@PostConstruct注解。

该注解使用的时候需要注意:

  • 被注解的方法不得有参数
  • 被注解的方法返回值为void
  • 被注解方法不得抛出已检查异常
  • 被注解方法必须是非静态方法
  • 被注解的方法只会被执行一次

@PostConstruct注解的方法,在对象加载完依赖注入后会被执行。与@PostConstruct对应的是@PreDestroy,被它注解的方法,在对象消亡之前执行。

我们来看下这个被@PostConstruct注解的setUp方法里面主要干了什么:

  • 从数据库中取出divide插件的数据
  • 如果插件数据不为空,则取出divide插件的selector数据。并且解析出selector里面的upstream,放到内存缓存中。
  • 创建一个ScheduledThreadPoolExecutor线程池,来进行周期性任务。周期为10s。
    @PostConstruct
    public void setup() {
        PluginDO pluginDO = pluginMapper.selectByName(PluginEnum.DIVIDE.getName());
        if (pluginDO != null) {
            List<SelectorDO> selectorDOList = selectorMapper.findByPluginId(pluginDO.getId());
            for (SelectorDO selectorDO : selectorDOList) {
                List<DivideUpstream> divideUpstreams = GsonUtils.getInstance().fromList(selectorDO.getHandle(), DivideUpstream.class);
                if (CollectionUtils.isNotEmpty(divideUpstreams)) {
                    UPSTREAM_MAP.put(selectorDO.getName(), divideUpstreams);
                }
            }
        }
        if (check) {
            new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), SoulThreadFactory.create("scheduled-upstream-task", false))
                    .scheduleWithFixedDelay(this::scheduled, 10, scheduledTime, TimeUnit.SECONDS);
        }
    }

周期性任务的主要功能就是进行探活检查,具体逻辑为:

  • 如果当前内存缓存UPSTREAM_MAP里面有数据,则遍历每项数据进行以下检查
  • 对每一个upstream,如果它是ip,则进行socket连接来探活;如果不是ip,则调用java本身的isReachable方法来探活
  • 对于不存活的upstream,则从内存缓存中剔除它,也从数据库的selector里的handle里的upstream里删除它。并且使用ApplicationEventPublisher发布这个数据更新事件。那么数据的更新就会被同步到网关中去。网关进行请求代理的时候,自然也不会转发到故障节点去。
  • 对于所有upstream都不存活的selector,将它从内存缓存UPSTREAM_MAP里面删除

画图举例来说明。假如说有一个服务A,有三个节点server1, server2, server3,一开始三个节点是好的。那么soul-admin会向这三个节点进行探活。

在这里插入图片描述

当其中server1节点挂掉之后,soul-admin进行探活的时候得知它挂了,那么下次进行探活的时候就提出server1,不会对它进行探活。

在这里插入图片描述

当server1节点重启恢复之后,由于我在之前的笔记里面写到的,节点启动的时候会向soul-admin注册,soul-admin里面的服务A的upstream又变成了3个。

在这里插入图片描述

本文学习了soul网关的探活机制,总体来说还是比较简单易懂。


2020-02-01补充:

后来看了一下,发现soul-plugin-divide里面也有upstream探活机制UpstreamCacheManager,不过默认是关闭状态。

UpstreamCacheManager里面有两个属性,UPSTREAM_MAP里面存储的是admin同步过来的upstream,UPSTREAM_MAP_TEMP里面存储的是探活机制探到的存活的upstream。不过因为
soul-plugin-divide里面的探活机制默认是关闭的,所以UPSTREAM_MAPUPSTREAM_MAP_TEMP中存储的数据一样的。

public final class UpstreamCacheManager {

    private static final UpstreamCacheManager INSTANCE = new UpstreamCacheManager();

    private static final Map<String, List<DivideUpstream>> UPSTREAM_MAP = Maps.newConcurrentMap();

    private static final Map<String, List<DivideUpstream>> UPSTREAM_MAP_TEMP = Maps.newConcurrentMap();

……
……
……

如果soul-plugin-divide的探活机制开启的话,默认是每30s进行一次探活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值