開心一刻
昨天看到一條廣告:全國比醜大賽,一等獎 2 萬獎金
我高高興興騎著腳踏車去了場地,結果被保安攔著不讓進
我心裡竊喜:莫非我長得不醜,不符合參賽條件?
我說道:為什麼不讓我進
保安:這是業餘人員間的比賽,職業選手不能參加
敢情不是不醜,而是太醜!

書接上回
上篇 不單獨部署註冊中心,又要具備註冊中心的功能,咋不讓我上天?
說道 任務分發中心
既整合了 Eureka Server
,還整合了 Eureka Client
,實現了對 任務執行器
的負責均衡,已經很完美的實現了需求
有兩個服務:任務分發中心、任務執行器
分發中心負責任務拆分,然後將拆分後的任務下發給執行器,執行器執行任務
任務分發中心和任務執行器都要支援水平擴節點
當我向領導反饋我的實現時,得到了我想要的肯定

但又給我引申了需求,他說
- 任務分發中心只呼叫一個服務:任務執行器,引入
open-feign
感覺沒什麼必要Eureka Server
肯定是儲存了任務執行器
的例項,是不是可以不開啟@EnableEurekaClient
(言外之意就是任務分發中心不要做Eureka Client
)
雖然我心中一萬隻草泥馬奔騰而過,十分不願意去修改,但理性告訴我他是對的,是可以繼續簡化(人家能當領導確實是有兩把刷子的!)
我們分析下,如果我們拿到了 任務執行器
列表,那麼我們就可以根據負載均衡策略選擇其中某個例項進行任務分發,所以重點是如何獲取 任務執行器
列表
獲取服務例項列表
如何獲取 任務執行器
列表,大家就不要想著 @EnableEurekaClient
了,因為引申需求的第 2 點就限制了不能用 EurekaClient
,那怎麼辦?
我就不繞圈子了,我們需要用到一個 holder
:EurekaServerContextHolder
,藉此我們就能拿到 任務執行器
例項列表,例如:

拿到例項列表後,該做什麼了?
是不是負載均衡選擇其中某個例項?
負載均衡
拿到例項列表後,我們可以自實現負載均衡策略,但是不推薦,這就跟我為什麼不自實現 註冊中心
是一個道理,選擇現成的、成熟的負載均衡器更具價效比
不是自實現不起,而是現成更具價效比!
這次就不選擇 Ribbon
了,因為我們選擇的 Spring Cloud 2021.0.8
預設包含的負載均衡器是 spring-cloud-balancer

服務例項列表已經獲取到了,負載均衡器也有了,接下來做什麼?
那就是將例項列表註冊給負載均衡器,如下所示

接下來是不是就只差任務分發了?
任務分發
我們要明確,我們的 task-executor
提供的是一個 HTTP
介面,所以我們接下來要考慮的是如何去請求這個介面
至於是請求哪個
task-executor
例項,就交給負載均衡器了
傳送 HTTP
請求的方式不要太多,而 Spring
的 RestTemplate
就是其中之一,為了不額外引用第三方 HTTP
工具,也為了適配負載均衡器,推薦就是用 RestTemplate

至此,就只差臨門一腳了,那就是透過 RestTemplate
進行任務分發

