Tera系统设计

设计背景

百度的链接处理系统每天处理万亿级的超链数据,在过去,这是一系列Mapreduce的批量过程,对时效性收录很不友好。在新一代搜索引擎架构设计中,我们采用流式、增量处理替代了之前的批量、全量处理。链接从被发现到存入链接库再到被调度程序选出,变成一个全实时的过程。在这个实时处理过程中,无论链接的入库还是选取,都需要对链接库进行修改,存储系统需要支持千万甚至上亿QPS的随机读写。旧的存储系统无论在单机性能,还是在扩展性方面,都无法满足,所以我们设计了Tera。

链接存储的需求

  1. 数据按序存储 支持主域、站点和前缀等多维度统计、读取。
  2. 自动负载均衡
    分区可以动态调整,在一个分区数据量变大或者访问频率过高时,可以自动切分,小的分区也可以自动合并。
  3. 记录包含时间戳和多个版本
    对于链接历史抓取状态等记录,需要保留多个版本,对于策略回灌等场景,需要根据时间戳判断,避免旧的数据覆盖新的。
  4. 强一致性
    写入成功,立即可被所有的用户看到。
  5. 按列存储
    在用户只访问固定的少数几列时,能使用更小的IO,提供更高的性能(相对于访问全记录),要求底层存储将这部分列在物理上单独存储。

设计目标

实现的功能

  1. 全局有序
    key可以是任意字符串(二进制串),不限长度,比较逻辑可由用户定义,按Key的范围分区,分区内由单机维护有序,分区间由Master维护有序。
  2. 自动分片
    用户不需要关心分片信息,系统自动处理热点区间的分裂,数据稀疏区间的合并。 单个分区的数据量超过阈值,自动切分为多个,单个分区的读写频率增高时,自动切分。
  3. 自动负载均衡和扩容
    单机上保存多个分区,分区的总大小和总访问量达到阈值时,可以触发将部分分区迁移到空闲的机器。
  4. 多版本
    每个字段(单元格)都可以保留指定多个版本,系统自动回收过期版本,用户可以按时间戳存取。
  5. 局部性群组(LocalityGroup)
    每个局部性群组内部包含多个列族,列族内列个数不限制,不同局部性群组在物理上单独存储,以提高访问效率。
  6. 行级原子性
    对一行的多列进行一次写入,要么全部成功,要么全部失败。

性能指标

Tera设计使用SSD+SATA磁盘混布机型。

  1. 单机吞吐
    顺序读写: 100MB/S
    随机读1KB: 30000QPS
    随机写1KB: 30000QPS
  2. 延迟
    延迟和吞吐需要折衷考虑,在延迟敏感性不高的场合,使用延迟换吞吐策略,延迟定位在10ms级,写操作延迟<50ms,读延迟<10ms。
    对于对延迟要求高的场合,读写延迟定位在<1ms,但吞吐会有损失,初期不做优化重点。
  3. 扩展性
    一期目标水平扩展至5000台机器,单机管理200个数据分片。

稳定性指标

能自动处理由于网络抖动带来的各种问题,不会因为少量节点的网络联通性问题导致集群不可用。能处理机器假死带来的异常,保证及时清除问题机器,不影响整个集群可用性与吞吐。

  1. 数据节点单点故障恢复时间
    数据节点故障,分区迁移到其他数据节点本身代价不大,50ms可以完成,但频繁迁移会导致数据本地化丧失,所以设计数据节点30S不可用,才进行切换。
  2. Master单点故障恢复时间
    为避免网络抖动带来的频繁切换,设定master的lease过期时间为10S,10秒无法服务才会被备份节点取代。
  3. 集群均衡度
    设计单机数据量超过集群平均数据量1.2倍触发负载均衡操作,单点访问频率超过集群平均负载2倍,且负载超过设计负载,触发负载均衡操作。

设计思路

数据存储

数据持久性

为保证数据安全性,要使用三副本存储,但维护副本的一致性与副本丢失恢复需要处理大量细节,基于一个分布式的文件系统构建,可以显著降低开发代价,所以我们选择了使用HDFS。 系统的所有数据(用户数据和系统元数据)都存储在HDFS上,通过HDFS+WriteAheadLog保证数据的持久性,每次写入,保证在HDFS上三副本落地后,才返回成功。

强一致性

数据会按key分区存储在HDFS上,分区信息由Master统一管理,Master保证每个分区同一时间只由一个数据节点提供读写服务,保证一致性。

延迟换吞吐

每次写操作落地一次导致的性能问题可以通过批量落地实现,比如每10ms数据落地一次,在数据落地前写操作不返回,代价是增加了5ms的平均响应时间。

存储接口封装

系统原型基于HDFS开发,但不会把HDFS作为唯一选择,后续可能搭建在其他分布式存储之上(例如NFS),所以会做好底层存储接口的封装,方便以后使用其他文件系统。