原文:https://cloud.tencent.com/developer/article/1169675
异步与machinery
目的
当后端要处理复杂的数据交互或者耗时的逻辑计算发生多次数据交互任务的情况一旦存在,为了实现每一次任务的可靠执行以及前端响应速度,任务队列的出现可以较好的解决这些问题。
场景与功能
场景
- 大批量的计算任务。如大量数据插入,通过拆分并分批插入任务队列,从而实现串行链式任务处理 或者实现分组并行任务处理,提高系统鲁棒性,提高系统并发度;
- 数据预处理。定期的从后端存储将数据同步到到缓存系统,从而在查询请求发生时,直接去缓存系统中查询,提高查询请求的响应速度。
- 错误重试功能。为了提高系统的可用性,当函数处理出现错误时,我们希望可以给予其重试的机会,增强系统的可用性。
golang machinery
特性
- 任务重试机制
- 延迟任务支持
- 任务回调机制
- 任务结果记录
- 支持Workflow模式:Chain,Group,Chord
- 多Brokers支持:Redis, AMQP, AWS SQS
- 多Backends支持:Redis, Memcache, AMQP, MongoDB
# 获取 machinery
go get github.com/RichardKnop/machinery/v1
架构
任务队列,简而言之就是一个放大的生产者消费者模型,用户请求会生成任务,任务生产者不断的向队列中插入任务,同时,队列的处理器程序充当消费者不断的消费任务。
- Server:业务模块,生成具体任务,可根据业务逻辑中,按交互进行拆分;
- Broker:存储具体序列化后的任务,machinery中目前支持到Redis, AMQP,和SQS;
- Worker:工作进程,负责消费者功能,处理具体的任务;
- Backend:后端存储,用于存储任务执行状态的数据;
Broker(redis)
-
启动与停止:
服务开启后,StartConsuming() 函数将以阻塞轮询的方式去Broker中获取任务,服务停止之后,StopConsuming()函数将会等待一系列go程结束。 -
任务获取:
StartComsuming()中,分别启动了两个go程来并行处理任务,因为针对延时任务和普通任务,machinery将任务存放于两个不同的rediskey中。- 对于普通任务,使用nextTask()函数用来从broker中获取任务,在redis作为broker时,machinery使用了LIST类型来存储任务,而nextTask()中使用了BLPOP来阻塞式的读取任务。
- 对于延时任务,使用nextDelayTask()函数从redis中的ZSET中,根据score来优先获取最近的任务(score为ETA的对应的unixnano值)。
-
任务查看:
GetPendingTasks()可以用来查看当前任务队列中处理pending状态,在等待被处理的任务的详细信息。 -
任务发布:
Publish()接口是实现任务发布的函数。
Backend
- 任务状态:
- Pending,任务到达Broker
- Received,任务从Broker中读取成功
- Started,任务开始执行
- Retry,任务需要重试
- Success,任务执行成功
- Failure,任务执行失败
Worker
- 启动与停止:
Worker启动是通过Launch()启动了一个进程,去订阅默认的任务队列,并且处理收到的任务。LaunchAsync()是Launch()的非阻塞版本,而通过Launch()中的代码,我们发现,其实就是调用了LaunchAsync()。Worker停止是通过Quit()函数来实现,其调用了Broker的StopConsuming()函数。 - 任务处理:
Worker中的Process()函数,将会处理在Broker中的待处理任务,并且负责了任务回调的触发功能。Process()函数的任务流程主要是: