xiaolang286 / feed

高可用feed流系统

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

高可用Feed流动态策略设计和实现


业务说明:

1、涉及业务:好友动态、个人动态(也涉及个人动态计数)、好友关系(也涉及关注数和粉丝数)
2、涉及操作:新增、查找、删除


设计要点:

1、涉及缓存设计和数据库设计
2、需要考虑峰值写入情况
3、需要考虑读写的性能
4、使用语言无限,可以是自己比较熟悉的语言


最终交付:

1、提供业务接口(部署到测试服务器上)
2、压测数据:包括压测场景及其压测结果数据
3、系统可支撑的量级评估
4、系统再进一步发展的瓶颈点评估


附加题:

1、思考怎么实现未读数(给出方案,或者进一步实现功能,这部分可以考虑按照小组来做)
2、涉及到视频和图片


业务接口:

1、好友动态
    http://127.0.0.1:7788/api/friendstimeline
    GET
    参数:timebegin、timeend、userid
    说明:利用时间段和用户id获取好友动态
2、个人动态
    http://127.0.0.1:7788/api/personaltimeline
    GET
    参数:timebegin、timeend、userid
    说明:利用时间段和用户id获取个人动态
    POST
    参数:action(add/delete)、userid、timestamp、value
    说明:发布个人动态需要提供时间,内容,用户id以及关键的操作(增加或删除)
3、好友关系
    http://127.0.0.1:7788/api/friendsinfo
    GET
    参数:userid
    说明:返回用户的关注对象和粉丝列表
    POST
    参数:action(add/delete)、userid、like和fan二选一
    说明:更改好友关系需要提供用户id以及关键的操作(增加或删除)和粉丝id或者关注对象的id(两者同时存在,以like为优先)
4、未读数
    http://127.0.0.1:7788/api/unreadnum
    GET
    参数:userid
    说明:返回用户好友动态的未读数


启动:

Mac
cd $GOPATH/src/feed
go build main.go
sudo ./main -c conf/feed-for-test.toml

Linux
cd $GOPATH/src/feed
./build.sh
cd feed
sudo ./bin/feedserver -c conf/feed-for-test.toml


核心设计:

MC:缓存层(L1+M+S)

Mysql: 存储层(分库分表)

Kafka: 队列

Redis: 存储未读数(对持久化要求不高的对象)

Feed流聚合: 推拉结合,设定阀值X,只向最早(时间有序)的X名粉丝push个人动态(mysql存储),其余由粉丝主动pull,在粉丝取关时会主动删除自己存储的对方的所有timeline(如果有的话)并且遵从一个重要的假设,即基于push方式时,用户在关注某一对象时,不关心对方之前发布的动态

视频、图片:发布动态时,首先获取资源的md5 key,通过存储多媒体资源在云上存储的KEY,或者进一步存储KEY的key,减轻聚合动态时的带宽和资源消耗


压测相关:

压测机器:

CPU:2
Mem:1.5G
Disk:50G
除mysql外均在远程机器上(ping值 1ms以内)

压测数据(T99,成功率100%,最大并发(<5000),cpu 100%):

    personaltimeline_Post personaltimeline_Get  friendsinfo_Post 
|_________________________________________________________________________
|30(ms) 600/5000/678(kB)  500/4800/1.43(MB)     800/8700/1.18(MB)
|_________________________________________________________________________
|50     1500/5893/788     1200/5000/1.50        1500/10894/1.42
|_________________________________________________________________________
|100    2000/5680/760     2000/5080/1.50        3500/11400/1.49
|_________________________________________________________________________
|200    5000/5400/733     5000/5100/1.50        5000/10400/1.40
|_________________________________________________________________________
|500   			           
|_________________________________________________________________________
|1000
|_________________________________________________________________________

   friendstimeline_Get   friendsinfo_Get     unreadnum
|_________________________________________________________________________
|30(ms) 200/1778/0.84(MB) 500/4432/0.71(MB)  1000/9591/1.50(MB)  
|_________________________________________________________________________
|50     500/2541/1.18     1200/6100/0.95     1500/10307/1.62
|_________________________________________________________________________
|100    1500/3443/1.60    2200/6472/1.00     2500/12485/1.97
|_________________________________________________________________________
|200    3000/3473/1.61    5000/6608/1.02     5000/12819/2.03
|_________________________________________________________________________
|500    5000/3457/1.60    
|_________________________________________________________________________
|1000
|_________________________________________________________________________
注:GET请求均命中MC的case下测试
服务器状态:0.33 0.25 0.14
除并发量小于1000的小压力case,其余CPU双核均跑满
mysql性能压测:sysbench

量级评估:

从SLA的角度考虑,针对测试服务器,推荐的量级分别是:
1.获取好友动态:3000r/s左右的请求量;
2.获取个人动态:5000r/s左右的请求量;
3.增删个人动态:5000r/s左右的请求量;
4.获取好友关系:6000r/s左右的请求量;
5.增删好友关系:10000r/s左右的请求量;
6.获取未读数:10000r/s左右的请求量;

可优化点:

压测发现,由于使用的队列处理post请求,瓶颈点在于CPU,可以想到的原因主要是consumer消费以及系统本身的处理逻辑;此外,mysql的性能由于单个消费者消费过慢,并没有充分发挥出来。因此磁盘IO不作为瓶颈点考虑,而将消费者线程作为可优化点考虑。
从性能上考虑,可优化的地方包括增加消费者线程,mysql批量写入等;
从可用性上出发,需要增加写失败重试逻辑;
从用户体验上出发,在变更好友关系时,针对push和pull的方式需要做更多针对上的考虑,本次只是以其中一种类型的用户体验优化考虑,参看聚合策略的重要假设。

Github

https://github.com/NewRegin/feed.git

About

高可用feed流系统


Languages

Language:Go 99.1%Language:Shell 0.9%