前言
最近接到一个需求,因为我们所处的业务领域流量具有非常强的周期性,因此对于微服务周期性的缩扩容是在所难免的,毕竟服务器资源都是耗钱的主。缩扩容会引发一系列的问题,例如访问中断,必然会产生错误的数据,虽然不在核心服务时段,但是也不可避免的引发一些问题。对于已经接收的流量,我们可以使用“优雅关机”来处理,先在服务注册中心注销我们的服务,停止接收新的请求,然后在真正停机前休眠一段时间让系统将残余的请求消化掉。
但是对于一些比较后端,或者异步的任务,或者是持续的流数据,又或者是消息处理等等,这类任务可能耗时比较久就不能这么处理了。
思路
我们要能够在不影响任务执行的情况下,对http请求能力进行缩扩容。但是任务基本上就是不能停机的。所以很自然的想到把http请求处理与task分开,因此借助配置我们可以选择在实例上觉得是否加载这些任务来做到分离。例如把它配置在jvm的环境变量中,然后在通过@Conditional结合@Configuration来动态加载,这样就可以让运行task的实例不停机,而随意对service进行缩扩容操作了。
show me the code
1 | #控制service中的task任务是否加载 这个属性会配置在jvm环境变量中 默认值为true 加载 |
2 | service: |
3 | task: |
4 | enable: ${service.task.enable:true} |
1 | /** |
2 | * @Description 根据配置,动态注入service后台定时调度的任务和kafka消息处理Bean,部署时task与用户请求处理实例分开【同一工程】,减少缩扩容时对任务调度的影响 |
3 | * @date 2020.12.10 13:59 |
4 | */ |
5 | @ConditionalOnProperty(name = "service.task.enable", havingValue = "true") |
6 | @Configuration |
7 | public class ServiceTaskConfiguration { |
8 | @Bean |
9 | public Task task(){ |
10 | return new Task(); |
11 | } |
12 | } |
1 | @ConditionalOnProperty注解源码 其实和实现Conditional接口是一样的效果 |
2 | 可以接收value和name参数进行条件匹配,来决定是否加载被修饰的Bean |
3 |
|
4 | @Retention(RetentionPolicy.RUNTIME) |
5 | @Target({ElementType.TYPE, ElementType.METHOD}) |
6 | @Documented |
7 | @Conditional({OnPropertyCondition.class}) |
8 | public @interface ConditionalOnProperty { |
9 | String[] value() default {}; |
10 |
|
11 | String prefix() default ""; |
12 |
|
13 | String[] name() default {}; |
14 |
|
15 | String havingValue() default ""; |
16 |
|
17 | boolean matchIfMissing() default false; |
18 |
|
19 | boolean relaxedNames() default true; |
20 | } |