背景
深度学习作为AI领域的核心技术被广泛应用于图像、语音、NLP、搜索、推荐等应用。深度学习任务包括离线模型训练和在线预测两个环节,在线预测是将深度学习模型应用到线上生产环境的重要一环,设计一套通用的在线预测服务以支持深度学习模型的快速灵活上线至关重要。本文将介绍58深度学习在线预测服务的设计与实现。
深度学习在线预测服务是58人工智能平台(WPAI,Wuba Platform of AI)中的一个子模块,首先回顾一下我们深度学习平台的架构(具体实现细节可以参考《58人工智能平台WPAI设计与实现》),如下图所示,整个平台包括硬件层、集群管理层、算法层、WEB管理层、在线预测服务等。硬件层提供GPU/CPU计算资源,由Kubernetes进行统一管理;集群管理层负责离线训练和在线预测任务POD的统一调度;算法层通过TensorFlow、Caffe等框架实现DNN、CNN、RNN等深度学习模型的封装;WEB管理层提供统一的操作界面;在线预测服务实现将模型应用于生产环境。
下文将从总体架构、TensorFlow模型在线预测服务、自定义模型在线预测服务、流量转发、服务部署、资源监控和WEB平台管理等七个方面来具体介绍58深度学习预测服务的设计与实现。
总体架构
58深度学习在线预测服务包括SCF接入层、模型实例层、Kubernetes管理层、资源层、存储层和WEB管理层:
SCF服务作为整个在线预测服务接入层,提供流量转发、协议解析JAR包热加载、请求协议解析和负载均衡等功能
模型实例层包括TensorFlow-Serving和自定义模型Serving。TensorFlow模型通过TensorFlow-Serving加载运行,而对于用户个性化的非TensorFlow模型则通过自定义模型Serving加载运行,自定义模型通过gRPC框架实现。
Kubernetes管理层具有资源管理和调度管理功能,通过Deployment资源管理对象,提供模型部署和模型滚动更新。
资源层由GPU、CPU、Memory和Network等组成,由Kubernets统一进行管理,为TensorFlow Serving和自定义模型Serving预测打分提供硬件支持。
存储层由HDFS、MySQL和InfluxDB组成,HDFS存储模型数据,MySQL为WEB系统提供任务配置和GPU监控数据存储,InfluxDB存储Kubernetes集群POD使用CPU、Memory、Network和FileSystem等资源数据。
WEB系统提供给用户使用,WEB系统包括任务管理、一键部署、资源使用监控、解析JAR包管理等功能,方便用户操作及使用。
TensorFlow在线预测服务设计
TensorFlow在线预测服务基于TensorFlow-Serving设计。TensorFlow-Serving是一种灵活的高性能服务系统,适用于机器学习模型,专为生产环境而设计。具有以下优点:
使用gRPC API提供服务,支持多种语言服务调用;
支持GPU加速推理,可使用GPU加速模型预测打分过程;
支持Batching操作;
支持模型版本管理,可动态装载、卸载模型;
支持分布式TensorFlow模型
TensorFlow在线预测服务整体设计如下图所示:
TensorFlow-Serving作为Tensorflow模型预测计算节点,提供模型预测打分功能。Kubernetes集群通过Deployment资源对象管理所有Tensorflow-Serving,提供模型部署和滚动更新操作,多Deployment资源对象能有效区分不同模型的Tensorflow-Serving节点。
SCF服务作为整个TensorFlow在线预测服务接入层,实现对协议解析JAR包的热加载,协议解析JAR包负责将SCF服务接口请求数据转换成在线预测请求PredictRequest对象和将在线预测返回PredictResponse对象转换成SCF服务接口返回数据。SCF服务Watch Kubernetes集群同步POD IP变化,并维护不同任务对应的后端TensorFlow-Serving节点IP列表关系,同时使用加权轮询负载均衡算法将流量均匀转发到后端节点上。
服务通用性设计
PredictRequest,Java请求TensorFlow-Serving对象
PredictResponse,Java请求TensorFlow-Serving返回对象
不同模型的预测,PredictRequest对象实现和PredictResponse对象数据提取都各不相同,为提升服务通用性,平台将PredictRequest对象实现和PredictResponse对象数据提取开放给用户,由用户实现此过程。
但是由于SCF无法反序列化/序列化PredictRequest/PredictResponse对象,不能将PredictRequest/PredictResponse对象直接作为协议传输。我们将SCF请求/返回协议定义为通用的Object类型,同时发布抽象解析类,用户继承抽象解析类实现PredictRequest/PredictResponse对象解析JAR包并上传到平台,平台SCF服务实现解析JAR包热加载,完成请求和返回数据的解析,有效解决不同种类模型请求数据、返回数据格式不同问题,保证接口的通用性,详细流程设计如下图所示:
自定义模型预测设计
五八业务部门除了TensorFlow模型,还存在自定义的模型,如用户对模型有个性化的修改。深度学习在线预测服务为兼容此类模型,实现自定义模型预测逻辑。自定义模型预测基于Docker容器和gRPC技术实现,为需要使用GPU进行加速而又不想转成TensorFlow模型或修改模型结构的业务方提供支持,实现服务高兼容性。
服务基于gRPC技术实现自定义模型预测服务端,服务端实现自定义模型加载及预测,支持C++、Java、Python和Golang等多种语言。
使用自定义模型预测功能,需要完成以下步骤:
定义请求gRPC接口协议
实现gRPC服务端模型打分逻辑,并封装为镜像
实现接口协议解析JAR包,将SCF通用协议解析为gRPC接口协议
流量转发设计
SCF服务作为整个预测服务对外的流量接入层,承担着在线请求的解析和转发作用。同时由于Kubernetes集群Service可以为一组相同功能的容器应用提供统一的入口地址,并将请求负载均衡分发到各个容器应用上,Service的负载均衡功能由node节点上的kube-proxy提供,使用Kubernetes Service流量转发步骤有:
1. SCF服务将流量发送各物理机对应端口上
2. Kubernetes kube-proxy将收到的流量转发到对应的后端POD容器上
Kubernetes Service流量转发流程如下图所示:
此方式有如下优点:
SCF服务能够部署在集群外部
无需关注流量转发负载均衡功能
同样也存在缺点:
两次流量转发,网络耗时较大
为解决上面的缺点,SCF服务将流量直接转发至后端POD容器上,这样只存在一次流量转发,有效的减少了在线预测服务网络耗时,流量转发示意图如下:
上面的方式抛弃了Kubernetes Service,由SCF服务充当Service角色,实现Service流量转发负载均衡策略。我们在线预测服务采用后者方案,使用加权轮询算法作为负载均衡策略,减少一次流量转发,有效降低在线预测服务网络耗时。
负载均衡-加权轮询算法
服务采用SCF服务转发流量至后端POD容器上,因此需要实现流量转发负载均衡,均匀转发流量到后端节点上,因此负载均衡算法好坏在一定程度上决定服务稳定性。常见负载均衡算法包括轮询法、随机法、哈希法、加权轮询法、加权随机法和最小连接数法等。服务采用加权轮询法,同时做了些许改动以适应当前场景。
加权轮询算法相关实现细节如下:
低有效权重节点在发现连接正常后需要快速加权,快速升高节点权重,以承担线上流量,升权计算公式:
effectiveWeight += (weight-effectiveWeight+1)>>1
高有效权重节点在发现连接异常后需要快速降权,快速降低节点权重,减少异常对线上流量影响,降权计算公式:effectiveWeight /= 2
通过Watch Kubernetes集群节点变化来增删节点候选池
节点连接异常会重新选择一次节点转发流量,保证线上请求有结果率
服务部署
Kubernetes Deployment资源对象集成上线部署、滚动升级、版本回滚等功能,同时还能设置滚动更新过程中最大不可用POD数据,最小升级间隔时间等等,能有效的提升服务更新过程稳定性。深度学习在线预测服务使用Kubernetes Deployment资源对象,用于支持模型部署、模型版本迭代、模型资源更新等功能。
服务部署主要包括以下操作:
1. WEB页面产生模型部署/迭代操作,并将请求发送至WEB后台处理
2. WEB后台使用Kubernetes Java Client包调用Kubernetes API接口,操作对应任务的Deployment资源对象,模型部署操作对应创建Deployment资源对象,模型迭代操作对应更新Deployment资源对象,如更新使用资源配置、模型版本配置、labels标签等
3. Deployment创建完成,根据配置选项部署TensorFlow-Serving或自定义模型Serving节点,Deployment配置更新,执行滚动更新,逐步销毁现有模型节点,创建更新后配置模型节点。同时Deployment负责控制节点数量,确保集群始终处于预期的工作状态。
GPU部署配置
GPU资源模型部署Deployment资源对象需要添加以下配置:
1. GPU驱动文件挂载到镜像内部
nvidia-docker-plugin是一个docker plugin,被用来帮助我们轻松部署container到GPU混合的环境下。类似一个守护进程,发现宿主机驱动文件以及GPU设备,并且将这些挂载到来自docker守护进程的请求中。以此来支持docker GPU的使用。
nvidia-docker安装完首次使用GPU资源,需要运行GPU镜像才能生成可挂载到镜像内部的驱动映射文件,生成GPU驱动映射文件方式如下:
docker pull nvidia/cuda:9.0-cudnn7-devel-ubuntu16.04 &&
nvidia-docker run nvidia/cuda:9.0-cudnn7-devel-ubuntu16.04 nvidia-smi
运行成功后宿主机上存在GPU驱动映射文件目录,并挂载到镜像内部/usr/local/nvidia目录,GPU驱动映射文件目录如下所示:
/var/lib/nvidia-docker/volumes/nvidia_driver/+GPU驱动版本号
2. 配置GPU卡使用数量
Kubernetes资源配置中资源限制limits中添加alpha.kubernetes.io/nvidia-gpu配置。
服务资源监控
节点计算资源数据收集
在线预测节点部署在服务内部,服务提供每个节点使用资源等数据,方便用户了解任务在资源上的消耗。
Heapster是容器集群监控和性能分析工具,天然支持Kubernetes,以Kubernetes内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据:CPU、Memory、Network、FileSystem等,然后将这些数据输出到外部存储,如InfluxDB,最后再通过相应的UI界面进行可视化展示,如WEB平台从InfluxDB中查询数据展示。
GPU数据收集
Heapster无法收集各POD节点GPU数据,因此平台需要额外收集GPU使用数据。
镜像启动程序中添加GPU使用数据收集模块,每分钟收集GPU数据(GPU使用率、显存使用率、温度等)并将数据汇报至WEB后台服务,WEB后台服务将数据持久化到MySQL数据库中。
WEB管理平台
WEB页面提供在线预测任务管理、模型一键部署和资源查看等功能,方便用户操作,减少用户使用成本。
任务管理
在线预测任务管理提供一系列任务操作,包括在线预测任务创建、编辑、删除和部署节点详情查看等操作,任务创建包括任务信息(任务编号、任务描述、模型名称等)和资源配置(模型节点数量、节点最大内存、节点最大CPU、是否使用GPU);任务编辑修改可修改节点数量、节点资源等配置参数;删除任务前提是业务方没有流量调用。
资源查看
在线预测任务模型资源存在使用限制,资源使用接近申请资源值,容易出现资源不足情况,导致模型预测打分计算变慢,耗时变高,因此了解模型节点实际使用资源情况,能有效避免资源使用达到上限。
必选的使用计算资源包括CPU、内存,其他资源包括网卡入流量、网卡出流量。
同时支持曲线图展示,了解整天各时间点资源使用状况,如下图所示:
可选计算资源包括GPU,监控数据如下图所示:
模型一键部署
WEB页面操作支持模型一键部署,部署模型或者模型迭代上线只需要输入部署模型版本号即可,支持滚动更新部署,升级中允许的最大Unavailable的POD个数为1个,新部署节点Ready为true进行下一个节点部署,逐步替换线上模型,不影响线上业务。
总结
本文主要介绍了58深度学习在线预测服务的实现过程,包括TensorFlow模型在线预测服务、自定义模型在线预测服务、流量转发、服务部署、资源监控、WEB平台管理等内容。深度学习在线预测服务作为深度学习应用到生产环境的最后一环,是深度学习重要组成部分,整个服务目前共有50+个在线预测模型,日均数亿流量,支撑了推荐(详细请参考《深度学习在58智能推荐系统中的应用实践》)、搜索、广告、图文识别、智能客服、智能外呼等应用。
后续我们将从以下几点对服务进行持续优化,帮助业务线将深度学习更好、更快捷的应用于生产环境:
支持分流,实现模型不同版本对比测试。
支持自动扩缩容,根据实时流量和任务资源使用率,完成节点自动扩缩容。
支持多模型串行预测,减少串行多次调用网络耗时开销。
参考资料:《58同城人工智能平台架构实践》《58人工智能平台WPAI设计与实现》
最后,58集团AI Lab人工智能实验室诚招算法和后台工程师,简历投递邮箱:zhankunlin@58ganji.com,详情请戳《五八同城AI Lab人工智能实验室招聘启事》