从1到100000000
   从分布式存储谈大型网站的架构设计

               孙梦石
           中山大学Web2.0俱乐部
前端?后端?

• 互动:你觉着什么是web前端,什么是web
  后端?
一个简单的任务

• 它是一个博客
• 它能发文章
• 它能显示文章

• 你需要多久来做它?是不是很容易?
最简单的架构


 PHP
 Apache



 MySQL
某一天,你火了

• 你成了名人了
• 每天有几百万人来访问你的博客

•   问题来了
•   很慢
•   很卡
•   挂了,打不开
现在的特点是?

• 数据规模:很小
• 访问量:
 – 主键查询巨大
 – 更新很少
• 实时性:不在乎更新的延时
• 可靠性:99.99%可用
你会怎么办?

• 最简单的方法,先把web服务器和数据库服
  务器分开。
        PHP
        Apache


         MySQL
你会怎么办?

•   优化代码?
•   调优服务器?
•   每天做备份?
•   加内存加CPU加硬盘,使用价值几万的NB服
    务器?

• 还是,使用廉价的服务器组成集群?
单机到分布式的好处

• 廉价
• 扩展性
• 容灾(据说陈总只做了raid?)
 – 断电了?
 – 磁盘坏了?
 – 机房起火了?
 – 广州没了?
那么到底应该怎么做?

• 互动:回顾下一次HTTP请求的流程


 Request

           Apache

                    MySql
HTTP服务器集群

• 各种服务器都带集群功能
• 关键在哪里?
 – 谁来决定由哪台服务器进行处理
 – Session怎么办
 – 有状态 or 无状态
互动:Session是什么?

•   为啥说数据库狠重要
•   你知道PHP中的Session如何实现的吗?
•   存储结构是什么样的?如何进行查找的?
•   多台机器之间的Session如何进行同步?
•   为啥要区分有状态无状态?
一个简单的数据库集群

• MySql Cluster听说过吗?
• 你认为它是做什么的?
Master/Slave
一致性的问题

• 互动:神马是一致性?

• 我们一定要一致性吗?
 – 同步的开销


• 折中的选择
 – 非一致
 – 最终一致
分布式架构雏形初现

PHP PHP
         PHP
Apache
     Apache
         Apache
         Read                Read
                Read/Write

           复制                复制
 MySQL            MySQL
                                    MySQL
 Slave            Master
                                    Slave
其他也很有用的方法

•   数据小,全部放内存
•   页面静态化
•   CDN(内容分发网络)
•   。。。
独乐不如众乐

• 现在不止是一个用户了
• 有用户表和日志表

• 问题来了:
• 数据库的大小随着用户的增多开始急剧上
  升,怎么办?
水平切分 & 垂直切分

User:
id        name          email
1         chenxianlan   chen@sysu.edu.cn
2         ouyangxuan    ou@sysu.edu.cn
3         wuyuhui       wu@sysu.edu.cn
4         liying        li@sysu.edu.cn
水平切分

User_00:
id         name          email
1          chenxianlan   chen@sysu.edu.cn
2          ouyangxuan    ou@sysu.edu.cn




User_01:
id         name          email
3          wuyuhui       wu@sysu.edu.cn
4          liying        li@sysu.edu.cn
垂直切分

User:                  User_email:
id      name           user_id   email
1       chenxianlan    1         chen@sysu.edu.cn
2       ouyangxuan     2         ou@sysu.edu.cn
3       wuyuhui        3         wu@sysu.edu.cn
4       liying         4         li@sysu.edu.cn
分开容易,合并难

• 垂直切分如何查询

• 原查询:
• select * from user where id = 1;
• 切分后:
• select * from user join user_email on id=user_id where id=1;


• 互动:这样做会有什么问题?
重点:水平切分的合并

• 依旧对于查询:
• select * from user where id = 1;

• 我们要查的数据在哪?
• id=1的数据在哪?在user_00里,还是
  user_01里?
路由:规则引擎
什么是规则

•   规则就是一个函数f
•   输入是查询条件
•   输出是数据(可能)所在的机器
•   规则也可以说是切分条件
•   如对于user表,切分条件是:
    – id>2的在user_01中,否则在user_00中
路由

• 本质来说还是个查找的过程,和什么很像?
• 于是逻辑结构也就决定了。
 – Hash
    • O(1)效率
    • 不支持范围查询
    • 需要频繁调整数据分布
 – Tree
    •   主要是B-Tree
    •   O(logN)效率
    •   支持范围查询
    •   需要频繁调整节点指针以适应数据分布
路由:Hash

• Hash
  – id % n
  – 最普通的hash
  – 如果id % 3 -> id % 4 总共会有80%的数据发生移
    动,最好情况下是倍分 id % 3 -> id % 6 会有50%
    的数据发生移动
  – 但数据移动本身就是个要了亲命了。
路由:一致性Hash
路由:一致性Hash

• 一致性Hash
 – 可以解决热点问题
 – 但如果热点均匀,加机器基本等于n->2n方案
路由:虚拟节点

• Hash
• –虚拟节点
   Hash       目标节点
   0          0
   1          1
   2          2
   3          3
   4          0
   …
   65535      3
路由:虚拟节点

