拼多多有多少好友购买过该商品如何实现?

745 阅读4分钟

可能有不少人用拼多多的时候注意到某些商品他会告诉你有多少好友买过该商品,乍一看,这个功能非常的简单,但是考虑到数据量,这个就不容易做了。

用mysql实现的开销

我们先来大致算一下做这个东西用mysql需要多大的开销。

首先我们需要维护购买了商品的人,热门商品这个可能是千万人级别的,然后一个人的好友数量可能是千级的,那么需要查询这个用户哪些好友购买过则需要从这千万级数据里面查找1000多数据,即使全部走索引,这个耗时也是非常长的,对数据库的压力也不小。

注意,这还仅仅是一个商品,如果我们需要对1000个商品进行这样的处理,可能维护的商品和用户之间的映射关系就在百亿级别,如果需要维护更多的商品呢?

可以看到,单纯的使用mysql完成这个需求成本太大了,即使用了分库分表的手段,也很难满足性能要求。

如何去做?

拼多多是如何做的呢?其实我也不知道,先别急着喷,我先说说我的方案。

实际上现在主流方案都是通过大数据平台,离线去计算,这种方案我就直接跳过了,没啥意思,成本高、时效性差。

那么有没有时效性高、成本低、性能好的方案呢?并且我不仅要看到我有多少好友买过,我还要看到我有哪些好友买过!

答案是有的,办法总比困难多,对于上述的场景,我们可以用位图(bitmap)来解决

什么是位图?

我先简单介绍一下位图,位图的本质是一段连续的内存地址,我们知道计算机只能存0和1,因此位图上的每一位也都是0或者1,我们通过把元素映射到位图的相应位置(下标),把相应的位置值改为1,那么就可以标志这个元素是存在的。我们需要查询某个元素的是否存在的时候,就可以通过下标进行访问,如果是1,则代表存在,0则代表不存在

如何利用位图去完成上述需求?

首先,我们需要建立用户和位图位的映射关系

“张三” -> 1
"李四" -> 2
"王五" -> 3

假如我们有10亿用户,那么我们只需要维护10亿映射关系就能用位图去存储用户信息,这个信息可以存在nosql数据库,甚至可以直接存在redis里面

我们看一下用位图穷举10亿用户需要多少内存: 1000000000bit/8/1024/1024=120M

也就是说,不应用任何优化手段,我们穷举一个商品的所有用户,只需要120M的空间,我们完全可以把这个数据放在redis里面。

去查询的时候,先取到用户的所有好友,然后通过好友id找到对应的bit位,然后去商品对应的位图里面去查询好友是否买过该商品。

我们可以看到即使最坏的可能下,所有用户都买过该商品,单一商品与用户的映射关系大小也是可控的,查询效率也是稳定的。

实际上,这个商品位图也是有优化空间的,基本上不太可能一个商品所有用户都去购买,一个商品有个上百万人购买已经很不错了,因此我们可以用咆哮位图来压缩空间。

如果允许一定的误差的话,我们可以不需要穷举所有用户,我们把买过的用户压缩(用户bit位取模)到一个更小的位图里面,比如说10M,1M的空间里面,这样的误差其实也不是不能接受。

大家还有没有好的方案?可以在下面交流一下!