TensorFlow Serving 由于其便捷稳定的特点在CTR(Click-through Rate,点击率) 预估业务场景被广泛的使用,但是其运行时会出现内存不断增长的问题,也不断有相关issue被提交到Github社区,且目前都是Open状态。本文分享了爱奇艺深度学习平台在实践中发现的两个TensorFlow Serving内存泄漏问题,并修复和提交了 PR 到社区,这里将详细介绍问题的背景以及解决的过程,希望能够有所帮助。

01

背景介绍

TensorFlow Serving(以下简称 TF Serving) 是谷歌开源、用来部署 TensorFlow模型的高性能推理系统。它主要具备如下特点:

  • 同时支持 gRPC 和 HTTP 接口

  • 支持多模型、多版本

  • 支持模型热更新和版本切换

另外,爱奇艺在 TF Serving的基础上,开源了 XGBoost Serving 来支持 GBDT 模型的推理服务,也同样继承了 TF Serving的以上特性。

总体来讲,使用 TF Serving 来部署推理服务的稳定性和性能都比较好,特别是CTR 预估这种对服务延迟和稳定性要求高的业务。不过,在 TFServing Github 的 [issue 列表]上,经常有人报告运行中出现内存不断增长导致 OOM 的问题。一个典型的内存issue <<Sharpincrease in memory usage -> server is killed>>

在 2018 年就有人提出,目前为止还是 open 状态。

爱奇艺深度学习平台在实践中也遇到了两个类似的问题,我们业务的线上推理服务是通过 Docker容器进行部署的,但是发现 TF Serving 在某些时候内存会不断增长导致容器 OOM。下面将逐个介绍这两个问题的背景是如何被解决的。

02

  模型特征 Raw Serving Tensor输入

先来介绍一下 TF 模型 SavedModel特征输入的两种方式。一种是模型输入只有一个,该输入的 placeholder 是一个 String,String 的内容是tf.Examples;另一种是模型输入有多个,每个输入placeholder 分别对应特征的Tensor。以tf.estimator的API为例子,两者的API分别为`tf.estimator.export.build_parsing_serving_input_receiver_fn`和`tf.estimator.export.build_raw_serving_input_receiver_fn`。使用saved_model_cli命令可以明显看到这两种模型输入的不同:

这两种方式在客户端和TF Serving 服务端的处理都有些不同,如下图所示,使用TF Examples的输入方式需要在客户端先序列化成 String,然后在TF Serving 服务端的模型里使用 parse example op 将 String 反序列化成输入特征的 Tensor,再执行模型的前向计算。而使用Raw Serving Tensor 就少了这两部分的操作。TF Examples的序列化和反序列化操作会给端到端的推理服务性能带来一定的损耗,因此我们的CTR 类业务基本都在使用第二种模型输入的方式。

介绍完模型输入的背景,下面看一下问题的现象是什么。有一天,业务在上线的时候发现 TF Serving容器监控中的内存突然开始不断增加,并且丝毫没有要停止的迹象。

我们迅速通过离线复现了问题,并用 gperftools 做了内存的 profiling,下图是从profiling 的 PDF 文件中截取部分出来

可以看到

DirectSession::GetOrCreateExecutors 这个函数通过hash table的 emplace创建了大量的 String 导致内存不断的增加。通过查看TF的源代码可以发现DirectSession 这个类里面有一个成员变量 executors_ 是一个unordered_map,里面保存了模型输入的 signature 到ExecutorsAndKeys 的映射。

DirectSession::GetOrCreateExecutors函数里面的逻辑如下:

根据上面的逻辑,如果input的数量有10个,那么特征输入的组合就有 10!= 3,628,800 种,如果一个key 有100 Byte,那就需要约 350MB 内存,如果超过 10 个就需要 3G 以上的内存了,这就是内存泄漏的原因。

不过内存泄漏的源头应该是发送给 TF Serving的 PredictRequest 里面inputs 特征顺序不断在变化,从而导致DirectSession::GetOrCreateExecutors函数一直查找不到匹配的输入,然后创建新的字符串插入到executors_ 中。而发送给 TF Serving的 PredictRequest 是通过 protobuf 定义生成的,inputs 是一个 string 到 TensorProto的 map。

再进一步查看 Protocol Buffers 关于 map 的文档定义,里面明确说明了map 迭代的顺序是没有定义的,代码不能依赖于map里面的 item 是某种特定的顺序。

回过头看最开始介绍的两种模型输入,使用 tf.Examples 方式的模型输入只会有一个,不会出现这个问题。我们的模型使用的是多个Raw Tensor 输入,input 特征至少有 10 个以上,因此才会出现这个问题。

找到了内存泄漏的原因,但是为什么会突然出现内存不断上涨呢,业务之前线上跑了很久从未出现过。业务反馈,发送请求的客户端修改了构造请求的逻辑,之前代码里面的顺序是固定的,现在的顺序不是固定的。虽然Protocol Buffers 的定义里面说 map 的迭代顺序是没有定义的,但是实现上如果插入的顺序一样,那么迭代的顺序估计是固定的,但是我们还是不能依赖这种未定义的实现。这样就把整个问题的来龙去脉弄清楚了。

最后,我们分别提了两个PR,一个是修改TF里面的函数GetOrCreateExecutors;一个是在 TF Serving 里面总是对 inputs 做一次排序,在TF Serving 里面排序可以省去一次在 TF里面的strings::StrCat 和查找。

