计算资源调度
数据平台会用很多计算资源, 一台算不了就要分布式, 因此需要一个计算资源调度的服务.
"江河日下"的 Yarn
作为一个经常跟 Hadoop 生态打交道的数据工程师, 首先逃不掉的就是 Yarn. 虽然如今已经风光不再了, 但 Hive/Spark 等还是可以"开箱即用"的跑上去.
Apache Yarn如日中天的 Kubernetes
如果说不了解 Kubernetes 恐怕要丢了工作了, 现在如日中天的 Kubernetes(下文统称 k8s) 的确也是一个非常优秀的资源调度框架. 通过简单的 YAML 文件 declarative 的方式声明所需的资源即可.
Kubernetes Architecture在数据平台中, Yarn 和 k8s 结合使用, 将 Hive/Spark 的 Driver 端通过一个 Docker Image 方式跑在 K8s 中, 解决大量并发计算时 Driver 端的资源问题, 并且使用 Docker Image 后也可以走公司统一的 CI/CD 流程, 非常方便.
关于在 k8s 上其他玩法, 推荐读这篇 Google 的 Paper: Design patterns for container-based distributed systems, 其中列举的几个模式都非常实用, 例如:
-
Sidecar Pattern: 最近大家密切关注的 Service-mesh 也可以看到 sidecar 模式的应用
Sidecar Pattern & Ambassador Pattern -
任务处理的场景, 非常适用工作队列模式
- 我认为最重要的 Scatter/gather 模式, 等我们的 Kafka 数据 sink 框架改造完成了我再来扯扯这个模式的应用.
不过"纸上得来终觉浅, 绝知此事要躬行", 还是建议找机会在 k8s 上把每个 Pattern 实现一遍
容易被忽略的虚拟机(AWS EC2)
尽管大家的关注点都在如日中天的 k8s, 也别忽略了"上个时代"(戏称, 勿喷)的虚拟机. 我用过最好用的是 AWS 的 EC2, 其他云计算厂商由于条件限制没怎么深入使用过.
为什么这么说, 因为如果一个云计算平台的 API 足够完善, 使用云计算平台启动一台虚拟机应该不比在 k8s 上启动一个 docker container 难多少(或许更简单), 那么通过 cloud-init 就可以在虚拟机启动后执行所需的任务, 然后在虚拟机节点完成任务后自动销毁节点达到节省成本的目的.
以我最熟悉的 AWS 为例, 例如计算任务脚本如下:
#!/bin/bash
# 示例脚本: job.sh
function do_job() {
# 这是工作脚本, 会在启动的 ec2 上执行
}
function destroy_instance() {
# 这里获取本机的 instance-id 并且发送 terminate 请求
local instance_id=`ec2-metadata --instance-id`
# terminate 需要对应的 IAM 权限
aws ec2 terminate-instances $instance_id
}
do_job
destroy_instance
启动任务也很简单, 一行命令搞定
# 示例命令
aws ec2 run-instances\
--image-id ami-abcd1234 \
--count 1 \
--instance-type m3.medium \
--key-name my-key-pair \
--subnet-id subnet-abcd1234\
--security-group-ids sg-abcd1234 \
--user-data file://job.sh
更多信息参见 AWS 官方文档
这就结束了吗? 并没有. AWS 还有一个我非常喜欢的产品: Autoscaling Group. 通过配合 SQS 就可以非常简单的实现 work queue 模式: 计算任务直接往 SQS 扔, autoscaling group 会自动根据策略扩容集群, 无需担心其他事情.
Autoscaling Group & SQS那么还有其他的资源调度框架吗?
"老掉牙"的 MapReduce
当然, "老掉牙"的 MapReduce 也是, 你信不信?
想一下, MapReduce 是如何分配 Mapper 的? 不就是实现一个 InputFormat
, 通过 getSplits
计算分片策略, 然后 MapReduce 框架自然会根据计算出来的 InputSplit
分配对应的 mapper 进程进行计算最后 reduce. 如果我们不需要 reducer 就直接省略即可.
有些抽象? 应该这年头没几个人会手撸 MapReduce 代码了. 我们举几个场景:
- Kafka topic 中的数据需要存储到 HDFS 进行后续分析, 那么我们就可以实现一个 InputFormat, 让一个 Kafka Topic 的 partition 作为一个 InputSplit, 数据开始和结束分别是一个 offset, 每隔一段时间执行, 并且将已经读取的数据的 offset 存储下来, 供下一次任务执行作为 start.
- 跨机房数据迁移, 会有数据下载任务. 那么我们就可以将下载文件的列表写到一个文本文件中, 通过实现 InputFormat 将计算 InputSplit 切分下载任务, 然后提交到 MapReduce 集群进行处理.
- 大家熟知的 Sqoop 也是类似的原理, 不在赘述.
总结
使用一个资源调度服务也不是什么高深技术, 更多的是要会活学活用, 根据具体的场景和手里的资源, "攒"出一个能够水平扩展尽快把活儿干完的系统.
欢迎扫描或者微信搜索 haitaoyao 关注微信公众号-- EOF --