在AIGC、视频处理等复杂模型推理场景中,同步请求易引发连接超时及负载不均等问题,PAI异步推理服务推出独立的队列服务框架,支持根据实例负载情况分发请求、异常实例任务自动迁移至健康节点,有效避免资源争抢与服务中断。本文详解如何使用异步推理服务。
实现原理
创建异步推理服务时,会在服务内部集成推理子服务和队列子服务。队列子服务有输入(input)和输出(sink)两个内置的消息队列。服务请求会先发送到输入队列,推理子服务实例中的EAS服务框架会自动订阅队列以流式的方式获取请求数据,调用推理子服务中的接口对收到的请求数据进行推理,并将响应结果写入到输出队列中。
当输出队列满时,即无法向输出队列中写入数据时,服务框架也会停止从输入队列接收数据,避免无法将推理结果写入输出队列。
如果不需要输出队列,例如将推理结果直接输出到OSS或者自己的消息中间件中,可在同步的HTTP推理接口中返回空,此时输出队列会被忽略。
创建高可用的队列子服务接收客户端请求。推理子服务的实例根据自己所能承受的并发度来订阅指定个数的请求,队列子服务会保证每个推理子服务实例上处理的请求不会超过订阅的窗口大小,避免实例过载,最终将订阅或查询的数据返回给客户端。
比如每个推理子服务实例只能处理5路语音流,则从队里子服务中订阅消息时,将window size配置为5。当推理子服务实例处理完一路语音流后将结果commit,队列子服务会为推理子服务实例重新推送一路新的语音流,保证该实例上处理的语音流最多不超过5路。
队列子服务通过检测推理子服务实例的连接状态进行健康检查,若该实例异常导致连接断开,队列子服务会将其标记为异常,并将已经分发给该实例的请求重新推送给其他正常实例进行处理,确保在异常情况下请求数据不会丢失。
创建异步推理服务
在创建异步推理服务时,系统会自动创建和异步推理服务同名的服务群组。同时,队列子服务会随异步推理服务自动创建,并集成到异步推理服务内。队列子服务默认启动1个实例,并根据推理子服务的实例数量动态伸缩,但最多不超过2个实例,每个实例默认配置为1核和4 GB内存。如果队列子服务的实例数的默认配置不能满足您的需求,请参照队列子服务参数配置及说明进行调整。
EAS的异步推理服务可以实现同步推理逻辑到异步推理的转换,支持以下两种部署方式:
进入自定义部署页面,并配置以下关键参数,其他参数配置详情,请参见控制台自定义部署参数说明。
部署方式:选择镜像部署或processor部署。
异步服务:选中异步服务。
参数配置完成后,单击部署。
准备服务的配置文件service.json。
部署方式为processor部署。
{ "processor": "pmml", "model_path": "http://example.oss-cn-shanghai.aliyuncs.com/models/lr.pmml", "metadata": { "name": "pmmlasync", "type": "Async", "cpu": 4, "instance": 1, "memory": 8000 } }
其中关键参数说明如下。其他参数配置说明,请参见JSON部署参数说明。
type:配置为Async,即可创建异步推理服务。
model_path:替换为您的模型的地址。
部署方式为镜像部署服务。
{ "metadata": { "name": "image_async", "instance": 1, "rpc.worker_threads": 4, "type": "Async" }, "cloud": { "computing": { "instance_type": "ecs.gn6i-c16g1.4xlarge" } }, "queue": { "cpu": 1, "min_replica": 1, "memory": 4000, "resource": "" }, "containers": [ { "image": "eas-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-eas/chat-llm-webui:3.0.1", "script": "python webui/webui_server.py --port=8000 --model-path=Qwen/Qwen-7B-Chat", "port": 8000 } ] }
其中关键参数说明如下。其他参数配置说明,请参见JSON部署参数说明。
type:配置该参数为Async,即可创建异步推理服务。
instance:推理子服务的实例数量,不包含队列子服务的实例。
rpc.worker_threads:为异步推理服务中EAS服务框架的线程数,该参数与订阅队列数据的窗口大小一致。线程数设置为4,即一次最多只能从队列中订阅4条数据,在这4条数据处理完成前,队列子服务不会给推理子服务推送新数据。
例如:某视频流处理服务,单个推理子服务实例一次只能处理2条视频流,则该参数可以设置为2,队列子服务最多将2个视频流的地址推送给推理子服务,在推理子服务返回结果前,不会再推送新的视频流地址。如果推理子服务完成了其中一个视频流的处理并返回结果,则队列子服务会继续再推送一个新的视频流地址给该推理子服务的实例,保证一个推理子服务的实例最多同时处理不超过2个视频流。
创建服务。
您可以登录eascmd客户端后使用create命令创建异步推理服务,如何登录eascmd客户端,请参见下载并认证客户端,使用示例如下。
eascmd create service.json
访问异步推理服务
如上文介绍,系统会默认为您创建与异步推理服务同名的服务群组,因群组内的队列子服务拥有群组流量入口,您可以直接通过下述路径访问队列子服务,详情请参见访问队列服务。
地址类型 | 地址格式 | 示例 |
地址类型 | 地址格式 | 示例 |
输入队列地址 |
|
|
输出队列地址 |
|
|
管理异步推理服务
您可以像管理普通服务一样管理异步推理服务,该服务的子服务会由系统自动管理。比如,当您删除异步推理服务时,队列子服务和推理子服务会同时删除;更新推理子服务时,队列子服务维持不变以获取最大的可用性。
由于采用了子服务架构,虽然您为异步推理子服务配置了1个实例,实例列表中仍会额外显示一个队列子服务实例。
异步推理服务的实例数量指的是推理子服务实例的数量,队列子服务的实例数量会随着推理子服务的实例数量自动变化。比如,当您将推理子服务实例数量扩容到3时,队列子服务的实例数量扩容到了2。
两个子服务间的实例数量配比规则如下:
停止异步推理服务时,队列子服务和推理子服务的实例数量均会缩容到0,实例列表为空。
推理子服务的实例数量为1时,队列子服务的实例数量也为1,除非配置了队列子服务的参数。
推理子服务的实例数量超过2时,队列子服务的实例数量将保持为2,除非配置了队列子服务的参数。
当您为异步推理服务配置了自动扩缩容功能,且配置了最小的实例数量为0时,当推理子服务缩容到0时,队列子服务将保持1个实例待命。
队列子服务参数配置及说明
队列子服务通常使用默认配置即可。如果有特殊需求,您可以在JSON文件的queue配置块进行自定义配置。示例如下:
{
"queue": {
"sink": {
"memory_ratio": 0.3
},
"source": {
"auto_evict": true
}
}
下面介绍具体的配置项。
配置队列子服务资源
队列子服务的资源默认按照metadata中的字段进行配置,但在有些场景下,您可以跟进本章节,对队列子服务的资源进行单独配置。
通过queue.resource声明队列子服务所使用的资源组。
{ "queue": { "resource": eas-r-slzkbq4tw0p6xd**** # 默认跟随推理子服务资源组。 } }
队列子服务默认跟随推理子服务的资源组。
当您需要使用公共资源组部署队列子服务时,可以声明resource为空字符串(""),这在您的专属资源组CPU和内存不充足时非常有用。
推荐使用公共资源组部署队列子服务。
通过queue.cpu和queue.memory声明每个队列子服务实例所使用的CPU(单位:核数)和内存大小(单位:MB)。
{ "queue": { "cpu": 2, # 默认值为1。 "memory": 8000 # 默认值为4000。 } }
如果您没有进行资源配置,队列子服务将按照1 CPU核、4 GB内存进行默认配置。这可以满足大多数场景的需求。
如果您的订阅者(比如推理子服务实例的数量)数量超过200时,建议将CPU核数配置为2核以上。
不建议在生产环境中缩小队列子服务的内存配置。
通过queue.min_replica配置队列子服务实例的最小数量。
{ "queue": { "min_replica": 3 # 默认为1。 } }
在使用异步推理服务时,队列子服务实例的数量将根据推理子服务实例的运行时数量自动调整,默认的调整区间为
[1, min{2, 推理子服务实例的数量}]
。特殊情况下,如果配置异步推理服务的自动扩缩容规则并允许将实例数量缩小到0时,将自动保留1个队列子服务实例。您也可以通过queue.min_replica调整最小保留的队列子服务实例数量。增加队列子服务实例的数量可以提高可用性,但不能提高队列子服务的性能。
配置队列子服务功能
队列子服务拥有多项可配置的功能,您可以通过以下配置方法进行调整。
通过queue.sink.auto_evict或者queue.source.auto_evict分别配置输出/输入队列自动数据驱逐功能。
{ "queue": { "sink": { "auto_evict": true # 输出队列打开自动驱逐,默认为false。 }, "source": { "auto_evict": true # 输入队列打开自动驱逐,默认为false。 } } }
默认情况下队列子服务的自动数据驱逐功能处于关闭状态,如果您的队列已满将无法继续输入数据。在某些场景下,如果您允许数据在队列中溢出,可以选择打开自动数据驱逐功能,队列将自动驱逐最老的数据以允许新数据写入。
通过queue.max_delivery配置最大投递次数。
{ "queue": { "max_delivery": 10 # 最大投递次数为10,默认值:5。当配置为0时,最大投递次数关闭, 数据可以被无限次投递。 } }
当单条数据的尝试投递次数超过设定阈值时,该数据将被视为无法处理,并将其标记为死信。详情请参见队列实例的死信策略。
通过queue.max_idle配置数据的最大处理时间。
{ "queue": { "max_idle": "1m" # 配置单条数据最大处理时长为1分钟,如果超过该时间将被投递给其它订阅者, 投递完毕后投递次数+1。默认值为0,即没有最大处理时长。 } }
示例中配置的时间长度为1分钟,支持多种时间单位,如h(小时)、m(分钟)、s(秒)。如果单条数据处理的时间超过了这里配置的时长,则有两种可能:
如果未超过queue.max_delivery设定的阈值,该条数据会被投递给其他订阅者。
如果已超过queue.max_delivery设定的阈值,该条数据将会被执行死信策略。
通过queue.dead_message_policy配置死信策略。
{ "queue": { "dead_message_policy": "Rear" # 枚举值为Rear(默认值)或者Drop, Rear即为放入队列末尾,Drop将该条数据删除。 } }
配置队列最大长度或最大数据体积
队列子服务的最大长度和最大数据体积是此消彼长的关系,计算关系如下所示:
队列子服务实例内存是固定的,因此如果调整单条数据最大体积,则会导致该队列最大长度减小。
在4 GB内存的默认配置下,由于最大数据体积默认为8 KB,则输入输出队列均可以存放230399条数据,如果您需要在队列子服务中存放更多数据项,可以参考上文中的内存配置,将内存大小按照需要提高。系统将占用总内存的10%。
对于同一个队列,不能同时配置最大长度和最大数据体积。
通过queue.sink.max_length或者queue.source.max_length分别配置输出队列/输入队列的最大长度。
{ "queue": { "sink": { "max_length": 8000 # 配置输出队列最大长度为8000条数据。 }, "source": { "max_length": 2000 # 配置输入队列最大长度为2000条数据。 } } }
通过queue.sink.max_payload_size_kb或者queue.source.max_payload_size_kb分别配置输出队列/输入队列单条数据最大数据体积。
{ "queue": { "sink": { "max_payload_size_kb": 10 # 配置输出队列单条数据最大体积是10 KB, 默认8 kB。 }, "source": { "max_payload_size_kb": 1024 # 配置输入队列单条数据最大体积是1024 KB(1MB), 默认是8 kB。 } } }
配置内存分配倾斜
通过queue.sink.memory_ratio来调整输入输出两个队列占用的内存大小。
{ "queue": { "sink": { "memory_ratio": 0.9 # 配置输出队列内存占比,默认值为0.5。 } } }
默认配置下,输入队列和输出队列均分队列子服务实例的内存。如果您的服务需要输入文本、输出图片,并期望在输出队列存放更多数据,则可以将queue.sink.memory_ratio相应提高;相反,如果您期望输入图片、输出文本,则可以将queue.sink.memory_ratio相应减小。
配置水平自动扩缩容
异步推理服务水平自动扩缩容配置方法,请参见自动扩缩容。
- 本页导读 (1)
- 实现原理
- 创建异步推理服务
- 访问异步推理服务
- 管理异步推理服务
- 队列子服务参数配置及说明
- 配置队列子服务资源
- 配置队列子服务功能
- 配置队列最大长度或最大数据体积
- 配置内存分配倾斜
- 配置水平自动扩缩容