转写时长超出60秒的语音文件,业界的竞品通常会使用创建异步转写任务的方式来提供支持。
一个简单、直接的实现方案,即:
- 网关服务接收到来自客户的转写请求时,将任务信息持久化至任务队列中。
- 由算法服务的实例从任务队列中提取任务,并执行转写操作。
- 待执行完毕之后,将转写结果保存至DB中,供调用方查询。
本文主要针对介绍任务队列的要求和选型。
在语音识别的文件转写的场景下,对于任务队列的常规诉求:
- 允许多个生产服务向队列中增加任务。
- 允许多个消费服务从队列中提取任务。
- 任务队列自身具备可靠性,避免自身成为影响整体系统可靠性的单点。
- 任务队列的读、写操作,效率满足业务要求,避免成为影响整体系统效率的单点。
- 单个任务,仅支持由一个消费服务提取和处理。
- 消费方在处理某指定的任务时,假如超时或者失败,则要求将任务重新放回到队列中,由其它消费服务的实例完成任务的处理。
- 消费方的实例异常重启后,该实例上当前正在处理的任务,需要重新被抓取至原实例或者新实例上,继续处理。
对于5、6,一般可以理解为任务的事务性。
关于实现任务队列的可选方案,一般有如下几种:
- Redis
- Kafka
- DB(比如MySQL)
一般而言,Kafka、Redis自身可以满足上述要求中的1、2、3、4,实现并不困难,但5、6,则存在一定的困难。
而基于DB的方案,可以很好的满足1、2、5、6,但在提供3、4时存在一定的困难。此外,当消费方的实例的数量增加时,由于需要采用轮询的方式来提取任务,可能导致DB的CPU占用率有所提升。当任务的并发度提升时,容易出现死锁的现象,或者提升DB处理数据行锁的开销。
语音识别业务中文件转写请求的特点:
- 当前的用户调用总量相对比较低。
- 同一时间,来自客户的请求的并发度比较低。
- 用户对于时延的敏感度相对比较低。
- 用户对转写任务的成功率有比较高的诉求。
综合考虑项目组当前的人力情况、技术储备情况、交付进度的要求,选择了基于DB来实现任务队列的方案。
在DB中新建任务队列表,包含如下字段:
- 任务ID,唯一标识。
- 创建时间,用于后续计算任务端到端转写时间。
- 任务结束时间,用于后续计算任务端到端转写时间。
- 任务状态,当前任务处于排队中、处理中、处理结束、失败。对于失败的任务,假如重试次数低于门限值,则需要重试。
- 锁定时间,用于确定任务是否超时,超时的任务需要重试。超时时间的定义,需要综合文件转写的实时比和语音文件自身的时长,给出恰当的定义,避免失败后等待过长的时间才能触发重试。
- 当前处理任务的实例的标识,用于确定任务当前由哪个实例在转写。当算法服务的实例重启时,可以加载本实例相关的任务,执行重试操作。
- 重试次数,系统需要提供自动重试的能力,可以规避某特定实例自身的问题导致的失败的现象,降低运维人员主动介入处理时的工作量。但不能无限制重试,需要定义重试的次数。
参考资料
- 分布式定时任务调度框架选型
- 浅谈分布式任务调度框架
- 使用 MySQL 实现任务队列
- 这些优秀的国产分布式任务调度系统,你用过几个?
- Elastic-job 介绍与使用
- elastic-job的原理简介和使用
- elasticjob