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


微架构设计之 微博计数器服务 杜传赢 @cydu chuanying@staff.sina.com.cn http://weibo.com/cydu http://blog.cydu.net/ • 新浪微博 -- 中国最具影响力的微博产品 • 信息实时聚合平台 • 数千个消息源的聚合 & 千万级的消息接收者 • 巨大的数据量 • 微博数据量 : 千亿级 • 高峰微博增加量 : 每秒 3万条 (春节 ) • 巨大的访问量 • 每天动态 API请求量超过 300亿次 • 每秒数百万次的服务调用 (包括内部调用 ) 微博计数器服务 微博计数 用户计数 未读计数 第⼀版 架构挑战: 开发速度 从无到有 2009.7月 新浪微博 上线 t.sina.com.cn 2009.8.28 正式立项 • mid => 每条微博的唯⼀标识 (64bit) • uid => 每位用户的唯⼀标识 (64bit) SELECT count(mid) FROM Status WHERE uid = 888 • mid => 每条微博的唯⼀标识 (64bit) • uid => 每位用户的唯⼀标识 (64bit) SELECT count(mid) FROM Status WHERE uid = 888 实时计算 计数索引 • 微博变多 : 实时 Count代价高 • 流量增大 : Feed页出微博计数 • 数据⼀致性 ? 如何更新 ? SELECT repost_count, comment_count FROM Status_count WHERE mid = 888 硬件加速 Handler Interface Innodb MyISAM Other storage engines … SQL Layer Handlersocket Plugin Listener for libmysql libmysql libhsclient Applications mysqld client app MySQL HandleSocket • 摩尔定律 : 每隔 18个月 , 性能提升⼀倍 ! • Jim Gray: • Tape is dead, disk is tape, flash is disk, ram locality is king Scale UP 访问量 (100W rps) 数据量 (1000亿 ) 开发速度 小结 : 切忌过度优化 先建设 , 再优化 第二版 (1) 架构挑战1: 访问量 从小到大 weibo.com独立访问量已是国内 第 六 大网站 突发热点更新 • 更新消息队列 • 消息更新异步化 • 削峰填谷 • 避免高峰时数据丢失 异步更新 MessageQueue ID分配器 + 消息队列 • 批量更新 : • 取多条消息 , Merge后再更新 , 降低写压力 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; 批量更新 大量读挑战 statuses/home_timeline get mid list get mid counter get mid counter get mid counter get mid content get mid content get mid content 超过 15倍的放大效应 ! 缓存优化 • 读写比 && 命中率 • Cache效率的关键 • “Cache就像万金油 , 哪痒你就抹哪 , 但是千万记得脱了 皮鞋再抹! ” -- by 朱聪 Client Mysql MC Client Mysql MultiGet • MultiGet Hole ? More Machines != More Capacity • Evections (缓存踢出 ) MC Client Mysql 第二版 (2) 架构挑战1: 访问量 从小到大 架构挑战2: 数据量 从少到多 0 100,000 200,000 300,000 400,000 1,000 50,000 140,000 250,000 300,000 368,000 400,000 2009.112010.10 2011.04 2011.10 2012.03 2012.8 2012.11 用户数(单位:千) 水平扩展 uid fans_num 20 ... 22 ... 24 ... uid fans_num 21 ... 23 ... 25 ... Partition 1 Partition 2 Partition by primary key 用户类数据 mid repost_num 24 ... 23 ... mid repost_num 22 ... 21 ... Partition 1 Partition 2Partition by time/mid 微博类数据 两层划分 Partition by mid + time 微博类数据 mid repost_num 34 ... 32 ... mid repost_num 33 ... 31 ... Partition 3 Partition 4 mid repost_num 24 ... 22 ... mid repost_num 23 ... 21 ... Partition 1 Partition 2 访问量 (100W rps) 数据量 (1000亿 ) 开发速度 访问量 数据量 + 小结 : 见招拆招 , 快速迭代 认真用好成熟解决方案 • 数据量越来越大 , 分表越来越频繁 /复杂 • 操作更复杂 , 风险大 , 成本也越来越高 • 访问量越来越大 , Cache命中率如何提升 ? • 内存使用效率低下 (Eg: 字符串 ,0数据 ,旧数据 ) • 副本过多时 , 数据更新代价高 • 完全依赖内存 , 存储成本高 • 高可用的要求 • 机器故障时的快速恢复能力及最低的线上影响 • 越来越复杂的需求带来的业务挑战 第二版的问题 : Pain Driven Development 第三版 (1) 架构挑战1: 高可用 由粗到细 REmote DIctionary Server by @antirez • 成熟 : 社区活跃 + 生产环境使用多 • 高速 : 全内存 , 性能优异 + 数据镜像 ,快速恢复 • 简单 : 友好的 DSL接口 + 丰富的数据结构 • 可控 : 架构简洁 + 代码量不大 RDB+AOF • RDB + AOF 同步模式 • 定期 bgsave 生成 RDB • 避免 AOF Load过慢 • syncfrom aof offset • 避免从头 Sync • 热升级 0 2000 4000 6000AOF RDB 0 off: 1989 RDB 1 off: 4698 RDB 2 off: 6489 @果爸果爸 / @Jokea Web Service (Update) Redis Mysql Cluster Transformer Web Service (Query) IDC 0: Web Service (Update) Redis Mysql Cluster Transformer Web Service (Query) Web Service (Update) Redis Mysql Cluster Transformer Web Service (Query) IDC : 2Message Queue 多机房 灾难降级A. 正常服务 B. 降级写服务 • 写延迟 (堵队列 ) • 拒绝写 (事后修数据 ) C. 降级读服务 • 只读新数据 (老数据出 0) • 新数据部分可 • 全部出默认值 D. 服务读写均不可用 • 不出计数 数据一致 • 最终⼀致性 ! • Randomkey check • RDB CRC check • Digest check (write crc) • 定期全量 sync • 数据基准修复 第三版 (2) 架构挑战1: 高可用 由粗到细 架构挑战2: 低成本 数据结构 关键字域 64bit mid h(mid 14) h(mid 25)h(mid 45) h(mid 78)h(mid 92) h(mid 69) 14 69 78 45 92 25 传统的 Hash表大量的指针开销 9 | 0 3 | 9 0 | 5 7 | 2 2 | 0 9 | 1 14 69 45 78 92 25 9 7 3 2 0 9 0 2 9 0 5 1 mid repost_num comment_num struct item { int64_t mid; u_short repost_num; u_short comment_num; }; • Value的长度短于指针长度 • 开放寻址 Hash表 (双重散列 ) • 以节省指针存储 h(k,i) = (h1(k)+i*h2(k)) % m 开放寻址 Hash节省内存 冲突次数 (<=) 冲突 key数占总数据 装载因子 该图表由 @果爸果爸 分析微博计数线上真实数据得出 E[X]: 期望探查次数 α: 装载因子 数据压缩 • 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位 )提取 还有几个小问题 • repost_num 和 comment_num 只用 16位存储 ,超 过 65535的转发数和评论数怎么办 ? • 采用开放寻址仍会冲突 , 在极端情况下 , 冲突加大影 响性能怎么办 ? 会有潜在的 ”死循环 ”吗 ? • 内存不够怎么办 ? (尽管已经精简使用 ,但数据量仍很 夸张 ) • 选取哪些 Key放到内存 ? 为什么不用 LRU? • 用户突然大量访问老的微博怎么办 ? • Eg: “转发我的第⼀条微博 ”, “去年今日的我 ” Weibo Counter Service新架构 Aux Block0 10006489 Sorted 1100 201 Sorted 00 1008030 160110 Block 3310 400 Block 2201 310 ... Block 10900 999 250280 330310 910996 SSD Disk Memory Index 1 Index 0 Sort Dump Unsorted 2280 250 Unsorted 3310 330 Rdb Increase with id Split array by range Cold Data Buffer Range Index Extend Block0 10009846 Cold Block0 2018519 第三版 (3) 架构挑战1: 高可用 由粗到细 架构挑战2: 低成本 架构挑战3: 多变需求 • 微博计数 • 评论数 / 转发数 • 表态数 • 喜欢数 / 开心数 / 吃惊数 / 悲伤数 / 愤怒数 • 用户计数 • 关注数 / 粉丝数 / 好友数 / 微博数 / 原创微博数 ... • 其他计数 • 未读数 / 提醒数 • 链接点击数 / 收藏数 • 会员数 / 应用计数 / 管理类计数 ... • 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 服务化支持 • 每个计数的统计 • 容量 / 目前使用量 • getCount / setCount / missCount / hitCount • errorCount / fullCount / collisionCount • 计数中每个列的统计 • 计数中每个 Table的统计 • 慢查询的统计 统计支持 对业务需求 ,业务状态 ,服务状态 ,架构缺 陷等更好的理解才能支持更好的决策 ! 小结 : 量体裁衣 , 精益求精 ! 访问量 (100W rps) 数据量 (1000亿 ) 开发速度 访问量 数据量 + 小结 : 量体裁衣 , 精益求精 架构没有最好 , 只有合适和更优 高可用 低成本 服务化 Q&A • 感谢各位 , 欢迎各种意见和建议 , 当然也包括拍砖 ! • 本文中提及计数服务相关设计和实现主要贡献者 : • @微博平台架构 @果爸果爸 @LinuxQueue @cydu • 之前的设计总结和讨论见 Blog: • http://blog.cydu.net/2012/09/weibo-counter-service-design-2.html
还剩43页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

wwwxd

贡献于2015-11-01

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf