妄谈时间序列表格型大数据系统设计

一直在特定领域的分布式系统一线摸爬滚打,曾取得一些微不足道的成绩,也犯过一些相当低级的错误。回头一看,每一个成绩和错误都是醉人的一课,让我在兴奋和懊恼的沉迷中成长。自己是个幸运儿,作为一个 freshman 就能够有机会承担许多 old guy 才能够有的职责。战战兢兢、如履薄冰的同时,在一线的实作和思考也让我获得了一些珍贵的经验,却直至今日才够胆量写出来一晒。这篇文章标题前面是“妄谈”两字,所持观点未必被所有人认可,我姑妄言之,有心之人姑听之。若有些友好的讨论,亦我所愿也。

我做的虽然也是分布式系统,却不够胆去讨论通用分布式系统的设计原则。因而这篇文章的主题限定到一个特定领域的分布式系统设计,这样即使别人有疑惑,我也可以把 TA 拖到我擅长的领域打败 TA :)

既然要限定,我们需要给这个系统下个定义,就有必要解释一下标题。

大数据(Big Data),这是由于分布式系统和云计算的风靡而变得很火的一个词。那么多大的规模才算大数据呢?目前没有定义,但要讨论这个问题,就必须给个确定的范围。在本文中,这个范围暂时定义为 10TB~1PB 的数据量。为什么是这个范围?我的理由是,小于 10TB 的数据规模有比较多的可选方案;大于 1PB 的数据规模,讨论的意义不大,下面会谈到。

表格型数据,是指数据是有结构的,类似于关系型数据库中的表,但不是关系型,至少不是完整的关系型。在大数据的范围内,不能说完全没有关系型的需求,但这个需求实际上是很小的。因为关系操作的复杂性,使得其在大数据上的性能非常差,此类的需求往往使用数据冗余等其它方式来实现。是性能原因,而不仅是实现难度导致它不被需求。

时间序列数据,是指数据是按照时间产生的,跟随时间而变化的分析型数据。其实分析型数据一般都是时间序列的。与操作型数据不同,在分析型数据中单单一条记录的信息是很小的,只有与其它数据进行对比、组合、分解,这条记录才会体现出其价值。

在这些限定词下,这个系统的用途就比较清楚了。它可以被用到很多地方:比如网站访问统计(Google Analytics 和百度统计)、APP 的数据统计、集群服务器状态收集、在线广告的展现和点击量等等。它是一个数据仓库,但庞大于一般的数据仓库,功能需求却少于一般的数据仓库,而且很强调性能。在这个级别上,我还没看到成熟的开放系统解决这个问题(也许我是孤陋寡闻),基本上每家都是自己实现,所以它也更值得讨论。

由于不知该如何系统地探讨,我下面只能把自己发散的思维整理为一条条简单的原则,可能会有很大的跳跃性。但是,谁在乎它连不连贯呢?

latency 对你很重要时,不要采用分层设计,优化做得越底层越好

事实上,对于有兴趣做这样一套系统的公司,latency 都很重要。因为 latency 不重要时它们完全可以使用 HBase。而且,当你有超过 1PB 数据时,你会发现其中很大一部分的 latency 不重要,那剥离出来这部分,用 HBase 吧。

在这个数据量上,必须采用分布式的实现方案。但不要为了系统逻辑的清晰而做存储层与应用层分离的实现,像 BigTable 那样。因为 locality 可以显著地降低 latency,做了存储层和应用层的分离,那你就放弃了很多可以优化的地方。否则你必须破坏分层的封装性,像 Facebook 对 HBase 做的那样。

MySQL 不是一个选项,分布式 MySQL 也不是,分布式 KV 也不是,做自己的系统吧

总会有人问这些问题:为什么数据库(分布式数据库、分布式 KV 存储)不能用于这样的场景?我只能说,原因关键是上面三个形容词:时间序列数据、表格型数据、大数据。此外可能还要加上性能、成本等其它因素。

问出上面这个问题的人,其实都可以去用数据库或者 KV 系统,大部分情况下他们的需求会被满足。因为实践过且不满足需求的人,不会问上面这个问题,所以自己找出为什么吧,更容易些。

索引很重要,但要注意控制粒度

