写点什么

我帮大厂做架构之——微信的“N 个朋友读过”怎么实现

用户头像
臧萌
关注
发布于: 2021 年 03 月 16 日
我帮大厂做架构之——微信的“N个朋友读过”怎么实现

大厂架构师,人人向往之。


但是我们可能没有机会在大厂做架构设计,但是这并挡不住我们从功能倒推,尝试理解这些架构是怎么做的。从这个思考的过程中,其实我们也可以收获不少。


我们可能都注意到过微信这么一个功能:



理解功能


对于订阅号里推送的文章,会标注有几位朋友读过。我开始并没有太注意过这个功能,有时候下意识是觉得只有我的朋友也关注了这个公众号,点开看了,这个读过的数字才会+1。


一个偶然的机会,我看到了一篇公众号文章讲到我们正在用的一个技术,就分享到了群里,群里大部分都是我的好友。一会儿不小心又刷到这个文章时,已经是 15 个朋友读过了。这时候我忽然感觉这个功能有点意思。因为群里的人肯定没有那么多人关注这个公众号,但是群里的人大部分都是我们的好友。也就是说,这个功能就是存粹的字面意义的有几个朋友读过这个文章。


思考对策


这时候,我忽然就对这个功能感兴趣了。因为我觉得这个功能不简单:公众号,多则几十万上百万的订阅者,要和每个人的好友列表(几百的级别)做交集,这数据量有点大啊,这个功能怎么做呢?


关键是,在我看来,这个功能并不是什么核心的功能,也就是说,不能占用太多的资源,这就让这个功能在我看来更有点意思了。


我当时设想了很多解决方案,但是基本思路离不开这么四个大表:文章,用户,好友关系,阅读记录。尤其是这几个表做 join,更 CAO DAN 了。根据微信的用户数量级,这事儿基本是没法做的,太贵了。即使放弃一部分准确性,也还是贵。


就为了想这个破事儿,多用了好几分钟的洗澡水。


以为自己 get 了

吃完饭后,又觉得这个功能和朋友圈点赞有点像,没准后台是一套中间件。放弃思考这个事情是怎么实现的,单单从功能上看,好像真的非常想。只不过朋友圈动态变成了公众号文章嘛。当时就觉得,嗯,肯定是一套系统。


再想想,再仔细想想

过了一阵子,又想起这个事儿,继续想,感觉又不大可能是朋友圈的那套系统。因为朋友圈面对的数量级是不一样的。一个人的朋友才几百个吧,不得了了。而且这个是两两之间的关系。这个公众号文章“N 个朋友读过”的功能,牵扯到要把这个信息推送给万级甚至百万级公众号的订阅者,然后统计好友是否阅读过的数据,数据集一下子膨胀太多了。


又浪费了几分钟的洗澡水,思考按照地区设计缓存(一个人的好友大部分都是同地区的);尝试放弃精度,使用 BloomFilter 压缩数据。但是根据公众号文章的数量,怎么压缩,那也是太平洋量级的数据,而且要面对查询延迟等问题,实在是没法弄。


后来又是吃饭的时间,就觉得这个事情的解决方向有问题。想到了消息。顿时觉得这个问题有了更好的解决方案:发消息。


发消息嘛,多简单多自然,而且是微信的看家本领,肯定是有成熟的中间件的。当一个好友看了一篇公众号文章,就给他所有的好友发送一个特殊格式的消息,告诉对方微信:我读了这篇文章。对方好友收到这个消息,就把这个数据存在本地,类似于(用户 ID,文章 ID)的一个关系表。(有优化空间,可以只给订阅了这个公众号的好友发这个消息)。


这样的好处显而易见:

  1. 成本低,服务器端没有复杂的 join 计算,也不需要向服务器动态查询数据

  2. 中间件成熟,消息中间件,成熟的不得了

  3. 数据本地存储,速度快


