百万并发场景中倒排索引与位图计算的实践

百万,并发,场景,倒排,索引,位图,计算,实践 · 浏览次数 : 43

小编点评

**新方案的设计思路:** * 使用列的倒排索引和倒排索引位运算的方式,将计算复杂度由原来的2n降至n。 * 采用列的倒排索引进行位图计算,避免完全扫描的效率低下。 * 使用RoaringBitMap压缩位图,以降低空间使用。 **新方案的优缺点:** **优点:** * 降低时间复杂度。 * 改善算法稳定性。 * 使用RoaringBitMap压缩位图降低空间使用。 **缺点:** * 只适用于简单的数据类型。 * 仅适用于等值查询。 * 对范围查询不适用。 **具体设计步骤:** 1. 预计算生成列的倒排索引和位图。 2. 生成列的倒排索引对应位图。 3. 根据用户请求查找列位图。 4. 通过位图计算生成候选规则集。 5. 从候选规则库中,根据业务优先级排序,查找最优的规则。 6. 进行逐级位运算,找到最终的规则。 **压缩位图的优化:** * 降低数据冗余。 * 使用二分查找快速查找容器。 * 使用跳表或哈希表等其他数据结构进行高效的查找。

正文

作者:京东物流 郎元辉

背景

Promise时效控单系统作为时效域的控制系统,在用户下单前、下单后等多个节点均提供服务,是用户下单黄金链路上的重要节点;控单系统主要逻辑是针对用户请求从规则库中找出符合条件的最优规则,并将该规则的时效控制结果返回客户端,比如因为临时疫情等原因针对仓、配、商家、客户四级地址等不同维度进行精细粒度的时效控制。

该系统也是Promise侧并发量最大的系统,双11高峰集群流量TPS在百万级别,对系统的性能要求非常高,SLA要求在5ms以内,因此对海量请求在规则库(几十万)中如何快速正确匹配规则是该系统的技术挑战点

朴素的解决方案

按照朴素的思想,在工程建设上,通过异步方式将规则库逐行缓存到Redis,Key为规则条件,Value为规则对应结果;当用户请求过来时,对请求Request(a,b,c,d..)中的参数做全组合,根据全组合出的Key尝试找出所有可能命中的规则,再从中筛选出最优的规则。如下图所示

31.png

该方案面临的问题是全组合的时间复杂度是2n,n≈12;算法的时间复杂度高且算法稳定性差**,最差情况一次请求需要4096次计算和读取操作。当然在工程上我们可以使用本地缓存做一些优化,但是无法解决最根本的性能问题。架构简图如下所示:

32.png

新的解决方案

上面方案是从行的角度看待匹配定位的,能够命中的行的每一列必然也是符合条件的,这里面存在某种隐约的内在联系。能否反过来思考这个问题,为此我们尝试进行新的方案,当然架构简图依然如上图所示,核心优化的是命中算法。

新的方案整体采用列的倒排索引和倒排索引位运算的方式,使得计算复杂度由原来的2n降至n**,且算法稳定性有非常好的保证。其中列的倒排索引是对每列的值和所分布的行ID(即Posting List)建立KV关系,倒排索引位运算是对符合条件的列倒排索引进行列间的位运算,即通过联合查询以便快速找到符合条件的规则行。

算法详细设计

1.预计算生成列的倒排索引和位图

通过对每列的值进行分组合并生成Posting List,建立列值和Posting List的KV关系。以下图为例,列A可生成的倒排索引为:301={1},201={2,3,4,5}等,需要说明的一点,空值也是一种候选项,也需要生成KV关系,如nil={7}。

33.png

2.生成列的倒排索引对应位图

将步骤1的倒排索引转成成位图,方便后续的位图计算,转换规则为行ID对应位图的下标位(步骤1、2可以合并操作)。

34.png

3.根据用户请求查找列位图,通过位图计算生成候选规则集

将用户请求中的入参作为Key,查找符合条件的位图,对每一列进行列内和空值做||运算,最后列间位图做&运算,得到的结果是候选规则集,如下图所示:

45.png

4.从候选规则库中,根据业务优先级排序,查找最优的规则

以候选规则为基点,按照业务优先级排序,进行逐级位运算&,当遍历完或位运算为0时,找到最后不为空的即为最优规则,该过程是从候选规则库逐渐缩小最优范围的过程。需要说明某列当用户请求位图不存在时,需要使用对应的空位图进行参与,以B列为例,入参B_1102不存在,需要使用B_nil参与&。

56.png

复杂度分析

通过上面的例子我们可以看到,在时间复杂度方面查找候选规则集时,进行一轮||运算,一轮&运算;在查找最优规则时进行一轮&运算,所以整体复杂度是3n≈n

在空间复杂度方面,相比原来的行式存储,倒排索引的存储方式,每列都需要存储行ID,相当于多了 (n-1)*Posting List存储空间,当然这是粗略计算,因为实际上行ID的存储最终转换为位图存储,在空间上有非常大的压缩空间。

工程问题-压缩位图

如果倒排索引位图非常稀疏,系统会存在非常大的空间浪费。我们举一个极端case,若千万规则库中命中的行ID是第1000万位,按照传统方式BitSet进行存储,需要消耗1.2MB空间,在内存中占用存在严重浪费,有没有压缩优化方案,在RoaringBitMap压缩位图方案中我们找到,相同场景在压缩位图方式下仅占144bytes;即使在1000万的位图空间,我们随机存储1万个值,两者比也是在31K vs 2MB,近100倍的差距,总的来说RoaringBitMap压缩率非常大。

RoaringBitMap本质上是将大块的bitmap拆分成各个小块,其中每个小块在需要存储数据的时候才会存在,所以当进行交集或并集运算的时候,RoaringBitMap只需要去计算存在的块而不需要像bitmap那样对整个大块进行计算,既做到了压缩的存储又做到计算性能的提升。

