AirJD 焦点
AirJD

没有录音文件
00:00/00:00
加收藏

微架构设计之微博计数器服务 by 杜传赢

发布者 microservice
发布于 1443403207144  浏览 7555 关键词 微服务, Redis, MySQL 
分享到

第1页

微架构设计之 微博计数器服务

杜传赢 @cydu chuanying@staff.sina.com.cn

http://weibo.com/cydu http://blog.cydu.net/



第2页

• 新浪微博 -- 中国最具影响力的微博产品 • 信息实时聚合平台 • 数千个消息源的聚合 & 千万级的消息接收者 • 巨大的数据量 • 微博数据量: 千亿级 • 高峰微博增加量: 每秒3万条(春节) • 巨大的访问量 • 每天动态API请求量超过300亿次 • 每秒数百万次的服务调用(包括内部调用)



第3页

微博计数器服务

未读计数 用户计数

微博计数



第4页

第⼀一版 从无到有

架构挑战: 开发速度



第5页

2009.7月



正式立项



2009.8.28



新浪微博

上线

t.sina.com.cn



第6页

SELECT count(mid) FROM Status WHERE uid = 888

• mid => 每条微博的唯⼀一标识(64bit) • uid => 每位用户的唯⼀一标识(64bit)



第7页

实时计算

SELECT count(mid) FROM Status WHERE uid = 888

• mid => 每条微博的唯⼀一标识(64bit) • uid => 每位用户的唯⼀一标识(64bit)



第8页

计数索引

SELECT repost_count, comment_count FROM Status_count WHERE mid = 888

• 微博变多: 实时Count代价高 • 流量增大: Feed页出微博计数 • 数据⼀一致性? 如何更新?



第9页

Scale UP



硬件加速



client app



libmysql



Applications



libhsclient



mysqld



Listener for libmysql



SQL Layer



Handlersocket Plugin



Handler Interface



Innodb



MyISAM



Other storage engines …



MySQL HandleSocket



• 摩尔定律: 每隔18个月, 性能提升⼀一倍! • Jim Gray: • Tape is dead, disk is tape, flash is disk, ram locality is king



第10页

小结: 切忌过度优化



数据量(1000亿)



先建设, 再优化



开发速度



访问量(100W rps)



第11页

第二版(1) 从小到大

架构挑战1: 访问量



第12页

weibo.com独立访问量已是国内 第 六 大网站



第13页

突发热点更新



第14页

异步更新

ID分配器 + 消息队列



• •MessageQueue



更新消息队列 消息更新异步化



• 削峰填谷



• 避免高峰时数据丢失



第15页

批量更新

UPDATE Status_count SET repost_count = repost_count +1 WHERE mid = 888;

UPDATE Status_count SET repost_count = repost_count +1 WHERE mid = 888;

UPDATE Status_count SET repost_count = repost_count +1 WHERE mid = 888;

Update Status_count SET repost_count =

repost_count +3 WHERE mid = 888;

• 批量更新: • 取多条消息, Merge后再更新, 降低写压力



第16页

大量读挑战

超过15倍的放大效应!

statuses/home_timeline get mid list

get mid content get mid content get mid content

get mid counter get mid counter get mid counter



第17页

缓存优化



Client



Client



MC



Mysql



Mysql



• 读写比 && 命中率 • Cache效率的关键 • “Cache就像万金油, 哪痒你就抹哪, 但是千万记得脱了

皮鞋再抹!” -- by 朱聪



第18页

Client Mysql



MC



MultiGet



• MultiGet Hole ? More Machines != More Capacity

• Evections (缓存踢出)



第19页

第二版(2) 从小到大

架构挑战1: 访问量

从少到多 架构挑战2: 数据量



第20页

用户数(单位:千)



400,000



300,000



300,000 250,000



140,000 2010,090.10125001,000.100 2011.04 2011.10



2012.03



368,000 2012.8



400,000 2012.11



200,000 100,000 0



第21页

Partition 1

uid fans_num 20 ... 22 ... 24 ...



Partition 2

uid fans_num 21 ... 23 ... 25 ...



水平扩展

Partition by primary key 用户类数据



Partition by time/mid 微博类数据



Partition 2 Partition 1



mid 24 23

mid 22 21



repost_num ... ...

repost_num ... ...



第22页

Partition 4 Partition 3



mid 34 32

mid 33 31



repost_num ... ...

repost_num ... ...



Partition 2 Partition 1



mid 24 22

mid 23 21



repost_num ... ...

repost_num ... ...



两层划分

Partition by mid + time 微博类数据



第23页

小结: 见招拆招, 快速迭代



数据量(1000亿)



认真用好成熟解决方案



数据量 访问量

+ 开发速度

访问量(100W rps)



第24页

第二版的问题: Pain Driven Development

• 数据量越来越大, 分表越来越频繁/复杂 • 操作更复杂, 风险大, 成本也越来越高

• 访问量越来越大, Cache命中率如何提升? • 内存使用效率低下(Eg: 字符串,0数据,旧数据) • 副本过多时, 数据更新代价高 • 完全依赖内存, 存储成本高

• 高可用的要求 • 机器故障时的快速恢复能力及最低的线上影响

• 越来越复杂的需求带来的业务挑战



第25页

第三版(1) 由粗到细

架构挑战1: 高可用



第26页

REmote DIctionary Server

by @antirez

• 成熟 : 社区活跃 + 生产环境使用多 • 高速 : 全内存, 性能优异 + 数据镜像,快速恢复 • 简单 : 友好的DSL接口 + 丰富的数据结构 • 可控 : 架构简洁 + 代码量不大



