它的传奇,不该只存在于财经报道:Snowflake设计揭秘(二)

177 阅读5分钟

上篇文章(它的传奇,不该只存在于财经报道:Snowflake设计揭秘)我们简单的阐述了通常情况下,企业要使用大数据时面临的一些问题,以及Snowflake的架构设计概览。这篇文章将根据概览,分别从存储层、虚拟数仓(计算引擎)层和云服务层进行其设计阐述。

微观层面上,技术的痛点

目的是赚钱,但凡已有开源的技术实现足够完美,都不至于重新设计开发

上篇讲宏观,这篇就开始讲微观。

自打Google发布了MapReduce的设计论文,技术发展至今,Hadoop生态成为了大数据领域的绝对主流。它将大批量数据横向拆分为了一个又一个数据“单元”存储在多台机器的硬盘中,多台机器不同的CPU利用同样的数据处理逻辑独立的处理这些单元,最终将结果整合返回给用户。这样的“分治思想”,是大数据处理的基石。

在Hadoop诞生的岁月中,硬盘资源一直比网络资源更划算,所以Hadoop的设计中,将物理机器视作集群中最小节点,机器内部的存储硬盘和cpu是合在一起使用的,而其优化设计之一便是,为了减少网络开销和延迟,尽可能将对于一个数据“单元”的处理逻辑分配到存储该数据的硬盘对应的机器的CPU上。这就是很多人听到过的,存算耦合的设计,或者说,shared-nothing架构。

随着时间的变迁,这样的设计开始显露不足。

  1. 硬件和CPU的利用率不一致

    乔布斯乔老爷子曾提到说,不需要提供太大的存储能力,因为未来网络价格会非常便宜,网络速度也会极快,那么就没有必要将所有内存存储在手机中,需要的时候连接“云”即可。同样的道理,也适用于大数据环境。随着集群规模的扩大,人们慢慢发现,数据量和任务量或者任务执行频率并非以同等倍数增加。大部分情况下,一台机器硬盘中存储着数据,但是CPU却是空闲的。这对于资源却是极大的浪费。

  2. 任务执行中节点变更

    在Hadoop生态中,任务的启动一般伴随着多个执行节点的占用。如果某个缓存着中间结果数据的节点突然发生异常,任务就可能伴随着重新shuffle计算的问题,从而导致总体计算效率的下降。

  3. 版本升级问题

    使用开源Hadoop生态的另一个恶心的问题就是版本升级。每一个组件都有其对应的版本的其他组件进行配套,就像Spark3.x会建议使用Hadoop3一样。但是,组件的升级会使所有的任务都适配新的版本,任务迁移影响很大,稳定性也很难保证。

如果说在企业内部,这些事情发生的频率尚且可控。大不了控制采购一批相同规格的机器,好几年不做升级罢了。但是面临“云”的环境时,就很难保证了。正如上一篇我提到的,不需要自己搭建,想要使用云服务的企业,会面临更复杂的抉择。毕竟,云服务商管理的机器数量巨大,机器种类规格相对丰富,出问题的概率是要比单一的小集群更高些的。

鉴于此,Snowflake选择了存算分离。

存算分离的核心理念是,绝大部分数据都是冷数据,读取频率不高的数据,可以使用价格便宜的方式存储,而不用在意读取性能。计算节点仅需要缓存热数据即可,以此获得更快的读取性能,而计算所需要的规模也远比存储所需要的规模小。Snowflake称这样的设计架构为multi-cluster shared-data 架构。

存储层:S3当家

因为S3足够好,Snowflake决定直接用它,而不是自建存储层。好在哪里呢?

  • S3的发展已经足够成熟,在使用效率、高可用等方面几乎没有太拉胯的地方
  • S3提供了HTTP的简易但全面的接口,可以很方便的获取数据。甚至支持通过GET接口,获取某一个范围的数据。
  • 在读取数据时,效率的优化也非常可观

基于这些特性,Snowflake设计出了更便捷的数据格式。

数据会被水平分割成大的不可变的文件,每个文件中,每个属性或者列值都会存储在一起,并进行压缩,这就是一种列式存储逻辑。每个文件头会标注这些元数据,以及数据中每一列的具体位置。这样,当虚拟数仓层需要计算的时候,会通过GET命令,仅获取文件头以及执行中用到的列数据即可。

数据计算结果也会存储到S3中。相比于传统的JDBC使用cursor(游标)的方式,界面上给用户呈现结果直接利用HTTP接口,似乎更简单轻便。

总结:利用稳定的S3设计及其接口,设计列式存储,最小化读取数据,减少网络开销和临时存储。