springboot集成與使用Sentinel的方法
前言
在上一篇中,我們初步了解了Sentinel的基本概念,以及其有關(guān)限流方面的基礎(chǔ)理論,本篇將通過(guò)簡(jiǎn)單的與框架進(jìn)行整合,看看Sentinel如何在實(shí)際項(xiàng)目中進(jìn)行使用
控制臺(tái)安裝與部署
在實(shí)際的小微服務(wù)中,使用Sentinel做限流還有另一個(gè)強(qiáng)大的利器,就是其提供的dashboard,盡管我們可以通過(guò)編寫Sentinel提供的一些API限流規(guī)則封裝一些通用的方法,但是這對(duì)于很多初次接觸Sentinel的同學(xué)來(lái)說(shuō),學(xué)習(xí)成本仍然不小,而提供的dashboard可以很方便的通過(guò)界面配置的方式達(dá)到上一篇中我們追求的效果,甚至更加靈活,而開(kāi)發(fā)人員無(wú)非要做的就是,在程序代碼中,只需要捕獲限流后的異常并拋給頁(yè)面提醒調(diào)用者即可,
進(jìn)入Sentinel的git,點(diǎn)擊下載提供的dashboard,最新的為1.8
下載到本地之后,其實(shí)就是一個(gè)springboot打成的jar包,windows環(huán)境下,cmd窗口,直接通過(guò)下面的命令啟動(dòng)即可,
java -jar -Dserver.port=9100 sentinel-dashboard-1.8.0.jar
啟動(dòng)成功后,訪問(wèn)一下吧,初次訪問(wèn),需要登錄用戶名和密碼,均為 : sentinel/sentinel
但是進(jìn)來(lái)之后發(fā)現(xiàn)空空如也,別緊張,這個(gè)dashboard默認(rèn)是懶加載的,意思就是沒(méi)有應(yīng)用接入進(jìn)來(lái),它就不展示任何信息,等到我們將本地的服務(wù)通過(guò)配置接入的時(shí)候就能看到效果了
springboot工程快速接入dashboard
1、導(dǎo)入基本的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector-java.version}</version> </dependency><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
2、yml配置
server: port: 8082spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://IT:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false username: root password: root#logging:# config: classpath:logback-spring.xml #日志 application: name: service-order #注冊(cè)中心使用nacos cloud: nacos: discovery: server-addr: IP:8848 #連接sentinel的dashboard sentinel: transport: dashboard: localhost:9100 #設(shè)置單個(gè)文件最大上傳大小 servlet: multipart: max-file-size: 20MBmybatis-plus: mapper-locations: classpath*:mapper/*.xml global-config: db-column-underline: true #開(kāi)啟駝峰轉(zhuǎn)換 db-config: id-type: uuid field-strategy: not_null refresh: true configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql語(yǔ)句便于調(diào)試#暴露的健康檢查服務(wù)端點(diǎn)management: endpoints: web: exposure: include: ’*’
3、編寫簡(jiǎn)單的controller接口
@RestControllerpublic class FlowController { @Autowired private FlowService flowService; @GetMapping('/testFlow') public String testFlow(){ return flowService.doFlow(); }}
瀏覽器訪問(wèn)一次:localhost:8082/testFlow 之后,這次再觀察dashboard,發(fā)現(xiàn)相關(guān)的可配置菜單和可視化界面的參數(shù)就都展示了出來(lái)
dashboard使用簡(jiǎn)單說(shuō)明
其實(shí)在上一篇中,我們談到了使用Sentinel提供的API配置的多種限流規(guī)則,比如基于QPS下的快速失敗,預(yù)熱,勻速隊(duì)列,關(guān)聯(lián)鏈路等,而dashboard上面的配置則正好對(duì)應(yīng)其底層的各種配置規(guī)則,下面我們演示幾種常用的場(chǎng)景吧
在簇點(diǎn)鏈路這一欄,圖中可以看到我們的后端服務(wù)接口即剛剛調(diào)用過(guò)的接口就會(huì)展示在這里,配置限流規(guī)則可以通過(guò)加號(hào)中的”添加流控“進(jìn)行配置,
規(guī)則1:QPS,如上所示,我們配置了針對(duì)訪問(wèn)testFlow這個(gè)接口的所有來(lái)源的請(qǐng)求進(jìn)行QPS的限流,每秒最大允許通過(guò)2個(gè)請(qǐng)求,
配置完畢后,當(dāng)我們?cè)俅慰焖僭L問(wèn)接口時(shí),會(huì)出現(xiàn)下面的結(jié)果,很明顯,我們的配置規(guī)則生效了
在上面的演示中,其實(shí)我們用到的就是最基本的降級(jí)策略,就是基于QPS的快速降級(jí),我們不妨點(diǎn)開(kāi)高級(jí)選項(xiàng),是不是發(fā)現(xiàn)這里有了更多的配置,其實(shí)在可視化界面下,使用它做限流規(guī)則配置時(shí)就是使用它提供的不同配置項(xiàng)組合使用
關(guān)聯(lián)配置
鏈路配置,比如多個(gè)微服務(wù)之間存在多級(jí)調(diào)用時(shí),請(qǐng)求第一個(gè)服務(wù)接口,而第一個(gè)服務(wù)再調(diào)用第二個(gè)服務(wù)接口,第一個(gè)服務(wù)請(qǐng)求接口失敗了,這時(shí)候再訪問(wèn)第二個(gè)服務(wù)接口時(shí)就會(huì)快速失敗,通過(guò)這種配置規(guī)則可以避免服務(wù)的雪崩
關(guān)于流控效果,在前一篇中我們通過(guò)簡(jiǎn)單的demo演示了效果,就不再贅述了
關(guān)于降級(jí)
還以前面的 /testFlow接口為例:
服務(wù)降級(jí)可能大家并不陌生,即在一個(gè)應(yīng)用中,當(dāng)請(qǐng)求到某個(gè)服務(wù)接口長(zhǎng)時(shí)間沒(méi)有響應(yīng)時(shí),為了避免更多的請(qǐng)求進(jìn)來(lái)造成服務(wù)的雪崩,我們采取一種機(jī)制,讓程序快速返回結(jié)果,或者干脆拋出友好的提示,讓調(diào)用者知道當(dāng)前的服務(wù)不可用,這樣就不至于出現(xiàn)服務(wù)端的線程資源被耗盡的情況
對(duì)于上述圖中的配置,解釋起來(lái)就是:超過(guò)了每秒請(qǐng)求的閾值之后,后面的請(qǐng)求再過(guò)來(lái)的時(shí)候,在5秒之內(nèi),服務(wù)處于不可用的狀態(tài),5秒之后,服務(wù)恢復(fù),我們通過(guò)快速刷新接口,可以看到效果
如果是異常數(shù)的配置,則觸發(fā)條件如下:
開(kāi)啟條件:1秒內(nèi),有一個(gè)/testFlow請(qǐng)求過(guò)來(lái),便開(kāi)啟熔斷檢查 觸發(fā)熔斷:當(dāng)前時(shí)間窗口內(nèi),有超過(guò)50%的請(qǐng)求產(chǎn)生異常 觸發(fā)熔斷之后的5秒內(nèi),再有請(qǐng)求過(guò)來(lái),都會(huì)被blockedSentinel異常處理、注解使用、與限流
在上面我們?yōu)?/testFlow這個(gè)接口配置了限流的規(guī)則,當(dāng)請(qǐng)求超過(guò)每秒2個(gè)時(shí),后端返回了下面的異常,這個(gè)異常是由Sentinel框架自身返回的提示
Blocked by Sentinel (flow limiting)
但在真實(shí)的開(kāi)發(fā)中,這樣做并不友好,而且對(duì)于調(diào)用者來(lái)說(shuō),并不知道到底出了什么問(wèn)題,甚至前端的同學(xué)也不知道怎么做后續(xù)的處理,因此需要服務(wù)端對(duì)Sentinel的異常進(jìn)行處理
@SentinelResource
使用這個(gè)注解,可以對(duì)我們要進(jìn)行限流的資源接口當(dāng)出現(xiàn)異常時(shí)進(jìn)行捕獲,比如下面的這個(gè)接口 getByResource,@SentinelResource的使用很簡(jiǎn)單,最基本的就是配置資源名稱,加上blockHandler ,blockHandler 里面是觸發(fā)限流規(guī)則時(shí)的方法,即在這個(gè)方法中進(jìn)行后續(xù)的業(yè)務(wù)處理,如拋出友好的提示等
@RestControllerpublic class RateLimitController { @GetMapping('/getByResource') @SentinelResource(value = 'getByResource',blockHandler = 'handleException') public ResponseResult getByResource(){ return ResponseResult.success('this is success result'); } public ResponseResult handleException(BlockException blockExe){ return ResponseResult.fail(412,'is block:' + blockExe.getMessage()); }}
同樣,我們?cè)赿ashboard中對(duì)這個(gè)接口進(jìn)行配置,每秒1次的QPS,正常訪問(wèn)時(shí),
快速訪問(wèn)時(shí),就走到了降級(jí)后的方法中了
但是如果這么做的話,很明顯的一個(gè)問(wèn)題就是,異常處理的邏輯和業(yè)務(wù)耦合在一起,代碼會(huì)越來(lái)越膨脹,后續(xù)不方便管理,因此我們單獨(dú)提供一個(gè)類,這個(gè)類專門用于提供不同的異常方法,
public class CustomerBlockHandler { public static ResponseResult handleException(BlockException exe){ return ResponseResult.fail(412,'is block:' + exe.getMessage()); }}
那么在接口中我們就可以這樣調(diào)用
@GetMapping('/getByResource1') @SentinelResource(value = 'customerBlockHandler', blockHandlerClass = CustomerBlockHandler.class, blockHandler = 'handleException') public ResponseResult getByResource1(){ return ResponseResult.success('this is success result'); }
同樣,再在控制臺(tái)配置限流規(guī)則后可以達(dá)到我們的效果,
Sentinel降級(jí)處理
有這么一種情況,當(dāng)調(diào)用接口時(shí),由于參數(shù)校驗(yàn)不通過(guò),或者后端拋出了運(yùn)行時(shí)的異常,如果沒(méi)有合適的處理,將會(huì)出現(xiàn)下面的結(jié)果,
@GetMapping('/createOrder') @SentinelResource(value = 'fallback') public String createOrder(String id){ if(id.equals('2')){ throw new IllegalArgumentException('參數(shù)異常'); } return orderService.createOrder(id); }
顯然,這是一種不太友好的情況,對(duì)于這種情況,就可以使用Sentinel的服務(wù)降級(jí)進(jìn)行處理了,改造后的接口如下:
@GetMapping('/createOrder') @SentinelResource(value = 'fallback',fallback = 'getFallBack') public String createOrder(String id){ if(id.equals('2')){ throw new IllegalArgumentException('參數(shù)異常'); } return orderService.createOrder(id); } public static String getFallBack(String id,Throwable t){ return id + ':=====>' + t.getMessage(); }
再次訪問(wèn)時(shí),可以看到出現(xiàn)了我們的降級(jí)方法,也可以理解為兜底的方法
同樣我們可以利用一個(gè)單獨(dú)的類,統(tǒng)一處理這樣的降級(jí),如下:
@GetMapping('/createOrder') @SentinelResource(value = 'fallback',fallbackClass = MyFallBackHandler.class,fallback = 'getFallBack') public String createOrder(String id){ if(id.equals('2')){ throw new IllegalArgumentException('參數(shù)異常'); } return orderService.createOrder(id); }
public class MyFallBackHandler { public static String getFallBack(String id,Throwable t){ return id + ':=====>' + t.getMessage(); }}
其實(shí)在真實(shí)的開(kāi)發(fā)中,不管是單應(yīng)用還是微服務(wù)之間的調(diào)用,一般情況下可能出現(xiàn)的異常我們基本上都是可以提前預(yù)知的,如超時(shí)異常,系統(tǒng)參數(shù)異常等,這樣我們就可以預(yù)設(shè)部分的降級(jí)處理方法,在適當(dāng)?shù)慕涌谏厦孢M(jìn)行引用即可
Sentinel降級(jí)處理結(jié)合feign的使用
在上一篇和本次的dashboard的講解使用中,我們提到了鏈路的處理規(guī)則,對(duì)應(yīng)于不同的微服務(wù)來(lái)說(shuō)就是不同的服務(wù)之間的調(diào)用,當(dāng)調(diào)用某個(gè)服務(wù)接口失敗時(shí)的情況,以openfeign的使用為例,本例我們?cè)赾reateOrder接口中,還調(diào)用了storage服務(wù)中的接口,
@Component@FeignClient(value = 'service-storage')public interface StorageFeignService { @GetMapping(value = '/storage/get/{id}') public Integer getPaymentById(@PathVariable('id') String id);}
@Autowired private StorageFeignService feignService; @Override public String createOrder(String id) { int storage = feignService.getPaymentById(id); log.info('storage is = {}',storage); return 'success'; }
設(shè)想,假如在調(diào)用getPaymentById接口失敗時(shí),為了不至于因?yàn)閳?bào)錯(cuò)或者長(zhǎng)時(shí)間的超時(shí)等待造成雪崩,我們可以統(tǒng)一feignService中進(jìn)行處理,這里需要提供一個(gè)類,比如FallBackStorageService,這個(gè)類實(shí)現(xiàn)了StorageFeignService 接口
@Component@FeignClient(value = 'service-storage',fallback = FallBackStorageService.class)public interface StorageFeignService { @GetMapping(value = '/storage/get/{id}') public Integer getPaymentById(@PathVariable('id') String id);}
@Componentpublic class FallBackStorageService implements StorageFeignService { @Override public Integer getPaymentById(String id) { return 1001; }}
即當(dāng)storage模塊中的getPaymentById服務(wù)接口異常或者不可用時(shí),將會(huì)由FallBackStorageService 中的getPaymentById進(jìn)行降級(jí),俗稱兜底
當(dāng)然不要忘了在yml中添加如下這一句配置,讓Sentinel支持在feign調(diào)用時(shí)對(duì)于異常的生效
feign: sentinel: enabled: true
那我們簡(jiǎn)單測(cè)試下吧,正常訪問(wèn)時(shí):
這時(shí)我們停掉storage服務(wù),再次訪問(wèn)上面的接口時(shí),很明顯就走到了我們的降級(jí)邏輯中,當(dāng)然我這里只是做了很簡(jiǎn)單的處理,可以在降級(jí)邏輯中添加更友好的提示信息
當(dāng)然上面是服務(wù)不可用的時(shí)候的降級(jí)邏輯,當(dāng)情況是異常時(shí)候,我們可以通過(guò)實(shí)現(xiàn)FallbackFactory接口進(jìn)行處理
@Componentpublic class FeignFallbackHandler implements FallbackFactory<StorageFeignService> { @Override public StorageFeignService create(Throwable throwable) { return new StorageFeignService(){ @Override public Integer getPaymentById(String id) {System.out.println('異常觸發(fā):' + throwable.getMessage());return 1001; } }; }}
本篇到這里就要結(jié)束了,通過(guò)本篇內(nèi)容,比較詳細(xì)的介紹了Sentinel的相關(guān)使用,基于dashboard配置的各種限流規(guī)則,以及結(jié)合程序中進(jìn)行使用,最后提到了和feign整合使用時(shí)的處理方法,篇幅較長(zhǎng),最后感謝觀看!
到此這篇關(guān)于springboot集成與使用Sentinel的方法的文章就介紹到這了,更多相關(guān)springboot Sentinel集成與使用內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. ASP常用日期格式化函數(shù) FormatDate()2. CSS hack用法案例詳解3. XML入門的常見(jiàn)問(wèn)題(四)4. HTML5 Canvas繪制圖形從入門到精通5. CSS可以做的幾個(gè)令你嘆為觀止的實(shí)例分享6. ASP 信息提示函數(shù)并作返回或者轉(zhuǎn)向7. 概述IE和SQL2k開(kāi)發(fā)一個(gè)XML聊天程序8. html加css樣式實(shí)現(xiàn)js美食項(xiàng)目首頁(yè)示例代碼9. CSS3實(shí)現(xiàn)動(dòng)態(tài)翻牌效果 仿百度貼吧3D翻牌一次動(dòng)畫特效10. CSS Hack大全-教你如何區(qū)分出IE6-IE10、FireFox、Chrome、Opera
