1、社区介绍:
年糕妈妈社区作为承接年糕妈妈微信用户到APP的平台,为超百万用户 提供科学育儿服务。社区主要包含关注、推荐、发现、搜索、育儿知识。用户可在社区发帖、参与话题、打卡、评论、点赞、收藏、加关注。
2、社区实现难点
- feed实现,如何保证高并发低延迟
- 高并发下各种数据统计。一个页面有帖子阅读数、评论数、点赞数,用户的粉丝数、关注数等
- 分页查询标签下的文章列表各种排序
3、社区实现方案
总体架构图如下:
复制代码
3.1 feed介绍
- feed:feed流中的每一条消息都是Feed,朋友圈中的一个消息就是一个Feed,微博中的一条微博就是一个Feed.
- feed流:持续更新并呈现给用户内容的信息流。每个人的朋友圈,微博关注页等等都是一个Feed流。
- Timeline:Timeline是一种Feed流的类型,微博,朋友圈都是Timeline类型的Feed流
- 年糕妈妈社区的关注feed 是由关注的人发布的帖子组成。
3.2 feed流实现模式
3.2.1 拉模式
a. 发布帖子简单,A发布帖子,只需要存储到帖子表即可
b. 关注取消流程简单,A取消关注B:此时只需要在A的关注列表里删除B,并在B的粉丝列表里删除A。
c. A获取feed流复杂,首先获取A的所有关注用户,然后获取这些用户所发布的帖子并进行排序,分页取出对应的一页帖子。
-
优点:
1、存储结构简单,存储量较小,feed数据只存一份 2、关注、发布feed流程简单,容易理解,适合快速开发。 复制代码
-
缺点:
1、获取用户feed流过程复杂,需多次查询 2、不适合关注人较多的情况下的高并发查询 复制代码
3.2.2 推模式
当一个用户触发行为(比如发帖子),自身行为记录到行为表中,同时也对应到这个用户的粉丝表,为每个粉丝插入一条feed。粉丝读取feed流,只需要读取feed流,排序即可。
-
优点
拉取feed流 业务流程简单,查询性能高 复制代码
-
缺点:
1、feed数据存储多份,尤其大V粉丝比较多的情况下,严重消耗存储资源 2、关注取消、发布feed 业务流程变复杂 3、feed可能延迟 复制代码
3.2.3 推拉模式结合
粉丝很多的用户称为大V。普通用户发布feed时,采用推模式。离线用户上线后定时拉取feed,后台将大V的feed同步到该用户的feed流中,来完成动态的拉和推。此模式避免了大V用户发布feed时,fee流存储急速扩大,导致用户查询feed 延迟。
3.3 计数中心实现
社区展示各种数,比如帖子详情页有阅读数、评论数、点赞数,用户的粉丝数、关注数、消息数等。在计数种类多,并发高下,如何实现数据计数,常见有以下方案。
3.3.1 传统count计数法
比如统计用户发帖数 select count(*) from post where user_id = xxx 来统计,次方法就是 count 计数法。
- 优点
count计数法实现简单,统计也比较精准,适合数量量小、低并发的业务。
- 缺点:
一个计数一个count,实现业务往往需要多次查询
3.3.2 计数(外置)冗余法
通过对社区计数业务分析,得出2个维度的计数
- 用户维度:关注数、粉丝数、发帖数、被赞与收藏数
- 帖子维度:阅读数、点赞数、评论数、收藏数
这2个维度的指标可以通过在用户表、帖子表中添加属性来单独存储,也可以新建2张表 用户计数、帖子计数表存储。
- 比发布帖子时,insert post,更新帖子数 update set post_num = post_num ++ where user_id = xxx
- 查询帖子计数时, select pv,like_num,comment_num from post where post_id = xxx
这种方式就是计数外置法,也是一种数据冗余方法。
-
优点
1、一次查询多种计数,一个维度计数无需多次查询 2、查询走主键索引,效率高 复制代码
-
缺点:
1、数据冗余,可能出现数据不一致情况 2、在高并发下,db 压力增大 复制代码
3.3.3 计数外置改进方案
针对年糕妈妈社区业务,我们抽象出计数服务中心(气泡服务),通过redis缓存实时计数,定时将redis计数数据同步到db。 这样避免了高并发给db带来的压力,同时提高了计数读写能力。
3.4 社区搜索
业务背景:社区搜索,通过输入关键词、选择 标签,查询帖子、育儿知识等。
3.4.1 搜索选型:
mysql5.6.4 及以上的innoDB 也引入了全文检索,可直接通过match 查询,方案简单,但内置的分词、搜索效果不一定能满足要求。 还是选择了更专业的搜索引擎elasticsearch 、opensearch
3.4.2 索引同步实现
-
全量同步
历史数据同步,通过扫描全表,将数据同步到索引里 复制代码
-
增量同步
新增数据、或修改数据同步。 方案一:在业务代码中,将数据同步到索引 优点:实现简单,数据同步分散在业务中,有业务维护 缺点:耦合高,业务代码混乱,无法复用 方案二:通过监听数据库的 binlog 日志,将数据同步到索引 优点:解耦,可复用 缺点:引入了额外的框架,增加了系统的复杂度 最后我们采用第二种方案,通过引入canal,实现binlog订阅和数据同步 复制代码
3.4.3 索引查询
-
使用搜索引擎自带API
需要学习成本,每位开发都需要额外学习api使用。有没有一种大家不需要学习就会用的工具呢
-
自研 esqlParse
结合 mybatis,将sql语句翻译成搜索引擎的API,实现索引查询。
优点:降低了开发学习成本,开发只需要写sqlmapper,即可实现索引查询
缺点:功能还不完善,某些复杂查询还不支持
3.5 感受
架构都是建立在业务之上,很难一次做的最好,更多的是一步步演进而来的。本文还有很多不完善的地方,也有过其他问题没讲解到,欢迎大家多多交流!