以下图821697800为例,对应的16进制数为30FA1D08, 其中高16 位为30FA,低16位为1D08。先用二分查找从一级索引(即Container Array)中找到数值为 30FA 的容器,该容器是一个Bitmap容器,然后在该容器查找低16位的数值1D08,即十进制下7432,在Bitmap中找到相应的位置,将其置为1即可。

57.png

适用场景分析

回顾上面的设计方案我们可以看到,这种方式仅适用于PostingList简单如行ID的形式,如果是复杂对象就不适合用位图来存储。另外仅适用于等值查询,不适用于like、in的范围查询,为什么有这种局限性?因为这种方式依赖于搜索条件的空间,在方案中我们将值的条件作为搜索的Key,值的条件空间希望尽可能是一个有限的、方便穷举的、小的空间。而范围查询导致这个空间变成难以穷举、近乎无限扩张的、所以不适用。

其他优化方式

除了使用位运算的方式对倒排索引加速,考虑到Posting List的有序性,还有其他的方式比如使用跳表、Hash表等方式,以ES中采用的跳表为例,进行&运算实际就是在查找两个有序Posting List公共部分,以相互二分查找的形式,将时间复杂度控制在log(n)的级别。

具体参见工业界如何利用跳表、哈希表、位图进行倒排索引加速?

38.png

与百万并发场景中倒排索引与位图计算的实践相似的内容:

百万并发场景中倒排索引与位图计算的实践

Promise时效控单系统作为时效域的控制系统,在用户下单前、下单后等多个节点均提供服务,是用户下单黄金链路上的重要节点;控单系统主要逻辑是针对用户请求从规则库中找出符合条件的最优规则,并将该规则的时效控制结果返回客户端,比如因为临时疫情等原因针对仓、配、商家、客户四级地址等不同维度进行精细粒度的时效控制。

通过实战操作学git

虽然说 ”好记性不如烂笔头”,但是学习不看等于没学,学习不用等于不会,所以说”实战才是检验真理的唯一标准“,通过实战则会学到很多东西。 因为陈** 太懒,并且不喜欢查百度,老是犯同样的问题,于是我通过完整的操作git流程和一些实战中的场景,将常用git流程和命令整理了下来,这样也方便我女盆友带入学习

百度飞桨(PaddlePaddle) - PP-OCRv3 文字检测识别系统 基于 Paddle Serving快速使用(服务化部署 - CentOS 7)

Paddle Serving 是飞桨服务化部署框架,能够帮助开发者轻松实现从移动端、服务器端调用深度学习模型的远程预测服务。 Paddle Serving围绕常见的工业级深度学习模型部署场景进行设计,具备完整的在线服务能力,支持的功能包括多模型管理、模型热加载、基于Baidu-RPC的高并发低延迟响应能力、在线模型A/B实验等,并提供简单易用的Client API。Paddle Serving可以

京东APP百亿级商品与车关系数据检索实践

本文主要讲解了京东百亿级商品车型适配数据存储结构设计以及怎样实现适配接口的高性能查询。通过京东百亿级数据缓存架构设计实践案例,简单剖析了jimdb的位图(bitmap)函数和lua脚本应用在高性能场景。希望通过本文,读者可以对缓存的内部结构知识有一定了解,并且能够以最小的内存使用代价将位图(bitmap)灵活应用到各个高性能实际场景。

无惧百万级并发,GaussDB(for Cassandra)让华为推送服务更快触达

摘要:推送服务(Push Kit)是华为提供的消息推送平台,建立了从云端到终端的消息推送通道。通过集成推送服务,您可以向客户端应用实时推送消息,让应用更精准触达用户,是开发者提升用户感知度和活跃度的一件利器。 本文分享自华为云社区《无惧百万级并发,GaussDB(for Cassandra)让华为P

[转帖]高性能 -Nginx 多进程高并发、低时延、高可靠机制在百万级缓存 (redis、memcache) 代理中间件中的应用

https://xie.infoq.cn/article/2ee961483c66a146709e7e861 关于作者 前滴滴出行技术专家,现任 OPPO 文档数据库 mongodb 负责人,负责 oppo 千万级峰值 TPS/十万亿级数据量文档数据库 mongodb 内核研发及运维工作,一直专注于

互联网大厂的缓存策略:抵抗超高并发的秘密武器,已开源!

大家好,我是冰河~~ 最近,有小伙伴私信我:冰哥,我最近出去面试,面试官问我如何设计缓存能让系统在百万级别流量下仍能平稳运行,我当时没回答上来。接着,面试官问我之前的项目是怎么使用缓存的,我说只是缓存了一些数据。当时确实想不到缓存还有哪些用处,估计这次面试是挂了。冰哥,你可以给我讲讲互联网大厂项目是

[转帖]图解LVS

https://www.jianshu.com/p/89c6f27771a4 LVS (linux virtual server)是 Linux标准内核的一部分。基于TCP/IP的负载均衡技术,转发效率极高,具有处理百万计并发连接请求的能力。由于工作在linux内核层,转发效率比工作在应用层的ngi

互联网项目的特点和架构目标

一、互联网项目架构-特点 互联网项目架构-特点 1.用户多:微信号称13亿用户; 2.流量大,并发高:百度统计,百度 一天承载超五十亿次搜索,天猫:双十一每秒4200万次请求; 3.海量数据:微信号称13亿用户,用户数据要存数据库;天猫,天猫的商品非常多; 4.易受攻击:项目是公网项目,容易受到不法

[转帖]x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨。 一.网卡调优方法 1、Broadcom的网卡建议关闭GRO功能 ethtool -K eth0 gro off ethtool -K