• Feeds

  • Archive for the ‘data’ Category


    多IDC的数据分布设计(二)

    在前文《多IDC的数据分布设计(一)》中介绍了多IDC数据一致性的几种实现原理,遗憾的是,目前虽然有不少分布式产品,但几乎都没有开源的产品专门针对IDC来优化。本文从实践的角度分析各种方法优缺点。

    背景资料 Latency差异

    Jeff Dean提到不同数据访问方式latency差异

    Numbers Everyone Should Know
    L1 cache reference                           0.5 ns
    Branch mispredict                            5 ns
    L2 cache reference                           7 ns
    Mutex lock/unlock                           25 ns
    Main memory reference                      100 ns
    Compress 1K bytes with Zippy             3,000 ns
    Send 2K bytes over 1 Gbps network       20,000 ns
    Read 1 MB sequentially from memory     250,000 ns
    Round trip within same datacenter      500,000 ns
    Disk seek                           10,000,000 ns
    Read 1 MB sequentially from disk    20,000,000 ns
    Send packet CA->Netherlands->CA    150,000,000 ns

    这个数据对于我们设计多IDC数据访问策略具有关键的指导作用,我们可以用这个数据来衡量数据架构来如何设计才能满足高并发低延迟的目标。
    这份数据实际上对所有网络应用及分布式应用开发者都具有很大借鉴作用,数据需要根据访问频率尽量放在latency小的地方

    1. 2PC/3PC/Paxos模式

    在上文中提到,2PC/3PC相比Paxos有明显的缺点,因此最好不用于生产环境,这里就不再详述。
    Paxos选择了CAP理论中的”Consistency, Partition”, 需要牺牲availability。它可以在多个IDC之间实现强一致性复制。

    Paxos缺点

    • IDC之间需要高速稳定网络
    • 一个2f+1个节点的网络中,需要f+1个节点完成事务才能成功。
    • Throughput低,不适合高请求量的场合。所以大部分分布式存储产品并不直接使用Paxos算法来同步数据。

    2. Dynamo模式

    Dynamo论文中并未专门描述Dynamo算法是否适合多IDC场景,只有少量文字提到

    In essence, the preference list of a key is constructed such that the storage nodes are spread across multiple data centers. These datacenters are connected through high speed network links. This scheme of replicating across multiple datacenters allows us to handle entire data center failures without a data outage.

    从上文看到,前提条件是“high speed network links” 可能对国内的情况不太适用。假如IDC之间网络不稳定,那会发生哪些情况呢?

    Quorum 算法中,如果要考虑高可用性,则数据需要分布在多个机房。双机房如NRW=322由于单机房故障后可能会发生3个点中2个点都在故障机房,导致出现数据不 可用的情况,所以合适的部署是NRW=533,需要3个机房。大部分请求需要2个机房节点返回才能成功,考虑到多IDC的带宽及latency,性能自然会很差。

    Quorum算法在读写的时候都要从quorum中选取一个coordinator,算法如下

    A node handling a read or write operation is known as the
    coordinator. Typically, this is the first among the top N nodes in
    the preference list. If the requests are received through a load
    balancer, requests to access a key may be routed to any random
    node in the ring. In this scenario, the node that receives the
    request will not coordinate it if the node is not in the top N of the
    requested key’s preference list. Instead, that node will forward the
    request to the first among the top N nodes in the preference list.

    如果严格按照Dynamo协议,coodinator一定要在N中第一个节点,那在3个机房中将有2/3的请求需要forward到异地机房的 coordinator执行,导致latency增大。如果对coodinator选择做优化,让client选取preference list中前N个节点中在本地机房的一个节点作为coordinator,这样会一定程度降低latency,但是会存在相同的key选择不同节点作为 coordinator的概率增大,导致数据conflict的概率增大。

    同时在多机房模式下,Failure detection容易产生混乱。Dynamo并没有使用一致性的failure view来判断节点失效。而是由每个节点独自判断。

    Failure detection in Dynamo is used to avoid attempts to
    communicate with unreachable peers during get() and put()
    operations and when transferring partitions and hinted replicas.
    For the purpose of avoiding failed attempts at communication, a
    purely local notion of failure detection is entirely sufficient: node
    A may consider node B failed if node B does not respond to node
    A’s messages (even if B is responsive to node C’s messages).

    而最近非常流行的Cassandra基本上可以看作是开源的Dynamo clone, 它在Facebook Inbox Search项目中部署在150台节点上,并且分布在美国东西海岸的数据中心。

    The system(Facebook Inbox Search) currently stores about 50+TB of data on a 150 node cluster, which is spread out between east and west coast data centers.

    虽然在它的JIRA中有一个提案 CASSANDRA-492 是讲”Data Center Quorum”,但是整体看来Cassandra并没有特别的针对对IDC的优化,它的paper[5]中提到

    Data center failures happen due to power outages, cooling
    failures, network failures, and natural disasters. Cassandra
    is configured such that each row is replicated across multiple
    data centers. In essence, the preference list of a key is con-
    structed such that the storage nodes are spread across mul-
    tiple datacenters. These datacenters are connected through
    high speed network links. This scheme of replicating across
    multiple datacenters allows us to handle entire data center
    failures without any outage.

    跟Dynamo中的描述几乎是相同的。

    3. PNUTS模式

    PNUTS模式是目前最看好的多IDC数据同步方式。它的算法大部分是为多IDC设计。

    PNUTS主要为Web应用设计,而不是离线数据分析(相比于Hadoop/HBase)。

    • Yahoo!的数据基本都是用户相关数据,典型的以用户的username为key的key value数据。
    • 统计数据访问的特征发现85%的用户修改数据经常来源自相同的IDC。

    根据以上的数据特征,Yahoo!的PNUTS实现算法是

    • 记录级别的master, 每一条记录选择一个IDC作为master,所有修改都需要通过master进行。即使同一个表(tablet)中不同的记录master不同。
    • master上的数据通过Yahoo! Message Broker(YMB)异步消息将数据复制到其他IDC。
    • master选择具有灵活的策略,可以根据最新修改的来源动态变更master IDC, 比如一个IDC收到用户修改请求,但是master不在本地需要转发到远程master修改,当远程修改超过3次则将本地的IDC设成master。
    • 每条记录每次修改都有一个版本号(per-record timeline consisitency),master及YMB可以保证复制时候的顺序。

    Yahoo!的PNUTS实际可理解为master-master模式。
    一致性:由于记录都需通过master修改,master再复制到其他IDC, 因此可达到所有IDC数据具有最终一致性。
    可用性

    • 由于所有IDC都有每条记录的本地数据,应用可以根据策略返回本地cache或最新版本。
    • 本地修改只要commit到YMB即可认为修改成功。
    • 任一IDC发生故障不影响访问。

    论文中提到的其他优点

    hosted, notifications, flexible schemas, ordered records, secondary indexes, lowish latency, strong consistency on a single record, scalability, high write rates, reliability, and range queries over a small set of records.

    总之,PNUTS可以很好的适合geographic replication模式。

    • 记录publish到本地YMB则认为成功,免除Dynamo方式需要等待多个Data Center返回的latency。
    • 如果发生master在异地则需要将请求forward到异地,但是由于存在master转移的策略,需要forward的情况比较少。

    极端情况,当record的master不可用时候,实现上似乎有些可疑之处,读者可自行思考。

    Under normal operation, if the master copy of a record fails, our system has protocols to fail over to another replica. However, if there are major outages, e.g. the entire region that had the master copy for a record becomes unreachable, updates cannot continue at another replica without potentially violating record-timeline consistency. We will allow applications to indicate, per-table, whether they want updates to continue in the presence of major outages, potentially branching the record timeline. If so, we will provide automatic conflict resolution and notifications thereof. The application will also be able to choose from several conflict resolution policies: e.g., discarding one branch, or merging updates from branches, etc.

    初步结论

    低带宽网络
    PNUTS record-level mastering模式最佳。
    高带宽低延迟网络
    (1Gbps, Latency < 50ms)
    1. 用Dynamo Quorum, vector clock算法实现最终一致性
    2. 用Paxos实现强一致性

    后记

    本文从开始准备到发布时间较长,由于在多IDC数据访问方面目前业界并无统一的成熟方案,相关资料和文献也相对较少,而且对这方面有兴趣且有相应环境的人不多,短时间要提出自己成熟独立的见解也具有一定难度,本文仅包含一些不成熟的想法的整理,由于自己对文中的观点深度也不是满意,所以一直没有最终完稿发布。但考虑到最近工作较忙,暂时没有精力继续深入研究,所以希望公开文章抛砖引玉,同时也欢迎对这方面课题有兴趣者进一步交流探讨。

    Resource

    1. Ryan Barrett, Transactions Across Datacenters
    2. Jeff Dean, Designs, Lessons and Advice from Building Large Distributed Systems (PDF)
    3. PNUTS: Yahoo!’s Hosted Data Serving Platform (PDF)
    4. Thoughts on Yahoo’s PNUTS distributed database
    5. Cassandra – A Decentralized Structured Storage System (PDF)
    6. Yahoo!的分布式数据平台PNUTS简介及感悟

    Dynamo一个缺陷的架构设计(译)

    在云计算的时代,Dynamo可以说是一本实现分布式存储的红宝书,借鉴Dynamo实现的产品如雨后春笋般冒出。前段时间本人曾在Twitter上戏称

    这年头,如果一个号称有“海量数据”的互联网公司,不做一个自己的Dynamo, 出去都不好意思跟人打招呼
    (http://twitter.com/xmpp/status/8023241449)

    另外一方面对于Dynamo设计思想也有不少反对的声音,比如2009/11/1在Hacker News上链接的一篇文章Dynamo: A flawed architecture引起不少争议,最后竟引起Amazon CTO Werner Vogels在Twitter上回应

    Darn, someone figured out that Dynamo is a flawed architecture. Luckily its only use is storing hundreds of millions of shopping carts :-)
    (http://twitter.com/Werner/statuses/5345892061)
    汗,有人发现Dynamo是一个缺陷的架构,幸运的是,我们只用它来存储了成百上亿的购物篮数据。:-)

    以下是这篇批判Dynamo文章大部分中心观点,所翻译的观点并不代表Tim立场。

    –译文开始–

    Dynamo: A flawed architecture

    在发表此文章之前,我也争论过Dynamo是否适合我们的系统。但是我很清楚这篇论文充满缺陷,它将错误的引导了读者让大家相信其设计,它的很多设计前后自相矛盾。下文会详细介绍这些缺陷。

    Dynamo的最终一致性

    首先,最终一致性对开发者意味什么呢?

    1. 写入的数据不能在后续的读操作中获取到。
    2. 写入的数据也有可能在后续的读操作中获取到,但读到后可能下一次又读不到。
    3. 因此对写操作后面的读取没有SLA(Service Level Agreement)保证。

    举例说明,由于Dynamo是一个key value存储,我们假设value中存储的是一个list, 当list写入数据之后另外一个client却未读取到,这时候它需要写入数据的话只能重新构建一个新的list,添加要存的值并将新list存入,这就会导致老的list数据丢失。

    (Update: 论坛上一些人指出,由于Vector Clock机制,数据丢失的场景不可能出现,我同意,不过我再提出几个其他问题。)

    1. Cassandra未用vector clock, 而只用client timestamps也达到了同样效果。
    2. Dynamo依赖合并冲突来解决此问题,一些场合下冲突很难解决。比如从list中错误的截取操作。(if deletion from the list is a valid operation – then how would one reconcile after mistaken truncation?)
    3. 另外一个场景,读取到脏数据后可能会影响后续的写入。(a stale read may end up affecting writes to other keys)

    一般的常识是读取脏数据是需要避免的,但是Dynamo中无任何措施来避免读取脏数据以及避免读取脏数据的客户端再次写入,这个在单IDC环境其实是完全可以避免的。

    Quorum一致性

    (译者注:Quorum是Dynamo的一个核心特性,主要思想是 写最小节点数W + 读最小节点数R > 所有节点数N)
    Dynamo开始就提到系统按最终一致性设计,但是在4.5中却提出用Quorum的方法来实现一定程度的一致性,意思是如果R+W>N, 则读操作就具备(强)一致性了。明显是误导。由于节点会出现不可用的情况,尤其在跨IDC情况下,任一节点随时都有可能离开quorum组,当它离开再加入的时候,R个节点返回的数据就是不一致的,因为故障节点的数据只具备“最终一致性”,而在当时返回的只能是脏数据。

    这就带来一个明显的问题,为什么要让未同步到最新数据的节点加入组?答案是Dynamo中无任何方法来判断一个节点是否数据同步,也无法判断有哪些数据不同步。因此只能做一个完全数据比较才能判断,Dynamo中用一种叫Merkle Tree的方法来实现,这个当然是一个代价昂贵且不灵活的操作,因为为了不影响Dynamo正常的读写业务,同步需要在后台执行。

    实现强一致性也可以用读取所有节点(R=N)的方式来达到,不过有2个问题。

    1. 一旦有一个节点未同步,读取就会失败。
    2. 读取的代价极高。

    我并不是第一个发现这些问题的人,比如另一知名的Cassandra产品Cassandra-225中就提到用一个中心commit log的方法来解决此问题。

    WAN considerations 跨IDC的问题

    值得指出的是,如果将Dynamo部署到多个机房,节点的断续情况会很容易发生。当一个节点连接不到,Dynamo的”hinted handoff”策略会使用一致性哈希算法将数据放入下一个节点。在多IDC环境下,下一节点通常在另一机房,因此会造成异地数据传输增加。当异地整个IDC都连不上网络分裂情况发生时,数据需要很长时间才能完全恢复。

    Disaster Recovery 灾难恢复

    Dynamo最终一致性及同步的设计对于是节点故障是有价值的,但是却无法估算有多少数据未同步。如果改用常规的commit log方式的话,很容易就能实现故障恢复并且计算未同步的数据量。

    未使用时间一致性(译者:基于timestamp的合并?)在某些场合下很难合并冲突。

    一致性还是可用性 Consistency versus Availability

    一般认为Dynamo选择了CAP理论中的AP,而BigTable选择了CA。不幸的是,Dynamo并没有搞清什么是A(availability)和P(Partition Tolerance)。读者被误导只能在C和P中做一个取舍,这个当然是错的。我们很容易在单IDC实现一致性及高可用性。大部分商业数据库就是如此,HBase/HDFS也是如此。

    很多人误以为即使在单IDC架构中,Dynamo方式比BigTable/GFS架构更合理。但Dynamo的优势其实是在多IDC。

    中心化还是去中心化

    Dynamo中提到

    In the past, centralized control has resulted in outages and the goal is to avoid it as much as possible. This leads to a simpler, more scalable, and more available system.
    过去,中心化设计导致了很多灾难,我们意识到要远离中心化。去中心化后,系统会更简洁,更具有可扩展性及高可用性。

    中心化确实会形成瓶颈,但是没有证据说明中心化就低可用性。大部分专业的存储系统通过双机热备的方式都具备高可用性。简单的说,只需要所有中心模块(电源,主板,RAID,交换机等)都按双份的方式来设计,只需要额外增加一点硬件成本,这些系统基本可以达到5个9的可用性。

    值得讽刺的是Dynamo其实在部分情况下还是一个中心化的体系,如交换机故障发生了网络分片,服务器分成2个独立的小网,这时候Dynamo对客户端是不可用的,尽管客户端可以连接上Dynamo。

    更讽刺的是我们看到Dynamo很多一致性问题都是去中心化设计所导致。

    –译文完–

    此文的讨论也非常精彩,对于想深入了解Dynamo的朋友是不可多得的资料。可参看 http://news.ycombinator.com/item?id=915212

    Friendfeed的MySQL key/value存储

    这是一篇2009年初的资料How FriendFeed uses MySQL to store schema-less data,相信大部分人已经看过了。如Fenng的中文介绍FriendFeed 使用 MySQL 的经验。本文从不同的角度再补充下。作者几个月前也曾经在广州技术沙龙作过一次Key value store漫谈的演讲,许多参会人员对key value方向存在强烈的使用意愿,但同时也对完全抛弃MySQL存在疑虑,本文介绍的方案也可以给这些人员一些架构参考。

    需求

    250M entities, entities表共有2.5亿条记录,当然是分库的。

    典型解决方案:RDBMS

    问题:由于业务需要不定期更改表结构,但是在2.5亿记录的表上增删字段、修改索引需要锁表,最长需要1小时到1天以上。

    Key value方案

    评估Document类型数据库,如CouchDB
    CouchDB问题: Performance? 广泛使用? 稳定性? 抗压性?

    MySQL方案

    MySQL相比Document store优点:

    • 不用担心丢数据或数据损坏
    • Replication
    • 非常熟悉它的特性及不足,知道如何解决

    结论

    综合取舍,使用MySQL来存储key/value(schema-less)数据,value中可以放:
    Python dict
    JSON object

    实际friendfeed存放的是zlib压缩的Python dict数据,当然这种绑定一种语言的做法具有争议性。

    表结构及Index设计模式

    feed数据基本上都存在entities表中,它的结构为

    mysql> desc entities;
    +----------+------------+------+-----+-------------------+----------------+
    | Field    | Type       | Null | Key | Default           | Extra          |
    +----------+------------+------+-----+-------------------+----------------+
    | added_id | int(11)    | NO   | PRI | NULL              | auto_increment |
    | id       | binary(16) | NO   | UNI |                   |                |
    | updated  | timestamp  | YES  | MUL | CURRENT_TIMESTAMP |                |
    | body     | mediumblob | YES  |     | NULL              |                |
    +----------+------------+------+-----+-------------------+----------------+

    假如里面存的数据如下

    {
    "id": "71f0c4d2291844cca2df6f486e96e37c",
    "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
    "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
    "title": "We just launched a new backend system for FriendFeed!",
    "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
    "published": 1235697046,
    "updated": 1235697046,
    }

    如果要对link字段进行索引,则用另外一个表来存储。

    mysql> desc index_link;
    +-----------+--------------+------+-----+---------+-------+
    | Field     | Type         | Null | Key | Default | Extra |
    +-----------+--------------+------+-----+---------+-------+
    | link      | varchar(255) | NO   | PRI |         |       |
    | entity_id | binary(16)   | NO   | PRI |         |       |
    +-----------+--------------+------+-----+---------+-------+
    2 rows in set (0.00 sec)

    优点是

    • 增加索引时候只需要 1. CREATE TABLE,2.更新程序
    • 删除索引时候只需要 1. 程序停止写索引表(实际就是一个普通表),2. DROP TABLE 索引表

    这种索引方式也是一种值得借鉴的设计模式,特别是key value类型的数据需要索引其中的内容时。