不单独部署注册中心,又要具备注册中心的功能,我能上天!
开心一刻
昨天看到一条广告:全国比丑大赛,一等奖 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
,然后调用接口
结果 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
目前支持两种负载均衡策略轮询和随机,默认是轮询;如果需要其他的复杂均衡策略,则需要自定义
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步