乐趣区

关于dubbo:Dubbo-令牌验证和优雅停机

前言

大家好,明天开始给大家分享 — Dubbo 专题之 Dubbo 令牌验证和优雅停机。在后面的章节中咱们介绍了 Dubbo 提早和粘滞连贯,理解了什么是提早和粘滞连贯以及日常的应用场景和实现原理,同时咱们晓得提早连贯是在应用实例对象的时候才创立通信连贯,粘滞连贯是尽可能的应用曾经创立的连贯,它们都有相似缩小连贯创立的作用。那本章节探讨一些轻松的话题就是令牌验证和优雅停机,那什么是令牌呢?以及它的作用是什么呢?。那就让咱们疾速开始吧!

1. 令牌验证和优雅停机简介

首先介绍什么是令牌,咱们通过一个生存中的小例子探讨什么是令牌。例如:咱们小伙伴常常坐火车出去玩那得首先购买火车票吧,而后咱们拿着火车票到安检口进行检票,检票胜利咱们就能够乘坐火车,如果检票失败则不能乘坐。这里的火车票就是咱们所说的令牌,只有拿到无效的令牌咱们才有权限或资格做后续的事件。

那什么是优雅停机呢?简略的了解就是在利用失常解决实现过后才退出利用,然而如果咱们通过kill -9 PID 等强制敞开指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。在我的 Dubbo 是通过 JDK 的 ShutdownHook 来实现优雅停机。

2. 配置形式

Dubbo 次要通过 XML、注解、配置文件的形式配置:

2.1 令牌验证配置形式

XML 配置形式

  1. 全局设置
<!-- 随机 token 令牌,应用 UUID 生成 -->
<dubbo:provider token="true" />

或者

<!-- 固定 token 令牌,相当于明码 -->
<dubbo:provider token="123456" />
  1. 服务级别设置
<!-- 随机 token 令牌,应用 UUID 生成 -->
<dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="true" />

或者

<!-- 固定 token 令牌,相当于明码 -->
<dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="123456" />

注解形式:服务级别设置

@DubboService(token = "true")
//@Service(token = "true")

配置文件:全局配置

dubbo.provider.token=true

2.2 优雅停机配置形式

Dubbo 中次要通过属性配置和编码方式:

属性配置

# dubbo.properties
dubbo.service.shutdown.wait=15000

编码方式

DubboShutdownHook.destroyAll();

Tips:应用 tomcat 等容器部署的场景,倡议通过扩大 ContextListener 等自行调用以下代码实现优雅停机

3. 应用场景

上面咱们看看 Dubbo 中令牌验证和优雅停机的应用场景。首先 Dubbo 中的场景形容是令牌验证在注册核心管制权限,以决定要不要下发令牌给消费者,能够避免消费者绕过注册核心拜访提供者,另外通过注册核心可灵便扭转受权形式,而不需批改或降级提供者。优雅停机在 Dubbo 中留神也是用于资源的回收解决等。上面咱们探讨罕用的应用场景:

  1. 令牌验证应用场景:从 Dubbo 令牌验证场景形容中咱们能够晓得能够通过令牌对消费者拜访接口进行受权拜访,即咱们能够通过自行拓展对注册信息进行动静调整以反对接口权限动静访问控制。
  2. 优雅停机应用场景:在 Dubbo 利用退出时敞开底层的网络连接资源、缓存操作资源等等。

4. 示例演示

上面咱们以获取图书列表为例进行实例演示次要演示令牌验证。我的项目构造如下:

上面咱们看看服务生产端的配置dubbo-provider-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-provider" metadata-type="remote"/>

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

    <bean id="bookFacade" class="com.muke.dubbocourse.tokenverify.provider.BookFacadeImpl"/>

    <!-- 裸露本地服务为 Dubbo 服务 -->
    <dubbo:service interface="com.muke.dubbocourse.async.api.BookFacade" ref="bookFacade" token="12345"/>

</beans>

下面咱们开启服务级别的 token 配置 token="12345" 设置 token 固定值。上面咱们看看服务生产端配置文件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"/>

    <!--1. 通过注册核心获取服务援用 -->
