最近工程师小谢遇到了一个难题, 就是手头上有千万级别的数据, 但是没有一个快糙猛的解决方案。

提出问题

想直接看 RedShift 相关的, 请跳过前两节瞎扯淡。 直接到第三节观看。

不像少部分优秀的可以活在彼岸的人, 可以醉心于写出完美的数据库, 在须臾间学会所有的程序语言; 世上大部分程序员都活在此岸, 他们要解决一个个特定的业务问题。

工程师小谢就很烦恼, 上次产品经理小刘提了个老酷炫的IDEA: “现金牛”。 观众们很过瘾, 但作为要实现功能的人, 小谢有点郁闷。

具体来说,难点在下面几个:

  1. 数据量很大。 公司是做菜品相关的,每天记录的菜品数据非常多。 而且随着公司业务发展,菜品增速增长率也很高。 (也就是“指数级上升”)

  2. 时间比较紧。 不像学校里的大作业,可以有一整个学期来实现到交付。 真正的需求是事情要尽可能早的完成,即使一开始不一定是完美的, 但是会更早得到外部反馈,正面/负面的评价有助于大家调整前进方向。

  3. 质量有要求。 基于“现金牛”的这个需求交付完成以后,又会有新的需求降临到小谢的肩上。 所以这个此时的解决方案,也要解决彼时的问题。 随着业务/数据量的增大,短时间内(比如说一年),解决方案得稳定靠谱。 长时间内(比如说三年),解决方案要能拓展,至少是便于重构的。

解决方案

上面的几个现世问题, 其实跟万千现世问题一样, 都是一个问题:如何在有限的资源下,完成既定的目标? 解决方案也都是通用的:转换资源、付出时间、更换目标

当然,小谢明白,脱离实际例子的方法论都没有意义。 所以小谢打算整一个数据仓库 (Data Warehouse)

数据仓库,跟数据库 (DataBase) 很像, 就像军械库是放军械的地方, 车库是放车的地方, 数据仓库/数据库就是放数据的地方。 多了个仓是因为还放仓鼠

二者不同之处详细来说, 就是因为要解决的问题不一样: 数据库是要给业务提供基础保证, 数据仓库则是给面向决策的数据分析提供便利; 所以二者的设计思想也不一样: 数据库遵守范式设计,强调数据约束、一致性,读写操作都有涉及, 数据仓库则是存储大量冗余数据、统计数据,对读的优化更多。

举个栗子就是今天中午小谢去吃了四斤烤鱼(真能吃), “四斤烤鱼”的数据存在了数据库里,是用来买单算钱的。 但“今天中午,四斤,烤鱼”这样的统计数据就存在了数据仓库里, 以用来之后的统计分析。

业界很多的数据仓库都是基于 Hadoop/Spark/Storm 的一套 Java 系技术栈的。 比如拼多多,用的就是 Hadoop/Hive/HBase/Kafka 一套技术栈。 比如小红书,用的也是 Hadoop/Hive/Spark/Kafka 一套技术栈。

但是问题来了: 这些小谢都不懂啊,很尴尬。 不过还好,小谢有钱, 他可以去招几个懂的。 很可惜,招聘是个玄学问题, 他看上的看不上他, 看上他的他看不上。

于是小谢想来想去, 也只能自己动手, 最终选择了:

RedShift, 亚马逊云服务全家桶 之 数据仓库 管理助手

特点

作为一种数据仓库的解决方案, RedShift 有几个特点:

  • 省事,假如你也用了 AWS 的其它服务。 自带监控,需要定制化的话还可以跟 AWS CloudWatch 结合; 往里面插入数据推荐用的 COPY 命令是和 AWS S3 联动的; 高可用、拓展性、备份等都是 AWS 保证的。

  • 提供全套 PostgreSQL 语法。 基本上兼容 PostgreSQL 的地方,换一下 DBDriver 就可以无痛使用了。 但是 RedShift 也只提供了一套 SQL 的标准, 假如要做 SQL 之外的(比如文件)数据存放, 就很吃力了。by design. wontfix

  • 贵,相对而言。 定价大概最便宜的实例类型 (dc1.large, 15GB Mem, 0.16TB SSD) 是一年一万多人民币, 不算人力价格的话,比自建数据仓库肯定要贵。 不过算上人力价格的话……就另说了。

部署

部署使用 RedShift 的主要步骤如下:

  1. 先别急着创建实例,先按照 AWS 的教程走一遍, 会对 COPY/Encoding/Cluster 有初步了解。 不喜欢读英文文档的同学,可以右上角切换成中文

  2. 创建合适的 AWS RedShift 实例。 恭喜你完成了_从无到有搭建数据仓库_这个成就。

  3. 对接业务,比如选择合适的 Driver。 我们用的是 django, 直接用 psycopg2 就可以连接了。 然后就是ETL、缓存、图表等通用的业务操作了。

心得

用了 RedShift 一阵子, 有几点学到的地方:

  • SQL 语句不是直接执行,而是编译后分发执行

不论我们执行任何语句,即使是 INSERT INTO 这种单条操作, RedShift 都要编译后执行,耗时 500ms 起步_所以要用COPY来做数据导入_。 又比如我们部署了四个 RedShift 节点,那在 SELECT * FROM orders WHERE business_id = 100 编译完成以后, RedShift 会把操作根据建表时选定的分区键 DISTKEY 把命令分发到各个节点操作。 所以合理的表结构也是查询速度的关键_通用的废话真理_。

  • 插入数据用 COPY 命令;更新数据 COPY 到临时表以后,用 DELETE USING + INSERT INTO 来更新数据

因为每条 SQL 都要编译,所以尽量做批量操作,单条操作是非常愚蠢的。 (就像我们最开始那么愚蠢一样=_=) RedShift COPY 命令支持 GZIP, JSON, From S3 等多种操作, 大部分情况下,加载速度和存储效率都会比普通的 INSERT 要好。 同理,更新单条数据采用了先删再增的方式。

  • 定时维护数据仓库

RedShift 不会自动回收 DELETE/UPDATE 所释放的空间, 需要用户手动运行 VACUUM 命令来清理表。 VACUUM 本身也是IO密集型操作, 所以最好是在空闲的时间(比如早上四点)定时跑。

  • 注意表的限制

在 RedShift 里, unique / primary key / foreign key都是展示信息, 没有实质约束力。

还有 RedShift.varchar 存储的是单字节字符, 像 MySQL 的 utf8 默认是三字节字符, 假如用了 utf8mb4 就是四字节字符。 所以 MySQL 里的 varchar(50) 换算到 RedShift 里就应该是 varchar(200)。 被Emoji坑了的人留

总结

总的来说, RedShift 的最大的好处在于用钱换取生产力, 简单易用,是 AWS 全家桶用户对数据仓库的一种解决方案。 具体用法多加注意,也没有什么特别之处。

不过最近好像是给亚马逊交了不少钱, 他们都派工程师上门免费 support 了。

小谢心想。

课外阅读