写点什么

PostgresML 比 Python HTTP 微服务快 8-40 倍

  • 2022-11-01
    北京
  • 本文字数:4243 字

    阅读完需:约 14 分钟

PostgresML比Python HTTP微服务快8-40倍

机器学习架构可能是现代系统中最复杂、最昂贵和最困难的领域了。技术的数量和所需硬件的数量都在为缩减人员、托管和延迟预算而竞争。不幸的是,随着以数据仓库、微服务和 NoSQL 数据库为中心的最先进的架构使用量的不断增加,该行业的趋势在这些方面只会变得更加糟糕。


针对这种不断增长的复杂性,PostgresML 是一种更简单的替代方案。在本文中,我们探讨了更优雅的架构的一些额外性能优势,并发现 PostgresML 在本地测试中比传统的 Python 微服务的性能高出了 8 倍,在 AWS EC2 上则高出了 40 倍

候选架构

考虑到 Python 微服务的所有可能优势,我们的第一个基准测试是在同一台机器上运行 Python 和 Redis。我们的目标是避免任何额外的网络延迟,这使得它与 PostgresML 的对比更加公平。我们的第二个测试是在 AWS EC2 上进行的,Redis 和 Gunicorn 由网络分隔开;这个基准测试被证明是相对具有破坏性的。


这两个基准测试的完整源代码可以在Github上找到。

PostgresML

PostgresML 架构由以下部分组成:


  1. 带有 PostgresML v2.0 的 PostgreSQL 服务器

  2. pgbench SQL 客户端

Python

Python 架构由以下部分组成:


  1. 接受并返回 JSON 的 Flask/Gunicorn 服务器

  2. 带有训练数据的 CSV 文件

  3. 带有使用 JSON 序列化推理数据集的 Redis 特征存储

  4. ab HTTP 客户端

ML

这两种架构都托管了相同的 XGBoost 模型,并针对相同的数据集运行预测。相关详细信息,请参阅方法论部分。

结果

吞吐量


吞吐量(Throughput)被定义为架构每秒可以服务的 XGBoost 预测的数量。在这个基准测试中,PostgresML 的性能比运行在同一台机器上的 Python 和 Redis 要高 8 倍


在 Python 中,大部分瓶颈来自于必须获取并反序列化 Redis 数据。由于这些特征是在外部存储的,因此它们需要通过 Python 传递到 XGBoost 中。XGBoost 本身是用 C++编写的,它的 Python 库只提供了一个便利的接口。来自 XGBoost 的预测必须再次通过 Python,序列化为 JSON,并通过 HTTP 发送到客户端。


这几乎是你可以为推理微服务所能做的最低限度的工作了。


另一方面,PostgresML 对数据和计算进行了配置。它从 Postgres 表中获取数据,该表已经采用了标准浮点格式,Rust 推理层通过指针将其转发给 XGBoost。


当基准测试达到 20 个客户端时,发生了一件有趣的事情:PostgresML 的吞吐量开始快速下降。这可能会让一些人感到惊讶,但对于 Postgres 的爱好者来说,这是一个已知问题:Postgres 并不擅长处理比 CPU 线程更多的并发活动连接。为了缓解这一问题,我们在数据库之前引入了 PgBouncer(一个 Postgres 代理和池化器),吞吐量也随之增加了,并且在达到 100 个客户端时继续保持不变。


值得注意的是,基准测试机只有 16 个可用 CPU 线程(8 核)。如果有更多的内核可用,瓶颈只会在有更多的客户端时出现。Postgres 服务器的一般建议是为每个可用 CPU 内核打开大约 2 个连接,尽管较新版本的 PostgreSQL 已经逐渐消除了这一限制。

为什么吞吐量很重要

吞吐量能让你事半功倍,用更少的资源做更多的事情。如果你能够使用一台机器每秒处理 30000 个查询,但现在只使用 1000 个查询,那么你不太可能需要在短时间内进行升级。另一方面,如果系统只能处理 5000 个请求,那么在不久的将来,你将会进行一项昂贵且可能会是压力很大的升级。

