查看原文
其他

亿优百倍|商品数据服务百倍性能优化之路

黄毅铭 eBay技术荟 2022-12-29

作者|黄毅铭

编辑|林颖

供稿|Marketing Tech Team

本文共5239字,预计阅读时间10分钟

更多干货请关注“eBay技术荟”公众号


导读

“亿优百倍“(“亿”指亿贝‘eBay’;“优”指优化;“百倍”指性能近百倍的提升)是由eBay智能营销团队推出的系列文章,希望将工作中在营销商品数据服务系统的架构、设计和代码方面的一些理解和研究跟大家一起分享和探讨,另外也给对数据服务同时有线上线下需求的行业提供一些参考。“亿优百倍”总共分为三篇:百倍性能优化之路、TiDB相关优化以及缓存与代码优化。本篇作为系列文的总起篇,主要讲述了项目的背景介绍、总体设计和优化路线图。


1 背景


从2020年4月开始,eBay智能营销部门开始打造新一代的营销商品数据服务,旨在为智能营销事业部的各种应用(站外广告投放、邮件营销、算法模型等)提供统一的eBay商品数据和服务。该服务需要涵盖丰富的线上及线下数据访问需求,并满足超高的查询性能及关键数据低延时等需求。在系统的搭建过程中,团队对整个系统的架构和代码做了各种极致的优化。截止2021年9月,在固定硬件的环境下,让系统核心的商品详情查询服务的性能有了近百倍的提升


2 介绍

2.1 什么是营销商品数据服务?

简单来说,营销商品数据服务(Marketing Inventory Service,以下简称MIS)提供的是eBay商品的查询服务。但是查询的访问方式有很多,性能要求也会各不一样。例如,以下是三种商品信息典型的查询方式:

1)根据商品ID查各种商品信息是典型的Key-Value(以下简称KV)查询;

2)根据卖家或商品类目查所有商品是典型的二级索引查询;

3)根据所有商品去查最高/最低/平均价格等是典型的全表扫描后聚合。

然而,在工业界是没有一种数据中间件可以同时以高性能满足这三种查询方式的。常见开源分布式数据库或数据中间件支持的数据访问方式如下表所示。

表1

我们MIS的愿景就是要搭建这样一个数据系统和服务,让数据消费者能够非常方便且高性能地以各种方式去访问商品数据。这就需要我们去整合多种数据中间件。而数据消费者无需知道这个数据具体是存储在哪种中间件上的,MIS会自动根据查询模式来做最优选择。


2.2 eBay没有类似的数据服务?

上节中描述的对商品数据查询的需求听上去非常的核心且基础。而eBay作为一家已经有几十年历史的互联网大厂,难道没有这样的系统吗?还需要重新搭建?答案是:的确没有这样一站式的系统。

那么我们来看看eBay现有的服务,以及这些已有服务和我们要搭建的系统的差别。了解了已有的服务,读者也会更加深刻地理解搭建MIS的愿景和技术挑战在哪里。

2.2.1 线上:eBay Oracle数据库和VLS

eBay的核心业务是电商平台,让买家能购买卖家提供的商品的一个网站。其业务系统是典型的OLTP(Online Transaction Processing)场景。其中,商品详情查询是最基础的服务。eBay将商品信息范式化(Normalization)地存储在各个Oracle表中。Oracle是分库分表的,单逻辑表可以轻松支持到数十万QPS的查询。然而因为范式化的存储,导致当需要查询其他商品信息时需要跨多表进行Join或二级索引查询。比如商品的基本信息可以直接从商品表查询,然而要拿到商品对应卖家的评级、商品的物流信息、商品的详细描述(长文本或HTML)等则需要级联查询到卖家、物流、商品描述等其他表。

View Listing Service(以下简称VLS)是eBay的一个核心商品查询服务。它可以把这种级联查询对服务消费者透明化。根据你要查的商品字段,它能自动地查询对应的表或服务。但是,当客户需要返回几十个商品属性字段且又要级联查询时,查询过程会有上百毫秒的延时,这显然是无法满足我们超高性能的需求。

2.2.2 线下:eBay基于Hadoop生态圈的数据仓库

除了线上买卖的核心业务,eBay仍然有非常多基于数据驱动的业务,比如营销就是其中之一。这种业务的特点是需要基于全量商品数据做分析,然后以分析结果来驱动业务的推进。这是典型的OLAP(Online Analytical Processing)场景。eBay选择Hadoop作为构建数据仓库的技术栈。eBay会将范式化的Oracle表反范式化(Denormalize)存储于HDFS,以提供更高性能的批处理作业分析。但是,基于Hadoop的技术无法满足典型OLTP场景的读写需求。同时,由于从Oracle往Hadoop同步数据产生的延时,一些关键商品属性(如价格、库存等)会存在准确性问题。


2.3 营销场景的需求

Oracle/VLS和Hadoop是OLTP和OLAP领域的佼佼者。然而,对于营销场景,他们之间的融合,无论是在读写性能需求,还是数据延时及一致性等方面都存在一定问题。

1)关于性能