• Hash
• 虚拟节点
 – 解决一致性hash的问题
 – 解决热点问题,只需要调整对应关系即可
 – 解决n->n+1问题,规则可以规定只移动需要移动的
   数据
 – 但方案相对的复杂一些
 – 一般推荐使用简单方案开始,使用n->2n方案扩容
 – 只有需要的情况下,再考虑平滑的扩展到虚拟节点
   方案即可
路由:B-Tree

• 路由
• B-Tree
  – Hbase !
  – 支持范围查询
  – 但方案过亍复杂,对亍大部分场景来说,引导
    列都是pk一类的单值查询,用树相对复杂。
  – 需要频繁的进行切分和合并操作---region server
    的噩梦。
究竟如何查询?

•   select * from user where id=1;
•   f(id=1)->user_00
•   select * from user_00 where id=1;
•   done!
这么简单吗?

•   id=1 or id=3?
•   ResultSet1:select * from user_00 where id=1;
•   ResultSet2:select * from user_00 where id=3;
•   ResultSet = ResultSet1与ResultSet2合并


• Id>1
• 需要全表扫描…
更多的问题

• Join
  – MySQL只支持同一个库内的join
  – 跨机?跨库?自己去实现
  – 互动:两张表,各有三个子表,Join的方式有
    多少?
• 跨机的Join,尽量避免
• 最好的分布式设计就是没有分布式
更多的问题

• 主键生成
• 各种函数
 – Count()
 – Max()/min()
 – Now()
• 你能用的仅仅是一个子集
• 实验课上写的各种复杂无比的SQL?忘了它
  吧…
插一个话题:Nosql

• 互动:你认为的Nosql是什么
• 关系数据库

            SQL

           关系代数
          和事务引擎

           KV存储
K-V存储

• 所有数据存储的最基本和最底层的结构
 – 不文件系统找指定的数据的作用相同,也是根
   据指定的key查找到对应的数据。
• 回忆数据结构
 – 二分查找
 –树
 – hash
插一个话题:Nosql

• Nosql与sql的核心区别就在于
 – 数据库层是否应该全部的放弃关系代数,将所
   有关系代数都交托给上层进行处理?
 – 事务是否是必须应该被放弃的东西?
 – 上层api,是否应该放弃sql引擎


• 钟摆效应
• 没有银弹!
我们的例子呢?

• 如何做切分?
 – 我们的原则是,尽量保证查询能在单机完成
 – 如果有不可避免的跨机Join,考虑下冗余


• 用户与文章都按照用户id切分,也即一个用
  户的所有文章都在一个节点中。
于是我们的架构变成了

                                           MySQL
                                           Slave

                                MySQL     复制
                                Master
PHP

Apache
    PHP                                    MySQL
                                           Slave

      Apache       R/W   路由
          PHP
                         F(x)
          Apache                            MySQL
                                            Slave

                                 MySQL    复制
                                 Master


                                            MySQL
                                            Slave
数据迁移
• 允许停机不?
 – 允许?可以跳过了
 – 不允许?继续

 –   将增量数据保持在本机
 –   全量复制
 –   本机数据增量复制
 –   部分停写
 –   数据检查
 –   规则切换
 –   删除数据
新的需求,搜索

• 用户多了,好文章也多了
• 想做搜索了。

• 互动:你会怎样做搜索?
 – select * from blog where content like ‘%web%’;
搜索引擎的核心:倒排索引

• 倒排索引(Inverted index)——是一种索引
  方法,被用来存储在全文搜索下某个单词
  在一个文档或者一组文档中的存储位置的
  映射。
倒排表

• 被索引的文本:
 – T0 = "it is what it is"
 – T1 = "what is it"
 – T2 = "it is a banana"
• 得到的倒排索引:
 –    "a": {2}
 –   "banana": {2}
 –   "is": {0, 1, 2}
 –   "it": {0, 1, 2}
 –   "what": {0, 1}
搜索的流程

• 输入Query
  –   what is it
  –   分词得到token
  –   what, is, it
  –   查询得到各token的倒排链
  –   sets=[[0,1], [0,1,2], [0,1,2]]
  –   对各倒排链集合求交集
  –   setsAND(sets) = [0,1]
  –   得到结果
  –   result=[0,1]
倒排索引如何建立

• Lucene
• Mysql插件
• Hadoop

• 但是,我们何时来建立倒排索引?
架构的变化

• 在线系统/离线系统
• 在线做什么?
• 离线做什么?
 – 数据挖掘、数据分析
 – 索引的构建
 – blablabla
新的架构
                                            MySQL
                                            Slave

                                 MySQL     复制
                                 Master
PHP

Apache
    PHP                                     MySQL
                                            Slave

      Apache       R/W    路由
          PHP
                          F(x)
          Apache                             MySQL
                                             Slave

                                  MySQL    复制
                                  Master
                   Dump
                                             MySQL
                                             Slave
        Lucene
未来

•   系统之间的解耦
•   各种缓存(没有讲到,但是狠重要)
•   能耗
•   异地容灾
•   开放平台
•   。。。
•   它们的核心,基本都在数据库
再插播题外话:数据库该学什么

• 互动:你会写SQL吗?
• 互动:你会写高效的SQL吗?
 – 赶集网石展《MySQL 数据库开发的三十六条军
   规》


• 如何才能用好数据库?
• 原理!
谢谢!

1到100000000 - 分布式大型网站的架构设计