硬件基础
分布式存储系统是运行在通用计算机硬件体系结构上的底层系统,熟悉各种硬件的性能,能帮助我们更好的调整架构,最大限度地发挥硬件的价值。
基础参数
常见硬件的大致性能参数如下:
类别 | 性能 |
---|---|
访问L1 Cache | 0.5ns |
分支预测失败 | 5ns |
访问L2 Cache | 7ns |
Mutex加锁/解锁 | 100ns |
内存访问 | 100ns |
千兆网络 | 每秒100MB |
从内存顺序读取数据 | 每秒4GB |
(同机房)网络来回RTT | 0.5ms |
(同城跨机房)网络来回RTT | 1~2ms |
(不同城跨机房)网络来回RTT | 300~100ms |
SATA磁盘寻道 | 10ms |
SATA磁盘顺序读取数据 | 每秒100MB |
固态盘SSD随机访问 | 0.1ms |
加粗的性能参数比较常用。SATA盘的寻道时间大约为10ms,顺序读取1MB数据的时间为:磁盘寻道时间+数据读取时间,即10ms + 1MB/100MB/s * 1000 = 20ms。大多数存储系统的瓶颈在磁盘的随机读写速度,一般存储引擎会针对不同的存储介质做不同的优化,比如将随机写操作转化为顺序写,大量顺序写操作的场景使用SAS盘,大量随机读的场景使用SSD盘。
不同持久化存储介质的性能参数如下:
类别 | 每秒读写次数(IOPS) | 每GB价格(元) | 特点 |
---|---|---|---|
SSD | 35000 | 20 | 随机读友好,随机写性能不佳 |
SAS | 180 | 3 | 随机读写 都需要 磁盘寻道 |
SATA | 90 | 0.5 | 随机读写 都需要 磁盘寻道 |
可以看出,SSD的随机读延迟小,能够提供很高的IOPS,但是由于有写入放大问题,其写入速度并不快。所以尽量将SSD应用在随机读比较多、且写入延迟不敏感的场景。
衡量指标
评价分布式存储系统有一些常用的指标:
- 性能。即系统单位时间的处理量(吞吐量)和处理的一个请求的响应时间。
- 可用性。即系统在面临各种异常时,可以正常服务的能力。
- 数据访问的一致性。
- 可扩展性。即一个系统 通过 横向扩展机器来 提高整体服务的能力。
性能估算
在系统设计之初,往往需要根据硬件的特点、系统组件的运行原理 估算一个读写操作的时间,来评估一个适合的设计方案。估算的结果不需要太精确,但结果不应该与实际结果相差一个数量级。
性能估算需要考虑程序的执行环境,如集群规模及机器配置,集群上其它服务占用资源的比例。对硬件性能指标有了初步认识以后,再做粗略的估算,如:
-
在公司内,dtc(分布式缓存)随机读的吞吐量为10w/s,估算一下(同城跨机房)同时开多少个线程发读请求,可以达到这个极限的吞吐量。 从网络上读写数据需要考虑网络的带宽,当读写的数据量很大,会导致网络带宽会成为瓶颈。现假设每次读写的数据量不大,同城跨机房环境下的一个RTT为1~2ms,粗略认为处理一个读请求的延迟为2ms,则单线程的随机读速度为500/s,则达到读的极限吞吐量需要开的线程数:10w / 500 = 200。
-
1GB 的4字节整数,内存排序时间为多少? 这个问题一般会通过排序算法的时间复杂度来估算,如快排的运算次数为1.4 * N * log(N),其中1.4为快排的系数,再根据CPU的运算频率计算出排序耗时。不过Google 的 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。
分布式存储 概述
特点
分布式存储系统是大量普通PC服务器通过Internet互联,对外作为一个整体提供存储的服务。有如下特点:
- 可扩展。可通过机器的堆叠,来增加系统整体的服务能力。
- 低成本。通过自动容错、负载匀衡、线性扩展等特性减少运维费用,通过廉价的集群减少采购成本。
- 高性能。有比较低的访问延迟和比较大的读写吞吐量。
- 易用。提供易用的接口、sdk、文档,完善的部署、运维、监控工具。
面临的问题
在开发分布式存储系统时,会面临很多技术难题,解决难题时都会根据实现难度、应用场景、硬件限制做不同的取舍。所以第一步应该了解在开发分布式存储系统时,会遇到什么问题?第二步了解每个问题的常见解决方案有哪些?业界有应用的先例吗?第三步多实践,在实践中积累根据场景取舍、架构设计的能力、开发能力。
分布式存储系统的主要挑战有:
-
数据分布 如何将数据分布到多台服务器?要保证数据在每台服务器上分布均匀。 如何实现跨服务器的读写操作?涉及读写操作与server间的交互流程设计。
-
多副本的数据一致性。 如果一块数据有多个副本,且每个副本对外都可提供读服务。那(即在机器崩溃等异常发生时)如何保持多个副本的一致性?如何保证同时从多个服务器读取的数据是一致的?
-
容错。 如何检测、监控服务器故障?出现故障时,如何迁移数据和服务?
-
负载均衡。 新增加的服务器集群如何实现服务的自动负载均衡?且在迁移过程不会降低系统的整体服务能力。
-
事务与并发。 互联网场景下,往往是读多写少。为了优化读性能,减少并发时的加锁,往往采用copy-on-write。那么如何实现多版本的并发控制(MVCC)? 事务有ACID属性,涉及多台服务器的事务往往采用两阶段提交算法,性能较低,所以大多数存储系统不支持。但很多系统会支持单行、或者跨行事务,那么如何在支持事务的前提下,尽量提高并发度?
-
易用性。 涉及对外接口的设计,监控、运维等工具的实现。
-
压缩/解压缩。 涉及根据数据的特点使用合理的压缩算法。要考虑算法应用数据的特点,要平衡算法执行的时间和压缩以后节省的空间。 在设计存储系统时,要考虑合理地存放数据,以达到高的压缩比。
数据模型
互联网场景下,面临的数据存储需求各有不同,大致可分为三类:
- 非结构化数据(Blob):包括图片、声音、视频、文档等。
- 结构化数据:一般是用二维表表示,比如淘宝的商户信息、交易信息。它的特点是 存储模式(schema)与内容 是分开的。
- 半结构化数据:类似HTML一样的自描述文档。它的特点是 存储模式(schema)与内容 是混合在一起的。
为了满足不同类型数据的存储,通常会设计不同的数据存储模型,业内也有不同的解决方案。
-
文件模型
对文件系统API作为用户交互接口。内部以目录树的形式组织文件,类似Unix目录,根目录/,子目录/usr,/bin,/home等,每个子目录可包含下一级的目录和文件。一般提供的操作有:
- open/close file
- read/write file
- open/close dir
- read dir
这类分布式文件系统主要存储Blob数据,业界有名的实现有: Google File System, Taobao File System, Facebook Haystack。这类存储系统的特点是 对象需要一次性写入,可以删除,但不能修改。
-
关系模型
每个关系可用一个二维表表示,表中的行、列的特征需要一个模型(schema)表示。提供的操作与SQL语言类似:INSERT,UPDATE,DELETE。这类系统主要存储较复杂的半结构化数据、结构化数据。比如业界比较有名的Google bigtable、Megastore, Apache Hbase, Amazon DynamoDB, Microsoft Azure Table。在实现时,为了减少不必要的复杂性,通常只选取SQL特性的子集进行支持,在扩展性和用户接口方面做一定的权衡。
-
键值模型 只支持针对<key,value>的操作,每行的记录由key和value组成。只支持基于key的操作,不支持范围查询:
- Put <key, value>
- Get <key, value>
- Delete <key, value>
这类系统主要存储关系简单的半结构化数据,业界有名的实现有:Amazon Dynamo, Taobao Tair。