当前位置: 首页 > 科技观察

如何在百亿表任意维度查询,毫秒级返回?

时间:2023-03-16 22:02:12 科技观察

随着闲鱼业务的发展,用户规模已达数亿,用户维度的数据指标达数百项。如何从亿级数据中快速筛选出预期的用户群体,进行精细化的群体化运营,是技术需要解决的问题。业内很多解决方案往往需要几分钟甚至几小时才能生成查询结果。本文为解决大数据场景提供了一种高效的数据筛选、统计、分析方法。从亿级数据中,任意组合查询条件,筛选出需要的数据,毫秒级返回。技术选型分析从技术角度来看,我们的业务场景有以下特点:需要支持任意维度的组合(和/或)嵌套查询,并且要求低延迟。数据规模大,至少数十亿级,需要支持持续扩展。单个数据索引有很多维度,至少有数百个,并且支持的需求不断增加。综合分析,这是一个典型的OLAP场景。OLTP和OLAP我们简单对比一下OLTP和OLAP:最常见的数据库,比如MySQL和Oracle,都是使用行存储,更适合OLTP。如果使用MySQL等行数据库来实现OLAP,一般会遇到两个瓶颈:数据量瓶颈:MySQL更适合百万级别的数据量。如果多了,查询和写入性能会明显下降。因此,一般采用分库分表的方式,将数据规模控制在百万级别。查询效率瓶颈:MySQL需要为常见的条件查询创建单独的索引或组合索引。非索引字段的查询需要扫描全表,性能下降明显。基于以上分析,我们的应用场景不适合行存数据库,所以我们重点关注列存数据库。行存和列存我们简单对比一下行存和列存的特点:需要一个查询表。列存储适用于数据的统计分析。考虑如下场景:一个表中有20个字段用来存储用户,我们想统计用户的平均年龄。如果是行存储,我们需要扫描全表,遍历所有的行。但是如果是列存,数据库只需要定位到年龄列,然后只扫描这一列的数据就可以得到所有的年龄,并计算平均值。性能理论上比行存储快20倍。在列存数据库中,HBase更为常见。HBase应用的核心设计集中在rowkey的设计上。一般应将常用的过滤条件组合设计到rowkey中,通过rowkey的get(单条记录)或scan(范围)查询即可。因此,HBase更适用于有限查询条件下的非结构化数据存储。在我们的场景中,由于所有字段都需要作为过滤条件,本质上还是需要结构化存储,需要低查询延迟,所以不能使用HBase。我们综合考虑了组内多种列式存储DB产品(ADS/PostgreSQL/HBase/HybridDB)。经过对读写性能、稳定性、语法完整性、开发部署成本等综合评估,最终选择HybridDBforMySQL计算规范构建众选引擎。HybridDBforMySQL简介HybridDBforMySQL计算规范对于我们的场景,核心能力主要包括:任意维度的智能组合索引(用户无需单独构建自己的索引)。百亿表查询毫秒响应。MySQLBI生态兼容,全面支持SQL。支持空间搜索、全文搜索和复杂数据类型(多值列、JSON)。那么,HybridDBforMySQL计算规范如何在大数据场景下实现任意维度组合的毫秒级响应呢?步骤如下:首先,HybridDB的高性能列式存储引擎内置存储谓词计算能力,可以利用各种统计信息快速跳过数据块,实现快速过滤。二是HybridDB的智能索引技术,可以自动对大宽表进行一键全量索引,并基于列索引智能组合各种谓词条件进行过滤。三是高性能MPP+DAG融合计算引擎,结合高并发和高吞吐,实现高性能的基于流水线的向量计算,计算引擎和存储紧密配合,让计算更快。四是HybridDB支持星型模式、雪花模型、聚合排序等多种数据建模技术,适度的业务数据建模可以获得更好的性能指标。综上所述,HybridDBforMySQL计算规范是一个以SQL为核心的多功能在线实时数仓系统,非常适合我们的业务场景,所以我们在其之上构建了我们的人群选择底层引擎。业务落地在搭建好人群选择引擎后,我们着重改造了消息推送系统,作为精细化人群运营的重要落地点。闲鱼消息推送介绍消息推送(PUSH)是信息到达用户最快的方式。闲鱼常用的PUSH方式是先计算线下的PUSH人群,准备相应的PUSH副本,然后在第二天的指定时间推送。通常,它们是周期性的PUSH任务。而临时的、紧急的、需要立即发送的PUSH任务,则需要BI同学的介入。每个PUSH任务平均需要BI同学半天左右的开发时间,操作起来也比较麻烦。此次我们将人群选择系统与原有的PUSH系统打通,大大提高了此类PUSH的数据准备和传输效率,解放了开发资源。系统架构离线数据层:用户维度数据分散在各个业务系统的离线表中。我们在实时计算层采用离线T+1定时任务将数据汇总导入用户宽表。实时计算层:根据人群筛选情况,从用户宽表中查询用户数量和用户ID列表,为应用系统提供服务。人群选择前台系统:提供可视化操作界面。运营同学选择过滤条件,保存为一组,用于分析或发送PUSH。每组对应一个SQL存储,类似:selectcount(*)fromuser_big_tablewherecolumn1>1andcolumn2in('a','b')and(column31=1orcolumn32=2)同时SQL可以支持多层和/或嵌入任何字段集的组合。使用SQL保存人群,当用户表中的数据发生变化时,可以随时执行SQL获取最新的人群用户来更新人群。闲鱼PUSH系统:从人群圈选前端系统获取人群对应的where条件,再从实时计算层逐页获取用户列表,推送给用户。在实现过程中,我们重点解决了分页查询的性能问题。分页查询性能优化方案:分页时,当人群规模较大(千万级)时,查询性能会随着分页数倒退而明显下降。因此,我们采用增加人群数据行数并导出到MySQL的方式来提高性能。表结构如下:批号:每导出一次种群,就增加一个新的批号,批号是一个时间戳,自增。行号:从1开始递增,每个批号对应的行号从1到N。我们构建“人群ID”+“批号”+“行号”的组合索引。在分页查询时,我们使用索引查询代替分页查询,以保证大页数时的查询效率。另外,为此额外导出数据的成本,得益于HybridDB强大的数据导出能力。数据量从几万到几百万不等,耗时从几秒到几十秒不等。综合权衡后,采用了该方案。PUSH系统改造和受益人圈层选择系统,为闲鱼精细化用户运营提供了强大的底层能力支撑。同时圈选人还可以应用到其他业务场景,比如需要对用户进行分级操作的场景,比如在首页焦点地图固定投票,这为闲鱼的业务提供了很大的优化空间。本文实现了海量多维数据中组合查询的秒级返回结果,是OLAP场景下通用的技术实现方案。同时介绍了使用该技术方案对原有业务系统进行改造的应用案例,取得了良好的业务效果,可供类似需求或场景参考。对于未来人群选择引擎中的用户数据,我们目前采用T+1的方式导入。这是因为人群相关指标的变化频率不是很快,很多指标(比如用户标签)都是离线T+1计算的,所以T+1的数据更新频率是可以接受的。后来我们基于HybridDB构建了一个更强大的商品圈选择引擎。闲鱼商品数据变化快于用户数据。一方面,用户会随时更新自己的产品;另一方面,由于闲鱼产品库存特性(立即售罄)等原因,产品状态会随时发生变化。因此,我们的选品引擎应该第一时间感知这些数据的变化,在投放层面做出实时调整。基于HybridDB(存储)和实时计算引擎,我们构建了更强大的“Mach”实时选品系统。参考:HybridDBforMySQL简介:http://click.aliyun.com/m/1000027814/