Spring Cloud微服務安全實戰_6-7_sentinel限流實戰


上一篇說了微服務上的限流,用的是guava的RateLimit做的簡單的限流,本篇說用阿里的sentinel   做微服務的限流。

sentinel  是阿里2018年開源的一個開源項目,具體中文文檔:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D 。

簡單來說 Sentinel就是干三件事: 限流、熔斷、降級,來保證服務高可用,不會崩掉(你本身不會崩掉,也不會因為依賴的其他服務崩掉把你帶死)

  

 

 

一、簡單的限流使用場景

流控

  實驗項目

    

 

 

  1,引依賴(微服務上)

 

   找到最新版的maven依賴,加到nb-order-api服務  

<!--阿里巴巴sentinel-->
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-core</artifactId>
   <version>1.7.1</version>
</dependency>

  2,定義資源

    最常見的就是你要保護的方法,或者一段邏輯。

    手動編碼方式,下面代碼中紅色部分就是定義資源try-catch中間就是要保護的邏輯

 * 創建訂單
     * @param info
     * @param
     * @return
     */
    //注解生效需在啟動類配置@EnableGlobalMethodSecurity(prePostEnabled = true)
    //@PreAuthorize("#oauth2.hasScope('write')")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @PostMapping
    public OrderInfo create(@RequestBody OrderInfo info,@AuthenticationPrincipal String username){

        try(Entry entry = SphU.entry("createOrder")){ //資源名稱-createOrder
            // 被保護的邏輯
            log.info("獲取到username = {}",username);
        }catch (BlockException ex){
            // 處理被流控的邏輯
            log.info("blocked!");
        }
        //查詢價格
        //PriceInfo price = restTemplate.getForObject("http://localhost:9080/prices/"+info.getProductId(),PriceInfo.class);
        //log.info("price is "+price.getPrice());
        return info;
    }

  3,定義規則

    針對某個定義的資源(上面的createOrder),定義一個規則,規則有很多種:流控規則、熔斷規則、降級規則,都可以對定義的資源定義規則,這里做一個流控規則的演示。

    新建sentinel的配置類

package com.nb.security;

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * sentinel規則,硬編碼方式
 */
@Component
public class SentinelConfig implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //系統啟動好以后執行
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("createOrder");//資源名稱
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1);//設置QPS=1,每秒1個請求
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

   實驗:啟動訂單服務,用postman直接請求創建訂單服務 http://localhost:9060/orders ,先跳過網關以方便做實驗

  

   查看打印日志可以看出,每秒只能有一個請求通過,其他的則走了catch限流邏輯,這里就可以自定義處理。

  

 3,sentinel日志

  實驗運行之后,會生成一些日志文件,在windows上的目錄是:C:\Users\dev\logs\csp

  

 

   sentinel-record.log.2020-03-16.0 , 可以看出sentinel定義的規則

