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

Preview:

DESCRIPTION

脉络清晰,浅显易懂的分布式架构设计介绍,主要探讨了分布式数据库的实现原理与应用。 —— 中山大学Web2.0俱乐部研讨会,2012年5月19日

Citation preview

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

孙梦石中山大学 Web2.0 俱乐部

前端?后端?

• 互动:你觉着什么是 web 前端,什么是web 后端?

一个简单的任务

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

• 你需要多久来做它?是不是很容易?

最简单的架构

Apache

PHP

MySQL

某一天,你火了

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

• 问题来了• 很慢• 很卡• 挂了,打不开

现在的特点是?

• 数据规模:很小• 访问量:– 主键查询巨大– 更新很少

• 实时性:不在乎更新的延时• 可靠性: 99.99% 可用

你会怎么办?

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

Apache

PHP

MySQL

你会怎么办?

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

服务器?

• 还是,使用廉价的服务器组成集群?

单机到分布式的好处

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

那么到底应该怎么做?

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

Request

Apache

MySql

HTTP 服务器集群

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

互动: Session 是什么?

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

一个简单的数据库集群

• MySql Cluster 听说过吗?• 你认为它是做什么的?

Master/Slave

一致性的问题

• 互动:神马是一致性?

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

• 折中的选择– 非一致– 最终一致

分布式架构雏形初现

Apache

PHP

Apache

PHP

Apache

PHP

MySQLMaster

MySQLSlave

MySQLSlave

ReadReadRead/Write

复制 复制

其他也很有用的方法

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

独乐不如众乐

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

• 问题来了:• 数据库的大小随着用户的增多开始急剧上

升,怎么办?

水平切分 & 垂直切分

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:

水平切分

id name email

1 chenxianlan chen@sysu.edu.cn

2 ouyangxuan ou@sysu.edu.cn

User_00:

id name email

3 wuyuhui wu@sysu.edu.cn

4 liying li@sysu.edu.cn

User_01:

垂直切分

id name

1 chenxianlan

2 ouyangxuan

3 wuyuhui

4 liying

User:user_id email

1 chen@sysu.edu.cn

2 ou@sysu.edu.cn

3 wu@sysu.edu.cn

4 li@sysu.edu.cn

User_email:

分开容易,合并难

• 垂直切分如何查询

• 原查询:• 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 切分,也即一个用户的所有文章都在一个节点中。

于是我们的架构变成了

Apache

PHPMySQLMaster

MySQLSlave

MySQLSlave

复制

Apache

PHP

Apache

PHP

MySQLMaster

MySQLSlave

MySQLSlave

复制

路由F(x)

R/W

数据迁移

• 允许停机不?– 允许?可以跳过了– 不允许?继续

– 将增量数据保持在本机– 全量复制– 本机数据增量复制– 部分停写– 数据检查 – 规则切换– 删除数据

新的需求,搜索

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

• 互动:你会怎样做搜索?– 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

新的架构

Apache

PHPMySQLMaster

MySQLSlave

MySQLSlave

复制

Apache

PHP

Apache

PHP

MySQLMaster

MySQLSlave

MySQLSlave

复制

路由F(x)

R/W

Lucene

Dump

未来

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

再插播题外话:数据库该学什么

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

规》

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

谢谢!

Recommended