在我们营销的邮件及站内推荐场景中,通常不仅需要该商品的基础信息,还要查询几十个其他商品属性来供推荐模型推演,此外还有数十万QPS的并发需求,这使得需要去级联查询的服务“VLS”无法扩展支持我们的需求。

2)关于延时

我们有很多批处理作业(如站外广告推送),如果只能拿到Hadoop系统延时为Day-1的数据,这会对捕捉快速变化的商机带来问题。

3)关于融合

因为线上访问和线下批处理的编程模型非常不一样,所以应用开发者在消费同一份商品数据的不同展现(Online Oracle v.s Offline Hadoop)上会有诸多因Schema、数据一致性和访问模式不同带来的困扰。同时,在各个业务子系统集成过程中也会带来接口、数据不一致等问题。

因此MIS的愿景就是要去解决上述这些问题,为我们各种营销场景的复杂商品访问需求提供统一的数据服务。


3 方案和架构


3.1 产品形态

让我们先来看看打算构建的MIS产品形态,以及它能不能解决我们的问题。

我们的系统会把数据以服务的方式提供出去。消费者通过一个RESTful API把查询需求提交给我们的系统,Request Body中带上了我们支持的一种SQL方言——Marketing Query Language(以下简称MQL)。MIS系统会分析查询的需求,并选择一个数据中间件来处理这个查询并返回数据。

我们会用多种数据中间件来存储同一份商品数据,并以该中间件最擅长的方式来服务。比如我们会选择NoSQL数据库来服务KV查询;会选择类SQL的数据库来服务二级索引查询;会选择Spark来做批处理。如果相应非常快,我们的服务会以同步的方式返回结果;如果响应比较慢,如一个Spark作业,则会异步地返回一个任务句柄以供后续获取计算结果。

这样的方案让我们达到了统一访问接口、透明化不同数据中间件和简化客户端的目的,同时也达到以最高性能服务特定访问模式的目的。但是,这也给我们带来了多数据存储一致性、如何分析并路由查询等新挑战。


3.2 架构

基于上节的描述,我们的系统架构图如下图所示:

图1 MIS系统分层架构图

(点击可查看大图)


下面我们将介绍架构中的几个重要思考以及一些重要问题的解决方案。因为本次分享的核心是“性能”,所以我们会在和性能相关的内容有更多的着墨。

3.2.1 Read Heavy还是Write Heavy?

一个和性能非常相关的问题是:让读更重(Read Heavy)还是写更重(Write Heavy)。VLS在需要多字段查询时非常慢,其中一个原因是:它需要去分析查询逻辑,并拿多个表或服务的数据做整合。这可以认为是一个“读重”的方案。而我们MIS服务的一个核心场景是:支持近百万QPS的根据商品ID获取商品详情的需求。这就让我们运用了另一种的方案——“写重”、“读轻”。我们的数据载入(Data Onboarding)层会把大量预计算的商品数据和其他维度的表都打到商品维度,做一个反模式化(De-Normalize)写入一张商品的大宽表(包含上百个字段)。在查询的时候只要把数据读出来,不用太多的计算和逻辑,就是一个“读轻”的操作。这个设计保证了我们的服务能在一些常见的数据中间件上达到P95延时<50ms的高QPS访问。

3.2.2 为什么选择TiDB?

主键KV查询、二级索引查询和批处理是我们要同时支持的三个重要场景。另一种说法是:OLTP和OLAP的融合——HTAP(Hybrid Transactional and Analytical Process)[1]。MIS方案一定会用到多个数据中间件,但是为了减少所需要的维护并且保持多数据库数据的一致性,我们希望尽量少用不同的数据中间件。因此,NewSQL[2]和HTAP领域的翘楚——TiDB,就成为了我们的选型方案。TiDB底层(基于SSTable的存储和Raft协议),做到了高性能的分布式存储和一致性保障。同时,TiDB能将二级索引物理存储起来,以提供高性能的查询。另外,SQL的接口和原生还可以支持Spark,提供批量读写的支持,也使得其编程和访问模型非常统一且友好。可以说选择了一个TiDB数据库,就能同时满足了若干个访问模式的支持,再融合Hadoop/DeltaLake就能基本满足我们线上线下的大多数需求。

3.2.3 怎么维护多数据库的数据一致性?

异构数据存储的一致性问题是业界的难题,常见的解决方法有多阶段锁和一些最终一致性的方案。多阶段锁需要引进额外的单点事务管理系统,而且性能较差,一般只在没有太高性能要求的场景下使用。而我们选择的是基于CDC(Change Data Capture)数据同步和每日数据校准的方案(示意图如下),来实现数据的最终一致性。

图2 基于Oracle Golden Gate的CDC数据同步和校正方案

(点击可查看大图)


我们的数据源头是eBay Oracle表,通过Oracle Golden Gate,我们把商品的变化事件监听下来并同步更新到TiDB中。该更新事件会记录时间戳。这样一来我们可以认为TiDB中的商品数据基本上是和eBay Oracle的商品表保持一致。

同时,这些更新事件会以每小时为单位的时间窗口落入HDFS(Hadoop Distributed File System),并采用DeltaLake这样的数据湖技术[3]将更新合并到我们HDFS上的商品表。这样我们的线下数据就只有一个小时的延时,而不是原来的24小时了。