延迟


延迟(Latency)被定义为返回单个 XGBoost 预测所需的时间。由于大多数系统的资源是有限的,吞吐量直接影响延迟(反之亦然)。如果有许多活动请求,则在队列中等待的客户端就需要更长的时间才能得到服务,并且整体系统延迟会增加。


在这个基准测试中,PostgresML 的表现也比 Python 好 8 倍。你会注意到,同样的问题在有 20 个客户端时也会发生,使用 PgBouncer 进行相同的缓解措施会减少其影响。与此同时,Python 的延迟继续大幅增加。


在描述架构的性能时,延迟是一个很好的度量指标。换句话说,如果我要使用这项服务,我最多会只能在这么长的时间内得到一个预测,而不管还有多少其他客户也正在使用它。

为什么延迟很重要

延迟在机器学习服务中很重要,因为它们通常作为主应用程序的附加部分来运行,有时必须在同一 HTTP 请求期间多次访问。


让我们以电子商务网站为例。典型的店面希望同时展示多个个性化模型。这类模型的示例可能包括针对重复购买的“再次购买”建议(二分分类),或“你所在地区的热门商品”(购买历史的地理聚类)或“像你这样的客户还购买了该商品”(最近邻模型)。


所有这些模型都很重要,因为随着时间的推移,它们已被证明在推动购买方面非常成功。如果推理延迟很高,那么模型就会开始争夺非常昂贵的空间、头版和结算,而企业不得不放弃其中的一些,或者更有可能是遭受页面加载缓慢的影响。没有人喜欢在订购食品杂货或晚餐时使用运行缓慢的程序。

内存利用率


众所周知,Python 比其他更优化的语言使用更多的内存,在这种情况下,它使用的内存是 PostgresML 的 7 倍。


PostgresML 是 Postgres 扩展,它与数据库服务器共享 RAM。Postgres 在只获取和分配它所需的内存方面非常高效:它重用 shared_buffers 和操作系统(OS)页面缓存来存储行以进行推理,并且只需要很少甚至根本不需要分配内存来服务查询。


同时,Python 必须为它从 Redis 接收到的每个特征以及它返回的每个 HTTP 响应分配内存。这个基准测试并未测量 Redis 的内存利用率,这是运行传统机器学习微服务的额外成本,而且通常是相当大的成本。

训练


由于 Python 经常使用 Pandas 来加载和预处理数据,因此它尤其需要更多的内存。甚至在将数据传递到 XGBoost 之前,我们已经达到了 8GB RSS(驻留集大小);在实际的拟合过程中,内存利用率几乎达到了 12GB。这个测试是 Python 的另一个最佳案例场景,因为数据已经被预处理过了,只是将其传递给了算法而已。


同时,PostresML 喜欢与 Postgres 服务器共享 RAM,只分配 XGBoost 所需的内存即可。数据集的大小非常大,但我们仅使用 5GB 的 RAM 就能成功地训练相同的模型。因此,在使用相同硬件的情况下,PostgresML 允许的数据集上的训练模型至少是 Python 的两倍。

为什么内存利用率很重要

这是另一个事半功倍的例子。FAANG 和研究型大学之外的大多数机器学习算法都要求数据集能够装入单个机器的内存中。分布式训练并不是我们所希望的,而且从简单的线性回归中仍然可以提取很多价值。


使用更少的 RAM 可以在更大、更完整的数据集上训练更大、更好的模型。如果你碰巧遭受了大量机器学习计算费用的困扰,那么在你的财年结束时,使用更少的 RAM 可能能给你带来惊喜。

UltraJSON/MessagePack/Serializer X 呢?

我们花了很多时间来讨论序列化,因此回顾该领域之前的工作是有意义的。


JSON 是对用户最友好的格式,但它肯定不是最快的。例如,MessagePack 和 Ultra JSON 有时在读取和存储二进制信息方面更快、更高效。那么,在这个基准测试中使用它们会比使用 Python 的内置 json 模块更好吗?


答案是:并非如此。




(反)序列化的时间很重要,但首先最终需要进行(反)序列化就是瓶颈。从远程系统(例如 Redis 这样的特征存储)中取出数据,通过网络套接字发送数据,将其解析为 Python 对象(需要内存分配),然后再将其转换为 XGBoost 的二进制类型,这会在系统中造成不必要的延迟。


PostgresML 对 Postgres 的特征进行了一次内存拷贝。没有网络,没有(反)序列化,没有不必要的延迟。

现实情况如何呢?

通过 ocalhost 进行测试很方便,但这不是最现实的基准测试。在生产部署中,客户端和服务器位于不同的机器上,而在 Python+Redis 架构中,特征存储又是在另一个网络跳转点上。


为了演示这一点,我们启动了 3 个 EC2 实例并再次运行基准测试。这一次,PostgresML 比 Python 和 Redis 的表现要好 40 倍




Redis 和 Gunicorn 之间的网络差距让事情变得非常非常糟糕……。从远程特征存储中获取数据增加了 Python 架构无法避免的请求毫秒数。在一个资源有限的系统中,额外的延迟造成了争用。大多数 Gunicorn 线程只是在网络上等待,成千上万的请求被卡在了队列中。


PostgresML 没有这个问题,因为特征和 Rust 推理层位于同一个系统上。这种架构选择消除了等式中的网络延迟和(反)序列化。


你会注意到我们前面讨论的并发性问题在有 20 个连接时影响了 Postgres,我们再次使用 PgBouncer 来挽救局面。一旦你知道了如何去做,扩展 Postgres 并不像听起来那么困难。

方法论

硬件

第一个基准测试中的客户端和服务器都位于同一台机器上。Redis 也是本地的。该机器是一台 8 核、16 线程的 AMD Ryzen 7 5800X,配备了 32GB RAM、1TB NVMe SSD,并运行有 Ubuntu 22.04。


AWS EC2 基准测试分别使用了一个托管了 Gunicorn 和 PostgresML 的c5.4xlarge 实例,以及两个 c5.5large 客户端和 Redis 实例。它们位于同一 VPC 中。

配置

Gunicorn 运行时有 5 个进程(Worker),每个进程有 2 个线程(Thread)。Postgres 分别为 1 个、5 个和 20 个客户端使用 1、5 和 20 个连接。PgBouncer 的 default_pool_size 设为 10,因此 20 和 100 个客户端最多能使用 10 个 Postgres 连接。


XGBoost 在推理过程中允许使用 2 个线程,在训练过程中使用所有可用的 CPU 内核(16 个线程)。


abpgbench 都使用了所有的可用资源,但都是非常轻量级的;这些请求分别是单个 JSON 对象和单个查询。这两个客户端都使用了持久连接, ab 通过使用 HTTP Keep-Alives 实现, pgbench 则通过在基准测试期间一直保持 Postgres 连接打开。

ML

数据

我们使用了来自 Kaggle 的飞行状态预测( Flight Status Prediction )数据集。经过一些后置处理,它最终变成了大约 2GB 的浮点特征。我们并没有使用所有的列,因为其中一些列是多余的,例如机场名称和机场标识符,它们指的是同一个东西。

模型

我们的 XGBoost 模型使用默认超参和 25 个估计量(也称为增强轮)进行训练。


用于训练和推理的数据可在此处获取。存储在 Redis 特征存储中数据可在此处获取。这只是一个子集,因为用单个 Python 进程(2800 万行)将整个数据集加载到 Redis 需要花费数小时。与此同时,Postgres COPY 只需要大约一分钟。


对 PostgresML 模型进行如下的训练:


SELECT * FROM pgml.train(    project_name => 'r2',    algorithm => 'xgboost',    hyperparams => '{ "n_estimators": 25 }');
复制代码


它的准确性很差(Python 版本也是如此),可能是因为我们遗漏了任何类型的天气信息,后者最有可能会导致机场的延误。

源代码

基准源代码可以在Github上找到。

反馈

