做事不能急,得一步异步的来;
在系统开发的过程中,必然存在耗时极高的动作,是基于请求响应模式无法解决的问题,通常会采用解耦的思维,并基于异步或者事件驱动的方式去调度整个流程的完整执行;
文件任务:在系统解析大文件数据时,在获取任务之后,会异步处理后续文件读写流程;
中间表:执行复杂场景的数据分析时,收集完待分析的对象之后,会并发执行各个维度的采集动作,并依次将数据写入临时的中间表中,方便数据查询动作;
在上述场景中,基于单次请求响应无法执行整个过程,必须对流程分段分步和异步推进,在流程中根据场景去判断,是异步有序驱动,还是异步并发处理,并基于各个节点的执行状态判断动作是否成功。
复杂任务的执行周期相对偏长,要确保稳定的执行则需要对任务做精细的设计和管理,通常会基于如下几个因素去描述任务:
设计合理的任务结构,以便更高效的管理流程,根据主题场景做任务分类,添加相应的执行计划,根据状态跟踪任务执行过程,并对失败动作进行捕捉和重试;
服务之间的通信模式一般分为:同步和异步两种;同步是指在请求端发出动作之后,会一直等待响应端完成,或者响应超时导致熔断,即在一次请求调用中耦合所有的处理流程;
服务中大部分的请求都是同步响应模式,可以提高系统的响应速度;但是在分布式中,首先要控制超时熔断的时间,避免在流量高峰期请求堆积,拖垮整个服务;另外对于被大量调用的公共服务,要提高并发的支撑能力,降低对请求链路的性能影响。
异步模式的最大优点就是实现请求和响应的完全解耦,任务只需要触发一次开始动作,后续的流程就会逐步的推进直到结束;各个服务节点处理逻辑不会受到整个请求链路的耗时限制;
实现异步有多种方式,例如:请求回调、发布订阅、Broker代理等;在之前异步章节中有详细描述,这里不再赘述;异步消除了服务节点之间的依赖关系,但是也同样提高了流程的复杂性;
事件驱动是一个抽象的概念,即通过事件的方式实现多个服务间的协同,驱动整个流程的处理逻辑;在业务层面是一种设计思想,在技术层面通常采用发布订阅的方式,同样也可以消除服务间的强依赖关系;
事件和异步在模式上很类似,事件驱动在设计上更加精细,例如在订单场景中:将订单的状态变化作为一个事件,服务间通过消息传递的方式,依次处理库存服务、物流服务等;由于事件携带了一定的业务信息和状态,流程解耦更加彻底的同时复杂度也会更高。
在结构设计中围绕任务、节点、数据三个核心要素,以确保对任务的执行过程有完整的跟踪和管理,要实现对任务的节点及相关的操作,具备执行重试或者直接取消撤回的控制;
状态管理是一项很复杂的工作,要衡量任务中各个状态标识是否合理,就要实时监控状态的变化,并且基于各种极端情况去验证流程,例如:重试设计、任务取消、任务暂停。
任务型的场景加上复杂的管理流程,执行时间自然也很长,如果场景中涉及到大文件的解析、或者数据调度,自然会引入任务分割与并发执行的机制;
比较常用的思路:根据任务调度的集群数,对数据核心编号进行哈希计算,可以采用取模和分段两种算法,然后基于多线程的方式并发处理各自服务内的分管任务。
不管是观察者模式,或者发布订阅模型,又或者说事件驱动设计,都可以理解为生产/消费的关系模型,围绕生产、存储、消费三个节点做管理;
整个模型在设计思路上比较合理,但是架构的复杂性也变的很高,比如数据一致性问题、状态机制、事务、幂等性、流程中断等;整个链路需要详细的追踪记录并且可视化管理,开发补偿动作的接口,用来及时解决可能出现的突发问题。
Spring框架本身就极具复杂度,这里单看事件模型的设计,包含三个核心角色:事件、发布、监听;与观察者设计模式在理念上相同;
事件:ApplicationEvent基础抽象类继承自JDK中EventObject类,具体事件要继承该类;source事件源,timestamp发生的系统时间;
public class OrderState { // 基础要素 private Integer eventId ; private String version ; private Long createTime ; // 消息定位 private String source ; private String target ; // 状态变化 private Integer orderId ; private Integer stateFrom ; private Integer stateTo ; } public class OrderStateEvent extends ApplicationEvent { public OrderStateEvent (OrderState orderState){ super(orderState); } }
发布者:Spring定义的顶级接口ApplicationEventPublisher,提供事件发布的能力;
@Service public class EventService implements ApplicationContextAware, ApplicationEventPublisherAware { private ApplicationEventPublisher applicationEventPublisher; public void changeState (Integer orderId,Integer stateFrom,Integer stateTo){ OrderState orderState = new OrderState() ; OrderStateEvent orderStateEvent = new OrderStateEvent(orderState) ; logger.info(Thread.currentThread().getName()+";"+orderStateEvent); applicationEventPublisher.publishEvent(orderStateEvent); } }
监听者:实现JDK中顶级接口EventListener,Spring扩展了多种事件监听器,以实现各种场景的需求,例如:有序无序、同步异步等;
@Component public class OrderStateListener implements ApplicationListener<OrderStateEvent> { private static final Logger logger = LoggerFactory.getLogger(OrderStateListener.class) ; @Async @Override public void onApplicationEvent(OrderStateEvent orderStateEvent) { logger.info(Thread.currentThread().getName()+";"+orderStateEvent); } }
应用仓库: https://gitee.com/cicadasmile/middle-ware-parent 编程文档: https://gitee.com/cicadasmile/butte-java-note