系统异步化改造——线程池入门

异步化

概念对比

  • 同步:做完一件事后再去做另外一件事
  • 异步:不用等一件事做完,就可以做另外一件事,比如将热水器打开烧水,设置100度会发出通知提醒,然后去做另外一件事,烧水时人可以同时处理别的事,水烧好后,人能收到通知,就知道水烧好了。

业务流程分析

标准异步化的业务流程

  1. 当用户要进行耗时很长的操作时,用户点击分析后,不需要在界面傻等,而是应该将这个任务保存到数据库中记录下来

  2. 用户要执行新任务时:

    • 提交任务成功
      • 如果我们的程序还有多余的空闲线程,可以立即去做这个任务
      • 如果我们的程序都在忙,那就放到等待队列中
    • 提交任务失败:任务队列满了
      • 拒绝这个任务,再也不执行
      • 通过保存到数据库中的记录来看到提交失败的任务,并且在程序闲的时候,可以把任务从数据库中取到程序中,再去执行
  3. 我们的程序(线程)从任务队列中取出任务依次执行,完成每一件事要修改一下任务的状态

  4. 用户可以查询任务的状态,或者在任务执行成功或者失败时能得到通知

  5. 如果要执行的任务很复杂,包含很多环节,每一个小任务完成时,要在程序(数据库)中记录一下任务的执行状态,进度

系统的业务流程

  1. 用户点击分析时按钮时,先把图表立刻保存到数据库中(作为一个任务)
  2. 用户可以在图表管理页面查看所有图表(已生成的、生成中的、生成失败)的信息和状态
  3. 用户可以修改生成失败的图表信息,点击重新生成

线程池

线程池的实现

public ThreadPoolExecutor(
        int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler
)
参数说明
  1. corePoolSize(核心线程数=>相当于正式员工):正常情况下,我们的系统应该能同时工作的线程数(随时就绪状态)
  2. maximumPoolSize(最大线程数=>哪怕任务再多,也只招这些人):极限情况下,我们的线程池最多有多少个线程
  3. keepAliveTime(空闲线程存活时间):超过这个时间,多余的线程就会自动结束工作,从而释放无用的线程资源
  4. TimeUnit unit(空闲线程存活时间的单位):秒、分
  5. workQueue(工作队列):用于存放给线程执行的任务,存在一个队列的长度(一定要设置一个长度,不要说队列长度无限,因为也会占用资源)
  6. threadFactory(线程工厂):控制每个线程的生成、线程的属性(比如线程名)
  7. rejectedExecutionHandler(拒绝策略):当任务队列满时,我们采取什么措施,比如抛异常、不抛异常、自定义策略
资源隔离策略
  • 比如重要的任务一个队列,非重要的任务一个队列,保证这两个队列互不干扰(VIP任务、普通任务)

线程池参数设置

当前AI的API处理能力为4QPS,每个任务处理时间为10秒,那么线程池的参数设置如下:

参数说明
corePoolSize4正常情况下可以设置为4
maximumPoolSize≤4考虑极限情况,不超过4
keepAliveTime秒级或分钟级多余线程的存活时间
TimeUnitTimeUnit.SECONDS时间单位设置为秒
workQueue20结合实际情况设置队列长度
threadFactory自定义控制线程的生成和属性(如线程名)
rejectedExecutionHandler自定义策略抛异常并标记数据库任务状态为"任务满了,已拒绝"

一般情况下,任务分为IO密集型和计算密集型两种。

  • IO密集型:吃带宽、硬盘、内存的读写资源,corePoolSize可以设置大一点,一般经验值是2n左右,建议以IO的能力为主
  • 计算密集型:吃CPU资源,比如音视频处理、图像处理、数学计算等,corePoolSize为CPU核数+1(空余线程),可以让每个线程都能利用好CPU的每个核,而且线程之间不用频繁切换(减少打架、开销)
  • 混合型:既吃CPU又吃IO,比如爬虫、日志处理、数据库查询、网络请求等,可以设置corePoolSize为CPU核数,然后设置workQueue为有界队列,防止任务过多导致OOM

实现工作流程

  1. 给chart表中增加任务状态字段(比如排队中、执行中、已完成、失败),任务执行信息字段(用于记录任务执行中、或者执行失败时,保存错误信息)
  2. 用户可以在图表管理页面查看所有图表(已生成的、生成中的、生成失败)的信息和状态
  3. 任务:先修改图表任务状态为“执行中”,等执行成功后修改为“已完成”、保存执行结果,执行失败时修改为“失败”,记录任务失败信息
  4. 用户可以在图表管理页面查看所有图表(已生成、生成中、生成失败)的信息和状态

库表设计

status  varchar(128) not null default 'wait' comment 'wait,running,succeed,failed',
add execMessage text null comment '执行信息';

进一步优化

  1. 增加重试功能(使用guava的Retrying重试)
  2. 考虑到AI生成脏数据的情况,在后端进行异常处理
  3. 如果任务没进入队列中(或者任务队列满了),可以用定时任务把他放到队列中(补偿)
  4. 给任务增加超时时间,超时自动设置为失败
  5. 反向压力:通过第三方调用的服务状态来选择系统当前的策略,比如根据AI服务的当前任务队列数来控制自己系统的核心线程数,从而最大化利用资源
  6. 我的图表页面增加一个刷新、定时自动刷新的按钮,保证获取到图表的最新状态(前端轮询)
  7. 任务执行成功或者失败,给用户发送消息通知(实时:websocket、server sid event)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Whoam_laowei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值