Snowflake论文
Snowflake 论文
The Snowflake Elastic Data Warehouse
背景
首先介绍了大背景,现在是云计算的好时代,SaaS可以给企业提供很好的便利性
传统的数据仓库在这种环境下面临两个问题
- 他们设置的资源是固定的,不能享受到弹性的优势
- 需要复杂的ETL管道和物理调优,对于像半结构这种支持就不太好,灵活性也不够
云时代改变了软件的交付方式和部署方式
对于传统的数据仓库来说,他们的ERP、CRM中其数据的增长,数据类型,都是可以预测的
但是云环境则变了
- 应用日志、web日志、传感器设备日志
- 媒体数据,以及半结构化数据,无结构化数据
传统的数据仓库搞不定,于是出现了各种大数据解决方案
不过这些大数据系统也是出现不久,缺乏很多数仓的一些特性,并不能很好的解决
既然传统数仓和大数据都不搞定,那么snowflake出来了
它的主要特点
- 原声的SaaS体验,不需要管理员、租用机器
- 多租户
- 极致的弹性和可用性
- 共享数据架构
- 半结构和无结构数据
- 时间旅行
- 端到端的安全性
存储和计算
shared-nothing架构可以适用于高性能的数据仓库,因为两个原因
- 扩展性
- 通用的硬件
对于节点都有本地数据,表是被水平分区,每个节点只需要处理自己的那份数据就行
这种设计对于星型模式很适用,因为只有小表需要广播,其代价很小
每个机器的配置都是一样的,几乎没有竞争的情况出现,从设计上来说也很优雅
但是shared-nothing架构有一个重要的缺点
- 紧耦合的计算资源,存储资源
某些场景中会有问题
- 多种负载场景,每个机器配置不同,有的是计算密集型、有的是I/O密集型
- 成员变更,此时需要 reshuffled 数据,会影响弹性和可用性
- 在线更新,成员变更只会影响部分节点,而在线升级软件则会影响所有节点
在一个企业内部,上述的问题基本都不大,都是可控的
但在云场景中,就很难控制,AWS的节点有很大不同,节点失败可能会更频繁,带来性能巨大波动
成员变更也会更经常发生
灰度变更对于缩短软件部署周期,增加可用性 都是非常有利的
而且也无法利用云的弹性能力
snowflake则隔离了存储和计算节点
- 计算节点,使用了 snowflake自己的计算节点
- 存储节点,使用的是AWS S3
为了减少计算节点和 存储节点的网络I/O,每个计算节点都有一个本地数据磁盘
本地磁盘保存了临时数据以及缓存,他们是热数据,使用SSD则可以加速性能
使的这种架构接近,甚至超过 shared-nothring架构
我们称这种架构为: multi-clustr, shared-data 架构
架构
主要包含了三层
- 数据存储,使用了S3来存储表数据
- 虚拟仓库,计算层,提供弹性伸缩
- 云服务层,关系所有元数据、数据库schema、访问控制信息、加密信息、统计信息等
数据存储
- 在选择S3或者自己开发类似HDFS存储,选择了前者
- 这样就可以把经历放在计算层了
- S3相比于传统存储,延迟会很高,而且都是HTTP服务
- 它只有覆盖没有append,但可以读部分数据,在put之前就要确定数据大小
- 表被水平分区为多个不可变的文件,类似于关系数据库的块、page
- 文件按照PAX、hybrid的方式 用列来存储
- 除了存储文件,S3也用来存储sort中的临时数据,这样可以避免OOM
- 元数据目录对象,比如哪个表由哪个S3文件组成的,统计信息、锁、事务日志,放在服务层
虚拟仓库
使用的是 AWS EC2机器,一组节点组成了一个 虚拟仓库VM
一个集群由多个VM组成,VM实例类似 T恤的大小,有各种尺码
弹性和隔离
- 工作节点之间不共享,他们独立的执行查询
- 不过工作节点之前共享一些CBO的信息,可能对提升利用率更有帮助
- 工作节点失败只要重试(没有实现部分重试),甚至可以全部关闭
- 每个VM可以运行多个查询
- 如果4节点需要运行15小时,那么差不多同样价格32个节点只需要运行2小时,但用户体验则大不同
本地缓存和文件窃取
- 每个工作节点都维护了表数据的缓存(本地磁盘),先前查询留下的部分数据
- 在工作节点之间共享,在并发和后续的进程之间共享,使用LRU
- 使用一致性hash,这样可以提高缓存利用率,下次再访问还是这个节点处理
- 一致性hash下,如果节点挂了并不是立即做shuffled,而是等LRU过期后再做
- 处理数据倾斜问题,当节点处理完自己的输入集后,就去其他节点发请求
- 如果其他节点还有未处理完的,就将文件列表发给请求者,请求者直接从S3下载,不需要经过掉队者节点传输
执行引擎
- 可扩展是其主要目标
- 列存,适合OLAP场景,适用于SIMD指令,更好的压缩
- 向量化的,一次执行几千个行的列数据,这个方法的首创者是 MonetDB/X100
- push模型,将关系操作的结果直接push到下游,而不是采用火山模型的pull方式,更好的cache利用率
- 很多在关系型DB中的开销不会出现在snowflake中,执行也不需要事务
- 查询只针对固定的不可变的文件
- 这里并不需要缓存池,大多数查询都是scan,join、group by、sort在内存紧张时都会溢出到磁盘
- 分析性的场景是非常大的join和聚合
云服务层
虚拟仓库是临时的,基于用户的资源
而云服务层 是多租户的,每个服务
- 访问控制
- 查询优化
- 事务管理
这些都是长期存活的,跨用户共享的
查询管理和优化
- 查询是用户递交给服务层,然后服务层处理 语法解析、数据绑定、访问控制、查询优化
- 查询优化是级联风格的,也就是 自上而下的CBO优化
- 在数据加载和更新的时候,统计信息会自动做优化
- 查询计划空间相比于其他系统要小一些,直到执行时候才会决定
- 这种设计减少了错误的优化决定,增加了系统的鲁棒性,但会降低一些峰值
- 不过它会使整体的稳定新、性能更可预测
- 查询优化完成后,就会分发查询到每个节点,并trace节点的执行情况
- 统计信息也会记录下来,方便用户查看
并发控制
- 所有的控制都是在 服务层完成的
- 工作场景是基于 分析,有大量的读、批量/少量的插入、批量的更新
- 实现了快照隔离
- 事务开始的时候,用户看到的是一个快照版本,也就是MVCC实现
- 因为在S3上修改数据只能覆盖,如insert、update、delete、merge 都是覆盖操作,所以用快照很方便实现
- 快照的操作会记录到元数据表中
- 元数据表中会记录表的版本,可以实现 实现时间旅行、克隆数据库对象等操作
剪枝
- 传统的B+树和类似的数据结构,提供了非常高效的事务处理性能
- 但对于snowflake则不合适
- 因为这里有大量的随机访问,对于S3这种设备来说会有很大的延迟,数据格式也是压缩的
- 只需要手动的维护索引,也增加了数据加载的时间,后期也要手动维护
- snowflake使用了比较流行的,类似parquet的方式,列存储中记录了min/max信息
- 查询中的where条件,就可以自动过滤一些数据了,这样也符号snowflake的设计,保持简单
- 除了静态的信息,还有动态的裁剪,比如在分布式join的时候,这是用 bloom filter这个技术实现的