论如何设计一个社交朋友圈内容架构(一)

338 阅读7分钟

前几天面试一家公司的时候,由于我项目经验中之前做过社交类的产品,面试官对该产品中的朋友圈功能产生关于朋友圈设计的讨论。

面试官问我,之前开发的这个社交产品的朋友圈功能是如何设计的。我回答说,在产品初期,用户量较少,所以我们选择了简单的设计,将用户发布的朋友圈内容直接存入MySQL数据库。在不考虑人工和机审的情况下,数据发布后直接写入数据库,用户在查询时也直接通过MySQL进行检索。

随着用户规模的快速增长,我们发现MySQL逐渐难以支撑高效的检索需求。因此,我们决定将朋友圈数据迁移至Elasticsearch(ES)。借助ES的全文搜索和分布式处理能力,极大地提升了查询速度,能够轻松处理海量数据查询的压力。

最后面试结束的时候,面试官提出了一个有关社交朋友圈场景设计的问题:假设现在设计一个社交朋友圈功能,在日活跃用户达到500万,每个用户每天发布5条朋友圈的情况下,应该如何设计这个功能? 具体需求是,用户可以查看所有用户发布的朋友圈,也可以查看好友发布的朋友圈,并且朋友圈需要按最新发布时间排序,或者按点赞量最高进行排序。

面试官进一步提问了以下几点:

  1. 如果使用MySQL,该如何设计表结构?
  2. 在这个数据规模下,哪些字段需要加索引以优化查询效率?
  3. 是否需要进行分库分表?如果需要,如何设计分库分表策略?
  4. 是否需要用缓存 如果需要用缓存的话 该怎么设计缓存类型以及数据结构呢?

分析:

首先,根据假设条件,用户数达到500万,每个用户每天发布5条朋友圈,这意味着每天的发布量约为2500万条。如此庞大的数据量,如果仅依赖单个数据库,不仅会对存储查询效率带来极大的压力,还会影响系统的整体性能。

在这种情况下,分库分表是必然的选择。通过分库分表,可以将数据分散到多个数据库和表中,从而提升查询效率、减轻单个数据库的负载压力,并且更好地应对高并发的访问场景。

确定分库分表策略:

既然已经确定需要进行分库分表,接下来就需要计算大概需要分多少库和多少表,并且明确如何进行分库分表。在这一步,我们可以考虑两种常见的分库分表策略:水平分库分表垂直分库分表

  1. 水平分库分表:是通过对相同的表进行拆分,将表中的数据按某个规则(例如用户ID或时间)拆分到不同的库或表中,从而减轻单个数据库的压力。
  2. 垂直分库分表:是按照功能模块或字段进行拆分,例如将用户的基本信息和朋友圈内容分成不同的表或库,达到降低数据冗余和查询压力的目的。

结合这个场景,由于朋友圈内容和点赞量等数据之间有较强的关联性,并且这些数据的访问频率较高,所以更适合采用水平分库分表的方式。通过用户ID或发布的时间来进行水平切分,可以确保每个库或表的数据量更为均匀,减少单库的负载压力。

计算分库分表的数量:

在确定了使用水平分库分表后,接下来需要计算大概需要分多少库和多少表才比较合适。

数据量估算:

首先,我们估算一下单个帖子所占的数据大小,以及每天大约会产生多少数据。假设单条帖子的结构如下:

  • post_id: 8字节(BIGINT)
  • user_id: 8字节(BIGINT)
  • content: 平均500字节(TEXT或VARCHAR类型)
  • media_url: 平均100字节(VARCHAR类型)
  • visibility: 1字节(TINYINT)
  • created_at: 8字节(DATETIME)

每条记录大约占 625字节
根据每日2500万条数据的发布量计算,每天大约会产生:

2500万条 × 625字节 ≈ 14.9GB

单表大小限制:

虽然MySQL单表的大小限制通常为2GB到4GB,但为了保持最佳性能,单表的记录数不宜超过1000万条。过大的单表会影响查询和插入的性能。因此我们需要控制单表的数据量在1000万条以内。

每张表的容量为:

1000万条数据 × 625字节 = 5.86GB

分表和分库策略计算:

基于每天2500万条发布量,如果每张表控制在1000万条数据以内,那么一天的数据需要约2.5张表来存储。以月为单位存储的话,每月大约会产生7.5亿条数据,这需要75张表

为了考虑未来数据量的增长和系统的可扩展性,假设系统设计需要支持未来5年的数据量,我们可以设置如下分库分表策略:

分库分表方案:

  • 分库数量:假设一个数据库可以存储10亿条记录,而一年产生的数据量约为9亿条(2500万条/天 × 365天),每个库可以存储大约1年的数据量。为支持5年的数据量,我们可以设置大约5到10个库
  • 分表数量:每张表控制在1000万条记录以内,每个库可以创建100张表。假设每月需要生成10张新表来存储当月数据,整个库可以容纳大约10亿条记录,支持1年的数据。

因此,建议的分库分表结构为:10个库,每个库内100张表,通过哈希取模或者user_idpost_id规则将数据分配到不同的库和表中。

如何分库分表:

可以根据**user_idpost_id**进行分库分表,具体策略如下:

  • user_id:代表用户的唯一标识符,每个用户在系统中都有一个唯一的ID。按user_id分库分表的好处是,用户的所有帖子都会存储在同一个库或表中,查询用户相关的帖子数据会更高效。

    • db_index = user_id % db_count:根据用户ID决定用户数据存储在哪个库。
    • table_index = user_id % table_count:根据用户ID决定用户数据存储在哪个表。
  • post_id:代表每条帖子的唯一标识符,每个帖子都有一个唯一的ID。按post_id分库分表适合处理大量发布内容的场景。虽然查询某用户的所有帖子可能需要跨库查询,但对于发布量大且注重内容查询的场景,这种方式依然高效。

    • db_index = post_id % db_count:根据帖子ID决定帖子数据存储在哪个库。
    • table_index = post_id % table_count:根据帖子ID决定帖子数据存储在哪个表。

确定方案并开始设计:

通过上面的分析,我们已经确定了分库分表的策略以及需要分配的库表数量。接下来,我们将基于这些分析结果,开始进行具体的场景设计。在下一章中,我将通过一个简单的Demo代码展示如何进行朋友圈内容的发布查询操作,演示具体的代码流程。