Zenghui Bao's World

about life, programming, misc thoughts.

分布式存储 理论与实践 初探 (一)

硬件基础

分布式存储系统是运行在通用计算机硬件体系结构上的底层系统,熟悉各种硬件的性能,能帮助我们更好的调整架构,最大限度地发挥硬件的价值。

基础参数

常见硬件的大致性能参数如下:

类别 性能
访问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应用在随机读比较多、且写入延迟不敏感的场景。

衡量指标

评价分布式存储系统有一些常用的指标:

  • 性能。即系统单位时间的处理量(吞吐量)和处理的一个请求的响应时间。
  • 可用性。即系统在面临各种异常时,可以正常服务的能力。
  • 数据访问的一致性。
  • 可扩展性。即一个系统 通过 横向扩展机器来 提高整体服务的能力。

性能估算

在系统设计之初,往往需要根据硬件的特点、系统组件的运行原理 估算一个读写操作的时间,来评估一个适合的设计方案。估算的结果不需要太精确,但结果不应该与实际结果相差一个数量级。

性能估算需要考虑程序的执行环境,如集群规模及机器配置,集群上其它服务占用资源的比例。对硬件性能指标有了初步认识以后,再做粗略的估算,如:

  1. 在公司内,dtc(分布式缓存)随机读的吞吐量为10w/s,估算一下(同城跨机房)同时开多少个线程发读请求,可以达到这个极限的吞吐量。 从网络上读写数据需要考虑网络的带宽,当读写的数据量很大,会导致网络带宽会成为瓶颈。现假设每次读写的数据量不大,同城跨机房环境下的一个RTT为1~2ms,粗略认为处理一个读请求的延迟为2ms,则单线程的随机读速度为500/s,则达到读的极限吞吐量需要开的线程数:10w / 500 = 200。

  2. 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、文档,完善的部署、运维、监控工具。

面临的问题

在开发分布式存储系统时,会面临很多技术难题,解决难题时都会根据实现难度、应用场景、硬件限制做不同的取舍。所以第一步应该了解在开发分布式存储系统时,会遇到什么问题?第二步了解每个问题的常见解决方案有哪些?业界有应用的先例吗?第三步多实践,在实践中积累根据场景取舍、架构设计的能力、开发能力。

分布式存储系统的主要挑战有:

  1. 数据分布 如何将数据分布到多台服务器?要保证数据在每台服务器上分布均匀。 如何实现跨服务器的读写操作?涉及读写操作与server间的交互流程设计。

  2. 多副本的数据一致性。 如果一块数据有多个副本,且每个副本对外都可提供读服务。那(即在机器崩溃等异常发生时)如何保持多个副本的一致性?如何保证同时从多个服务器读取的数据是一致的?

  3. 容错。 如何检测、监控服务器故障?出现故障时,如何迁移数据和服务?

  4. 负载均衡。 新增加的服务器集群如何实现服务的自动负载均衡?且在迁移过程不会降低系统的整体服务能力。

  5. 事务与并发。 互联网场景下,往往是读多写少。为了优化读性能,减少并发时的加锁,往往采用copy-on-write。那么如何实现多版本的并发控制(MVCC)? 事务有ACID属性,涉及多台服务器的事务往往采用两阶段提交算法,性能较低,所以大多数存储系统不支持。但很多系统会支持单行、或者跨行事务,那么如何在支持事务的前提下,尽量提高并发度?

  6. 易用性。 涉及对外接口的设计,监控、运维等工具的实现。

  7. 压缩/解压缩。 涉及根据数据的特点使用合理的压缩算法。要考虑算法应用数据的特点,要平衡算法执行的时间和压缩以后节省的空间。 在设计存储系统时,要考虑合理地存放数据,以达到高的压缩比。

数据模型

互联网场景下,面临的数据存储需求各有不同,大致可分为三类:

  1. 非结构化数据(Blob):包括图片、声音、视频、文档等。
  2. 结构化数据:一般是用二维表表示,比如淘宝的商户信息、交易信息。它的特点是 存储模式(schema)与内容 是分开的。
  3. 半结构化数据:类似HTML一样的自描述文档。它的特点是 存储模式(schema)与内容 是混合在一起的。

为了满足不同类型数据的存储,通常会设计不同的数据存储模型,业内也有不同的解决方案。

  1. 文件模型

    对文件系统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。这类存储系统的特点是 对象需要一次性写入,可以删除,但不能修改。

  2. 关系模型

    每个关系可用一个二维表表示,表中的行、列的特征需要一个模型(schema)表示。提供的操作与SQL语言类似:INSERT,UPDATE,DELETE。这类系统主要存储较复杂的半结构化数据、结构化数据。比如业界比较有名的Google bigtable、Megastore, Apache Hbase, Amazon DynamoDB, Microsoft Azure Table。在实现时,为了减少不必要的复杂性,通常只选取SQL特性的子集进行支持,在扩展性和用户接口方面做一定的权衡。

  3. 键值模型 只支持针对<key,value>的操作,每行的记录由key和value组成。只支持基于key的操作,不支持范围查询:

    • Put <key, value>
    • Get <key, value>
    • Delete <key, value>

    这类系统主要存储关系简单的半结构化数据,业界有名的实现有:Amazon Dynamo, Taobao Tair。


参考

《分布式系统工程实践》
杨传辉的博客
阳振坤的博客
《大规模分布式存储系统》
《大数据日知录:架构和算法》