<!--    <dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade">-->
<!--    </dubbo:reference>-->

    <!--2.url 间接指定服务提供者所做机器以及端口 -->
    <dubbo:reference id="bookFacade"
                     interface="com.muke.dubbocourse.common.api.BookFacade" url="dubbo://localhost:20890">
    </dubbo:reference>

</beans>

下面的 XML 中如果应用第一种形式能够失常拜访咱们的 bookFacade 服务,如果应用第二种直连的形式绕开注册核心则会失去以下谬误:

Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /192.168.101.8:20890Caused by: java.net.ConnectException: Connection refused    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)

因为咱们的服务开启 token 验证如果绕开注册核心间接调用则 token 会验证不通过。

<script async src=”https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js”></script>
<ins class=”adsbygoogle”

 style="display:block; text-align:center;"
 data-ad-layout="in-article"
 data-ad-format="fluid"
 data-ad-client="ca-pub-4279907681900931"
 data-ad-slot="6812672741"></ins>

<script>

 (adsbygoogle = window.adsbygoogle || []).push({});

</script>

5. 原理剖析

上面咱们次要剖析 Dubbo 中的令牌验证源码。

token 的解析过程

当咱们的服务服务端的服务裸露时会调用办法 `org.apache.dubbo.config.ServiceConfig

doExportUrlsFor1Protocol` 其外围代码如下:

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        
                //...
        // 获取在服务提供端配置的 token 值,例如:token="123456" 
        if(ConfigUtils.isEmpty(token) && provider != null) {token = provider.getToken();
        }

        if (!ConfigUtils.isEmpty(token)) {
            // 如果配置值为:true 或 default 则产生一个随机的 token 值
            if (ConfigUtils.isDefault(token)) {map.put(TOKEN_KEY, UUID.randomUUID().toString());
            } else {
              // 设置为配置的 token 值
                map.put(TOKEN_KEY, token);
            }
        }
        //init serviceMetadata attachments
        serviceMetadata.getAttachments().putAll(map);

       //...
    }

在下面的代码中咱们能够看到从咱们的配置中获取 token 值并注册到注册核心,如果配置值为:truedefault 则产生一个随机的 token 值,否则应用配置的 token 值。

token 应用过程

在服务生产端调用申请达到服务提供端前会通过一些了的过滤器,其中就包含了对 token 的校验过滤器。外围代码如下:

public class TokenFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation inv)
            throws RpcException {
        // 获取 token 参数值
        String token = invoker.getUrl().getParameter(TOKEN_KEY);
        if (ConfigUtils.isNotEmpty(token)) {Class<?> serviceType = invoker.getInterface();
            Map<String, String> attachments = inv.getAttachments();
            String remoteToken = (attachments == null ? null : attachments.get(TOKEN_KEY));
            // 验证消费者携带的 token 与服务提供端的 token 是否相等
            if (!token.equals(remoteToken)) {throw new RpcException("Invalid token! Forbid invoke remote service" + serviceType + "method" + inv.getMethodName() + "() from consumer" + RpcContext.getContext().getRemoteHost() + "to provider" + RpcContext.getContext().getLocalHost());
            }
        }
        return invoker.invoke(inv);
    }

}

通过下面的过滤器对 token 进行验证,如果验证通过则调用前面的执行器,如果验证失败则抛出异样。

6. 小结

在本大节中咱们次要学习了 Dubbo 中的令牌验证和优雅停机,以及常见的应用场景和应用形式。同时咱们也通过示例演示和源码剖析对 Dubbo 的令牌验证原理进行解析。其中令牌验证核心思想就是通过服务提供端提供的 token 或者随机产生的 token 放入注册核心进行治理,而后服务生产端获取 token 令牌并且在调用服务提供端时携带 token,服务提供端依据生产端携带的 token 进行验证。在优雅停机方面 Dubbo 是通过 JDK 的 ShutdownHook 来实现优雅停机。

本节课程的重点如下:

  1. 了解 Dubbo 中令牌验证和优雅停机
  2. 理解令牌验证和优雅停机应用形式
  3. 理解令牌验证和优雅停机应用场景
  4. 理解 Dubbo 中令牌验证原理

作者

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

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

微信公众号:

退出移动版