不足之处也很明显:

  1. 不准确:比如说 A 和 B 两个用户。A 先读了文章 1,然后和 B 加了好友,那么 B 其实是收不到 A 阅读了文章 1 的消息的,因为当时 A 和 B 还不是好友

  2. 数据会丢失:微信重装,换机器,清空缓存等都有可能让本地缓存的数据丢失

  3. 隐私:毕竟本地存储了本应在服务器端存储的数据,那么是否可以得到具体是哪位好友看了哪篇文章呢?


但是这个问题应该不大:

  1. 毕竟如开头所说,这个功能不是核心功能,也没有具体列出是哪几位好友读过,即使不准确,不大会引起沟通问题。是一个“尽量做好就可以”的功能。

  2. 公众号文章有很强的时效性,也没多少人关心一年半载之后,有几个好友读过某篇订阅号的文章。而之前设想的设计,都用了太多的资源,保证数据的准确性和持久性。

  3. 隐私这个其实可以通过隐藏用户 ID 来解决,也就是说,只下发文章 ID 被你的好友读过这么一个消息,并不包含好友的 ID。也就是从(用户 ID,文章 ID)表变成了(文章 ID,1,时间戳)这种完全不包含任何好友信息的数据结构。


想到这里,我基本确定这个功能是通过发送特殊格式的消息做到的了。


反思和收获——技术在做事的过程中占几分?


进一步思考,如果我真的在鹅厂负责做这个功能,那么这个事情做成,有几分看技术功底,又有几分看别的能力呢?


玩技术的,都喜欢高大上。我开始的惯性思维想到的解决方案,也是相当高大上的,对吧?大表 join,准确性,支撑十亿级用户体量等等等等。讲出来你说唬人不唬人?我觉得那是相当唬人的。数据大了,问题搞复杂了,就有各种优化的可能,又是一套系统可以搞起,可以继续嗨。


但是这解决问题了吗?并没有,相反,这是在制造问题。作为一个在一线干了十几年工程师的写代码做软件的人来说,想到这里,我就很自然的刹车了,因为这个思路绝对是行不通的。毕竟先选对路线,再说不畏艰难。如果有公路不走,非得绕山路,那是图啥呢?


回到上面的问题。思考整个做“鹅厂虚拟编外架构师”的过程,技术,真的是最重要的吗?技术当然重要,但是它的重要性是通过解决问题来体现的,如果舍本逐末,那就做不成事情了。同样的观点,我在我的观点《职场求生攻略》中也有很多文章提及,比如讲技术观,讲积累等等。


如果你能认同这些观点,不好意思这篇文章最后的部分浪费了你两分钟。如果你不认同,我倒是推荐你看看我的专栏,比如《24丨技术观:程序员在技术的成长之路上,有哪些陷阱?》《25 | 系统架构:如何从写代码的程序员,成长为软件系统架构师?》。反正看两篇也不要钱,不需要订阅哈。


再说一下我上一篇 FAQ,《职场求生攻略答疑篇之 5 —— 我,程序员,非常焦虑》。其实程序员的积累,很大程度在于解决问题的能力,而非技术能力。当然,技术能力也很重要。但是凭技术让自己升职加薪,在很多公司/岗位下,是很容易遇到瓶颈的,而且技术也可能被淘汰。但是解决问题的能力,不会过时。非但不会过时,反而越来越值钱。就拿这篇文章的例子来说,如果架构师犯了和我一开始一样的错误,真的铺开了做这个功能,人力成本+存储成本+计算成本,是远远远远远远大于招一个成熟的架构师的成本的。架构师能定对了方向,对于一个项目的成败,是有决定性的作用的。对吧?


当然订阅也欢迎 :-)



欢迎订阅专栏《职场求生攻略》

发布于: 2021 年 03 月 16 日阅读数: 52
用户头像

臧萌

关注

一线程序员,偶尔写写字 2017.10.20 加入

《零基础学 Java》,《职场求生攻略》 视频课作者 《Java入门1·2·3》作者

评论

发布
暂无评论
我帮大厂做架构之——微信的“N个朋友读过”怎么实现