上面说过,对于分析型数据而言,单条记录没那么重要,所以快速地获取一条记录不会成为此类系统的目标,而且索引会降低数据更新的性能。但是能不要索引吗?开玩笑,那你怎么查询!索引必须要有,但要考虑到业务场景,做到合适的粒度。所谓合适的粒度,就是能快速获得目标数据而又不至于影响数据更新的性能。

内存很重要,能省则省,能用就用完

内存的重要性大家都明白,但很少人能真正理解。能省则省——说的是不要用浪费空间的数据结构;能用就用完——说的是在保证服务器能正常工作的前提下,使用最多的内存。

IO 很重要,做任何能减少 IO 次数和数据量的事,如果要折衷,选择优化次数

对于分析型数据而言,CPU 向来不是瓶颈,IO 才是。做任何能减少 IO 次数和数据量的事,比如各种缓存(块缓存、索引缓存、请求结果缓存),比如数据压缩。如果在减少 IO 次数和减少数据量上做折衷,选择减少 IO 次数,除非这会导致数据量爆炸。

即使没分层,也不要随机写

即使能直接访问到本地文件系统,也不要使用随机写,不要向一个文件中插入内容,而是将更新与基准合并写入另一个文件。这样性能更高,真的。

支持 CRUD?不,只支持 CRA,A for aggregate

其实很多数据都可以表示成时间序列型数据,例如 MySQL 的数据表内容完全可以用时间序列的操作日志来表示,这也是 Twitter 首席工程师 Nathan Marz 提倡的,他说有 CR 就够了。虽然我没有那么极端,但是朋友,我们处理的就是时间序列数据啊,所以我们完全不需要 UD。增加 A 的原因是,聚合会减少数据量,聚合会提升查询性能。

一定要压缩数据,选择一个合适的压缩算法

原因很简单,这能够减少 IO 数据量。但不要傻乎乎地压缩整个文件,跟 BigTable 学,分块压缩。考虑到对数据更新和读取的性能偏重不同,选择对自己合适的压缩算法。因为列存储的压缩比一般而言更高,所以

如果能做列存储,就做吧

尽量分离更新和读取的压力

如果数据需要做清洗,可以聚合,那么在导入系统前做这件事,而不是让承担查询压力的系统做这件事。

实时性没那么重要,批量更新会让你更轻松

如果能接受一天的延迟,就每天一批;能接受一个小时的延迟,就不做分钟级更新。更新次数越少,预聚合效果越好,数据量越小;更新次数越少,一致性越容易保证;更新次数越少,事故处理越从容。实时更新的话,很多事情会变得非常复杂,尤其是故障处理。

用数据冗余实现关系型需求或者高性能需求

如果有关系型运算需求,一定要逼 PM 改掉。实在改不掉,在导入系统前(或者过一段时间后)计算得到结果,直接导入到系统中。高性能需求也是这样,提前在系统外聚合好再导入,让系统做最少的事情它才能更快。

分布式架构?不重要,重要的是可靠性

至于采取什么样的分布式架构,其实不重要。只要它能实现 IO 的(大致)负载均衡,并且可靠就够了。另外,值得一提的是,如果想实现中心机,选举,分片自动分裂、合并、迁移等 fancy 分布式技术,首先想想自己公司是不是行业领导者。Perfect is the enemy of good. 对于很多人来说,Zookeeper 足够了。

好的运维工具,比完美的设计更靠谱[20110222]

在完成一个大规模系统时,往往很难做到完美,尤其是当这个完美设计很复杂时。事实上 fancy 的功能也不是不能折中,例如可伸缩性通过运维工具而不是内建于系统中实现,其复杂度会大大下降,稳定性会大大提高。所以如果没有足够的能力或者时间去实现一个完美的系统,不如好好地去做一些简洁方便的运维工具。

借鉴别人经验

这个不用我解释了吧。找一切可利用的信息,和一些人讨论,自己做决定。 :)

(暂时写到这里,但我可能会更新这篇文章,当我想到更多时。)

《妄谈时间序列表格型大数据系统设计》上有3条评论

  1. 赞,小伙。有个问题,你觉得facebook的hbase集群在处理此类需求有啥不足的地方?

    1. 实话说,不是不可以,就两点问题:1. 改起来别扭,且需要对 HBase 足够了解,而写一个单独的系统可能更容易些。2. 有点儿浪费机器。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注