springboot集成與使用Sentinel的方法
前言
在上一篇中,我們初步了解了Sentinel的基本概念,以及其有關限流方面的基礎理論,本篇將通過簡單的與框架進行整合,看看Sentinel如何在實際項目中進行使用
控制臺安裝與部署
在實際的小微服務中,使用Sentinel做限流還有另一個強大的利器,就是其提供的dashboard,盡管我們可以通過編寫Sentinel提供的一些API限流規則封裝一些通用的方法,但是這對于很多初次接觸Sentinel的同學來說,學習成本仍然不小,而提供的dashboard可以很方便的通過界面配置的方式達到上一篇中我們追求的效果,甚至更加靈活,而開發人員無非要做的就是,在程序代碼中,只需要捕獲限流后的異常并拋給頁面提醒調用者即可,
進入Sentinel的git,點擊下載提供的dashboard,最新的為1.8
下載到本地之后,其實就是一個springboot打成的jar包,windows環境下,cmd窗口,直接通過下面的命令啟動即可,
java -jar -Dserver.port=9100 sentinel-dashboard-1.8.0.jar
啟動成功后,訪問一下吧,初次訪問,需要登錄用戶名和密碼,均為 : sentinel/sentinel
但是進來之后發現空空如也,別緊張,這個dashboard默認是懶加載的,意思就是沒有應用接入進來,它就不展示任何信息,等到我們將本地的服務通過配置接入的時候就能看到效果了
springboot工程快速接入dashboard
1、導入基本的依賴
<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 #注冊中心使用nacos cloud: nacos: discovery: server-addr: IP:8848 #連接sentinel的dashboard sentinel: transport: dashboard: localhost:9100 #設置單個文件最大上傳大小 servlet: multipart: max-file-size: 20MBmybatis-plus: mapper-locations: classpath*:mapper/*.xml global-config: db-column-underline: true #開啟駝峰轉換 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語句便于調試#暴露的健康檢查服務端點management: endpoints: web: exposure: include: ’*’
3、編寫簡單的controller接口
@RestControllerpublic class FlowController { @Autowired private FlowService flowService; @GetMapping('/testFlow') public String testFlow(){ return flowService.doFlow(); }}
瀏覽器訪問一次:localhost:8082/testFlow 之后,這次再觀察dashboard,發現相關的可配置菜單和可視化界面的參數就都展示了出來
dashboard使用簡單說明
其實在上一篇中,我們談到了使用Sentinel提供的API配置的多種限流規則,比如基于QPS下的快速失敗,預熱,勻速隊列,關聯鏈路等,而dashboard上面的配置則正好對應其底層的各種配置規則,下面我們演示幾種常用的場景吧
在簇點鏈路這一欄,圖中可以看到我們的后端服務接口即剛剛調用過的接口就會展示在這里,配置限流規則可以通過加號中的”添加流控“進行配置,
規則1:QPS,如上所示,我們配置了針對訪問testFlow這個接口的所有來源的請求進行QPS的限流,每秒最大允許通過2個請求,
配置完畢后,當我們再次快速訪問接口時,會出現下面的結果,很明顯,我們的配置規則生效了
在上面的演示中,其實我們用到的就是最基本的降級策略,就是基于QPS的快速降級,我們不妨點開高級選項,是不是發現這里有了更多的配置,其實在可視化界面下,使用它做限流規則配置時就是使用它提供的不同配置項組合使用
關聯配置
鏈路配置,比如多個微服務之間存在多級調用時,請求第一個服務接口,而第一個服務再調用第二個服務接口,第一個服務請求接口失敗了,這時候再訪問第二個服務接口時就會快速失敗,通過這種配置規則可以避免服務的雪崩
關于流控效果,在前一篇中我們通過簡單的demo演示了效果,就不再贅述了
關于降級
還以前面的 /testFlow接口為例:
服務降級可能大家并不陌生,即在一個應用中,當請求到某個服務接口長時間沒有響應時,為了避免更多的請求進來造成服務的雪崩,我們采取一種機制,讓程序快速返回結果,或者干脆拋出友好的提示,讓調用者知道當前的服務不可用,這樣就不至于出現服務端的線程資源被耗盡的情況
對于上述圖中的配置,解釋起來就是:超過了每秒請求的閾值之后,后面的請求再過來的時候,在5秒之內,服務處于不可用的狀態,5秒之后,服務恢復,我們通過快速刷新接口,可以看到效果
如果是異常數的配置,則觸發條件如下:
開啟條件:1秒內,有一個/testFlow請求過來,便開啟熔斷檢查 觸發熔斷:當前時間窗口內,有超過50%的請求產生異常 觸發熔斷之后的5秒內,再有請求過來,都會被blockedSentinel異常處理、注解使用、與限流
在上面我們為 /testFlow這個接口配置了限流的規則,當請求超過每秒2個時,后端返回了下面的異常,這個異常是由Sentinel框架自身返回的提示
Blocked by Sentinel (flow limiting)
但在真實的開發中,這樣做并不友好,而且對于調用者來說,并不知道到底出了什么問題,甚至前端的同學也不知道怎么做后續的處理,因此需要服務端對Sentinel的異常進行處理
@SentinelResource
使用這個注解,可以對我們要進行限流的資源接口當出現異常時進行捕獲,比如下面的這個接口 getByResource,@SentinelResource的使用很簡單,最基本的就是配置資源名稱,加上blockHandler ,blockHandler 里面是觸發限流規則時的方法,即在這個方法中進行后續的業務處理,如拋出友好的提示等
@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()); }}
同樣,我們在dashboard中對這個接口進行配置,每秒1次的QPS,正常訪問時,
快速訪問時,就走到了降級后的方法中了
但是如果這么做的話,很明顯的一個問題就是,異常處理的邏輯和業務耦合在一起,代碼會越來越膨脹,后續不方便管理,因此我們單獨提供一個類,這個類專門用于提供不同的異常方法,
public class CustomerBlockHandler { public static ResponseResult handleException(BlockException exe){ return ResponseResult.fail(412,'is block:' + exe.getMessage()); }}
那么在接口中我們就可以這樣調用
@GetMapping('/getByResource1') @SentinelResource(value = 'customerBlockHandler', blockHandlerClass = CustomerBlockHandler.class, blockHandler = 'handleException') public ResponseResult getByResource1(){ return ResponseResult.success('this is success result'); }
同樣,再在控制臺配置限流規則后可以達到我們的效果,
Sentinel降級處理
有這么一種情況,當調用接口時,由于參數校驗不通過,或者后端拋出了運行時的異常,如果沒有合適的處理,將會出現下面的結果,
@GetMapping('/createOrder') @SentinelResource(value = 'fallback') public String createOrder(String id){ if(id.equals('2')){ throw new IllegalArgumentException('參數異常'); } return orderService.createOrder(id); }
顯然,這是一種不太友好的情況,對于這種情況,就可以使用Sentinel的服務降級進行處理了,改造后的接口如下:
@GetMapping('/createOrder') @SentinelResource(value = 'fallback',fallback = 'getFallBack') public String createOrder(String id){ if(id.equals('2')){ throw new IllegalArgumentException('參數異常'); } return orderService.createOrder(id); } public static String getFallBack(String id,Throwable t){ return id + ':=====>' + t.getMessage(); }
再次訪問時,可以看到出現了我們的降級方法,也可以理解為兜底的方法
同樣我們可以利用一個單獨的類,統一處理這樣的降級,如下:
@GetMapping('/createOrder') @SentinelResource(value = 'fallback',fallbackClass = MyFallBackHandler.class,fallback = 'getFallBack') public String createOrder(String id){ if(id.equals('2')){ throw new IllegalArgumentException('參數異常'); } return orderService.createOrder(id); }
public class MyFallBackHandler { public static String getFallBack(String id,Throwable t){ return id + ':=====>' + t.getMessage(); }}
其實在真實的開發中,不管是單應用還是微服務之間的調用,一般情況下可能出現的異常我們基本上都是可以提前預知的,如超時異常,系統參數異常等,這樣我們就可以預設部分的降級處理方法,在適當的接口上面進行引用即可
Sentinel降級處理結合feign的使用
在上一篇和本次的dashboard的講解使用中,我們提到了鏈路的處理規則,對應于不同的微服務來說就是不同的服務之間的調用,當調用某個服務接口失敗時的情況,以openfeign的使用為例,本例我們在createOrder接口中,還調用了storage服務中的接口,
@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'; }
設想,假如在調用getPaymentById接口失敗時,為了不至于因為報錯或者長時間的超時等待造成雪崩,我們可以統一feignService中進行處理,這里需要提供一個類,比如FallBackStorageService,這個類實現了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; }}
即當storage模塊中的getPaymentById服務接口異常或者不可用時,將會由FallBackStorageService 中的getPaymentById進行降級,俗稱兜底
當然不要忘了在yml中添加如下這一句配置,讓Sentinel支持在feign調用時對于異常的生效
feign: sentinel: enabled: true
那我們簡單測試下吧,正常訪問時:
這時我們停掉storage服務,再次訪問上面的接口時,很明顯就走到了我們的降級邏輯中,當然我這里只是做了很簡單的處理,可以在降級邏輯中添加更友好的提示信息
當然上面是服務不可用的時候的降級邏輯,當情況是異常時候,我們可以通過實現FallbackFactory接口進行處理
@Componentpublic class FeignFallbackHandler implements FallbackFactory<StorageFeignService> { @Override public StorageFeignService create(Throwable throwable) { return new StorageFeignService(){ @Override public Integer getPaymentById(String id) {System.out.println('異常觸發:' + throwable.getMessage());return 1001; } }; }}
本篇到這里就要結束了,通過本篇內容,比較詳細的介紹了Sentinel的相關使用,基于dashboard配置的各種限流規則,以及結合程序中進行使用,最后提到了和feign整合使用時的處理方法,篇幅較長,最后感謝觀看!
到此這篇關于springboot集成與使用Sentinel的方法的文章就介紹到這了,更多相關springboot Sentinel集成與使用內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!
相關文章:
