高并发系统设计 -- 粉丝关注列表如何设计

粉丝关注列表如何设计和落地

业务场景

在这里插入图片描述

上图我们简称relation页。relation页展示用户的关系相关信息,包含两个子页面:

  1. follower页,展示关注该用户的所有用户信息。
  2. attention页,展示该用户关注的所有用户信息

主要操作

用户可以为自己增加,删除attention,即关注某个其他用户或者对其他用户取消关注。可以删除follower,即取消其他某个用户对自己的关注。

业务特点

  1. 海量的用户数据。亿级的用户数量,每个用户千级的帖子数量,平均千级的follower/attention数量。
  2. 高访问量。每秒十万量级的平均页面访问,每秒万量级的帖子发布。
  3. 用户分布的非均匀。部分用户的帖子数量/follower数量,相关页面访问数量会超出其他用户一到几个数量级
  4. 时间分布的非均匀分布,某个用户可能突然在某个时间成为热点用户,其follower可能徒增数个量级

一个典型社交类系统的典型特性归结为三个关键词:大数据量,高访问量,非均匀性

relation存储层设计

最简单的就是基于DB存储,只需要两张表即可。

table_relation表:id主键,关注者id,被关注者id

table_user_info表:id主键,用户信息(头像,名称,注册时间,大v认证,手机号等信息)

所以我们这里只需要查询两张表就可以查询出关注,粉丝和用户信息:

select count(1) from table_relation where 关注者id = 'xx';
select count(1) from table_relation where 被关注者id = 'xx';
select * from table_user_info where id = 'xx';

随着用户数量的增多,table_relation和table_user_info表的行数增多。千万,亿级用户,每个用户相关关系百级,那么就需要水平切分。

对于某一个用户的信息查询,首先根据userId计算出它的数据在哪一个分片,再在对应的分片info表里查询到相关数据。userId分片的映射关系有多种方式,例如:hash取模,userId字段的某几个特殊位,一致性hash等等。

这里有一个问题。table_relation根据follower进行拆分,查询某个用户关注的人很容易,因为相同的followerId的数据一定分布在相同的分片上(我关注了谁)。但是一旦需要查询谁关注了某个用户(谁关注了我),这样查询需要路由到所有分片上进行,因为相同的attentionId的数据分散在不同的分片上,查询效率低。由于查询follower和attention的访问量是相似的,所以无论根据followerId还是attentionId进行拆分,总会有一般的场景查询效率低下。

所以针对上述问题,进行垂直拆分,分为follower表和attention表,分表记录某个用户的关注者和被关注者,接下来在对follower表和attention表分别基于userId进行水平拆分。

follower表:主键id,userId,followerId

attention表:主键id,userId,attentionId

这个时候实现查询:

select count(1) from table_follower_xx where userId = 'xx';
select count(1) from table_attention_xx where userId = 'xx';
// 查询用户
select * from table_user_info where userId in (xx);

上述三条语句,前两条可以落在相同的分片上,DB操作次数为两次,但最后一条仍需要查询多次DB。

同时,进行垂直拆分的时候,如果我们要写DB,就提升了一倍。而且上述操作仍然需要count查询,即使在userId上建立了索引仍然会有问题存在:

  1. 对于某些用户,他们被很多人关注(比如明星几千万的关注),他们在follower表进行count查询的时候,需要在userId上扫描的行数仍然很多,我们称这些用户为热点用户。每一次展示热点用户的关注者数量的操作都是低效的。另一方面,热点用户由于被很多用户关注,他的timeline页面会被高频的访问,使得原本低效的展示操作总是被高频的访问,性能风险进一步扩大。
  2. 当某一个用户的follower比较多的时候,通常会在relation页面里无法一页展示完,因此要进行分页处理,每一页显示固定数量的用户,然而DB实现分页的时候,扫描效率随着offset增加而增加,使得这些热点用户的relation页展示到最后几页的时候变得低效。
  3. 用户详细信息的展示,每次展示relation页面的时候,需要对每个follower或者attention分别查询info表,使得info的查询服务能力无法随着info分片线性增加。被attention限制住了。