2020-03-16 09:02:21.729 INFO [FlowRuleManager] Flow rules loaded: {}
2020-03-16 09:02:21.732 INFO App name resolved: com.nb.security.NbOrderApiApplication
2020-03-16 09:02:21.734 INFO [SentinelConfig] Application type resolved: 0
2020-03-16 09:02:21.736 INFO [MetricWriter] Creating new MetricWriter, singleFileSize=52428800, totalFileCount=6
2020-03-16 09:02:21.738 INFO [DynamicSentinelProperty] Config will be updated to: [FlowRule{resource=createOrder, limitApp=default, grade=1, count=1.0, strategy=0, refResource=null, controlBehavior=0, warmUpPeriodSec=10, maxQueueingTimeMs=500, clusterMode=false, clusterConfig=null, controller=null}]
2020-03-16 09:02:21.741 INFO [FlowRuleManager] Flow rules received: {createOrder=[FlowRule{resource=createOrder, limitApp=default, grade=1, count=1.0, strategy=0, refResource=null, controlBehavior=0, warmUpPeriodSec=10, maxQueueingTimeMs=500, clusterMode=false, clusterConfig=null, controller=com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController@2e2b9f53}]}
2020-03-16 09:03:24.012 INFO [InitExecutor] Found init func: com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit
2020-03-16 09:03:24.017 INFO [InitExecutor] Executing com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit with order 2147483647
2020-03-16 09:03:24.019 INFO Add child <sentinel_default_context> to node <machine-root>
2020-03-16 09:03:24.023 INFO [SlotChainProvider] Global slot chain builder resolved: com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder
2020-03-16 09:03:24.030 INFO Add child <createOrder> to node <sentinel_default_context>
2020-03-16 09:03:24.032 INFO [AuthorityRuleManager] Load authority rules: {}
2020-03-16 09:03:24.037 INFO [SystemRuleManager] Current system check status: false, highestSystemLoad: 1.797693e+308, highestCpuUsage: 1.797693e+308, maxRt: 9223372036854775807, maxThread: 9223372036854775807, maxQps: 1.797693e+308
2020-03-16 09:03:24.039 INFO [DegradeRuleManager] Degrade rules loaded: {}
2020-03-16 09:03:24.042 INFO [MetricExtensionProvider] MetricExtension resolved, size=0
2020-03-16 09:03:25.743 INFO [MetricWriter] New metric file created: C:\Users\dev\logs\csp\com-nb-security-NbOrderApiApplication-metrics.log.2020-03-16
2020-03-16 09:03:25.744 INFO [MetricWriter] New metric index file created: C:\Users\dev\logs\csp\com-nb-security-NbOrderApiApplication-metrics.log.2020-03-16.idx

   com-nb-security-NbOrderApiApplication-metrics.log.2020-03-16 可以看出流量變化情況

 

|--timestamp-|------date time----|--resource-|p |block|s |e|rt

1584320604000|2020-03-16 09:03:24|createOrder|1|0|1|0|14|0|0|0
1584320610000|2020-03-16 09:03:30|createOrder|1|0|1|0|0|0|0|0
1584320611000|2020-03-16 09:03:31|createOrder|1|0|1|0|0|0|0|0
1584320713000|2020-03-16 09:05:13|createOrder|1|0|1|0|1|0|0|0
1584320716000|2020-03-16 09:05:16|createOrder|1|1|1|0|1|0|0|0
1584320718000|2020-03-16 09:05:18|createOrder|1|0|1|0|0|0|0|0
1584320719000|2020-03-16 09:05:19|createOrder|1|0|1|0|1|0|0|0
1584320722000|2020-03-16 09:05:22|createOrder|1|1|1|0|0|0|0|0
1584320723000|2020-03-16 09:05:23|createOrder|1|0|1|0|0|0|0|0
1584320724000|2020-03-16 09:05:24|createOrder|1|0|1|0|0|0|0|0

         其中 p 代表通過的請求, block 代表被阻止的請求, s 代表成功執行完成的請求個數, e 代表用戶自定義的異常, rt 代表平均響應時長。

   

  4,啟動 Sentinel 控制台

    官方文檔 https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0#2-%E5%90%AF%E5%8A%A8%E6%8E%A7%E5%88%B6%E5%8F%B0

     下載 Dashboard jar包 :https://github.com/alibaba/Sentinel/releases ,是一個springboot項目。

      

 

 

     啟動jar包: 其中 -Dserver.port=8888 用於指定 Sentinel 控制台端口為 8888

