基於Nacos和Sentinel實現灰度路由和流量防護一體化

基於 Nacos 和 Sentinel ,實現灰度路由和流量防護一體化的解決方案,發佈在最新的 Nepxion Discovery 5.4.0 版本,具體參考:

源碼主頁,請訪問 :源碼主頁
指南主頁,請訪問 :指南主頁
文檔主頁,請訪問 :文檔主頁

Nepxion Discovery 框架在實現灰度發佈和路由功能前提下,結合 Nacos 和 Sentinel ,對流量再實施一層防護措施,更能達到企業級的流量安全控制的目的。它的功能包括:

  • 封裝遠程配置中心和本地規則文件的讀取邏輯,即優先讀取遠程配置,如果不存在或者規則錯誤,則讀取本地規則文件。動態實現遠程配置中心對於規則的熱刷新;
  • 封裝 NacosDataSource 和 ApolloDataSource ,支持 Nacos 和 Apollo 兩個遠程配置中心,零代碼實現 Sentinel 功能。更多的遠程配置中心,請參照 Sentinel 官方的 DataSource 並自行集成;
  • 支持原生的流控規則、降級規則、授權規則、系統規則、熱點參數流控規則;
  • 支持擴展 LimitApp 的機制,通過動態的 Http Header 方式實現組合式防護機制,包括基於服務名、基於灰度組、基於灰度版本、基於灰度區域、基於機器地址和端口等防護機制,支持自定義任意的業務參數組合實現該功能,例如,根據傳入的微服務灰度版本號+用戶名,組合在一起進行熔斷;
  • 支持微服務側 Actuator、Swagger 和 Rest 三種方式的規則寫入;
  • 支持控制檯側基於微服務名的 Actuator、Swagger 和 Rest 三種方式的批量規則寫入;
  • 支持開關關閉上述功能spring.application.strategy.sentinel.enabled=true ,默認是關閉的。

[Nacos] 阿里巴巴中間件部門開發的新一代集服務註冊發現中心和配置中心爲一體的中間件。它是構建以“服務”爲中心的現代應用架構 (例如微服務範式、雲原生範式) 的服務基礎設施,支持幾乎所有主流類型的“服務”的發現、配置和管理,更敏捷和容易地構建、交付和管理微服務平臺。

[Sentinel] 阿里巴巴中間件部門開發的新一代以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性的分佈式系統的流量防衛兵。它承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峯填谷、集羣流量控制、實時熔斷下游不可用應用等。

環境搭建及依賴引入

服務端在 Discovery 框架原有依賴的基礎上,再引入如下依賴:

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-service-sentinel</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-sentinel-starter-nacos</artifactId>
    <!-- <artifactId>discovery-plugin-strategy-sentinel-starter-apollo</artifactId> -->
    <version>${discovery.version}</version>
</dependency>

原生 Sentinel 註解

參照下面代碼,爲接口方法增加 @SentinelResource 註解, value爲sentinel-resource , blockHandler 和 fallback 是防護其作用後需要執行的方法:

@RestController
@ConditionalOnProperty(name = DiscoveryConstant.SPRING_APPLICATION_NAME, havingValue = "discovery-guide-service-b")
public class BFeignImpl extends AbstractFeignImpl implements BFeign {
    private static final Logger LOG = LoggerFactory.getLogger(BFeignImpl.class);

    @Override
    @SentinelResource(value = "sentinel-resource", blockHandler = "handleBlock", fallback = "handleFallback")
    public String invoke(@PathVariable(value = "value") String value) {
        value = doInvoke(value);

        LOG.info("調用路徑:{}", value);

        return value;
    }

    public String handleBlock(String value, BlockException e) {
        return value + "-> B server sentinel block, cause=" + e.getClass().getName() + ", rule=" + e.getRule() + ", limitApp=" + e.getRuleLimitApp();
    }

    public String handleFallback(String value) {
        return value + "-> B server sentinel fallback";
    }
}

原生 Sentinel 規則

Sentinel 在配置中心訂閱的 Key 格式,如下:

1. Nacos的Key格式:Group爲元數據中配置的[組名],Data Id爲[服務名]-[規則類型]
2. Apollo的Key格式:[組名]-[服務名]-[規則類型]

Sentinel 規則的用法,請參照 Sentinel 官方文檔。