引入缓存

针对上面的问题,我们这里就需要引入缓存来解决。

同时,在DB层面,我们可以在userInfo表的信息中,将每个用户的关注者和被关注者的数量存入DB,这样一来,对于timeline页和feed页的relation摘要展示仅仅通过查询userInfo表即可完成。

同时可以在缓存中也添加上关注者和被关注者的数量。一些大V账号,我们也可以进行服务器端的本地缓存进行二级缓存

引入缓存之后的业务操作实现方式也相应做了调整:

  1. 某用户timeline/feed页面的relation摘要信息展示:展示方式首先分局用户作为key查询缓存,未命中的时候,再查询DB。
  2. 某用户relation页面详细信息展示,分为两个子页面:follower列表展示和attention展示:
    • 同样先查询follower和attention的缓存,对于频繁被查询的热点用户,它的数据一定在缓存中,由此将DB数据量最多,访问频度最高的用户档在缓存外。
    • 对于每个用户的info信息,热点用户由于被更多的用户关注,他更有可能在详情页面被查询到,所以这类用户总在本地缓存中能够被查询到,本地缓存设置一个不长的过期时间。

热点用户需要考虑的实时性问题

对于热点用户的follower详情页,由于热点用户过长的缓存list,它们每次被查询都有极高的网络传输,同时因为热点,查询频率也更高,加重了网络负担。info查询中follower和attention的数量随时变化着,为了使得查询的数值实时,系统需要在尽量间隔短的时间重新进行count,对于热点用户,如果期望实现秒级数据延迟,那么意味着每秒需要对百万甚至千万级别的数据进行count。如何解决这些动态变化着的数据的大访问量,实时性成为挑战。

新增的用户是放在最前面的,往往我们最前面的N页查询是比较频繁的,占总查询的百分之99.

我们就可以去单独分出来一个list页,在redis中,我们把新增的关注用户放在list页,我们可以直接去查询这块新增数据。

剩下后面的数据的话,我们可以去查询redis list查询,也可以去查询db。

db层面做sql优化,时间会短一点,同时我们可以查询后面用户的数据。我们也可以存在list中,时间设置的稍微短一些,这样方便。

当需要查看某个用户的relation详情页时,涉及对follower和attention列表的分页查询。通常单个用户的关注的人数量有限,绝大用户在1000以内,且每次查询对第一页查询的频率远高于后面的页,那么无论直接将列表存入DB或者是缓存中,都能做到较高的吞吐量。但是对于热点用户的follower,情况就比较复杂一点:follower的数量是不可控的,即使是小概率的翻页操作,对于follower很多热点用户,仍然是高访问量的操作;且每次翻页的扫描成本很高。单个分布式缓存的value列表无法承载过长的follower列表。

针对热点用户的follower列表查询问题,采用基于增量化的实现辅助解决。首先,同一个follower列表的前N页(假设5页)的访问频率占用到总访问量的绝大部分。而前N页的follower个数是常数个;其次follower列表的展示以follow时间进行排序,最近加入的follower通常排在最前面,即增量化模块的最新数据最有可能放在首N页。作为增量化的消费者每次拉取的最近N页条变更事件直接存入热点用户的follower缓存中。

最后最重点的一个问题,如果大V上了一个综艺或者拍了一个电视剧,短时间内突然爆火。导致粉丝关注越来越多从几百万或者一千万直接干到四五千万了,这时候要怎么办呢?如果把他的关注列表和粉丝列表都放在和普通用户的关注列表和粉丝列表一个分片下,是会影响正常用户的性能的,所以我们要怎么做呢?

这里我们如果碰到这种大V了,我们可以进行数据迁移,把大V单独放在一个放到一个分片上,这样就不会影响正常用户的操作了。