两个PR地址

爱奇艺 TensorFlow Serving 内存泄漏优化实践相关推荐

  1. 维护几十种语言和站点,爱奇艺国际站WEB端网页优化实践

    1.前言 爱奇艺国际站(www.iq.com)提供了优质的视频给海外各国用户,自上线以来,现已支持几十个国际站点,并且在东南亚多个国家保证了海量用户高速观看体验. 国际站业务的特点是用户在境外访问,后 ...

  2. 【机器学习】机器学习在爱奇艺视频分析理解中的实践

    原标题:大规模机器学习在爱奇艺视频分析理解中的实践 AI 前线导读:视频包含了图像.声音.文字等多种信息,可以表达生动.丰富的内容.随着 AI 时代的带来,互联网视频应用高速发展,视频更成为一种人人可 ...

  3. 【视频分析】大规模机器学习在爱奇艺视频分析理解中的实践

    原标题:大规模机器学习在爱奇艺视频分析理解中的实践 AI 前线导读:视频包含了图像.声音.文字等多种信息,可以表达生动.丰富的内容.随着 AI 时代的带来,互联网视频应用高速发展,视频更成为一种人人可 ...

  4. 开发效率提升50%以上,爱奇艺官网主站的Nuxt实践

    01 背景 让每一个用户获取到稳定.及时的页面体验,是前端工程师们一直以来努力的方向. 作为一个拥有丰富内容资源的视频网站,爱奇艺官网主站需要频繁进行节目上线或者下线.各种活动配置等操作调整,对于页面 ...

  5. 爱奇艺数据仓库平台和服务建设实践

    该文根据[i技术会]现场演讲整理而成 首先介绍一下爱奇艺公司整体的业务情况以及数据仓库1.0的设计和出现的问题,针对数仓1.0的缺陷,是如何演进到数仓2.0架构以及数仓2.0需要解决的问题和需要达成的 ...

  6. 爱奇艺微服务标准技术架构实践

    背景 为数以亿计的用户提供优质的视频服务的爱奇艺技术产品团队,为了适应业务的快速迭代和创新,并支撑海量的用户请求,很多团队都对各自的业务系统自发地进行了微服务架构的改造. 在微服务化的过程中,各业务团 ...

  7. 爱奇艺视频推荐领域的ANN实践

    本文内容来自于 由阿里云开发者社区 x 达摩院领航举办的3月20日向量检索专场Meetup讲师演讲内容 发表于" AI 检索技术博客" 公众号 讲师介绍 张吉 爱奇艺深度学习云研发 ...

  8. 爱奇艺 PC Web Node.js 中间层实践

    文章转载自公众号  爱奇艺技术产品团队 , 作者 前端研发团队 黑夜无论怎样悠长,白昼总会到来. 爱奇艺作为中国最大的互联网视频综合门户,一直致力于给用户提供更好的使用体验及观影品质.PC主站作为爱奇 ...

  9. 低代码在爱奇艺鹊桥数据同步平台的实践

    前言 为应对软件危机,诞生了软件工程,以期望其达到降低软件生产成本 .改进软件产品质量.提高软件生产率水平的目标.自上个世纪60年代以来,从模块化.面向对象设计到设计模式,从瀑布流模型到敏捷开发,de ...

最新文章

  1. php面积计算html代码,计算PHP页面中的所有HTML标记
  2. centos7 搭建nfs共享文件
  3. Android中文API (109) —— SimpleCursorTreeAdapter
  4. python爬虫能干什么-Python爬虫能做什么
  5. 全球及中国生物柴油行业产量规模及市场消费需求预测报告2021-2027年
  6. 闲得无聊?不如用Python设计一个经典小游戏
  7. 家长工作比较忙,没有什么时间来带孩子,交给家里老人会养成一些坏习惯吗?
  8. Raspberry Pi 构建一个飞机观察器
  9. 附下载,《爱分析·中国BI商业智能行业报告》
  10. Unity 原生版本管理工具VersionControl - Plastic SCM 详解
  11. 插桩java_字节码插桩技术
  12. 【FPGA】05_按键消抖
  13. python与数据思维基础_7个python案例中的数据思维
  14. 非线性最小二乘问题的分析与理解(附高斯牛顿法matlab代码)
  15. 清子指弹FC吉他五重奏nes《最终幻想1 》地图音乐步行 (FC游戏音乐)
  16. 修改UE4的缓存路径
  17. iRedmail配置手册
  18. 首位文博虚拟宣推官“文夭夭”上岗
  19. UVa Problem 10001 Garden of Eden (伊甸园)
  20. CSS中的line-height,height与line-height

热门文章

  1. FFmpeg命令行--调整视频播放速度
  2. css display table 自适应高度、宽度问题
  3. android 5.1.1开机优化(framework层)
  4. Python给图片加水印(非常简单)
  5. yolo v5.50 坑
  6. Opencv 未经处理的异常 Microsoft C++ 异常: cv::Exception,位于内存位置
  7. 蓝桥杯 漏掉的账目明细 DFS搜索 数据处理
  8. 扫雷游戏 C语言实现
  9. ESP8266学习 六 通过闪存文件系统上传web端程序
  10. 博主的简历: 金东升 justin.jin