啟動 task-dispatcher
、task-executor
,然後呼叫介面
http://192.168.2.10:8080/dispatcher/job/dispatch?jobId=689
結果 success
,日誌輸出如下
-
task-dispatcher
2024-07-05 22:53:52.606|INFO|http-nio-8080-exec-9|30|com.qsl.task.web.JobController :收到作業[jobId=689]執行請求 2024-07-05 22:53:52.606|INFO|http-nio-8080-exec-9|31|com.qsl.task.web.JobController :作業[jobId=689]拆分任務中... 2024-07-05 22:53:52.606|INFO|http-nio-8080-exec-9|33|com.qsl.task.web.JobController :作業[jobId=689]拆分完成,得到作業列表[[123, 666, 888, 999]] 2024-07-05 22:53:52.611|INFO|http-nio-8080-exec-9|39|com.qsl.task.web.JobController :任務[123]執行結果:success 2024-07-05 22:53:52.614|INFO|http-nio-8080-exec-9|39|com.qsl.task.web.JobController :任務[666]執行結果:success 2024-07-05 22:53:52.617|INFO|http-nio-8080-exec-9|39|com.qsl.task.web.JobController :任務[888]執行結果:success 2024-07-05 22:53:52.619|INFO|http-nio-8080-exec-9|39|com.qsl.task.web.JobController :任務[999]執行結果:success
-
task-executor
2024-07-05 22:53:52.609|INFO|http-nio-8081-exec-3|17|com.qsl.task.web.TaskController :收到任務[taskId=123]執行請求 2024-07-05 22:53:52.609|INFO|http-nio-8081-exec-3|18|com.qsl.task.web.TaskController :任務[taskId=123]執行中... 2024-07-05 22:53:52.610|INFO|http-nio-8081-exec-3|19|com.qsl.task.web.TaskController :任務[taskId=123]執行完成 2024-07-05 22:53:52.612|INFO|http-nio-8081-exec-2|17|com.qsl.task.web.TaskController :收到任務[taskId=666]執行請求 2024-07-05 22:53:52.613|INFO|http-nio-8081-exec-2|18|com.qsl.task.web.TaskController :任務[taskId=666]執行中... 2024-07-05 22:53:52.613|INFO|http-nio-8081-exec-2|19|com.qsl.task.web.TaskController :任務[taskId=666]執行完成 2024-07-05 22:53:52.615|INFO|http-nio-8081-exec-4|17|com.qsl.task.web.TaskController :收到任務[taskId=888]執行請求 2024-07-05 22:53:52.616|INFO|http-nio-8081-exec-4|18|com.qsl.task.web.TaskController :任務[taskId=888]執行中... 2024-07-05 22:53:52.616|INFO|http-nio-8081-exec-4|19|com.qsl.task.web.TaskController :任務[taskId=888]執行完成 2024-07-05 22:53:52.618|INFO|http-nio-8081-exec-1|17|com.qsl.task.web.TaskController :收到任務[taskId=999]執行請求 2024-07-05 22:53:52.618|INFO|http-nio-8081-exec-1|18|com.qsl.task.web.TaskController :任務[taskId=999]執行中... 2024-07-05 22:53:52.618|INFO|http-nio-8081-exec-1|19|com.qsl.task.web.TaskController :任務[taskId=999]執行完成
目前 task-executor
是單例項,我們再啟動一個例項,來看看負載均衡效果
-
task-executor 8081
2024-07-05 22:59:01.311|INFO|http-nio-8081-exec-6|17|com.qsl.task.web.TaskController :收到任務[taskId=123]執行請求 2024-07-05 22:59:01.312|INFO|http-nio-8081-exec-6|18|com.qsl.task.web.TaskController :任務[taskId=123]執行中... 2024-07-05 22:59:01.312|INFO|http-nio-8081-exec-6|19|com.qsl.task.web.TaskController :任務[taskId=123]執行完成 2024-07-05 22:59:01.391|INFO|http-nio-8081-exec-7|17|com.qsl.task.web.TaskController :收到任務[taskId=888]執行請求 2024-07-05 22:59:01.391|INFO|http-nio-8081-exec-7|18|com.qsl.task.web.TaskController :任務[taskId=888]執行中... 2024-07-05 22:59:01.391|INFO|http-nio-8081-exec-7|19|com.qsl.task.web.TaskController :任務[taskId=888]執行完成
-
task-executor 8090
2024-07-05 22:59:01.379|INFO|http-nio-8090-exec-2|17|com.qsl.task.web.TaskController :收到任務[taskId=666]執行請求 2024-07-05 22:59:01.380|INFO|http-nio-8090-exec-2|18|com.qsl.task.web.TaskController :任務[taskId=666]執行中... 2024-07-05 22:59:01.380|INFO|http-nio-8090-exec-2|19|com.qsl.task.web.TaskController :任務[taskId=666]執行完成 2024-07-05 22:59:01.394|INFO|http-nio-8090-exec-1|17|com.qsl.task.web.TaskController :收到任務[taskId=999]執行請求 2024-07-05 22:59:01.394|INFO|http-nio-8090-exec-1|18|com.qsl.task.web.TaskController :任務[taskId=999]執行中... 2024-07-05 22:59:01.394|INFO|http-nio-8090-exec-1|19|com.qsl.task.web.TaskController :任務[taskId=999]執行完成
至此,引申需求是不是完美實現了?

但有一點需要注意,既然 task-dispatcher
不再作為 Eureka Client
, 有個配置最好關閉

完整程式碼:integrate-eureka2
https://gitee.com/youzhibing/qsl-project/tree/master/integrate-eureka2
總結
-
有儲存功能的容器(如
Eureka Server
、Spring
)一般都會提供holder
(鉤子)來獲取容器中的例項 -
儘量選同體系內的元件(比如都用
Spring
自帶的元件),不會存在相容性問題 -
spring-cloud-balancer
目前支援兩種負載均衡策略輪詢和隨機,預設是輪詢;如果需要其他的複雜均衡策略,則需要自定義