非常感谢所有支持这一努力的人。我们希望听到来自更广泛的 ML 和工程社区关于应用程序和其他真实世界场景的反馈,以帮助我们确定工作的优先级。 你可以通过在我们的Github上为我们加注星标来表示你的支持。


项目 Github 地址:https://github.com/postgresml/postgresml


原文链接:

https://postgresml.org/blog/postgresml-is-8x-faster-than-python-http-microservices/#throughput


声明:本文为 InfoQ 翻译,未经许可禁止转载。

2022-11-01 15:135441

评论

发布
暂无评论
发现更多内容

DevEco Studio端云协同开发之云函数

白晓明

HarmonyOS 端云协同 云函数

瓴羊Quick BI智能报表,让报表化复杂为简单!

巷子

Teradata在华落幕,国产化崛起,袋鼠云数栈会是更好的选择吗?

袋鼠云数栈

云小课|MRS基础原理之Hue组件介绍

华为云开发者联盟

大数据 华为云 企业号 2 月 PK 榜 华为云开发者联盟

Wallys/QSDK IPQ6010/wifi mesh function supports qcn9074/qcn6024 M.2 E Key Interface

Cindy-wallys

IPQ6010 ipq6018 IPQ6000

华为云CodeArts Artifact,5大特性守护制品质量与安全

华为云开发者联盟

云计算 开发 华为云 企业号 2 月 PK 榜 华为云开发者联盟

瓴羊Quick BI率先提供移动端自助分析整体解决方案,成为行业的领导者!

流量猫猫头

揭穿数据分析的六大谎言

葡萄城技术团队

父母、离别

毛广斌

生活

C++中const和constexpr关键字解析:常量、函数和指针

小万哥

程序员 后端 开发 C/C++ const

多模并起,万向融合 | 2023年2月《中国数据库行业分析报告》精彩抢先看

墨天轮

数据库 HTAP MatrixDB 多模数据库 超融合数据库

平时报表很复杂吗?瓴羊Quick BI智能报表轻松解决!

夏日星河

阿里张勇:全力投入生成式AI大模型建设,为行业发展提供好算力支撑

阿里技术

人工智能 云计算

NFTScan 与 KNN3 在 NFT 数据层面达成合作伙伴关系

NFT Research

NFT web3

【2.17-2.24】写作社区优秀技术博文一览

InfoQ写作社区官方

热门活动 优质创作周报

在流媒体时代,如何看待音乐版权?

HIFIVE音加加

知识产权 音乐 版权

LeetCode题解:2357. 使数组中所有元素都等于零,哈希表,详细注释

Lee Chen

JavaScript 算法 LeetCode 哈希表

这周末,StarRocks 邀请开发者们一起来上海 GAIDC 开源集市,各种任务等你来挑战!

StarRocks

数据库

3DMAX中的7个基本建模小窍门

Finovy Cloud

blender 3ds Max Cinema 4D

不被同事骂的代码规范,程序员们值得拥有!

程序员小毕

Java 程序员 程序人生 架构师 代码

中冶赛迪:基于鲲鹏DevKit开发智慧城市基础设施管理平台,性能提升47%

Geek_2d6073

深入浅出玩转监控宝|网站监控之创建网站监控任务

云智慧AIOps社区

监控宝 监控工具 监控指标 #监控 网站监控

ChatGPT模拟MySQL数据库 | 社区征文

NineData

MySQL 数据库 编程 技术栈 ChatGPT

Python基础知识入门(二)

漫步桔田

在字节跳动,造赛博古籍

字节跳动技术范儿

后端 nlp 搜索 OCR 多模态

ChatGPT对于普通人有什么机会和影响?

引迈信息

人工智能 AI AIGC ChatGPT

电商难做?低代码开发平台为企业转型升级保驾护航

加入高科技仿生人

低代码 电商 数据管理 b2b

DawnSql快速入门

陈飞

微服务 分布式数据库 实时数仓

PostgresML比Python HTTP微服务快8-40倍_语言 & 开发_Lev Kokotov_InfoQ精选文章