Dubbo 令牌驗證和優雅停機

前言

你們好,今天開始給你們分享 — Dubbo 專題之 Dubbo 令牌驗證和優雅停機。在前面的章節中咱們介紹了 Dubbo 延遲和粘滯鏈接,瞭解了什麼是延遲和粘滯鏈接以及平常的使用場景和實現原理,同時咱們知道延遲鏈接是在使用實例對象的時候才建立通信鏈接,粘滯鏈接是儘量的使用已經建立的鏈接,它們都有相似減小鏈接建立的做用。那本章節討論一些輕鬆的話題就是令牌驗證和優雅停機,那什麼是令牌呢?以及它的做用是什麼呢?。那就讓咱們快速開始吧!java

1. 令牌驗證和優雅停機簡介

首先介紹什麼是令牌,咱們經過一個生活中的小例子討論什麼是令牌。例如:咱們小夥伴常常坐火車出去玩那得首先購買火車票吧,而後咱們拿着火車票到安檢口進行檢票,檢票成功咱們就能夠乘坐火車,若是檢票失敗則不能乘坐。這裏的火車票就是咱們所說的令牌,只有拿到有效的令牌咱們纔有權限或資格作後續的事情。git

那什麼是優雅停機呢?簡單的理解就是在應用正常處理完成事後才退出應用,可是若是咱們經過kill -9 PID 等強制關閉指令,是不會執行優雅停機的,只有經過 kill PID 時,纔會執行。在個人 Dubbo 是經過 JDK 的 ShutdownHook 來完成優雅停機。spring

2. 配置方式

Dubbo 主要經過 XML 、註解、配置文件的方式配置:shell

2.1 令牌驗證配置方式

XML 配置方式apache

  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" />

或者api

<!--固定token令牌,至關於密碼-->
<dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" token="123456" />

註解方式:服務級別設置緩存

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

配置文件:全局配置tomcat

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. 示例演示

下面咱們以獲取圖書列表爲例進行實例演示主要演示令牌驗證。項目結構以下:

idea

下面咱們看看服務消費端的配置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

微信公衆號:

相關文章
相關標籤/搜索