java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar

    

 

 

     默認用戶名 密碼都是sentinel ,如需修改請參照官方文檔

    

 

     首頁 ,默認是他自己

                

 

 

     

    5,客戶端接入控制台 

       官方文檔 https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0#2-%E5%90%AF%E5%8A%A8%E6%8E%A7%E5%88%B6%E5%8F%B0

      有兩種方式,一種是通過制定JVM參數的形式,這種springboot不友好這里就不說了。

      如果是springboot項目就應該這么做,通過Spring Cloud Alibaba Sentinel配置https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

      引依賴(不需要上面說的 sentinel-transport-simple-http的依賴了          

        <!-- https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel-->
        <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
         <version>0.9.0.RELEASE</version>
        </dependency>

        使用注解定義資源 

        

 

 

          配置控制台信息   application.yml

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8888

          這里的 spring.cloud.sentinel.transport.port 端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一個限流規則,會把規則數據 push 給這個 Http Server 接收,Http Server 再將規則注冊到 Sentinel 中

    啟動order-api,http://localhost:8888 就可以訪問sentinel控制台了 

二,熔斷降級 

  為什么要有熔斷降級? 

  服務雪崩舉例:

 

  

 

 

 

 

  比如A是訂單服務,它會調用商品服務B,調用價格服務C,調用用戶服務D。

  服務一切正常的時候是沒問題的,假設用戶服務D因為網絡抖動或者壓力變大,導致響應時間變慢,原來是10毫秒,現在變成了100、1000毫秒。

  這時候A服務調D服務的時候,當前線程就會卡住了,線程就會等待D服務的響應。等待的時候繼續有請求進來調用A服務,A服務就會開新的線程去調D服務,D服務沒響應,就會在這等着。這樣請求A服務的繼續進來,請求就一直的等着,到了一定閾值后,就沒辦法新建線程了,所有線程都占滿了,此時A服務也失去響應了。此時有依賴A服務的服務也不行了,引起連鎖反應。根本的問題是D服務不行了,這樣導致跟D有依賴關系的所有的服務都出問題。這就是服務雪崩。

  熔斷:

    這時候就需要用熔斷的方式,保證某一個服務出問題,不會把直接或者間接依賴它的所有的服務都帶死。

               

 

 

 

 

    原理就是在所有的服務前面加一個熔斷器,熔斷器平常處於關閉的狀態,熔斷器一旦發現后面服務(服務D)有問題不可用了,就打開熔斷器。此時服務A再調用服務D的時候,到熔斷器這就直接返回了。

    請求不會到達服務D,服務A這就不會因為服務D響應變慢而有線程堆積,等待,這樣就解決了服務雪崩的問題。

    

    熔斷器機制示意

        

 

      1,當一個請求過來

          如果熔斷器是關閉的,請求就放給后面的業務父服務。

          如果業務服務出問題(拋異常、網絡抖動、壓力大響應時間變長、服務超時),在熔斷器這都會做一個統計,比如從熔斷器放過去10個請求,5個超時,3個報錯,熔斷器都會進行統計。

          可以在自己配置熔斷器什么情況從關閉狀態變為打開狀態。如果觸發了熔斷器打開狀態,請求到熔斷器這就直接返回回去了。

      2,如果是因為網絡抖動 或者 瞬時壓力變大導致的熔斷器打開,等網絡恢復或者后面壓力變小了,其實是又可以正常提供服務的,就需要有個機制讓熔斷器知道后面的服務恢復正常了,重新讓熔斷器回到關閉狀態。

        機制就是:熔斷器這會有一個定時任務,在一定的時間周期內,到了時間周期,就將熔斷器轉為【半打開狀態】,會放一個請求給后面的業務服務,如果業務服務可以成功處理,就從半打開狀態變為關閉狀態。

              如果放過去的這一個請求仍然是失敗狀態,熔斷器就回到打開狀態。過一個時間周期,再做一次這么的循環,一旦有一個請求成功了,就轉為關閉狀態。

    降級:

      熔斷器打開的時候,指定一個更簡化的業務邏輯處理。

      比如,后面的服務是一個推薦的服務,正常的推薦是根據用戶的用戶畫像,算出推薦的商品,但是這個服務需要實時計算的,如果壓力大變慢了,熔斷器處於打開狀態后,可以指定一個預先設計好的簡化的邏輯,一個商品列表,靜態的。當熔斷器打開的時候就直接返回這個列表,用戶還可以看到一個商品列表,但是就不是根據用戶推薦給他的,服務降級了。

 

  在sentinel指定熔斷降級規則

  1,通過編碼方式

    

 

 

 

 

    

 

 

 

 

 

     調用創建訂單,跨省

    

 

     熔斷異常信息

      

 

 

     降級

      

 

 

       

   一般通過控制台指定各種規則,那就可以去掉 SentinelConfig配置了。

代碼 :https://github.com/lhy1234/springcloud-security/tree/chapt-6-6-sentinel-ratelimit

 

歡迎關注個人公眾號一起交流學習:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM