关于java:Dubbo-延迟与粘滞连接

5次阅读

共计 5893 个字符,预计需要花费 15 分钟才能阅读完成。

前言

大家好,明天开始给大家分享 — Dubbo 专题之 Dubbo 提早和粘滞连贯。在前一个章节中咱们介绍了 Dubbo 并发管制,Dubbo 为咱们提供两大类的配置:生产端的配置和服务提供端配置,咱们别离能够对服务提供端和服务生产端进行并发数量的管制。同时咱们也例举了常见的应用场景并且进行了源码解析来剖析其实现原理。有的小伙伴学习了并发管制可能会想到:如果咱们的服务生产端有大量的服务须要援用,那咱们的 Dubbo 应用程序可能启动相当的迟缓其起因是:当咱们生产端利用启动的时候须要获取近程服务的代理对象的援用,如果咱们每一个获取的近程代理对象都在启动的时候创立连贯,这样必定会影响咱们的应用程序启动,幸好咱们的 Dubbo 提供一种配置的形式解决这个问题。那同时也延长出另外一个问题,就是咱们对某个服务的调用能不能始终调配到上次调用的服务提供者呢?带着这些疑难咱们开始本章节学习,咱们会通过介绍什么是提早和粘滞连贯?怎么通过参数配置扭转默认行为?来解决这些问题。上面就让咱们疾速开始吧!

1. 提早和粘滞连贯简介

通过后面对 Dubbo 相干章节的介绍我置信大家应该有个根本的概念就是咱们 Dubbo 中服务生产方持有服务提供端的服务援用,这个援用又通过层层的代理最终通过咱们的 TCP/IP (底层应用 Netty 进行网络通讯)与近程服务端进行通信。在 Dubbo 中为了优化生产端获取服务提供端的援用对象时候创立底层的物理连贯,比方在与 Spring 集成中咱们的援用对象须要通过 Spring 容器进行对外公布 Bean 实例,然而此时咱们并没有真正的应用代理对象,只是将代理对象交给 Spring 治理。为了使代理对象在真正应用的时候才去创立底层的物理从而缩小底层连贯的创立和开释这就叫做提早连贯。同理粘滞连贯的意思就是尽可能让客户端总是向同一提供者发动调用,除非该提供者挂了,再连另一台。下图简略的形容了粘滞连贯在第二次、第三次调用服务的时候调用原服务提供者:

2. 配置形式

上面咱们次要通过 XML 和 注解的形式进行配置介绍:

2.1 提早连贯:

  1. XML 形式
<dubbo:reference id="bookFacade"
                     interface="com.muke.dubbocourse.common.api.BookFacade" lazy="true" ></dubbo:reference>
  1. 注解形式
@Reference(lazy = true)

2.2 粘滞连贯

  1. XML 形式
<dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade" sticky="true" />

办法级别管制:

<dubbo:reference id="xxxService" interface="com.muke.dubbocourse.common.api.BookFacade">
    <dubbo:mothod name="queryAll" sticky="true" />
</dubbo:reference>
  1. 注解形式
@Reference(sticky = true)

从下面的配置中咱们能够简略的总结:提早连贯通过 lazy 进行配置,粘滞连贯应用 sticky 进行配置。

3. 应用场景

依据后面的介绍咱们大略了解了什么是提早和粘滞连贯。其中提早连贯就是为了缩小无用的连贯而在真正应用对象时候才创立连贯,而粘滞连贯是为了屡次调用都尽可能地应用同一个服务提供者也有缩小服务连贯创立的作用。上面咱们简略的介绍几种常见应用场景:

  1. 当咱们的服务生产端须要大量的援用服务提供者或者创立近程连贯老本十分高 (个别指耗时工夫) 时咱们能够思考开启提早连贯。
  2. 假如咱们的利用有大量的静态数据须要加载到利用本地缓存 (JVM 缓存) 时当第一次调用 Service A 进行缓存加载,那么在第二次调用的时候咱们冀望也调用方才曾经存在缓存的服务 Service A 这样进步了服务的访问速度。这种场景能够应用粘滞连贯。
  3. 如果咱们的利用调用过程存在某种状态,例如:调用服务 Service A 进行用户登录返回 token,那第二次调用查问用户信息的时候须要依据携带的 token 来查问用户的登录状态,此时如果拜访 Service A 那么用户登录的 token 信息是存的,如果拜访到 Service B 这时就不存在 token (假如这里没有应用分布式缓存)。这种场景能够应用粘滞连贯。

4. 示例演示

上面我以获取图书列表为例进行演示。我的项目构造如下:

咱们的提早连贯次要配置在服务生产端 dubbo-consumer-xml.xml 配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="demo-consumer" logger="log4j"/>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!--lazy="true" 提早连贯 -->
    <dubbo:reference id="bookFacade"
                     interface="com.muke.dubbocourse.common.api.BookFacade" lazy="true" ></dubbo:reference>

</beans>

通过 lazy="true" 配置生产端援用服务提供者服务时开启提早连贯。上面咱们持续看看粘滞连贯配置:

    <!--sticky="true" 开启粘滞连贯 -->
    <dubbo:reference id="bookFacade"
                     interface="com.muke.dubbocourse.common.api.BookFacade" sticky="true" ></dubbo:reference>

通过 sticky="true" 配置生产端援用服务提供者服务时开启粘滞连贯。

Tips:这里在演示粘滞连贯的时候小伙伴们在部署利用的时候至多须要部署两个或以上的实例能力看出成果。如果咱们开启粘滞连贯那么咱们能够看到总是拜访同一个服务提供者。

5. 实现原理

上面咱们通过源码的形式简略的剖析它们的实现原理。

首先是 提早连贯 其外围办法 `org.apache.dubbo.rpc.protocol.dubbo.
DubboProtocol#protocolBindingRefer` 代码如下:

    /***
     *
     * 协定绑定并创立连贯
     *
     * @author liyong
     * @date 16:11 2020-03-08
     * @param serviceType
     * @param url
     * @exception
     * @return org.apache.dubbo.rpc.Invoker<T>
     **/
    @Override
    public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {optimizeSerialization(url);

        // 创立 DubboInvoker 并且创立网络连接
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);

        return invoker;
    }

这里的 DubboInvoker 是咱们近程 RPC 调用的封装,这里 `org.apache.dubbo.rpc.protocol.dubbo.
DubboProtocol#getClients` 办法创立客户端连贯并且绑定申请处理器外围代码如下:

/***
     *
     * 获取客户端连贯, 并且绑定了申请处理器
     *
     * @author liyong
     * @date 16:55 2020-03-08
     * @param url
     * @exception
     * @return org.apache.dubbo.remoting.exchange.ExchangeClient[]
     **/
    private ExchangeClient[] getClients(URL url) {
        //...
        ExchangeClient[] clients = new ExchangeClient[connections];
        for (int i = 0; i < clients.length; i++) {if (useShareConnect) {clients[i] = shareClients.get(i);// 共享连贯

            } else {clients[i] = initClient(url);// 不共享 新建连贯
            }
        }

        return clients;
    }

其中 initClient 办法创立连贯外围代码如下:

      private ExchangeClient initClient(URL url) {

        //...

        ExchangeClient client;
        try {
            // 是否提早连贯 lazy="true"
            if (url.getParameter(LAZY_CONNECT_KEY, false)) {
                // 这里并没有创立连贯对象
                client = new LazyConnectExchangeClient(url, requestHandler);

            } else {
                //HeaderExchangeClient 连贯到服务器并绑定申请处理器
                client = Exchangers.connect(url, requestHandler);
            }

        } catch (RemotingException e) {//...}

        return client;
    }

依据咱们的配置获取 LAZY_CONNECT_KEY 参数 (lazy) 的值,当咱们配置为 true 时创立 LazyConnectExchangeClient 对象,为 false 是创立物理连贯。

上面持续探讨 粘滞连贯 外围办法 `org.apache.dubbo.rpc.cluster.support.
AbstractClusterInvoker#select` 如下:

protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation,
                                List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {if (CollectionUtils.isEmpty(invokers)) {return null;}
        String methodName = invocation == null ? StringUtils.EMPTY_STRING : invocation.getMethodName();

        // 获取粘滞连贯配置
        boolean sticky = invokers.get(0).getUrl()
                .getMethodParameter(methodName, CLUSTER_STICKY_KEY, DEFAULT_CLUSTER_STICKY);

        //ignore overloaded method
        if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {stickyInvoker = null;}
        // 开启粘滞连贯配置 且存在曾经创立的 stickyInvoker 粘滞连贯
        if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {
            // 有效性检测
            if (availablecheck && stickyInvoker.isAvailable()) {return stickyInvoker;}
        }

        // 依据负载平衡策略进行服务抉择
        Invoker<T> invoker = doSelect(loadbalance, invocation, invokers, selected);

        if (sticky) {
            // 如果配置粘滞连贯为 true 则以后抉择的 Invoker 保留在 stickyInvoker 粘滞连贯变量
            stickyInvoker = invoker;
        }
        return invoker;
    }

从下面的代码咱们能够看出从 URL 中获取 sticky 配置判断是否开启粘滞连贯,如果开启那么在第一次获取 InvokerstickyInvokernull 创立一个 Invoker 代理对象,当第二次获取 Invoker 时会判断是否存在 stickyInvoker 如果存在且没有被排除则持续应用后面保留下来的 Invoker 代理对象也就是stickyInvoker

Tips:这里 URL 包含咱们配置的 XML 或注解配置中的参数、通信协定、序列化形式等等参数,能够参考后面章节详细描述。

6. 小结

在本大节中咱们次要学习了 Dubbo 提早和粘滞连贯,同时咱们也剖析了提早和粘滞连贯的实现原理。提早连贯实质上是提早 Dubbo 底层物理连贯的创立,而粘滞连贯实质上是反复利用已创立的连贯。

本节课程的重点如下:

  1. 了解 Dubbo 提早和粘滞连贯
  2. 理解了提早和粘滞连贯应用形式
  3. 理解延提早和粘滞连贯应用场景
  4. 理解提早和粘滞连贯实现原理

作者

集体从事金融行业,就任过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就任于某银行负责对立领取零碎建设。本身对金融行业有强烈的喜好。同时也实际大数据、数据存储、自动化集成和部署、散布式微服务、响应式编程、人工智能等畛域。同时也热衷于技术分享创建公众号和博客站点对常识体系进行分享。关注公众号:青年 IT 男 获取最新技术文章推送!

博客地址: http://youngitman.tech

微信公众号:

正文完
 0