分布式异步任务处理组件(一)

前言

人生艰难;求职因为简历问题屡屡碰壁,当年轻狂,想着山高任我行,但是没想到,现实却是山高且无路,于是乎,本着实现当初自研工具组件的梦想(其实就是为了给简历增加一点色彩~),证明一下自己的技术能力和代码水平,绞尽脑汁回想之前工作中遇到的业务场景,是否有大部分业务场景下需要用到的业务操作,且堪堪可以将其中的代码从业务代码中抽离出来,于是乎,一场头脑风暴在脑海里了展开。。。。。

突然灵光乍现,之前有一个业务场景要做延迟生效,基本的批处理定时任务已经无法完成,需要为每个任务单独维护计时器,网上一番搜索下来,并没有很成熟的解决方案,很多还是依赖具体的业务逻辑和架构环境。总之,最终选用了JDK本地延时队列+定时批处理+共享锁来实现;但是当时总觉得不够完美,因为事务的一致性一部分依赖异常机制来保证,但是无奈业务实现为主(相信很多职场中摸爬滚打的技术伙伴深有体会)所以,do i t now——

相信很多童鞋在业务场景中,经常遇到需要批量异步处理任务,这种任务一般具有几个特点,处理时间长,实时性要求不高,不要求提交立即执行,只要保证在可容忍时间范围内最终执行成功;任务本身可能具有事务性,但是没有牵扯到其他事务或者与其他事务弱关联等等;--后续再补充;

大部分童鞋的做法可能是起一个线程池,将任务丢给线程池慢慢执行;

但是!

这种做法确实是完美的吗?先来讲几个问题——

线程池本身具有本地化特性,但是我们业务服务一般情况下会做集群部署和统一配置;尽管一般情况下各集群节点尽量保证机器性能持平,QPS负载基本均衡-

但是还是有以下几个问题--

  1. 我们一般在做线程池配置时会做单机性能冗余(相信没有几个童鞋敢在生产环境中去配置自认为刚刚好的线程数量吧!),集群架构下的性能冗余本身就是一种浪费;
  2. 异步任务本身执行时间长,实时性要求比较低,放在核心业务服务或者机器上本身就是一种资源浪费;(当然一般会专门部署机器用来做异步任务处理,但是代码不会单独拆分出来只是对流量做了请求转向--之前工作过的规模还算比较大的公司就是这么干的)
  3. 面向小需求的开发模式(协作开发,各自负责各自的业务需求,或者可以理解为面向接口的开发:)),导致异步任务实现逻辑混乱,其基本执行步骤是一样的,但是可能个人有个人的实现方案,Redis,kafka,Mysql等~,难以维护和扩展---这其实是大部分组件开发的最基本需求,我们常用的代码模式抽象出来;尤其业务关联性小的代码,加上一些服务组件的特性(后续详解),就变成了中间组件;
  4. 特定场景;like我遇到的业务场景,集群模式下如何做延时任务定时触发执行,并且保证性能和一致性,整个后边会展开细讲,实时执行的异步任务可以理解为延时为0的特殊延时任务;当然对此可以做一些优化;

这些问题目前就想到这么多,后续考虑到会做补充;但是在具有一定流量的生产环境和开发团队下,我觉得任何一条理由也足够支撑我们去实现这个;

回归到具体的业务需求中来--

集群模式下的定时自动触发任务异步执行,接下来会逐步讲一下实现方案:

一般来说,使用定时批量查询+延时队列是比较优的方案,延时队列可以使用JDK中的也可以使用现有消息队列提供的延时功能或者Redis的过期通知功能实现;

基本思想就是定时或者实时产生延时任务,定时是指定时批量查询未来可接受一段时间内需要处理的延时任务;之后放入延时队列中精确计时;

几个需要需求场景---

  1. 怎么保持可靠性
  2. 怎么保证一致性;
  3. 怎么保证性能;

几个问题:消息队列实现延时队列需要保证消息消费唯一性,处理消息堆积问题;Redis需要解决性能问题--轮训访问;

瓶颈点:延时计时--或者说倒计时属于实时性CPU密集型操作,这种操作如果依赖其他组件必然出现准确性或者性能问题;所以倒计时操作必须在本地完成;这一点要求其实基本上拒绝了使用其他中间件实现方案,所以只能依赖本地完成;本地完成的问题在于如何维护集群状态下的一致性;

至此,大概确定了架构方案--消息队列+线程池;

细节--

hanler自动注册;

自动保证消息消费顺序性,一致性,可靠性;

集群模式下自适应性分布式线程池;

把这些代码抽离出来,基本上就可以了;

你可能感兴趣的:(分布式)