最后,由于流式处理导致可能存在的掉数据情况,以及考虑到实现Exactly Once的成本问题,我们选择每天去拿eBay在Hadoop上维护的商品数据全表做矫正。因为时间戳的维护,我们可以保证不会有旧数据覆盖新数据的情况,而只会把丢失的数据补回来。

3.2.4 延时和性能的折中

上节中还有一个我们没有提到的重要细节,就是基于对业务的理解选取在性能和延时之间的折中办法。前面讲到我们会反模式化把商品打成大宽表存储在TiDB中。在听Oracle Golden Gate时,我们只监听了一张商品核心表的变化。那么,来自别的表的其他商品属性怎么保持更新呢?

因为eBay商品核心Oracle表已经存储了30多个常见、重要、时间敏感的字段(如价格、库存、是否在线等)。监听这张核心表的变化已经能足够满足业务对实时性的需求了。而其他字段(如商品的品牌、类目、卖家评级、物流信息、商品的基于模型的评分等等)属性要不是不太变化,就是对延时不太敏感,不需要我们去做实时更新,只需要在每天的数据校正中去更新就可以了。这样的折中选择就可以极大地降低系统复杂性并且减少需要对TiDB做更新的量,从而提升系统的整体性能。


4 系统性能优化之路

4.1 性能需求

上述讲到我们的系统将通过统一的查询接口(MQL)提供数据服务。我们能提供异步的批处理,该计算主要发生在eBay维护的Hadoop集群上。该批处理会通过Spark对我们用DeltaLake维护的商品表进行读操作。同时,我们提供同步的基于主键和二级索引(主要是卖家和商品类目)的查询,该查询的处理主要会发生在TiDB上。而这两类查询又以基于商品主键(即item_id查询商品详情)的业务需求为最高。根据我们对主要客户的调研,截止到2021年底,对此类KV的查询需求将达到500K QPS之多。因此我们也主要针对此访问场景对系统做了各种优化。


4.2 性能基准

因为我们提供了类SQL的查询接口,因此上节描述的基于KV的访问将表现为如下查询语句:

根据客户程序的不同场景,在in语句内的商品数量可能不同,查询的商品字段数量也会不同,因此IO表现也会不同。为了简化Benchmark,我们选择了最常见的模式——采用20个左右的核心商品字段,一次拿10个商品来做压测。

同时,我们引入了一个新的指标IPS(Item Query per Second)来代替QPS(Query per Second),从而统一需求和沟通术语。举例来说,我们的性能优化目标是500K IPS,而测试时每个查询会带10个商品,因此打到服务端和TiDB的查询是50K QPS。

从数据量上,我们在TiDB上有大约70个商品属性字段。而eBay活跃商品(包括Item和Multi-SKU)的总量约有30亿。我们选取了7份Replica的方式来存储这30亿行商品数据。

在测试环境上,因为商品更新和上下线,我们的数据库会被持续地写入和更新。这样的生产环境有大约每秒4,000至16,000的更新量,因此我们需要压测一个混合读写的场景,而不是在隔离环境中做只读操作的压测。这一点非常关键,在后续的系列文中也会讲到在这种读写混合场景下带来的性能问题和解决方案。


4.3 性能优化之路

在分享具体经验前,让我们先看看我们的性能优化蓝图和最终结果。这有利于读者了解我们主要在哪些方面做了优化,以及它们带来的性能提升大致有多少。

图3 MIS性能优化之路

(点击可查看大图)


从图中可以看到,我们在刚开始搭建系统时吞吐量最差情况只有约5K IPS(由于读写干扰),到最后通过各种优化达到了500K IPS的目标,实现了性能近百倍的提升。


5 总结


本篇主要描述了营销场景的需求,并分享了在营销商品数据服务系统的架构、设计方面的一些理解和研究,希望能给大家带来帮助。

在后续的系列文中,我们将在以下几方面来介绍我们的性能优化经验:

1)TiDB相关的优化:

  • 读写混合带来的问题以及HTAP分离;

  • TiDB 跨数据中心以及地域亲和性(Locality)方面的优化;

  • 查询稳定性优化;

  • 磁盘IO优化等。

2)缓存层的设计:

  • 横向扩展带来的问题;

  • 缓存层的引入和设计。

3)代码层面的优化:

  • 使用Protobuf、简化商品图片URL等IO优化;

  • 反射优化、低效依赖库实现优化及替换、执行计划缓存等CPU优化。

下期我们将分享“商品数据服务TiDB性能优化”,千万不要错过呦!


参考资料:

[1]https://en.wikipedia.org/wiki/Hybrid_transactional/analytical_processing

[2]https://en.wikipedia.org/wiki/NewSQL

[3]https://delta.io/


往期推荐

eBay支付核心账务系统之“展”翅高飞

干货|eBay基于Istio的应用网关的探索和实践

eBay支付账务系统架构解析之“读”一无二

ClickHouse集群|Operator跨k8s集群管理


 点击阅读原文,一键投递

         eBay大量优质职位虚席以待

         我们的身边,还缺一个你

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存