什么是任务依赖,举个栗子,互联网公司常常在凌晨进行一些数据统计任务,这些任务之间有必定的依赖关系,好比:微信
1)task3须要使用task2的输出做为输入架构
2)task2须要使用task1的输出做为输入微信支付
这样的话,tast1, task2, task3之间就有任务依赖关系,必须task1先执行,再task2执行,载task3执行。优化
对于这类需求,常见的实现方式是,使用cron人工排执行时间表:spa
1)task1,0:00执行,经验执行时间为50分钟架构设计
2)task2,1:00执行(为task1预留10分钟buffer),经验执行时间也是50分钟设计
3)task3,2:00执行(为task2预留10分钟buffer)接口
这种方法的坏处是:事件
1)若是有一个任务执行时间超过了预留buffer的时间,将会获得错误的结果,由于后置任务不清楚前置任务是否执行成功,此时要手动重跑任务,还有可能要调整排班表ip
2)总任务的执行时间很长,老是要预留不少buffer,若是前置任务提早完成,后置任务不会提早开始
3)若是一个任务被多个任务依赖,这个任务将会称为关键路径,排班表很难体现依赖关系,容易出错
4)若是有一个任务的执行时间要调整,将会有多个任务的执行时间要调整
不管如何,采用“cron排班表”的方法,各任务耦合,谁用过谁痛谁知道(采用此法的请评论留言)
优化方案是,采用MQ解耦:
1)task1准时开始,结束后发一个“task1 done”的消息
2)task2订阅“task1 done”的消息,收到消息后第一时间启动执行,结束后发一个“task2 done”的消息
3)task3同理
采用MQ的优势是:
1)不须要预留buffer,上游任务执行完,下游任务总会在第一时间被执行
2)依赖多个任务,被多个任务依赖都很好处理,只须要订阅相关消息便可
3)有任务执行时间变化,下游任务都不须要调整执行时间
须要特别说明的是,MQ只用来传递上游任务执行完成的消息,并不用于传递真正的输入输出数据。
上游须要关注执行结果时要用“调用”,上游不关注执行结果时,就可使用MQ了。
举个栗子,58同城的不少下游须要关注“用户发布帖子”这个事件,好比招聘用户发布帖子后,招聘业务要奖励58豆,房产用户发布帖子后,房产业务要送2个置顶,二手用户发布帖子后,二手业务要修改用户统计数据。
对于这类需求,常见的实现方式是,使用调用关系:
帖子发布服务执行完成以后,调用下游招聘业务、房产业务、二手业务,来完成消息的通知,但事实上,这个通知是否正常正确的执行,帖子发布服务根本不关注。
这种方法的坏处是:
1)帖子发布流程的执行时间增长了
2)下游服务当机,可能致使帖子发布服务受影响,上下游逻辑+物理依赖严重
3)每当增长一个须要知道“帖子发布成功”信息的下游,修改代码的是帖子发布服务,这一点是最恶心的,属于架构设计中典型的依赖倒转
优化方案是,采用MQ解耦:
1)帖子发布成功后,向MQ发一个消息
2)哪一个下游关注“帖子发布成功”的消息,主动去MQ订阅
采用MQ的优势是:
1)上游执行时间短
2)上下游逻辑+物理解耦,除了与MQ有物理链接,模块之间都不相互依赖
3)新增一个下游消息关注方,上游不须要修改任何代码
有时候上游须要关注执行结果,但执行结果时间很长(典型的是调用离线处理,或者跨公网调用),也常常使用回调网关+MQ来解耦。
举个栗子,微信支付,跨公网调用微信的接口,执行时间会比较长,但调用方又很是关注执行结果,此时通常怎么玩呢?
通常采用“回调网关+MQ”方案来解耦:
1)调用方直接跨公网调用微信接口
2)微信返回调用成功,此时并不表明返回成功
3)微信执行完成后,回调统一网关
4)网关将返回结果通知MQ
5)请求方收到结果通知
这里须要注意的是,不该该由回调网关来调用上游来通知结果,若是是这样的话,每次新增调用方,回调网关都须要修改代码,仍然会反向依赖,使用回调网关+MQ的方案,新增任何对微信支付的调用,都不须要修改代码啦。