第27页

AOF 0



RDB+AOF









RDB 0 off: 1989



RDB 1 off: 4698



• RDB + AOF 同步模式



• 定期 bgsave 生成RDB



• 避免AOF Load过慢



• syncfrom aof offset



• 避免从头Sync



• 热升级



RDB 2 off: 6489

@果爸果爸 / @Jokea



第28页

Web Service (Update)

IDC 0:

Mysql Cluster



Web Service (Update)

Message Queue

Mysql Cluster



多机房Web Service (Update)

IDC : 2

Mysql Cluster



Transformer

Redis



Transformer

Redis



Transformer

Redis



Web Service (Query)



Web Service (Query)



Web Service (Query)



第29页

A. 正常服务

B. 降级写服务

• 写延迟(堵队列) • 拒绝写(事后修数据)

C. 降级读服务

• 只读新数据(老数据出0) • 新数据部分可 • 全部出默认值

D. 服务读写均不可用

• 不出计数



灾难降级



第30页

• 最终⼀一致性! • Randomkey check • RDB CRC check • Digest check (write crc) • 定期全量sync • 数据基准修复



数据一致



第31页

第三版 (2) 由粗到细

架构挑战1: 高可用

架构挑战2: 低成本



第32页

关键字域

64bit mid



h(mid 14) h(mid 69)



h(mid 45) h(mid 25)



h(mid 92)



h(mid 78)



数据结构



14 45





9|0 3|9

69 7 | 2



0|5



78 25

2|0 9|1



传统的Hash表大量的指针开销



第33页

开放寻址Hash节省内存 mid



repost_num comment_num



h(k,i) = (h1(k)+i*h2(k)) % m







struct item { int64_t mid; u_short repost_num; u_short comment_num;

};

• Value的长度短于指针长度 • 开放寻址Hash表(双重散列) • 以节省指针存储



69 45



72 39



第34页

E[X]: 期望探查次数 α: 装载因子



冲突key数占总数据



该图表由@果爸果爸 分析微博计数线上真实数据得出

装载因子



冲突次数(<=)



第35页

数据压缩

• repost_num & comment_num • 32bit *2 => 16 bit * 2

• mid • string => int64_t

• Value block compress by @吴廷彬 • Value定长块实时压缩和解压(对上层透明)

• Key prefix compress by @吴廷彬 @drdrxp • key基本有序后, 64 bit的key相同前缀(Eg: 高32位)提取



第36页

还有几个小问题

• repost_num 和 comment_num 只用16位存储,超 过65535的转发数和评论数怎么办?

• 采用开放寻址仍会冲突, 在极端情况下, 冲突加大影 响性能怎么办? 会有潜在的”死循环”吗?

• 内存不够怎么办? (尽管已经精简使用,但数据量仍很 夸张)

• 选取哪些Key放到内存? 为什么不用LRU? • 用户突然大量访问老的微博怎么办?

• Eg: “转发我的第⼀一条微博”, “去年今日的我”



第37页

Weibo Counter Service新架构



Increase with id Split array by range



900 996 Block 10 910 999



...



310 310 Block 3 330 400



201 280 Block 2 250 310



Memory SSD Disk



Sort Dump



100 110 Sorted 1 160 201



0 30 Sorted 0 80 100



Range Index

Cold Data Buffer

0 46 Extend Block 98 1000 0 89 Aux Block 64 1000 0 19 Cold Block 85 201

Index 1 Index 0



310 Unsorted 3 330 280 Unsorted 2 250



Rdb



第38页

第三版(3) 由粗到细

架构挑战1: 高可用

架构挑战2: 低成本

架构挑战3: 多变需求



第39页

• 微博计数 • 评论数 / 转发数 • 表态数 • 喜欢数 / 开心数 / 吃惊数 / 悲伤数 / 愤怒数

• 用户计数 • 关注数 / 粉丝数 / 好友数 / 微博数 / 原创微博数 ...

• 其他计数 • 未读数 / 提醒数 • 链接点击数 / 收藏数 • 会员数 / 应用计数 / 管理类计数...



第40页

• add counter weibo



服务化支持



• add column weibo mid hint=64 max=64 primarykey



• add column weibo comment hint=16 max=32 default=0 suffix=cntcm



• add column weibo repost hint=16 max=32 suffix=cntrn



• add column weibo attitude hint=8 max=32 suffix=cntan



• set 19089006004.cntcm 987654



• incr 888888.cntrn



• get 123456.cntan



• del 19089006004



第41页

• 每个计数的统计



统计支持



• 容量 / 目前使用量



• getCount / setCount / missCount / hitCount



• errorCount / fullCount / collisionCount



• 计数中每个列的统计



• 计数中每个Table的统计



• 慢查询的统计



对业务需求,业务状态,服务状态,架构缺 陷等更好的理解才能支持更好的决策!



第42页

小结: 量体裁衣, 精益求精!



第43页

小结: 量体裁衣, 精益求精



数据量(1000亿)



架构没有最好, 只有合适和更优 高可用 服务化



数据量 访问量

+

开发速度



低成本



访问量(100W rps)



第44页

Q&A

• 感谢各位, 欢迎各种意见和建议, 当然也包括拍砖!

• 本文中提及计数服务相关设计和实现主要贡献者: • @微博平台架构 @果爸果爸 @LinuxQueue @cydu • 之前的设计总结和讨论见Blog: • http://blog.cydu.net/2012/09/weibo-counter-service-design-2.html



支持文件格式:*.pdf
上传最后阶段需要进行在线转换,可能需要1~2分钟,请耐心等待。