最实用的高并发任务执行架构设计 | 架构篇

技术架构设计

初始设计

演化阶段一

演化阶段二

演化阶段三

代码设计

总结


前言

==

随着互联网与软件的发展,除了程序员,架构师也是越来越火的职业。他们伴随着项目的整个生命过程,他们更像是传统工业的设计师,将项目当做生命一般细心雕琢。

目前对于项目架构而言,基本都会需要设计的几个架构。

1、业务架构

项目或者产品的市场定位、需求范围、作用场景都是需要在项目启动初期进行系统性分析的。在设计业务架构中,架构师还需要明确角色。我看过很多关于架构的文章,谈到角色的很少。

什么是角色?

例如:商场作为一个整体系统,角色就有消费者、店员、收费员、保安等等。各个角色完成好自己角色所需要承担的任务,整体系统就能完美的运行。

对应到软件系统中,根据产品的定位和需求,也会有着对照的角色,比如:用户、数据审核者、产品制作者、运维人员等。在项目启动初期,架构师需要对项目中的每个角色做好职责定位,我相信在这点上,大部分开发同学在工作中,或多或少都有过职责不明确带来的困扰

2、技术架构

在软件项目研发过程中,我们会用到许多外部组件。在使用组件中,架构师必须结合业务需求合理的选择各个组件。项目是个生命,她会成长,架构师需要明白如果一开始就选择重量级组件会让还是个孩童的项目不受重负,架构师也需要明白如果技术架构的设计不具备拓展性,那么这个孩子无法茁壮成长。所以技术架构尤为重要。

3、物理架构

物理架构又叫做部署架构,项目产品如果要在生产环境稳定运行,一个稳定又高效的物理架构是必不可少的。而且往往物理架构和技术架构是相辅相成的,性能监控、异常告警、业务日志等等设计,都是为了让项目做更好的自己。

高并发任务执行架构

=========

在我十年的工作中,业务相关、中间件、大数据都有做过。本文主要分享一下高并发任务执行框架设计,会由浅入深的讲述一下设计演化过程。如果你不只是想做业务后端开发,那么本文会给你一个全新的视野。

需求场景


我们列一下该项目的需求场景,看看工作中是否遇到过。

1、有个复杂的数据需要制作,而且制作的时间很长,无法让请求方持续等待。所以请求方只能给你个回调地址,需要你完成这个制作后将产物通知他。

2、复杂的制作过程需要消耗资源,而且资源有限,无法无限量提供。如果你有接触过AI,就会比较了解资源有限的感受。除了ASR、TTS这类识别类型的AI功能能做到近实时的反馈,大部分的算法在运行的时候都会消耗整张显卡,而且耗时很长。

初看场景,很多后端可能会第一时间想到elastic-job(一个分布式任务调度框架)。即便你熟悉使用elastic-job,一开始就选择重框架是不是有种杀鸡用牛刀的感觉。不着急,我们一步步分析,一步步设计。

业务架构设计


高度抽象一下我们的业务,对产品设计者而言,貌似是个简单的不能再简单的东西。等到了技术架构,我们深入分析其中演化的功能点,就会发现这是个庞大的机器。我们先给他起个简单的名字:Task Execution Engine(缩写:TEE)

技术架构设计


下面我们开始进行核心模块的技术架构设计,按照我们的初始需求开始我们的设计旅程。

初始设计

设计说明:

1、业务后端发出q1请求,我们首先需要对该请求的参数做矫正,为了可用性考虑。

2、参数校验过后,给到执行引擎模块。执行引擎主要的职责有从资源表获取资源数据、将任务参数与资源参数封装到任务对象内、将任务提交线程池。有一点要说明执行引擎最好使用队列模式,任务先进队列,可以通过while循环方式或者定时线程池都可以,后面会推荐更好的。

3、任务执行的状态与结果需要同步到数据库中,建议使用mysql

小结:

按照初始需求,该设计相对比较简单,完全够用了。但是按照产品的迭代,业务方的需求不会仅限于此。继续演化。

演化阶段一

随着业务的上线,业务端会马上迎来新的问题。

1、由于提交的任务太多了,排在后面的任务迟迟无法等到自己获取到资源执行任务。当然我们可以完全靠增加资源来解决,但是资源的数量在产品前期是不可知的。所以需要有一些策略,比如让用户可以取消自己任务,而不是一直等待。

2、任务的种类开始增加,业务端不满足于单一制作,开始要求多样化

3、任务的执行过程开始需要用到其他资源,不再是一个资源对一个任务的模式了。

4、任务的整体执行情况不可知,需要一定的量化分析,至少让业务组知道每天的任务成功率。

按照需求进行第二版的设计,在尽量不改变原来整体设计的情况下,补充功能。

设计说明:

1、为了解决排队问题,增加了双队列算法来解决。用图解的方式解释一下双队列

逻辑简单说明一下,任务优先提交至执行队列,引擎的定时读取队列的顺序优先为等待队列。如果等待队列中的任务可以获取所需资源,则立即启动线程执行,否则原封不动回到等待队列。引擎其次读取执行队列,如果无法获取资源则进入等待队列,如获取资源,则立即启动线程执行。

那么取消队列,则只需要将队列中的任务踢出队列即可。在送回队里的过程中,一定要保证队列的有序性。

2、创建了任务池,增加了任务封装层,在任务池中挑选需要执行的任务类。

3、增加了策略机模块,添加资源调度策略,由资源调度策略堆任务所需资源合理分配。可以由业务方提供分配方案,尽可能保证任务的公平性。

4、数据库增加统计表,可以考虑使用定时任务,将任务表的数据统计存入统计表

小结

现在看上去已经比较完善了,合理了任务调度、增加了任务种类、合理的资源调度,好像还不错。但是产品总会有新要求的,那么继续演化。

演化阶段二

渐渐的,你设计的引擎还不错。那么新的挑战来了。

1、更多的业务方找到你,希望也使用你的项目进行任务制作,但是他们并不想共享资源,而是希望有自己的独立资源,和独立的队列。但并不是所有的资源都需要独立,一些可以支持高并发的资源,是可以共享的。简而言之,更多的业务方,由业务方为维度的独立队列,独立和共享的资源分配

2、业务方找到你,说如果把任务1的结果给到任务2,其实就能拿到我要的结果。问题来了,原子任务要具备可以编排成复杂任务的能力

3、任务的状态过程无法监控。OK,任务状态机

4、既然大家都需要对接你的项目,能不能提供标准的sdk,我只需要引入就可以完美的对接你的系统。

5、相同的任务参数,是不是制作出来的结果一致呢?那么是否需要增加结果缓存,降低对资源的消耗呢?

6、完正的生产项目必然需要将日志、告警等关键信息传递出来,一旦发生问题可以马上定位到问题的起因。

这些问题对于新人来说还是很有挑战的,需要对系统深层的含义有充足的理解。没事,我来好好来说下设计所需要掌握的知识点。

设计说明:

1、需要在资源表中区别资源类型,共享资源组所有业务组都可以使用,独立资源则资源具备业务标识。在执行引擎的队列管理中,也需要区分业务组,避免共用排队。这里给一个建议,共享的资源一定要是可以支持并发或者可以部署多个实例的,避免所有的业务组产品制作瘫痪

2、增加了高级任务概念,高级任务可以将任意的原子任务进行组合编排,形成全新的任务。需要定义专属于TEE的语法规则。对语法规则引擎的开发,有一些建议。你可能会选择规则引擎,建议其实可以自己开发,毕竟语法不会太过复杂,没必要引入三方的引擎

3、增加任务状态机,执行引擎在提交线程的同时,也想任务状态机提交任务线程信息。任务的进度状态可以同步给任务状态机中,同时一旦任务执行过长的时间,除了任务自己的超时机制外,也可由状态机的看门狗程序将卡死线程释放、资源回收

4、研发属于TEE的SDK,作为内部系统不建议SDK增加鉴权模块。毕竟你对接的往往都是业务后端,鉴权不通过的话根本渗透不到TEE层面。给开发SDK一些建议,尽量引用较少的包,避免业务端引入带来的包冲突。SDK也需要添加一些回调Consumer或者Function,尽可能让业务端对接起来代码简单

5、增加了缓存策略,可以设想一下,大部分情况下,相同的参数制作出来的结果也必然相同。使用redis,将任务参数与任务结果进行缓存,主键可以采用任务参数的MD5值。任务在提交给任务执行引擎前,检查缓存中是否已经存在结果。缓存的过期时间按照具体情况而定。

6、增加日志系统和监控系统的对接,状态机与任务执行中的信息接入到日志系统中。对于日志系统的建议是,最好采用成熟的ELK架构。可以考虑两种方式

a、将日志异步推送到消息队列(例如:kafka),使用flink将kafka存入es。

b、使用logstash将日志内容清洗处理,推送到es。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值