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

380 阅读6分钟

接上一篇,本期我们继续看虚拟数仓层。

虚拟数仓层:EC2的集合

Snowflake利用VM(Virtual Warehouse)作为一个EC2(在Snowflake中也叫做Worker node,工作节点)集合的代称。正如第一篇文章介绍的,用户无需关心底层有多少机器,像选衣服一样选择VM的大小就行了。

特性一:弹性和独立

因为存算彻底分离,所以在用户不需要的时候,直接关闭甚至销毁VM是完全ok的,完全不会影响到底层的存储数据。(相比于现在跟公有云厂商租用机器而言,简直太爽了)。

在Snowflake中,一个查询仅能运行在一个VM上,因此不同VM的执行结果是完全独立的。依赖于S3存储文件的不可变性,不同的执行逻辑与结果也不会相互影响。一个用户账户下,所有的VM共享底层的S3的存储数据,因此不同VM的查询均可以直接读取使用,而不用进行机器间的数据迁移和拷贝。如果一个worker node挂掉了,因为中间文件大部分在S3中,worker node重试也不影响最后计算结果。这都是存算分离带来的实际好处。

从用户视角,存储的一致性保证了用户的数据可以轻松进行分享和存储;独立的计算逻辑也可以保证自身任务的公平和私密:不必在一个资源池里与其他人抢夺资源,别人也看不到自己执行逻辑,还能随时扩展计算规模。

从价格的角度,相同的/cpu/时间的价格计算,使用4个计算节点执行15个小时,与使用32个节点计算2个小时,虽然价格一致,但是后者更容易被接受。这样的思路,也是Snowflake的续租率很高的原因。你的收费是来自真实使用的资源,而没有因为存储不能关闭机器从而浪费掉的CPU。

更多优化点:

  1. 为了提升资源利用率,未来考虑Worker node在VM之间共享。
  2. worker node的重试机制。

特性二:本地缓存及文件窃取

除了存储层描述的,Snowflake通过设计元数据和列式存储减少了一次查询读取的数据量,但是读取完的数据也不能扔了啊,它还能再次利用。Snowflake通过LRU算法,判断每个Worker node里本地缓存的数据是否需要被替换了,换言之,如果该Worker node上一次计算使用这个表一些列数据,下一次还用的到,那下一次就不需要走S3下载数据了,直接读本地缓存即可,这速度是不是杠杠的。

另外,为了提升Worker node命中几率,query优化器在Worker node和实际使用的数据table做了个Hash。也就是如果上一次用这个Worker node读取了这个table的数据,下一次使用这个table的数据的任务尽可能还是推给这个Worker node。这样双重缓存逻辑可以保证大部分情况下读取数据效率的提升。(相较于Hadoop和Spark这种每次现读,确实能快不少啊)

至于数据倾斜,大数据人最头疼的问题,Snowflake也给出了自己的设计。每一次Worker node从S3读取完自己任务内所需的数据文件后,就会广播给其他同VM里的Worker node问要不要帮助。当一个Worker node发现,卧槽,自己还有好多要读的,别人都读完了,就会把自己还需要读的数据的信息以及已经读的range返回给其他来“凡尔赛”的节点。凡尔赛节点收到后,通过range直接从S3读取剩下的数据,而不是等从那个worker node节点同步数据。这被称为file stealing。这种方式,相较于Hadoop无法从一半开始读数据而言,简直不要更快。

特性三:执行引擎

很明显,别人使用10台机器跟我使用1000台机器的计算效率一致时,我的存在也没啥子价值。所以,单纯提升并发能力不是一个好思路,毕竟Snowflake是希望能提供最好性价比的DAAS服务。

为此,Snowflake设计了自己的SQL执行引擎。它有三个核心亮点:

  1. 列式计算:列式计算比行式计算要快得多,充分利用列式计算可以最高效的利用CPU和SIMD指令。
  2. 向量化计算:相比于Mapreduce,Snowflake摒弃了具体化中间结果,数据是以流水线的方式处理的,单次可处理几千行的列式存储数据,这种方式可以节省IO并大大提高缓存效率。
  3. Push的方式:当前节点处理完成后,主动Puth到下一个处理节点,而不是像Mapreduce一样等Reduce启动后主动拉数据。这样减少了节点的缓存,毕竟执行完就推出去,完全不需要存在本地等着。这样的方式也支持了DAG的任务设计,而不是传统的单任务的树状设计。DAG有多个来源和多个去向,为共享通道和执行提供了可能。

除此之外,Snowflake还简化了执行逻辑。在执行期间,它完全不考虑事务的问题,也不提供内存缓存池,每次读取就是直接从S3读取数据。另外,当内存不足时,Snowflake支持常见的操作(sort,group by,join等)阐述的中间数据溢出到磁盘,或者S3中。毕竟,完全是内存的计算虽然更快,但是使用场景也很容易被限制。Snowflake更直接的处理这些数据,可以适配更复杂的聚合和join场景。

总结:

  1. 数据可以共享,计算我要独占。从/cpu/时间计算价格,我付的钱就是我使用的钱,没有浪费。
  2. 数据能不读就不读,要读也按照列读。之前读的不要丢,下次还能继续用。下次还是我用,别人也没必要读。我读不了完的数据,送给凡尔赛同事读,总体计算效率杠杠的。
  3. 列式向量化计算堪称当前各个计算引擎提升效率的超级“大杀器”,Snowflake直接就设计开发了。利用Push的方式推动数据,意味着节点的处理逻辑更简单轻量,搭配S3的吞吐效率,也不难理解为什么Snowflake的查询效率那么快。