9.2 排行榜的技术特点与现实生活中的排行榜不同,互联网应用中的排行榜一般具有如下特点。
曝光量大:一个成功的排行榜会受到大量用户的关注,这是一个自带流量的功能场景,会带来高并发读取排行榜的请求。
竞争激烈:为了获得流量优势和排名靠前的奖励,排行榜可能受到参与者的激烈竞争,这就要求排行榜服务能应对高并发的写请求。
实时变化:不同于考试结果排名,互联网应用中排行榜的排名情况在实时变化,参与者会随时关心自己的最新名次。
周期滚动:排行榜可能以月、周、天、小时甚至分钟为周期滚动排名。
所以,在排行榜的技术实现方面,要重点考虑高并发读/写、实时展示最新排名,以及可以轻松支持周期滚动的能力。在设计排行榜服务时,首先要考虑的问题是使用什么存储系统来维护排行榜。假如使用关系型数据库的话,因为它对高并发读/写的支持较弱,而且为了支持按照积分排序,在关系型数据库中需要根据积分字段,使用 SELECT语句的 ORDER BY子句来实现。而该方式具有如下缺点。
性能开销:在有大量数据的情况下,排序操作会耗费大量的系统资源和处理时间,尤其是当需要进行多字段排序或者排序字段的数据类型不 ...
本章我们介绍一个看似简单但又复杂、极为常见的排行榜服务的设计。本章的学习路径如下。
9.1节介绍排行榜的应用场景。
9.2节介绍排行榜技术的特点,便于我们做合适的技术选型。
9.3节介绍最常见的Redis ZSET排行榜方案,并剖析其中的具体技术细节。
9.4节介绍粗估排行榜的实现方案。
9.5节介绍精确排名与粗估排名结合的超长排行榜的实现方案。
本章关键词:存储选型、ZSET、粗估排名、线段树。
9.1 排行榜的应用场景排行榜在互联网产品中应用非常广泛,下面列举几个常见的应用场景。
游戏排行榜:游戏排行榜是游戏中很重要的组成部分,玩家通过游戏排行榜能够相互比较,并且能够获得一些游戏道具奖励。游戏排行榜通常采用的是分数排名,而排名的计算需要使用排序算法或其他比较算法。因此,游戏排行榜可激励玩家参与更多的游戏,提高游戏的互动性。
商品排行榜:在电商平台中,商品排行榜通常可以让消费者快速了解当前最热门商品的信息,从而方便其做出购物决策。而且,排行榜上的商品也有较高的销售量,对促进销售起到了一定的作用。
视频排行榜:视频网站可以根据用户的点击量、分享量、评论量等指标生成热门视频排行榜, ...
8.3 海量计数服务设计通过前面的讨论,我们已经确定采用Redis作为计数数据的存储系统,本节就围绕Redis设计一个海量计数服务。
8.3.1 Redis数据类型本节我们讨论使用哪种Redis数据类型来存储计数数据。
我们知道,Redis支持5种数据类型:String、List、Set、Hash、ZSET。从直观上看,我们可以使用String对象保存计数数据。Redis String对象支持保存整数、浮点数、字符串。如果使用String对象保存整数,那么Redis底层会以整数编码的形式存储这个整数,并且支持使用INCRBY命令和DECRBY命令对此整数进行加减。
以作品维度的计数(评论数、点赞数、分享数、转发数、收藏数)为例,我们可以使用5个String对象来保存一个作品的计数,如表8-1所示。
其中:
当用户对某作品ID=content_id点赞时,计数服务会向Redis执行INCRBY count_{content_id}_like 1 命令为点赞数加1;
当用户取消对某作品ID=content_id的点赞时,计数服务会向Redis执行 ...
8.2 如何存储计数数据下面通过计数数据的特点,详细介绍为什么计数要单独存储,以及如何进行存储选型。
8.2.1 计数数据的特点计数数据一般具有如下特点。
读请求量巨大:无论是作品维度的计数,还是用户维度的计数,都有较大的访问量,所以计数的展示需要支持高并发读取。
写请求量巨大:对于点赞、点踩、评论、转发、收藏等这些场景,由于用户触发动作的成本很低,计数会以较高的并发量增加,所以计数的增加需要支持高并发写入。
非产品的绝对强依赖:与用户钱包账户余额数据不同,具有累计性质的计数数据是否能正常展示通常不会影响用户使用产品的功能。在极端情况下,如发生网络抖动、服务Bug、请求击垮机房、机房故障等,计数作为一种纯粹的加成效果,在无法展示时不会过于影响用户的心情。
对数据的精确性要求与数值的增加成反比:例如,当点赞数少于一定的数量时,用户会非常在意点赞数量并查看有哪些人为他点赞了;但是当点赞数已经达到千或万级别时,用户对点赞总数的关注会变得更加粗糙,不会再关注点赞数个位数的增加情况,而是更关注点赞数的级别跃迁,如点赞数从10000个增加到20000个。大部分用户产品也是按照这样的数据规律来做设 ...
本章讲解一个相对简单但又很常见的服务:计数服务。本章的内容组织结构如下。
8.1节介绍计数的常见用途。
8.2节针对计数的数据特点,做出存储选型。
8.3节正式介绍海量计数服务设计,也会对存储空间进行优化,对如何应对高并发访问进行深入探讨。
本章关键词:存储选型、内存优化、冷热分离、异步、聚合。
8.1 计数的常见用途具有累计性质的计数数据广泛存在于各种用户应用中,比如:
用户发布的每个作品,有点赞数、分享数、评论数、转发数、收藏数;
用户主页,有关注数、粉丝数、作品数、热度等;
评论列表中的每条评论,有点赞数、点踩数。
上述1和3属于作品维度的计数(评论也可以被认为是一种作品),在相当程度上反映了一个作品的受欢迎程度;而2属于用户维度的计数,可以直观地展示用户的活跃度与影响力。示例如图8-1所示 。
在进行各类计数数据的展示时,初学者非常容易直白地认为数据的统计计数应该来源于数据记录本身。比如点赞数可以从作品点赞记录数据中统计总数得到,评论数可以从作品评论记录中统计总数得到……实际上,这样的做法有极大的并发访问风险。更安全、可靠的做法是将数据本身与数据记录解耦,将计数数据独 ...
7.7 完整架构总览通过对内容发布系统的全部功能的设计,我们可以看到这是一个较为复杂、高度依赖监听内容各种状态变更事件的系统,内容的创建、修改、审核、发布、删除都属于内容状态的变更。图 7-10展示了内容发布系统的完整架构视图,希望能让我们更直观地感受整个内容发布系统的运转原理。
下面结合图7-10来系统性地复习内容发布系统的完整运转流程。
创作者创建内容。客户端先将图片、音频、视频等文件上传到对象存储系统(在存储音视频文件前通常会进行音视频转码),然后在关系型数据库的item_info表中创建内容元信息,并将内容存储到item_record表中。如果内容文本较短(短文本),则直接将其存储到分布式KV存储系统中;而如果文本内容过长,则以文本文件的形式将其存储到对象存储系统中。新创建的内容可能需要审核,对于满足审核条件的内容,内容发布系统与审核中心建立送审消息队列,并向审核中心发送所创建的内容的消息,实现新创建的内容与审核服务的异步交互。
创作者修改内容。创作者修改内容与创作者创建内容的业务架构流程是高度类似 的。如果此次内容修改涉及图片、音频和视频的改动,则客户端先将新的图片、音频 ...
7.6 内容展示设计前面已经完成了对内容创建、内容修改、内容审核、内容删除、内容分发的流程设计,本节将详细介绍内容展示设计,这是本章要讲解的最后一个重点功能。
用户读取内容,直观来看,是用户与数据库的item_info表、分布式KV存储系统(内容文本的存储源)、分布式对象存储系统(图片和视频的存储源)的交互。不过,出于应对高并发请求量的考虑,实际上这里需要引入更多的机制。让我们先从内容数据的特点入手。
7.6.1 内容数据的特点内容生产是一个天然的读多写少且读远多于写的场景,创作者修改内容的请求量极少,用户读取内容的可能性极大。
对于一般的互联网应用的内容,由于用户创建和修改内容有一定的操作成本,所以注定了内容的创建和修改场景的请求量级不会太高。它的QPS一般是百级别的,如果QPS上千,那么几乎可以称得上国民级应用了。总体上,内容生产的高并发情况很少,且内容生产对内容生效的响应时间容忍性相对宽松,所以对应的高并发处理方式相对简单。即在高并发的内容创建和修改的极端情况下,对内容的发布或修改进行异步化处理,将发布或修改的内容投递到消息队列中,内容发布系统的消费消息队列进行内容的创建、修改或 ...
7.5 内容分发设计内容被正式发布后并没有万事大吉,我们还有很重要的一个问题要讨论,那就是如何才能让别人看到这条已发布的内容。
7.5.1 内容分发渠道根据刷社交软件的经验,我们知道一个用户的作品可以通过多种渠道呈现给其他用户。比如推荐Feed流可以把我们可能感兴趣的内容推送给我们,Timeline Feed(或称为关注人动态)可以让我们刷到所关注的人最近发布的内容,我们还可以主动按照自己的兴趣去搜索与某关键词相关的作品,去某热门话题下查看相关的用户讨论,去我们喜爱的创作者主页查看最新作品这些能看到内容的场景就是内容分发渠道。
按照微服务的划分,这些内容分发渠道有各自的业务开发团队、技术栈和应用服务。比如推荐Feed流渠道会由专门的算法团队维护,他们使用大数据处理、推荐算法等技术构建内容推荐服务。
7.5.2 何时通知分发渠道
为了让内容在创作者的作品列表中曝光,需要将内容放到作品列表中;
为了让内容被推荐,需要根据内容特征,将内容放入对应的推荐召回池中;
为了让内容被创作者的关注者看到,可能需要将内容投递到关注者的收件箱中;
为了让内容在创作者的主页上展示,可能需要把内容放入创作者的 ...
7.4 内容的全生命周期管理设计本节讲解内容的全生命周期管理设计,前面产生的各种问题都会在本节得到解答,比如:内容元信息的存储为什么使用两张数据表,数据表每个字段的实际用途是什么,如何处理内容审核结果,等等。
7.4.1 内容的创建设计当创作者在产品客户端新创建了一条内容并准备将其提交到内容发布系统的服务端时,我们应该怎么处理这个请求?
首先,客户端需要进行内容数据类型的识别和归类。如果新创建的内容包含长文本图片,则需要先将它们以文件形式上传到分布式对象存储系统中。如果分布式对象存储系统成功存储了这些文件,则会返回长文本URI和图片URI;如果新创建的内容包含视频,则由于涉及必要的视频编解码,所以需要先将本地视频文件上传到由专门的视频团队开发的视频服务中(这个服务会先对视频进行转码,然后把结果存储到分布式对象存储系统中),并由视频服务返回一个唯一的视频ID代表这个视频,我们可以根据这个视频ID从视频服务中获取视频。
然后,在将这些特殊文件存储到服务端后,客户端会收到服务端的响应,接收到长文本URI、图片URI和视频ID。
最后,客户端携带创作者信息、内容可见性设置、内容短文本及服务端 ...
7.3 内容审核设计本节介绍与内容发布系统息息相关的一个周边系统:审核中心。审核中心虽然不属于内容发布系统本身的内容,却是内容发布系统的重要合作方,它或多或少会影响内容发布系统的自身架构设计,其中的一些细节值得我们关注。
7.3.1 内容审核的必要性有人可能认为把内容存储到存储系统中就算完成内容发布了,其实不然。由于内容是由创作者自由创作的,别有用心的创作者可能会借助社交应用恶意传播暴力、反动、色情、 诈骗、侵权或者其他不良的信息,不但污染了产品的内容生态,引起用户的不适与反感,还可能直接激怒大众,导致产品下架……所以,任何产品,只要为用户提供了相对宽松、自由的可发布内容的权限,对其内容的审核就是重中之重!
7.3.2 内容审核的时机策略下面设计内容审核的时机策略。
(1)方案一
方案一:只要用户发布和修改内容,就属于内容变更,此时要把最新的内容发送到审核中心进行审核(下文简称“送审”),等待审核通过后再使内容发布生效。
可以说,方案一很保险,因为全部的内容变化都可以被审核中心感知,但是并未考虑互联网应用中海量用户每天发布的内容是什么规模。比如,推特在2022年上半年的每日用户发推量已 ...