海量统计数据的分布式MySQL集群——MyFOX

8,939 views

Published on

Published in: Technology
1 Comment
15 Likes
Statistics
Notes
No Downloads
Views
Total views
8,939
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
261
Comments
1
Likes
15
Embeds 0
No embeds

No notes for slide

海量统计数据的分布式MySQL集群——MyFOX

  1. 1. 海量统计数据的分布式MySQL集群<br />
  2. 2. 关于我自己<br />朋春:<br /><ul><li>2006年,百度
  3. 3. 2010年,淘宝,数据产品化团队
  4. 4. PHPER,VI党</li></li></ul><li>关于MyFOX—概况<br />目前:<br /><ul><li>8个节点,16台MySQL
  5. 5. 300 * 12 * 0.5 * 8 = 14T存储空间
  6. 6. 每天超过4亿条记录
  7. 7. 每天40G原始数据</li></li></ul><li>关于MyFOX—成本<br /><ul><li>4W * (16 + 2) = 72W
  8. 8. 14T存储空间
  9. 9. 30%压缩率
  10. 10. 72 / 14 * 0.3 = 1.54W / T</li></li></ul><li>关于MyFOX—速度<br />
  11. 11. 我们将要讨论什么?<br /><ul><li>背景
  12. 12. 架构与数据装载
  13. 13. 数据的透明查询
  14. 14. 一些小故事</li></li></ul><li>背景<br />
  15. 15. 数据量<br />
  16. 16. 成本(Oracle)<br />
  17. 17. 我们需要什么?<br /><ul><li>去O
  18. 18. SQL查询
  19. 19. 海量存储
  20. 20. 可横向扩展
  21. 21. 对应用透明
  22. 22. 兼顾性能</li></li></ul><li>选择?<br />
  23. 23. 应用特点—写入<br /><ul><li>离线数据
  24. 24. 批量写入(4亿+ )
  25. 25. 分表分库规则</li></li></ul><li>应用特点—查询<br />SELECT b.brand_nameAS f0, FLOOR(SUM(p.gmv_trade_amt)) AS f1, FLOOR(SUM(p.gmv_trade_amt)) AS f11, SUM(p.gmv_auction_num) AS f2, <br /> SUM(p.gmv_winner_num) AS f3 <br />FROM rpt_brand_info_dAS p<br />INNER JOIN dim_brand AS b<br /> ON b.brand_id = p.brand_id<br />WHERE p.category_id in ('1101') <br />ANDp.thedate <= '2011-03-10' <br />ANDp.thedate >= '2011-03-08' <br />GROUP BY b.brand_name<br />ORDER BY SUM(p.gmv_trade_amt) DESC LIMIT 1500<br /><ul><li>大量聚合函数
  26. 26. JOIN
  27. 27. 可缓存</li></li></ul><li>我们需要<br />数据<br />魔方<br />云梯<br />MyFOX<br />数据查询<br />数据装载<br />存储集群<br />MyISAM<br />
  28. 28. 小结<br />MyFOX是什么?<br /><ul><li>中间层
  29. 29. 负责
  30. 30. 数据装载
  31. 31. 透明查询</li></li></ul><li>架构与数据装载<br />
  32. 32. 部署架构<br />M<br />路由信息库<br />MyFOX(虚拟机)<br />S<br />热节点(MySQL)<br />冷节点(MySQL)<br />15k SAS硬盘,300G * 12,8节点<br />7.2k SATA硬盘,1T * 12,8节点<br />MySQL<br />MySQL<br />MySQL<br />MySQL<br />MySQL<br />=<br />=<br />=<br />
  33. 33. 数据装载<br />切分<br />装载<br />云梯<br />OLAP集群<br />中间层<br />路由表<br />
  34. 34. 切分规则—冗余复制<br /><ul><li>每个机器上都保存一份完整的数据
  35. 35. 适用于
  36. 36. 小表
  37. 37. 被频繁访问
  38. 38. 可能被JOIN</li></li></ul><li>切分规则—字段哈希<br /><ul><li>按给定字段的值分区
  39. 39. 每个节点上保存一个分区</li></li></ul><li>切分规则—条目切割<br /><ul><li>按字段哈希分区
  40. 40. 然后每N行切片
  41. 41. 切片装桶</li></li></ul><li>示例:条目切割<br /><ul><li>分区
  42. 42. 切片
  43. 43. 阈值(200W)
  44. 44. 上浮动(5%)
  45. 45. 装桶
  46. 46. 一个桶装满再开新桶
  47. 47. “桶”即实际的物理表</li></ul>rpt_topranks_v3^Athedate=20100816, toprank_id=11^A2090000<br />rpt_topranks_v3^Athedate=20100816, toprank_id=12^A2120000<br />rpt_topranks_v3^Athedate=20100816, toprank_id=13^A760000<br />rpt_topranks_v3^Athedate=20100816, toprank_id=14^A289<br />thedate=20100816, toprank_id=11^A2090000<br />thedate=20100816, toprank_id=12^A2000000<br />thedate=20100816, toprank_id=12^A120000<br />thedate=20100816, toprank_id=13^A760000<br />thedate=20100816, toprank_id=14^A289<br />thedate=20100816, toprank_id=11^A2090000<br />thedate=20100816, toprank_id=14^A289<br />thedate=20100816, toprank_id=12^A2000000<br />thedate=20100816, toprank_id=13^A760000<br />thedate=20100816, toprank_id=12^A120000<br />rpt_topranks_v3_0.t_a10_22<br />
  48. 48. 数据装载<br /><ul><li>接口异步化
  49. 49. LOAD DATA LOCAL INFILE …
  50. 50. 节点之间并行
  51. 51. 节点内轮流翻转</li></li></ul><li>数据装载—原子性<br /><ul><li>全量数据(REPLACE)
  52. 52. Begin:CREATE TABLE table_$pid ...
  53. 53. Query: LOAD DATA … INTO TABLE table_$pid ...
  54. 54. Commit:RENAME TABLE table TO table_bak, table_$pid TO table
  55. 55. Rollback: DROP TABLE table_$pid</li></li></ul><li>数据装载—原子性<br /><ul><li>增量数据(APPEND)
  56. 56. Begin: SELECT MAX(autokid) FROM table
  57. 57. Query: LOAD DATA … INTO TABLE table ...
  58. 58. Commit:DELETE FROM table WHERE autokid <= ? AND 路由值
  59. 59. Rollback:DELETE FROM TABLE table WHERE autokid > ?</li></li></ul><li>路由值<br /><ul><li>稀疏索引
  60. 60. KEY -> VALUE
  61. 61. 枚举特征</li></ul>mysql > SELECT route_value, node, path, hittimeFROM new_route_info_10 LIMIT 1G<br />*********************** 1 row **************************<br />route_value : rpt_topranks_v3:{“thedate”:20110308,”toprank_id”:110}<br />node : 7<br />path : rpt_topranks_v3_5.t_9e_438<br />hittime : 2011-03-09 02:27:33<br />
  62. 62. 思考<br /><ul><li>如何纵向扩容(增加副本)?
  63. 63. 如何横向扩容(增加节点)?</li></li></ul><li>数据迁移<br />DB1<br /><ul><li>横向扩容
  64. 64. 冷数据迁出
  65. 65. 好钢用在刀刃上
  66. 66. 内存硬盘比
  67. 67. 方法
  68. 68. scp文件
  69. 69. SELECT TO OUTFILE,LOAD DATA INFILE …
  70. 70. federated</li></ul>APP<br />DB2<br />
  71. 71. 压缩存储<br /><ul><li>非常适合压缩
  72. 72. 方法
  73. 73. myisampack
  74. 74. myisamchk
  75. 75. 结果
  76. 76. 压缩率29.84%
  77. 77. 查询慢10%</li></li></ul><li>监控预警<br /><ul><li>装载队列
  78. 78. 队列滞塞
  79. 79. 装载错误
  80. 80. 数据一致性
  81. 81. COUNT
  82. 82. 抽样checksum
  83. 83. 数据均衡性
  84. 84. 超大分片</li></li></ul><li>小结<br />
  85. 85. 数据的透明查询<br />
  86. 86. 瞧瞧这个SQL:<br />SELECT IF(INSTR(f.keyword,' ') > 0, UPPER(TRIM(f.keyword)), CONCAT(b.brand_name,' ',UPPER(TRIM(f.keyword)))) AS f0,<br />SUM(f.search_num) AS f1,<br />SUM(f.uv) AS f2, <br /> ROUND(SUM(f.search_num) / SUM(f.uv), 2) AS f3,<br /> AVG(f.uv) AS f4 <br />FROM dm_fact_keyword_brand_d f<br />INNER JOIN dim_brand b ON f.keyword_brand_id = b.brand_id<br />WHERE f.keyword_type_id = 1 AND f.keyword != '' <br /> AND keyword_cat_id IN ('50002535') <br /> AND thedate <= '2011-03-10' <br /> AND thedate >= '2011-03-08' <br />GROUP BY f0<br />ORDER BY SUM(f.search_num) DESC LIMIT 0, 1500<br />
  87. 87. 数据查询<br />缓存<br />路由层<br />SQL解析<br />APC<br />语义理解<br />查询路由<br />字段改写<br />分片SQL<br />计算规则<br />查询层<br />取分片数据<br />缓存<br />计算层<br />结果合并<br />
  88. 88. 路由层—语义理解<br />WHEREthedate <= '2011-03-10' <br /> AND thedate > '2011-03-07'<br /> AND toprank_id IN (2, 3)<br />AND aa NOT LIKE 'lalala%'<br />toprank_id<br />thedate<br />thedate:20110308,toprank_id:2<br />
  89. 89. 路由层—语义理解<br /><ul><li>多表JOIN如何处理?</li></li></ul><li>路由层—字段改写<br />SELECT a AS f0,<br /> SUM(f.search_num) AS f1,<br />SUM(f.uv) AS f2, <br /> ROUND(SUM(f.search_num) / SUM(f.uv), 2) AS f3,<br /> AVG(f.uv) AS f4 <br /><ul><li>AVG(aa)
  90. 90. 1 + SUM(aa)
  91. 91. SELECT a FROM … ORDER BY b
  92. 92. 重复查询列</li></li></ul><li>查询层—取分片数据<br /><ul><li>困难
  93. 93. 分片SQL很多
  94. 94. PHP单线程
  95. 95. MySQL查询阻塞
  96. 96. 异步并发
  97. 97. nginx + drizzle
  98. 98. http协议,curl_multi_get
  99. 99. JSON格式</li></ul>查询SQL <br />nginx<br />drizzle<br />mysql<br />
  100. 100. 查询层—数据缓存<br /><ul><li>缓存哪部分数据?
  101. 101. 最终结果
  102. 102. 分片数据</li></ul>缓存<br />查询层<br />取分片数据<br />缓存<br />计算层<br />结果合并<br />
  103. 103. 计算层—无聚合字段<br /><ul><li>分片是有序的
  104. 104. 二路归并
  105. 105. LIMIT运算</li></li></ul><li>计算层—有聚合字段<br /><ul><li>分片是有序的
  106. 106. 聚合规则处理(SUM, MAX, MIN, DISTINCT)
  107. 107. 表达式求值
  108. 108. 堆排序
  109. 109. LIMIT运算</li></li></ul><li>我压力很大<br />SELECT ...<br />FROM ...<br />ORDER BY SUM(aa) DESC LIMIT 0, 10<br />LIMIT 0, 1000 <br />SELECT ...<br />FROM ...<br />ORDER BY AVG(aa) DESC LIMIT 0, 10<br />*#?&*)(*)^&*%^&%& <br />
  110. 110. 小结<br /><ul><li>三层
  111. 111. 缓存策略
  112. 112. Alpha = 80:
  113. 113. 跨节点JOIN
  114. 114. COUNT(DISTINCT …)
  115. 115. OR逻辑
  116. 116. 子查询、UNION查询
  117. 117. 不可穷举的路由字段</li></li></ul><li>一些小故事<br />
  118. 118. 小流量实验<br />
  119. 119. 未经过QA的产品<br /><ul><li>黑盒测试不好搞
  120. 120. 单元测试
  121. 121. 8k行程序,10k行测试代码
  122. 122. 88.1%测试覆盖率</li></li></ul><li>缓存失效<br />
  123. 123. 索引使用<br />SELECTobject_idAS id … <br />FROM rpt_topranks_v3<br />WHERE partition_by1 = 1101<br />SELECTobject_idAS id … <br />FROM rpt_topranks_v3<br />WHEREpartition_by1 + 0 > ? <br /> AND partition_by1 + 0 < ?<br />
  124. 124. 谢谢各位<br />朋春<br />pengchun@taobao.com<br />

×