流控規則

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group , Data Id 爲 discovery-guide-service-b-sentinel-flow ,規則內容如下:

[
    {
        "resource": "sentinel-resource",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "refResource": null,
        "controlBehavior": 0,
        "warmUpPeriodSec": 10,
        "maxQueueingTimeMs": 500,
        "clusterMode": false,
        "clusterConfig": null
    }
]

如圖所示:
流控規則

降級規則

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group , Data Id 爲 discovery-guide-service-b-sentinel-degrade ,規則內容如下:

[
    {
        "resource": "sentinel-resource",
        "limitApp": "default",
        "count": 2,
        "timeWindow": 10,
        "grade": 0,
        "passCount": 0
    }
]

如圖所示:
降級規則

授權規則

增加服務discovery-guide-service-b的規則,Group爲discovery-guide-group,Data Id爲discovery-guide-service-b-sentinel-authority,規則內容如下:

[
    {
        "resource": "sentinel-resource",
        "limitApp": "discovery-guide-service-a",
        "strategy": 0
    }
]

如圖所示:
授權規則

系統規則

增加服務 discovery-guide-service-b 的規則, Group 爲 discovery-guide-group ,Data Id 爲 discovery-guide-service-b-sentinel-system ,規則內容如下:

[
    {
        "resource": null,
        "limitApp": null,
        "highestSystemLoad": -1.0,
        "highestCpuUsage": -1.0,
        "qps": 200.0,
        "avgRt": -1,
        "maxThread": -1
    }
]

如圖所示:
系統規則

熱點參數流控規則

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group , Data Id 爲 discovery-guide-service-b-sentinel-param-flow ,規則內容如下:

[
    {
        "resource": "sentinel-resource",
        "limitApp": "default",
        "grade": 1,
        "paramIdx": 0,
        "count": 1,
        "controlBehavior": 0,
        "maxQueueingTimeMs": 0,
        "burstCount": 0,
        "durationInSec": 1,
        "paramFlowItemList": [],
        "clusterMode": false
    }
]

如圖所示:
熱點參數流控規則

基於灰度路由和 Sentinel-LimitApp 擴展的防護機制

該方式對於上面 5 種規則都有效,這裏以授權規則展開闡述。

授權規則中, limitApp ,如果有多個,可以通過“,”分隔。“strategy”: 0 表示白名單,“strategy”: 1 表示黑名單。

基於服務名的防護機制

修改配置項 Sentinel Request Origin Key 爲服務名的 Header 名稱,修改授權規則中 limitApp 爲對應的服務名,可實現基於服務名的防護機制。

配置項,該配置項默認爲 n-d-service-id ,可以不配置。

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-id

增加服務 discovery-guide-service-b 的規則, Group 爲 discovery-guide-group , Data Id 爲 discovery-guide-service-b-sentinel-authority ,規則內容如下,表示所有 discovery-guide-service-a 服務允許訪問 discovery-guide-service-b 服務。

[
    {
        "resource": "sentinel-resource",
        "limitApp": "discovery-guide-service-a",
        "strategy": 0
    }
]

基於灰度組的防護機制

修改配置項 Sentinel Request Origin Key 爲灰度組的 Header 名稱,修改授權規則中 limitApp 爲對應的組名,可實現基於組名的防護機制。

配置項

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-group

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group , Data Id 爲 discovery-guide-service-b-sentinel-authority ,規則內容如下,表示隸屬 my-group 組的所有服務都允許訪問服務 discovery-guide-service-b 。

[
    {
        "resource": "sentinel-resource",
        "limitApp": "my-group",
        "strategy": 0
    }
]

基於灰度版本的防護機制

修改配置項 Sentinel Request Origin Key 爲灰度版本的 Header 名稱,修改授權規則中 limitApp 爲對應的版本,可實現基於版本的防護機制。

配置項

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-version

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group ,Data Id 爲 discovery-guide-service-b-sentinel-authority ,規則內容如下,表示版本爲 1.0 的所有服務都允許訪問服務 discovery-guide-service-b 。

[
    {
        "resource": "sentinel-resource",
        "limitApp": "1.0",
        "strategy": 0
    }
]

基於灰度區域的防護機制

修改配置項 Sentinel Request Origin Key 爲灰度區域的 Header 名稱,修改授權規則中 limitApp 爲對應的區域,可實現基於區域的防護機制。

配置項

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-region

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group ,Data Id 爲 discovery-guide-service-b-sentinel-authority ,規則內容如下,表示區域爲 dev 的所有服務都允許訪問服務 discovery-guide-service-b 。

[
    {
        "resource": "sentinel-resource",
        "limitApp": "dev",
        "strategy": 0
    }
]

基於機器地址和端口的防護機制

修改配置項 Sentinel Request Origin Key 爲灰度區域的 Header 名稱,修改授權規則中 limitApp 爲對應的區域值,可實現基於機器地址和端口的防護機制。

配置項

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-address

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group ,Data Id 爲 discovery-guide-service-b-sentinel-authority ,規則內容如下,表示地址和端口爲 192.168.0.88:8081 和 192.168.0.88:8082 的服務都允許訪問服務 discovery-guide-service-b 。

[
    {
        "resource": "sentinel-resource",
        "limitApp": "192.168.0.88:8081,192.168.0.88:8082",
        "strategy": 0
    }
]

自定義業務參數的組合式防護機制

通過適配類實現自定義業務參數的組合式防護機制。

// 版本號+用戶名,實現組合式熔斷
public class MyServiceSentinelRequestOriginAdapter extends DefaultServiceSentinelRequestOriginAdapter {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String version = request.getHeader(DiscoveryConstant.N_D_SERVICE_VERSION);
        String user = request.getHeader("user");

        return version + "&" + user;
    }
}

在配置類裏 @Bean 方式進行適配類創建

@Bean
public ServiceSentinelRequestOriginAdapter ServiceSentinelRequestOriginAdapter() {
    return new MyServiceSentinelRequestOriginAdapter();
}

增加服務 discovery-guide-service-b 的規則,Group 爲 discovery-guide-group , Data Id 爲 discovery-guide-service-b-sentinel-authority ,規則內容如下,表示版本爲 1.0 且傳入的 Http Header 的 user=zhangsan ,同時滿足這兩個條件下的所有服務都允許訪問服務 discovery-guide-service-b 。

[
    {
        "resource": "sentinel-resource",
        "limitApp": "1.0&zhangsan",
        "strategy": 0
    }
]

運行效果:當傳遞的 Http Header 中 user=zhangsan ,當全鏈路調用中, API 網關負載均衡 discovery-guide-service-a 服務到 1.0 版本後再去調用 discovery-guide-service-b 服務,最終調用成功。

如圖所示:
在這裏插入圖片描述
當傳遞的 Http Header 中 user=lisi ,不滿足條件,最終調用在 discovery-guide-service-b 服務端被拒絕掉。

如圖所示:

在這裏插入圖片描述

當傳遞的 Http Header 中 user=zhangsan ,滿足條件之一,當全鏈路調用中, API 網關負載均衡 discovery-guide-service-a 服務到 1.1 版本後再去調用 discovery-guide-service-b 服務,不滿足 version=1.0 的條件,最終調用在 discovery-guide-service-b 服務端被拒絕掉。

如圖所示:
在這裏插入圖片描述

基於 Swagger 的 Sentinel 規則推送

分爲基於單個服務實例和基於服務名對應的多個服務實例的 Sentinel 規則推送。

基於單個服務實例的 Sentinel 規則推送

直接訪問該服務實例的 Swagger 主頁即可。

如圖所示:
在這裏插入圖片描述

基於服務名對應的多個服務實例的 Sentinel 規則推送

需要開啓 discovery-console 服務,並訪問其 Swagger 主頁即可。

如圖所示:
在這裏插入圖片描述
作者介紹:

任浩軍 10 多年開源經歷,Github ID:@HaojunRen,Nepxion 開源社區創始人,Nacos Group Member,Spring Cloud Alibaba & Nacos & Sentinel Committer ,曾就職於平安銀行平臺架構部,負責銀行 PaaS 系統基礎服務框架研發。

王偉華 10 餘年 Java 開發,Github ID:@vipweihua,對微服務架構研究多年,當前更多關注於微服務中的網關、限流熔斷、灰度路由等,現就職於平安銀行平臺架構部,從事銀行 PaaS 系統基礎服務框架研發。

鏈接:原文地址
來源:阿里巴巴中間件 公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章