之八 2流高手速成記:基于Sentinel實現微服務體系下的限流與熔斷

我們接上回
上一篇中 , 我們進行了簡要的微服務實現,也體會到了SpringCloudAlibaba的強大和神奇之處
我們僅改動了兩個注釋 , 其他全篇代碼不變,原來的獨立服務就被我們分為了provider和consumer兩個獨立部分,二者各司其職,分工明確
篇尾我們留下了一個疑問,consumer對provider有依存關系 , 如果下游的provider出現異常,上游的consumer如何自處?
其實這種單一的上下游關系僅是微服務日常運轉下各種復雜情境的一個縮影,真實的生產環境下各個微服務節點可能會形成更為復雜的依賴關系,那我們該如何解決這些問題?
本節中我們引入Sentinel框架:
什么是 Sentinel?

在基于 SpringCloud 構建的微服務體系中,服務間的調用鏈路會隨著系統的演進變得越來越長,這無疑會增加了整個系統的不可靠因素 。
在并發流量比較高的情況下,由于網絡調用之間存在一定的超時時間,鏈路中的某個服務出現宕機都會大大增加整個調用鏈路的響應時間,而瞬間的流量洪峰則會導致這條鏈路上所有服務的可用線程資源被打滿,從而造成整體服務的不可用,這也就是我們常說的 “雪崩效應” 。
而在微服務系統設計的過程中 , 為了應對這樣的糟糕情況,最常用的手段就是進行 ”流量控制“ 以及對網絡服務的調用實現“熔斷降級” 。因此,Sentinel 就因運而生了 。
Sentinel 是一款面向分布式服務架構的輕量級流量控制組件,主要以流量為切入點,從流量控制、熔斷降級、系統自適應保護等多個維度來保障服務的穩定性,核心思想是:根據對應資源配置的規則來為資源執行相應的流控/降級/系統保護策略 , Sentinel 的主要特性如下圖:
之八 2流高手速成記:基于Sentinel實現微服務體系下的限流與熔斷

文章插圖
以上內容來源于Sentinel官方文檔,看到這一大堆不明所以的名詞接釋,新入坑的同學可能已經勸退了 。。
接下來我們依然沿用前幾篇的思想,先不要管這一堆的理論,先來看怎么用,實際運用過程中如何達到我們預期的效果,返回來再看這些名詞,你自然會有更清晰的認知
Sentinel怎么用?Sentinel的使用分為兩部分 —— 代碼和控制臺
首先我們先下載Sentinel控制臺:https://github.com/alibaba/Sentinel/tags , 本節中我使用的是Sentinel1.8版本
下載編譯好的jar包,而后執行命令行:
java -jar .\sentinel-dashboard.jar --server.port=9999之后我們打開瀏覽器,輸入地址:http://127.0.0.1:9999/
打開Sentinel控制臺如圖所示:
之八 2流高手速成記:基于Sentinel實現微服務體系下的限流與熔斷

文章插圖
整個面板是空白的,什么都沒有?!不用著急,我們繼續往下看代碼的部分
上一節我們提到了微服務環境下consumer工程存在的隱患問題,接下來我們就要消除這個隱患!
dubbo-nacos-consumer工程引入Sentinel依賴庫<!-- 引入sentinel依賴 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>這一步肯定是必須的,沒什么好解釋的
添加Sentinel相關配置
之八 2流高手速成記:基于Sentinel實現微服務體系下的限流與熔斷

文章插圖
在SpringCloudAlibaba體系下,我們以Nacos為配置中心,所以我們編輯Nacos中的相關配置即可,非常方便
我把代碼文本也貼出來,便于大家自行復制
# sentinel看板配置spring.cloud.sentinel.transport.dashboard = 127.0.0.1:9999# 開啟對sentinel看板的饑餓式加載 。sentinel默認是懶加載機制,只有訪問過一次的資源才會被監控,通過關閉懶加載,在項目啟動時就連接sentinel控制臺spring.cloud.sentinel.eager = true這兩句的主要意圖在于將Consumer工程關聯到Sentinel控制臺,便于后續通過控制臺統一管控
改造原有的PersonController我們先創建一個ViewObject
之八 2流高手速成記:基于Sentinel實現微服務體系下的限流與熔斷

文章插圖
代碼如下:
package com.example.dubbonacosconsumer.vo;import com.example.dubbonacosapi.model.Person;import java.util.List;public class SelectRetVo {private List<Person> persons;private String error;public List<Person> getPersons() {return persons;}public void setPersons(List<Person> persons) {this.persons = persons;}public String getError() {return error;}public void setError(String error) {this.error = error;}}然后是PersonController的改造
package com.example.dubbonacosconsumer.controller;import com.alibaba.csp.sentinel.annotation.SentinelResource;import com.alibaba.csp.sentinel.slots.block.BlockException;import com.example.dubbonacosapi.model.Person;import com.example.dubbonacosapi.service.PersonService;import com.example.dubbonacosconsumer.vo.SelectRetVo;import org.apache.dubbo.config.annotation.DubboReference;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;@RestController@RequestMapping("/person")public class PersonController {@DubboReferencePersonService service;@PostMapping("/insert")public Integer insert(Person person) {return service.insert(person);}@PostMapping("/update")public Integer update(Person person) {return service.update(person);}@PostMapping("/delete")public Integer delete(int id) {return service.delete(id);}@GetMapping("/select")@SentinelResource(value = "https://www.huyubaike.com/biancheng/person/select", blockHandler = "selectBlock")public SelectRetVo select() {SelectRetVo vo = new SelectRetVo();vo.setPersons(service.select());vo.setError("ok");return vo;}public SelectRetVo selectBlock(BlockException e) {SelectRetVo vo = new SelectRetVo();vo.setPersons(new ArrayList<Person>());vo.setError(“當前訪問人數過多,請稍后...”);return vo;}}

推薦閱讀