由此我们可以看到,微博的大v认证是从产品的角度解决是技术的问题,是一举两得的解决方案,微信红包的抢拆分离也是同样的效果。

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: libevent是一个开源的C语言网络编程库,主要用于处理高并发网络连接。它提供了对事件驱动的支持,使得开发者可以方便地编写高效的并发网络应用程序。 libevent的核心是事件循环机制。在传统的网络编程中,通常需要使用多线程或多进程来处理并发连接,而使用libevent可以通过一个事件循环来处理多个连接。在事件循环中,可以注册多个事件,并定义回调函数来处理事件的触发。当有事件发生时,libevent会调用相应的回调函数来处理事件的处理逻辑。这样可以大大简化并发编程的复杂性,并提高程序的性能。 libevent的事件模型基于操作系统提供的I/O多路复用机制,如select、poll和epoll等。它可以在不同的操作系统平台上运行,并提供一致的接口和高效的事件处理机制。借助这些机制,libevent可以同时处理大量的并发连接,并保持低延迟和高吞吐量。 除了处理网络连接,libevent还提供了其他常用的功能,如定时器和信号处理等。它允许开发者在事件循环中注册定时器事件,可以用于定时任务的调度。同时,libevent还可以处理来自操作系统的信号,并提供了对信号的处理接口,以便开发者能够处理各种系统事件。 总之,libevent是一个功能强大、简单易用的高并发网络编程库,适用于开发各种类型的网络应用。无论是开发服务器、代理、聊天程序还是实时应用,libevent都能帮助开发者快速编写高性能的并发网络程序。 ### 回答2: libevent是一个开源的C/C++网络库,用于高性能的事件驱动编程。它提供了一个轻量级、可移植的框架,用于开发高并发的网络应用程序。 它的设计目标是提供一个高效的事件处理器,可以处理成千上万个并发连接,并且支持多线程并发处理。libevent基于事件驱动模型,通过异步I/O和回调函数来实现高并发处理网络请求。 libevent提供了一系列的函数来注册和监听各种网络事件,包括读、写、超时和信号等等。当一个事件发生时,libevent会调用相应的回调函数来处理事件。通过这种方式,我们可以非常方便地处理并发连接,并实现高性能的网络编程。 libevent的优点主要包括: 1. 高性能:libevent使用异步I/O和事件驱动模型,能够处理成千上万个并发连接,具有很高的处理能力。 2. 可移植性:libevent提供了统一的接口,可以在多种操作系统上运行,包括Linux、Windows、Mac等。 3. 易用性:libevent简单易用,只需注册感兴趣的事件和相应的回调函数,就可以实现高效的网络编程。 4. 多线程支持:libevent支持多线程并发处理,可以充分利用多核CPU的性能优势。 总之,libevent是一款非常适合高并发网络编程的开源库,它可以帮助我们实现高性能的服务器程序,提升系统的并发处理能力。无论是开发网络服务器还是网络应用程序,libevent都是一个不错的选择。 ### 回答3: libevent 是一个用于高并发网络编程的 C/C++ 库。它提供了一个跨平台的异步事件驱动的网络编程框架,能够实现高效地处理大量并发连接的需求。 libevent 的主要特点包括: 1. 异步事件驱动:libevent 使用事件驱动模型,主要利用非阻塞 I/O 和事件回调机制,能够高效地处理大量并发事件。 2. 跨平台支持:libevent 提供了跨不同操作系统的支持,包括 Windows、Linux、Unix 等,并且提供了统一的 API 接口,方便开发者进行跨平台开发。 3. 支持多种网络协议:libevent 支持 TCP、UDP、HTTP 等多种网络协议,为开发者提供了丰富的网络编程能力。 4. 高性能:libevent 的设计目标之一是高性能,它通过使用多路复用技术,将系统资源高效地利用起来,能够同时处理大量并发连接,并且保持低延迟。 5. 灵活易用:libevent 提供了简洁的 API,使用起来非常方便,可以快速实现高并发网络编程的需求。 总之,libevent 是一个强大而灵活的 C/C++ 库,适用于各种需要处理高并发连接的网络应用程序。无论是开发高性能服务器、代理、负载均衡器还是其他类似应用,libevent 都是一个值得推荐的选择。它的高效性能、跨平台支持和简洁易用的 API 接口使得开发者能够快速构建稳定可靠的高并发网络应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡桃姓胡,蝴蝶也姓胡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值