分布式系统工程实践
杨传辉
日照
淘宝
分布式系统工程实践
................................
................................
................................
.......................
1
1
引言
................................
................................
................................
................................
...........
3
2
基础知识
................................
................................
................................
................................
...
3
2.1
硬件基础
................................
................................
................................
.......................
4
2.2
性能估算
................................
................................
................................
.......................
4
2.3
CAP
................................
................................
................................
................................
6
2.4
一致性模型
................................
................................
................................
...................
7
2.5
NOSQL
与
SQL
................................
................................
................................
...............
9
2.6
Two
-
Phase commit
................................
................................
................................
......
10
2.7
Paxos
................................
................................
................................
...........................
11
3
关键技术实现
................................
................................
................................
.........................
12
3.1
网络编程框架
................................
................................
................................
.............
12
3.2
HA
与
Replication
................................
................................
................................
........
13
3.3
分裂
................................
................................
................................
.............................
14
3.4
迁移
................................
................................
................................
.............................
15
3.5
负载均衡
................................
................................
................................
.....................
16
3.6
Chubby
................................
................................
................................
........................
16
3.7
分布式事务
................................
................................
................................
.................
17
3.8
Copy
-
on
-
write
与
Snap
shot
................................
................................
........................
17
3.9
操作日志与
checkpoint
................................
................................
..............................
19
3.10
列式存储与压缩
................................
................................
................................
.....
19
4
通用存储系统分类
................................
................................
................................
.................
20
5
典型存储系统工程实现
................................
................................
................................
.........
21
5.1
单机存储引擎
................................
................................
................................
.............
21
5.1.1
随机访问存储引擎
................................
................................
.........................
21
5.1.2
通用存储引擎
................................
................................
................................
.
22
5.1.3
单机存储优化
................................
................................
................................
.
23
5.2
SQL
数据库
................................
................................
................................
.................
23
5.3
线上最终一致性系统
................................
................................
................................
.
24
5.4
线上弱一致性系统
................................
................................
................................
.....
26
5.5
半线上及线下系统
................................
................................
................................
.....
29
5.5.1
两层结构
................................
................................
................................
.........
29
5.5.2
GFS
................................
................................
................................
...................
30
5.5.3
Bigtable
................................
................................
................................
............
31
6
通用计算系统分类
................................
................................
................................
.................
32
7
典型计算系统工程实现
................................
................................
................................
.........
33
7.1
MapReduce Offlin
e
................................
................................
................................
.....
33
7.2
Online
计算
................................
................................
................................
.................
34
7.2.1
流式计算
................................
................................
................................
.........
34
7.2.2
并行数据库的
SQL
查询
................................
................................
.................
35
7.2.3
数据仓库复杂查询
................................
................................
.........................
36
8
应用
................................
................................
................................
................................
.........
38
8.1
电子商务类
................................
................................
................................
.................
38
8.2
搜索类
................................
................................
................................
.........................
38
8.3
社交类
................................
................................
................................
.........................
39
8.4
邮箱类
................................
................................
................................
.........................
40
8.5
图片及视频类
................................
................................
................................
.............
40
8.6
数据仓库类
................................
................................
................................
.................
40
8.7
云服务类
................................
................................
................................
.....................
41
9
工程实现注意事项
................................
................................
................................
.................
41
9.1
工程现象
................................
................................
................................
.....................
41
9.2
规范制订
................................
................................
................................
.....................
42
9.3
经验法则
................................
................................
................................
.....................
42
9.4
质量控制
................................
................................
................................
.....................
42
9.4.1
测试第一
................................
................................
................................
.........
42
9.4.2
代码
Review
................................
................................
................................
....
42
9.4.3
服务器程序的资源管理
................................
................................
.................
43
10
致谢
................................
................................
................................
................................
.
43
11
参考文献
................................
................................
................................
.........................
43
11.1
书籍类
................................
................................
................................
.....................
43
11.2
论文类
................................
................................
................................
.....................
43
11.2.1
分布式理论
................................
................................
................................
.....
43
11.2.2
Google
系列
................................
................................
................................
....
44
11.2.3
Dynamo
及
P2P
系列
................................
................................
......................
44
11.2.4
存储系统
................................
................................
................................
.........
44
11.2.5
计算系统
................................
................................
................................
.........
44
11.2.6
其它
................................
................................
................................
.................
44
11.3
网页类
................................
................................
................................
.....................
45
11.3.1
个人博客类
................................
................................
................................
.....
45
11.3.2
专题类
................................
................................
................................
.............
45
11.3.3
其它
................................
................................
................................
.................
45
1
引言
NOSQL
的资料很
多,
不过不成体系,让分布式系统开发工程师无所适从
。笔者
根据过去
跟
着阳老师
开发类似
Google GFS/MapReduce/Bigtable
的系统以及对
Dynamo, PNUTS
等典型系
统的理解
尝试梳理流行的分布式存储和计算系统
的分类,设计及实现
。
本文结构安排如下:
基础知识:
一个大规模数据处理系统工程师必备的基础知识;
关键技术实现:工程实践中遇到的典型问题的解决思路;
通用存储系统分类
:讲述笔者
关于存储系统
如何划分的个人观点;
典型存储系统工程实现:选取
典型的
存储
系统讲述
大致实现;
通用计算系统分类
:讲述笔者对于计算系统如何划分的个人观点;
典型计算系统工程实现:
讲述典型计算系统的大致实现;
应用:存储
&
计算
系统应用的一些实例;
工程实现注意事项:
总结设计和开发过程中
可能犯的一些错误;
致谢及参考资料:列出一些值得看的论文和网页资料;
每个章节涉及的话题都很大,由于笔者的水平实在是非常
非常
有限,只能说是尽力把自己知
道并能够说明白的写下来,
作为自己对过去工作的回忆
。
把其中任何一个话题讲明白都
远远
超出了我的能力范畴
,写错的地方在所难免,
各位同学发现问题
尽管笑一笑,
当然,欢迎任
何形式的讨论,
我会尽量和更多的同学讨论来不断完善这个文档。
本文只是一个
初始
综述,
后续
将
细化每一个问题
并发表到博客中。
2
基础知识
本章描述工程实现需要的一些基础知识,由于篇幅的关系,只抽取一些认为对理解和设计大
规模系统必要的基础知识
进行
描述
。另外,
假设读者
了解
NOSQL
基
本概念,做过
或者看过
一两个类似的系统,阅读过
GFS/Bigtable/Paxos
相关的论文。
分布式理论有一个特点是:大
致的做法是很容易想到的,但是完全没
有问题的做法非常难想,理解理论的用处就
在于区分
出想法的问题在哪儿以及实现的难度。
2.1
硬件基础
分布式系统开发工程师需要了解硬件的大致价格,熟记硬件的性能。
硬件
大致
性能如下:
标记为红色性能参数比较常用,其中,磁盘的性能指标专指分布式平台专用的大容量
SATA
磁盘,寻道时间为
8~10ms
,顺序读取速率为
40~50MB
。
某些应用
使用
SAS
磁盘或者
Flash
盘,性能较好,评估时需查看硬件的性能参数。磁盘和网络都有一个特征,一次读写的数据
量越大性能越好,这是由硬件特征及底层软件算法决定的,如
tcp
慢连接和磁盘寻道时间长。
2.2
性能估算
给定一个问题,往往会有多种设计方案,而方案评估的一个重要指标就是性能,如何在系统
设计时估算而不是程序执行时测试得到性能数据是系统架构设计的重要技能。性能估算有如
下用途:
1)
多种设计方案选择;
2)
评价程序实现是否足够优化;
3)
向框架
/
服务提供方提出性能要求的依据;
L1 c
ache reference
0.5ns
Branch mispredict
5ns
L2 cache reference 7ns
Mutex lock/unlock 100ns
Main memory reference 100ns
Send 1M bytes over 1Gbps network 10ms
Read 1M sequentially from memory 0.25ms
Round trip within data center
0.5ms
Disk seek
8~10ms
Read 1MB sequentially from disk 20~25ms
很多同学喜欢
通过查看程序运行时
CPU
及网络的使用情况来评价程序是否足够优化,
这
也是一种很重要的方法。然而,这种方法掩盖了不优化的实现,如
O(N)
的算法被错误实现
成
O(N^2)
,网络收发冗余数据等。
性能评估需要假设程序的执行环境,如集群规模及机器配置,集群上其它服务占用资源的比
例。
对硬件性能指标有了初步认识以后,我们可以做出一些简单的判断,如:
某
K
-
V
引擎
RD
:
我们的
K
-
V
引擎
单
客户端同步读取每秒可以达到
18000/s
。
问:是否批量读取?
答:是,每批读取
10
个记录。
由于
tcp Round trip
时间为
0.5ms
,读取请求个数的理论极限为
2000/s
,而
上例中
K
-
V
引
擎的
RD
却说单客户同步读取可以达到
18000/s
,可以断定
该
RD
指的是批量读取方式。且这
已经是单机能够做到的极限值了。
下面我们通过几个实例说明如何进行性能评估。
1.
1
GB
的
4
字节整数
,
内存
排序时间为多少?
拿到这个问题,我们往往会计算
CPU
运算次数,如快排的运算次数为
1.4 * N * log(N)
,
其中
1.4
为快排的系数,再根据
CPU
的运算频率计算出排序耗时。不过这种方法很土也不是
很准,
Jeff Dean
告诉我们可以这样估算:排序时间
=
比较时间(分支预测错误)
+
内存访
问时间。快排过程中会发生大量的分支预测错误,所以比较次数为
2^28 * log (2^28)
≈
2^33
,
其中约
1/2
的比较会发生分支预测错误,所以比较时间为
1/2 * 2 ^ 32 * 5ns = 21s
,另外,快
排每次找到分割点都需要一遍内存移动操作,而内存顺序访问性能为
4GB/s
,所以内存访问
时间为
28 * 1GB / 4GB = 7s
。因此,单线程排序
1GB 4
字节整数总时间约为
28s
。
2.
Bigtable
设计的性能指标分析
假设
Bigtable
总体设计中给出的性能指标为
:
系统配置:
50
台
4
核
8GB
内存
12
路
SATA
硬盘,同样数量的客户端;
Table
:
row name
:
16
-
byte
,
column
:
16
-
byte
,
value
:
1KB
;
64KB data block
;
no compression
;
R
andom reads (in disk)
:
1KB/item*300item/s*50=15MB/s
Random reads (in memory)
:
1KB/item*4000item/s*50=200MB/s
Random writes
:
1KB/item*2000item/s*50=100MB/s
S
equential reads(in disk)
:
1KB/item*1000item/s*50=50MB/s
Sequential writes
:
1KB/item*2000item/s*50=100MB/s
先看磁盘中的随机读取性能,由于在
Bigtable
的设计中每个随机读取
都要读取一个
64KB
的大块,而磁盘中读取
64KB
数据时间为:磁盘寻道时间
+
读取时间
= 10
ms + 64KB / 50MB/s
=
12
ms
。所以每秒读取
300
个记录
指多客户端读取或者单客户端异步
/
批量读取
。由于每台
机器有
12
个
SATA
大容量磁盘,随机读的理论值为
12 * 1s / 12ms
= 10
00
个
/s
。设计为每秒
读取
300
个是考虑到有负载平衡等因素简单地打了一个折扣
。
再看内存中的随机读取。一般来说,内存操作都是每秒
1W~10W
。由于网络发送小数据
有较多
overhead
且
Bigtable
内存操作有较多的内存开销,所以保守设计为单机每秒读取
4000
个记录。
其它的可类似分析。性能分析可能会很复杂,因为不同的情况下决定性能的瓶颈不一样,
有的时候是网络,有的时候是磁
盘,有的时候甚至是机房的交换机。这种性能分析的经验是
需要慢慢积累的。
最后,我们再看看某一个
MapReduce
应用的例子
。
MapReduce
可以简单地分为几个过
程:
Map
处理时间
+ shuffle
和排序时间
+ reduce
处理时间,虽然
shuffle
、
map
处理和排序
可以部分并行,但性能估算的时候不必考虑。假设
50
台机器,原始输入为
50G
,
例中
MapReduce
应用的
map
函数
处理时间为
100s
,
reduce
函数
处理时间为
60s
,
shuffle
的中间
结果数据量为
300G
,
reduce
输出的最终结果大小
为
600M
。
Map
处理时间
=
输入读取时间
+ Map
函数
处理时间
+
输出中间结果时间
其中,输入读取时间
= 50G / 2.5G = 25s (50
台机器,假设每台机器读取带宽为
50M/s)
,
M
ap
函数
处理时间
= 60s
,
输出中间结果时间
= 300G / 15G = 20s (50
台机器,每台机器
12
个磁盘,假设用满
6
个
磁盘,带宽为
6 * 50M = 300M)
所以,
Map
处理时间
= 25s + 60s + 20s = 105s
Shuffle
和排序时间
= shuffle
时间
+
排序时间
其中,
shuffle
时间
= 300G / 2G = 150s (50
台机器,假设每台机器的读取和写入带宽均为
40M
,单机总带宽为
80M)
排序时间
=
单机排序
6G
的时间,假设每条记录为
1KB =
排序比较时间
+
访问时间,
约为
25s
所以,
shuffle
和排序的时间
= 150s + 25s = 175s
Reduce
处理时间
= reduce
函数
处理时间
+
最终结果输出时间
其中,
reduce
函数
处理时间
= 100s
,
最终结果输出时间
= 600M / 500M (50
台机器,单机写
DFS
假设时间为
10M/s) = 1s (
忽略
)
所以,
例中的
MapReduce
应用
运行一遍大致需要的时间
= Map
处理时间
+ shuffle
和排
序时间
+ Reduce
处理时间
= 105s + 175s + 100s = 380s
,当然,
MapReduce
过程中还有框架
的开销和其它应用的影响,我们可以简单地认为影响为
20%
,所以总时间
= 380s + 380s * 20%
= 456s
,约为
7~8 min
。
当然,
MapReduce
应用
实际的性能估算不会如此简单,实际估算时需要考虑每台机器上
启动的
Map
和
Reduce
个数等因素,且需要根据实验的结果不断地验证和重新调整估算。但
是,我们至少可以保证,估算的结果和实际不会相差一个数量级,估算结果可以用来指导初
期的设计和
Map/Reduce Worker
的个数、
Map/Reduce
任务数选择,评估应用的可优化空间
并作为向
MapReduce
框架提供小组提出需求的依据。
性能估算是大规模系统设计中较难掌握的技能,开始性能估算时可能估计得很不准,不过不
要气馁,通过在项目中不断练习,大规模系统的分析和设计能力
才能做到有理可依
。
2.3
CAP
CAP
是一个很时髦的概念
,
然而,
对于设计和实现大规模分布式系统而言,只需要在脑海里
面有一个粗略的概念即可。
我们先看看
CAP
是怎么回事。
CAP
理论由
Berkerly
的
Brewer
教授提出
,在最初的论文中
,
三者含义如下:
一致性
(
C
onsistency)
:
任何一
个读操作总是能读取到之前完成
的写操作结果
;
可用性
(
A
vailability)
:
每一个操作总是能够在确定的时间内返回;
分区可容忍性
(Tolerance of network
P
artition)
:在出现网络分区的情况下,仍然能够满足一
致性和可用性;
CAP
理论认为,三者不能同时满足,并给出了证明,简单阐述如下:
假设系统出现网络分区
为
G1
和
G2
两个部分,在一个写操作
W1
后面有一个读操作
R2
,
W1
写
G1
,
R2
读取
G2
,
由于
G1
和
G2
不能通信,如果读操作
R2
可以终结的话,必定不能读取写操作
W1
的操作结
果。
然而,
这种对一致性及可用性的定义方法在工程实践上意义不大,
CAP
理论只是粗略地告诉
我们
“天下没有免费的午餐”。
比如
Availability
的定义,
10
秒钟停服务和
1
个小时停服务在
工程实践中完全是两个概念。因此
,我们往往会修改
CAP
的
定义如下:
一致性
(
C
onsistency)
:
读操作
总是能读取到之前完成的写操作结果,满足这个条件的系统
称为
强一致系统,这里的“之前”一般对同一个客户端而言,但可能是一个客户端的多个
Session
;
可用性
(
A
vailability)
:
读写操作在
单台
机器发生故障的情况下仍然能够
正常执行,而不需要
等到机器重启或者机器上的服务分配给其它机器才能执行;
分区可容忍性
(Tolerance of network
P
artition)
:
机房停电
或者机房间网络故障
的时候仍然能
够满足一致性和可用性;
工程实践对网络分区考虑较少,
一般可以认为:一致性和写操作的可用性不能同时满足,
即
如果要保证强一致性,那么出现机器故障的时候,写操作需要等机器重启或者机器上的服务
迁移到别的机器才可以继续。
2.4
一致性模型
Amazon
的
CTO
专门在官网中阐述了一致性模型,
足见其重要性,可以认为,
一
致性要求
直
接决定了存储系统设计和实现的复杂度。
为了更好的描述客户端一致性,我们通过以下的场景来进行,这个场景中包括三个组成部分:
存储系统
存储系统可以理解为一个黑盒子,它为我们提供了可用性和持久性的保证。
Process A
Process
A
主要实现从存储系统
write
和
read
操作
Process B
和
Process
C
Process
B
和
C
是独立于
A
,并且
B
和
C
也相互独立的,它们同时也实现对存储系统的
write
和
read
操作。
下面以上面的场景来描述下不同程度的一致性:
强一致性
强一致性(即时一致性)
假如
A
先写入了一个值到存储系统,存储系统保证后续
A,B,C
的读取操作都将返回最新值
弱一致性
假如
A
先写入了一个值到存储系统,存储系统不能保证后续
A,B,C
的读取操作能读取到
最新值。此种情况下有一个
“
不一致性窗口
”
的概念,它特指从
A
写入值,到后续操作
A,B,C
读取到最新值这一段时间。
最终一致性
最终一致性是弱一致性的一种特例。假如
A
首先
write
了一个值到存储系统,存储系统
保证如果在
A,B,C
后续读取之前没有其它写操作更新同样的值的话,最终所有的读取操
作都会读取到最
A
写入的最新值。此种情况下,如果没有失败发生的话,
“
不一致性窗
口
”
的大小依赖于以下的几个因素:交互延迟,系统的负载,以及复制技术中
replica
的
个数(这个可以理解为
master/salve
模式中,
salve
的个数)。
一致性
模型
的变体如下:
Causal consis
tency
(因果一致性)
如果
Process A
通知
Process B
它已经更新了数据,那么
Process B
的后续读取操作则读取
A
写入的最新值,而与
A
没有因果关系的
C
则可以最终一致性。
Read
-
your
-
writes consistency
如果
Process A
写入了最新的值,那么
Process A
的后续操作都会读取到最新值。但是其它用
户可能要过一会才可以看到。
Session consistency
此种一致性要求客户端和存储系统交互的整个会话阶段保证
Read
-
your
-
writes
,数据库分库
以后
一般会提供这种一致性保证,使得同一个
Session
的读写操作发送到同一台数据库节点
。
Monotonic read consistency
此种一致性要求如果
Process A
已经读取了对象的某个值,那么后续操作将不会读取到更早
的值。
Monotonic write consistency
此种一致性保证系统会序列化执行一个
Process
中的所有写操作。
为了便于后续的说明,
我们修改
Amazon CTO
关于最终一致性的定义
。
Dynamo
通过
NWR
策略提供的最终一致性主要是针对
Dynamo
的多个副本而言的,它们之间保持最终一致。不
过对于用户,我们假设
N=3, W=2, R=2
的一种情况,用户
先调用
W1
写
A
和
B
两个副本后成
功返回,接着调用
W2
写
B
和
A
两个副本后成功返回,可能出现在副本
A
上
W1
先于
W2
执
行,而在副本
B
上
W2
先于
W1
执行,虽然副本
A
和
B
都
能够
通过执行满足交换律的合并操
作,比如基于
”
last write wins
”
的策略进行合并使得最终副本
A
和
B
上的数据完全一致,
但是
可能出现一些异常情况,比如副本
A
和
B
所在的机器时钟不一致,合并的结果是
W1
把
W2
给覆盖了
,
W2
的操作结果消失了
。这显然
与用户的期望是不一致的。
为了方便后续对系统进行划分,
我们
把
Amazon Dynamo
这种需要依赖操作合并,可能
会丢失数据的模型从最终一致性模型中排除出去
。
最终一致性
模型要求同一份数据同一时
刻只能被一台机器修改,
也就是说机器宕机
时需要停很短
时间写服务
。
Amazon Dynamo
提
供的一致性模型我们归类到一般的弱一致性模型中。
2.5
NOSQL
与
卑
NOSQL
可以认为是选取了
SQL
特性的子集,
在扩展性和用户接口友好
两个
方面做了一
个权衡。
“越多选择,越多迷茫”
,实践经验告诉我们,如果将
SQL
的
功能完全暴露给用户,
用户一定会使用一些我们不希望的功能,比如多表
join
,外键,等
等
。
NOSQL
的意义在于
,
我们预先定义一些特性,这些特性满足某一个应用的需求,并且
只满足这些特性使得我们的
系统很容易扩展。
SQL
定义了一个功能全集,
NOSQL
根据应用特点选取几种特定的应用定义
不同的特性集合
,以适应互联网数据量高速膨胀的需求。
一般来说,
NOSQL
的应用会比
SQL
的应用更加注意可用性,
所以
NOSQL
应用对外表现
为经常可以选择最终一致性模型
。不过,从通用系统的角度看,这里的最终一致性指:大多
数操作允许读取老的数据
,少数操作仍然希望读取最新的数据,并且应用不希望出现数据丢
失的情况。
所以,不能因为
NOSQL
就容忍数据丢失的情况,虽然这会极大地加大系统设计
和实现的难度。
另外,
NOSQL
不等于必须用
MapReduce
做计算模型,虽然二者经常结对出现,不过本
质上是不相关的。
NOSQL
比较常见的模型包括:
KV
模型
:只支持最简单的针对
<key, value>
对的操作
支持简单
table
schema
的模型,如
Bigtable
模型
由于
NOSQL
相对
SQL
而言更加注重扩展性、成本等,
NOSQL
有一些共同
的设计原则:
假设失效是必然发生的
:
NOSQL
注意扩展性和成本,机器数变多时,原本属于异
常现象的机器故障变成一种正常现象,
NOSQL
也采用一些比较便宜的普通
PC
机,
要求通过软件的方法处理错误。
限定应用模式。从最为简单的
KV
应用模型,到复杂的支持用户自定义
schema
的
Bigtable
模型,
NOSQL
支持的接口永远不可能和
SQL
相比。一般来说,
NOSQL
系统
都只支持随机读和顺序读
,少量系统支持表索引,类似外键这种影响扩展性且不实
用的功能基本是不需要支持的。
扩容:
数据库扩容一般是成倍增加机器的,而
NOSQL
系统一般是一台
或者少量几
台构成一个机器组加入系统。
一般有两种
数据分布方法,一种是一致性
Hash
,这
个算法在
Dynamo
论文中有详细的介绍,另外一种方法是将整个表格分成连续的小
段,每个小段是一个子表,由全局管理机器负责将每个小段分配到新加入的数据读
写服务机器。
用一个例子说明取舍
SQL
的部分特性带来的好处。比如单机
SQL
的
add
操作,这是
非
常容易的,然而,在多机上的实现变得非常困难。
因为我们需要操作多个副本,可能出现某
些
操作成功,某些永远不成功的情况,我们只能通过一些锁的方法来解决,比如分布式事务
的两阶段悲观锁或者另外一种
乐观锁。
Mysql
团队也有部分同学开始通过削减
SQL
模型不必要的特性来满足互联网数据高速增
长的需求,它们发起了一个叫做
Drizzle
的项目。
Drizzle
诞生于
MySQL
(
6.0
)关系数据库的
拆分。在过去几个月里,它的开发者已经移走了大量非核
心的功能(包括视图、触发器、
已编译语句、存储过程、查询缓冲、
ACL
以及一些数据类型),其目标是要建立一个更精简、
更快的数据库系统。
个
group
同一时刻总是有一个
Master
节点作为代表,
Slave
节点上的状态与
Master
不一致时
以
Master
为准。
工程实践中,分裂仍然是很复杂的,因此国
内几
乎所有的分布式存储系统都采用预先切
分
好
tablet
的方法。只要切分
得比较细,系统支撑一两年是没有问题的,等到出现问题时可
以整个系统停服务对数据重新划分。
3.4
迁移
我们仍然假设整个大表按照类似
Bigtable
中的方法被划
分为很多的子表
tablet
。
子表迁
移在
集群主控机的指导下进行,迁移的做法和分裂有很多共通
之处。
假设机器
A
需要将子表迁移到机器
B
,迁移的做法与单机
子表分裂
时
拷贝数据的方法类
似。分为两个阶段,第一个阶段将机器
A
的待迁移子表的数据拷贝到
机器
B
,
这个阶段新来
的修改操作只记录操作日志;第二个阶段停止写服务,将第一个阶段
拷贝数据过程中接收到
的修改操作拷贝到机器
B
;数据迁移完成时主控机修改被迁移子表的位置信息,整个迁移过
程结束。
同样,如果单机存储引擎支持快照功能,整个流程会更加容易和高效。
Bigtable
的迁移依赖于底层
GFS
提供可靠的文件存储
,
Bigtable
写操作的操作日志持久
化到
GFS
中,且每个
tablet
由一台
Tablet Server
提供服务。当
Tablet Server
出现宕机或者负
载平衡
需要执行子表迁移操作时,
只需要停止源
Tablet Server
对待迁移
tablet
的服务并在目
的
Tablet Server
上重新加载
tablet
即可。
由于
Bigtable
有
GFS
提供可靠存储,我们可以认为
Tablet Server
服务节点是无状态的。
我们
在这里提出
一种设计方案:将机器分成一个一个的
group
,每一个子表都在某个
group
的每台机器
存放一个备份
,同一个时刻
一个
group
中只有一台机器提供写服务,其它
机器都提供读服务。
将子表从
group A
迁移到
group B
其实就是将子表从
group A
中的
Master
机器迁移到
group B
中的
Master
机器,整个过程由集群的主控机来协调。
下面我们考虑一下
迁移过程中发生的各种异常情况:
1,
迁移的第一个阶段
group A
中
Master
宕机:
group A
中某台与
Master
保持
强同步的
Slave
接替
Master
对外服务,
整个迁移过程
失败结束
;
2,
迁移的第二个阶段
group A
中
Master
宕机:
group A
中某台与
Master
保持强同步的
Slave
接替
Master
对外服务,整个迁移过程失败结束
;
3,
迁移过程中
group B
中
Master
宕机:整个迁移过程失败结束;
4,
拷贝数据完成后集群主控机修改子表位置信息失败:此时被迁移
tablet
在
group A
和
group B
中的数据完全一样,任意一个
group
提供服务均可;
5,
迁移完成后
group A
中
Master
宕机:
group A
中某台与
Master
保持强同步的
Slave
接
替
Master
对外服务,
这个
Slave
可能
不
知道子表已经迁移的信息。
子表迁移后客户端写操作
需要重新建立连接,这个过程会请求集群的主控机,
但是
group A
的机器可能使用老数据继
续提供读服务,这就需要
Master
将子表迁移信息告知
group A
中的其它机器。
上述的机器同构的做法有一个问题:
增加副本需要
全部
拷贝
一台机器
存储的
数据,
如果
数据总量为
1TB
,拷贝限速
20MB/s
,拷贝时间为十几个小时,另外,
子表迁移
的
工程实现
也比较麻烦
。
因此
,
工程上多数系统静态分配好每个子表所在的机器并且不迁移,如数据库
sharding
预先分配好每一份数据所在的机器。
另外一种做法是设计的时候
分离静态数据和修
改数据,定期合并,迁移的时候只迁移静态数据,这个思想在
淘宝最近研发的
Oceanbase
系统里面有所体现。
3.5
负载均衡
负载平衡是一个研究课题,难点在于负载平衡的策略和参数
调整,工程化的难度不大,
和数据挖掘相关的
项目有些类似,需要不断地做假设并做实验验证。
负载平衡有两种思路,一种是集群总控机根据负载情况全局调度,另一种思路是采用
DHT
方法。
第二种思路可以参考
Amazon Dynamo
的论文
,
DHT
算法中每个节点分配的
token
决定
了数据及负载的分布。
假设
DHT
环中有
S
个节点,一种比较好的
token
分配方法是将整个
Hash
空间分成
Q
等份,
Q >> S
,
token
分配维持每个节点分配
Q/S
个
token
的特性。当节点
下线时,需要将它所服务的
token
分配给其它节点,从而保持每个节点包含
Q/S
个
token
的
特性;同样,当新节点上线时,也需要
从集群中已有的节点获取
token
使得最终维持每个节
点
Q/S
个
token
的特性。
第一种
思路需要工作机通过
heartbeat
定时将读、写个数,磁盘,内存负载等信息
发送
给主控机,主控机根据负载计算公式
计算出需要迁移的数据放入到迁移队列中等待执行
。
负
载平衡的时候需要注意控制节奏,比如一台工作机刚上线的时候,由于负载最轻,如果主控
机
将大量的数据迁移到新上线的机器,由于迁移过程不能提供写服务,整个系统的对外表现
性能会因为新增机器而变差。
一般来说,从新机器加入到集群负载达到比较均衡的状态需要
较长一段时间,比如
30
分钟到一个小时。
3.6
Chubby
Chubby
是
Google
的
Paxos
实现,
Paxos
靠谱的实现不多,
Chubby
毫无疑问是做的最优秀的
。
Chubby
通过类似文件系统接口的方式给用户暴露分布式锁服务。
我们先看看应用是如何使
用
Chubby
服务的。
在
GFS/Bigtable
论文中,我们至少能够看到有如下几处
使用了
Chubby
。
1, Master
选举。
Master
宕机时,
与
Master
保持强同步的
Slave
切换为
Master
继续提供服务。
在这个过程中,
Master
和
Slave
都定时向
Chubby
请求成为
Master
的锁,
Master
锁有一个
Lease
的期限,如果
Master
正常,一定会在
Master
锁没有过期的时候申请延长锁的时间,继续提
供服务。当
Master
宕机且锁的
Lease
过期时,
Slave
将抢到
Master
锁
切换为
Master
。
2,
tablet
服务。为了保证强一致性,一个
tablet
同一时刻只允许被一个
Tablet Server
加载
提
供服务。每个
tablet server
启动时都向
Chubby
服务获取一个锁,每当
Master
发现
tablet server
出现异常时,它也尝试获取该
Tablet server
的锁。
Master
和
Tablet Server
二者只有一个节点
能够获取到锁,如果锁被
Master
获取,可以确定
Tablet Server
已经宕机,此时可以将它服
务的
tablet
分配给其它机器。
3,
存储
Bigtable
表格的
sche
ma
信息。
由于
Chubby
可以认为是一个一致的共享存储,并且
schema
的访问压力不大,
Chubby
可以存储
schema
信息。
我们再来看看
Chubby
内部大致是如何实现的。
Chubby
一般有五台机器组成一个集群,可以
部署成两地三机房,这样任何一个机房停电都不影响
Chubby
服务。
Chubby
内部的五台机器
需要通过实现
Paxos
协议选取一个
Chubby Master
机器,其它机器是
Chubby Slave
,同一时
刻只有一个
Chubby Master
。
Chubby
相关的数据,比如锁信息,客户端的
Sessio
n
信息都需
要同步到整个集群,采用半同步的做法,超过一半的机器成功就可以回复客户端。每个
Chubby Master
和
Chubby Slave
都希望成为
Chubby Master
,
Chubby Master
有一个
Lease
期限,
如果
Chubby Master
正常,它将在
Lease
快到期的时候延长
Lease
期限,如果
Chubby Master
宕机,
Chubby
集群内部将触发一次
Paxos
选举过程。
每个
Chubby Slave
都希望自己成为
Chubby Master
,它们类似于
Paxos
协议中的
Proposer
,每
个
Chubby
集群中的节点都是
Acceptor
,最后可以确保只有一个和原有的
Chubby Master
保持完全同步的
Chubby Slave
被
选取为新的
Chubby Master
。
当然,无论是
Paxos
选举还是
Session
,锁信息同步,
Chubby
集
群内部机器故障检测都远没有这么简单,这里的实现也是笔者的揣测,如果有同学感兴趣,
可以参考
Berkerly DB
中半同步(包括选举过程)的实现,这部分代码是由
Google
内部开源
出来的。
3.7
分布式事务
对于分布式事务,大多数情况下我们应该想的是如何回避它,两阶段锁的方法不仅效率
低,而且实现特别复杂。
有的时候,我们需要和业务方一起探讨如何规避分布式事务。
这里
我们会用到
流行的概念
BASE
,
即基本可用,柔性状态,柔性一致和最终一致等。对一个
“
基
本可用
”
系统来说,我们需要把系统中的所有功能点进行优先级的划分,
比如转账业务和淘
宝的收藏夹业务两者对一致性的要求
肯定
是不同的。
柔性状
态对用户来说是一个完整的系统,
它的一致性是不允许有任何损失的,就是说用户支付了
10
块钱,那么他的帐户上必然是只
扣掉了
10
块钱;但是对于系统内
部的状态,我们可以采用一种柔性的策略,比如说系统内
分布了
ABC
三个功能模块,我们允许它们在某一时刻三个模块的状态可以不一致。我们会
通过业务和技术的手段,比如说异步机制或者批处理方式来保证系统通过柔性状态一致来获
得可用性。
目前底层
NOSQL
存储系统实现分布式事务的只有
Google
的系统,
它在
Bigtable
之上用
Java
语言开发了一个系统
Megastore
,实现了两阶段锁,并通过
Chubby
来避免两阶段锁协
调者宕机带来的问题。
Megastore
实现目前只有简单介绍,还没有相关论文。
在这个问题上,
我们只能说是
Google
的同学工程能力太强了,我们开发
NOSQL
系统的时候还是走为上策。
3.8
Copy
-
on
-
write
与
湡獨
Copy
-
on
-
write
技术在互联网公司使用比较多,这时因为大多数应用的读写比例接近
10
:
1
,
Copy
-
on
-
write
读操作不用加锁,极大地提高了读的效率,特别是现在服务器一般都
有
8
个或者
16
个核。
Copy
-
on
-
write
技术还带来了一个好处,那就是
Snapshot
的时候不需要
停服务,而
Snapshot
功能对于分布式文件系统非常重要。
Copy
-
on
-
write
技术
在树
形结构中比较容易实现,假如我们实现一个支持
Copy
-
on
-
write
的
B
树,基本可以用来
作为
大多数管理结构的内部数据结构,比如
GFS
的
chunk
管理,文件
名管理,
Bigtable
中的子表管理。
Copy
-
on
-
write
的示意图如下:
的是建立一张全局的索引表,索引和数据相互独立,这样做的优点是可以根据索引直接定位
到主键,缺点是
索引维护成本较高。
对于给定主键或者索引
列值
的查询,
直接将请求发送到
相应的数据节点
;否则,将请求发送
到所有的数据节点。与并行数据库类似,由合并节点来生成
最终结果。
数据仓库存储子系统
处理机器故障问题,
可以采用
5.4
中的线上最终一致性系统实现。
大致的架构如下:
M
a
s
t
e
r
S
l
a
v
e
S
l
a
v
e
D
a
t
a
S
e
r
v
e
r
G
r
o
u
p
M
a
s
t
e
r
S
l
a
v
e
S
l
a
v
e
D
a
t
a
S
e
r
v
e
r
G
r
o
u
p
M
e
r
g
e
r
M
e
r
g
e
r
M
e
r
g
e
r
M
e
r
g
e
r
数
据
访
问
中
间
层
R
e
a
d
c
l
i
e
n
t
R
e
a
d
c
l
i
e
n
t
R
e
a
d
c
l
i
e
n
t
C
o
n
f
i
g
M
a
s
t
e
r
U
p
d
a
t
e
r
U
p
d
a
t
e
r
C
o
n
f
i
g
S
l
a
v
e
r
e
p
l
i
c
a
t
i
o
n
H
e
a
r
t
b
e
a
t
&
C
o
n
t
r
o
l
W
r
i
t
e
c
l
i
e
n
t
W
r
i
t
e
c
l
i
e
n
t
H
e
a
r
t
b
e
a
t
&
C
o
n
t
r
o
l
W
r
i
t
e
d
a
t
a
W
r
i
t
e
d
a
t
a
G
e
t
d
a
t
a
l
o
c
a
t
i
o
n
G
e
t
d
a
t
a
l
o
c
a
t
i
o
n
H
e
a
r
t
b
e
a
t
&
C
o
n
t
r
o
l
H
e
a
r
t
b
e
a
t
&
C
o
n
t
r
o
l
如上图,
通过
Updater
节点将数据写入数据节点,数据节点
按照
Data
Server Group
的形式组
织,
通过
Master/Slave
备份来保证可靠性
,同一个
Data Server Group
中
Master
出现故障后
由
Slave
接替其继续提供服务,保证可用性。
客户端的查询操作在
Merger
节点上执行,它
合并相应
Data Server
Group
中的数据分片并进行
limit, order by, group by
等操作。
当出现负
载不均衡时,
Config Master
将指导数据分片从负载高的
Data Server Group
迁移到负载低的
Data Server Group
。
8
应用
本章讲述笔者对于一些典型应用的存储问题的理解,这里必须声明:任何一个应用涉及的知
识都远超过笔者的能力范畴,后续的内容只是阐述个人很肤浅的理解,漏洞很多,请谅解。
8.1
电子商务类
阿里巴巴引领着电子商务的方向。以淘宝为例,
淘宝面临的存储相关问题包括
卖家商品,
交易信息,
用户信息,用户评价,
用户收藏,购物车
,图片
等等,并且
淘宝累积存储了
不同
业务系统收集的
海量
业务数据,比如
访问点击、交易过程、商品类目属性以及呼叫中心客服
内容等
。
淘宝大多数存储系统的特点是:数据量大,记录条数特别多,
单点记录不大,
读写比例
高
,且可能要求事务。
由于访问量特别大,以前采用
Oracle +
小型机的解决方案,对于不
需要事务的需求,可以通过
Mysql
sharding
的方式实现
。
我们正在做的
Oceanbase
系统
巧妙
地
利用读写比例大且单条记录一般比较小的特点,
将动态更新的数据放在
单机
内存中并通过
强同步保证可靠性及可用性,动态数据定期与静态数据合并。
淘宝的小文件
存储系统
TFS
已经开源了,目前主要是用来存储海量图片文件。
淘宝
TFS
处理百亿级别的图片存储,数据量
PB
级别,
这个问题属于
5.4
中提到的线上最终一致性系
统的范畴,
不过通用系统的解决方案过于复杂,性价比不高。于是,淘宝天才的工程师们利
用图片应用的特点设计了通用的
小文件存储系统
TFS
(
TFS
开源
)
。
图片存储系统
的特点主要有
两个
:
1,
用户
一次性准备好文件所有数据
并
提交到文件系统,每个文件打开后一次性写入所
有数据并关闭;
2,
用户不关心文件的名字,
用户不会指定某个文件进行写操作,
可以等到
文件写成功
后生成文件名并由客户端保存。
TFS
利用这两个特点大大地简化了文件系统写流程和元数据管理服务器的设计,而这也
正是海量文件系统最为复杂之处。
淘宝是一个开放、共享的数据公司,还通过数据仓库提供各种数据给客户。
目前使用了
Oracle RAC
集群提供服务,当然,也通过
Hadoop + HIVE
进行一些线下的预处理。
淘宝的主搜索其实是一个实时搜索,
卖家
更新的商品信息需要秒级别反映到用户的搜索
结果中。
淘宝的主搜索是很灵活的,可以根据
商
品类别,卖家名称,商品属性等进行搜
索,
因此,主搜索的存储系统需要建立不同维度的索引信息,
主搜索使用内部的
iSearch
产品,
机器被分成
56
组,每组
14
台,组内机器存储相同的数据。
商品更新
发生在
Oracle
商品库
中
,
并以异步的方式同步到主搜索
索引
系统。
8.2
搜索类
搜索类公司的核心竞争力
,或者说
互联网公司的
核心竞争力都
可以认为
就是数据以及对
数据的处理
能力,比如商业价值挖掘,用户意图挖掘等。
搜索类最成功的当然就是
Google
,
它能取得现在的成功很大程度上得益于底层的
GFS/MapReduce/Bigtable
等
带来的大规模数
据处理能力。
搜索
流程大致包括:
抓取、数据分析、建立索引
及
索引服务
。
通过
spider
将网页抓取过
来后存储到本地的分布式存储系统
,即网页库中。
网页库的业务逻辑并不复杂,无非就是对
某一个网页或者一批网页,
如某个域名下的所有网页的查询
,删除一批网页或者更新网页相
关的信息,比如权重等。
但是网页库的数据量太大,假设需要处理
500
亿网页,每个网页平
均存储大小为
5
0KB
,
那么,网页库的
大小为
50GB * 50KB = 2.5PB
,这已经
远远超出了关系
型数据库的处理能力。
网页库应用为半线上应用,采用
GFS
加
Bigtable
的方案最为合适。不
过为了规避
复杂性,可以简单地将
网页库通过
Hash
的方法分布到多台机器组成的分布式集
群中,
并通过支持
MapReduce
来进行
线下挖掘,
Rank
调研等。
将网页库的内容进行
一系列的处理,比如计算
PageRank
,网页去
重,最终将生成倒排
表用于
线上服务。
搜索命令的处理大致分成两步:第一步从倒排表中找出匹配的网页索引
信息,第二步根据索引信息从网页库中获取网页内容。
倒排表有一个特点就
是读取量
特别大,
要求延迟很小,且
倒排表一般是定时生成的,也就是说,倒排表中的数据基本是静态的
。
倒
排表的
问题域和存储系统有些差别,这是因为
每个关键词对应的网页信息非常多,
需要分散
到多台机器以便
后续的计算。因此
,主流的搜索引擎一般将机器分成多个
group
,每个
group
可能包含几十台机器,存储相同的数据
,每个查询请求都发送到
所有的
group
,每个
group
中选择一台机器
进行计算,计算
完成后合并最终结果。
8.3
社交类
IM
类
IM
类应用需要存储的数据有两类:用户数据及消息数据。
用户数据
的存储比较简单
,
假设每个用户的信息为
10K
,有
10
亿用户,用户数据量为
10K *
1
GB = 1
0
TB
,可以使用
5.4
中的线上最终一致性系统方案或者
专用的根据用户
id
进行数据划分的方案。
消息
分为两种,
在线消息和离线消息
,其中,离线消息存储时一个必要的功能,而在线
消息是一个
plus
,
它和离线消息在数据量上有巨大差距,
可以选择不在服务器端存储
。
个人
消息和群消息也有一些区别。
个人消息处理比较简单,
而群的消息处理
和
SNS
中订阅好友
动态
有些类似。
SNS
中用户更新动态时
,系统会将这个动态更新
推送给用户的所有好友,而
在
IM
中,用户往群里面发送一条消息,有两种处理方法:第一种方法是推送给群里面的所
有用户,第二种方法是直接保存到群中。
采用第一种方法
群
消息的数据量会增大很多倍,
采
用第二种方法减少了群消息的数据量,不过几十上百个用户同时读取群消息,即使群消息是
顺序
存储的,最后
在磁盘上
也变成了
随机跳读。
另外一种折衷的方案是对在线用户采用第一
种方法,离线用户采用第二种方法,即只将群消息推送给在线用户,
离线用户上线后
主动拉
取群
离线消息。
SN
S
&
微博客
前面已经提到了
SNS
&
微博客
的消息推送功能
,这是
通过将消息推送给所有的好友实现
的,可以开发一个
类似
Active MQ
的
支持发布
/
订阅机制的消息队列。
另外,微博客支持实
时搜索,
例如新浪微博中搜索关注人说的话,
这
和邮件系统的搜索类似,只需要对用户订阅
的消息进行字符串匹配。
微
薄中的一个难点问题是某些用户被关注程度特别高,
如果采用推
送的方式
将
对系统产生很大的压力,
个人认为可以采用推拉结合的方式。