大数据集群迁移全览(揽)
在互联网降本增效的氛围背景之下,我也接手了一个降本增效的大活: 对大数据集群进行“瘦身”,并把公有云上部署的集群迁移到公司机房,即从云上迁移到云下
从最终效果来看确实很明显,大数据集群基本迁移到云下,成本一年节省了40多万
好像又可以写一篇爽文了(我为什么要说又),但是不管是对我还是对一些用户来说,更想看到的应该还是迁移是怎么做的,每个组件具体怎么迁的,中间是不是要注意什么细节,如果我一个不知道大数据怎么用的人又应该怎么了解迁移这件事
于是就有了这篇繁忙之中写下的文章
迁移背景
云上大数据集群的成本都来自于机器。20多个节点一年成本70多万
其实对于大数据集群来说,这个成本一点不算夸张,只是从19年运行至今,基本只扩容而没有缩容过的集群,实在是有太多可以优化的空间了: 一年前无用的历史副本可以清理、部分节点使用率非常低可以缩容、部分存储类大数据组件功能类似可以合并等
当然,对于降本这个目标来说,最有效的方案还是四个字: 迁移,下云!
既然云上的成本这么高,我们就把集群搬到自己的机房,直接“买断”所有成本
在运维同学的积极配合下,很快就在公司机房弄好了三台高性能机器
开始我们的迁移重头大戏吧
迁移前后架构图
迁移前

迁移后

除了组件升级,以及部署环境从云上迁移到了云下,整体部署架构保持不变,依然是分为实时和离线数仓两部分,除了实时数据依然需要从 MySQL 抽取之外,所有的离线任务和数据都是从云下抽取、在云下计算、最后存入云下HDFS
迁移方案制定
大数据迁移,究竟是在迁什么,大的粒度可以分成服务和数据两部分,但这两个粒度重合的部分还是很大:服务迁移的第一步一般是迁移数据,而数据的迁移又是通过执行各种组件指令来操作的
所以我们还是从大数据服务出发,尽量从使用者的角度,了解具体的迁移步骤
再细看每个服务要怎么迁移,又可以分为以下纬度:
-
类型: 按功能大体可分为存储类、计算类、交互界面类和调度服务类
-
需要双跑/处理方式: 我们遵循不影响云上服务的原则,迁移期间,服务在云上继续运行,云下重新部署,一些服务借着迁移的机会进行升级或者下线
-
迁移准备和迁移过程: 组件的迁移一般可以分成两个阶段,前期的迁移方案准备、数据提前同步,以及正式迁移当天的配置和域名切换等
-
迁移后: 一般迁移后容易忽略的就是监控、数据清理和备份等完善工作,这些工作也应该提前有所规划
有了这个迁移方法框架,我们就可以列出详细每个组件的迁移方案了
| 组件 | 类型 | 需要双跑/处理方式 | 迁移准备 | 迁移过程 | 迁移后 |
|---|---|---|---|---|---|
| Ambari | 集群管理 | 需要 | 部署云下服务、配置迁移 | 直接切换域名 | |
| Hadoop | 离线数仓 | 需要 | 部署云下集群、配置迁移 | 全量数据迁移+增量数据迁移 | |
| Hue | 数据查询门户 | 需要+升级 | 最新版本编译、部署云下服务 | 直接切换域名 | |
| Impala&Kudu | 实时数仓 | 下线 | |||
| Ranger | 权限管理 | 需要+升级 | 部署云下服务、权限手动迁移 | 直接切换域名 | 验证权限配置是否有效 |
| Clickhouse | 离线数仓(查询加速) | 需要 | 全量数据迁移 | 增量数据迁移 | 下线 |
| Presto | 查询引擎 | 需要 | 部署云下服务、配置迁移 | 直接切换 | |
| Starrocks | 实时数仓 | 直接迁移+升级 | 云下服务启动 | 逐步下线云上节点,并添加云下节点到集群 |
主要组件迁移方式
Ambari
先稍微花点时间介绍一下 Hadoop 和 Cloudera。Hadoop 是在 Apache 基金会下的分布式文件存储和计算框架。当然对于企业来说,使用社区版可能需要做很多稳定性优化和适配。Cloudera 是最早的一批使用和优化 Hadoop 的公司,由它优化的 Hadoop 社区版简称为 CDH(Cloudera's Distribution Including Apache Hadoop),也是使用范围最广泛的 Hadoop 版本。不过后面 CDH 也转向商业化了,6.3.2 是最后一个开源版本
我们公司使用的大数据集群基于 CDH 5.15 版本,大数据团队主要在快速部署、新组件集成、组件bug修复等方面做了二次开发。新组件集成就是在 Ambari 上面完成的了。它是所有大数据组件的管理平台,对大数据组件的安装、服务状态展示和配置提供可视化页面

在机器申请好之后,第一件事就是来安装 Ambari,基本过程如下:
-
/etc/yum.repos.d 目录添加 cdh5.repo
-
域名映射: 在 /etc/hosts 配置类似 10.10.10.1 -> router1.bigdata.com 的映射
注意云下的 hosts 文件中不要添加云上节点的域名,避免相互影响 -
Ambari 集群配置迁移,这里官方提供 blueprint 的方案,但在后续的集群初始化步骤一直卡住,索性直接把云上的 Ambari 数据库迁移下来,启动之后再修改配置
-
安装完成后,仔细检查所有服务和 域名 、 hostName 相关的配置,比如 HDFS 配置的 ZK 地址,这些配置全部从云上替换成云下的节点地址
-
按照 Zookeeper -> HDFS -> Yarn -> Hive -> Hue 等组件的顺序,安装 Hadoop 集群
HDFS
HDFS 是 Hadoop 生态的对象存储服务,是所有其他大数据组件的基础
HDFS 的迁移参考了两种方案: 单个集群配置双机架同步,以及跨集群迁移的方式
第一个方案,云上云下共用一套集群,云下的 DataNode 配置成另一个机架,利用HDFS的写入副本机制,让所有数据的第二块副本写到云下,最后逐步下线云上的 DataNode ,完成迁移
后者则需要部署一套完全独立的 Hadoop 集群,并将HDFS数据、Azkaban任务同步到云下,相当于模拟一套和云上完全一样的集群。独立双跑一段时间后,将用户任务逐步迁移到云下集群,最后下线云上集群
第一种方案明显技术复杂度更高,新写入的数据需要跨云传输第二块副本,在跨云传输带宽受限于运营商的情况下,迁移过程很难做到对业务完全无感知。第二种方式则更安全,云上集群理论上不会有任何变更操作,对业务影响也最小
和业务开会讨论后,我们选择了第二种方案
方案这里参考了有赞的这篇离线集群迁移实战,写得很详细
确定要迁移的目录
按使用场景和方式,HDFS 数据主要分为以下几种:
-
hive 分区表数据
-
hive 非分区表数据(少数)
-
用户目录: 这里可能包括用户直接上传的 jar 包,可能有一些 spark 任务依赖,因此需要同步
distcp
distcp 是 HDFS 自带的数据同步指令,它支持限速、文件校验、设置并发度等,建议使用之前先了解它的参数
以下是建议设置的参数:
-
-m: 设置迁移的并发度,全量同步时可以适当调大,默认为 20
-
-bandwidth: 设置带宽限制,全量同步时可以适当调大。不过注意 bandwidth 是针对每个子任务的限制,因此 -m 设置足够大的话一般就能跑满带宽了,不需要设置
-
-Ddistcp.liststatus.threads: 启动distcp任务时,需要先扫描所有需要同步的目录数
-
-i: 是否忽略错误,这里注意 distcp 在同步大目录时,目录下有子文件变更就很容易报错,所以同步全量数据时我是忽略了报错,后续增量同步时去掉
-
-puga: 设置迁移后的文件所属用户、用户组和权限保持不变
-
-update: 只同步有更新过的文件。在同步一些用户自己上传 jar 包的目录、临时表目录的时候比较有用
不建议设置的参数:
-
-delete: 此选项会完全替换目标HDFS原本的目录,一般和 -overwrite 参数一起使用,比如完全覆盖掉之前HDFS内的脏数据
但是我们在云下部署的是新集群,需要进行的是完整的同步,因此不需要这种同步模式 -
-skipcrccheck: 默认开启的文件 checksum 校验必然会增加同步时的开销,但为了保证数据一致性还是打开更好
数据同步
HDFS 数据同步过程大概分为两个阶段: 一周的全量数据同步,以及持续整个任务迁移阶段的增量数据同步
-
全量数据同步: 在运营商提供了 30M/s 的跨云带宽基础上,开足马力,带宽和并发尽量拉大,一周完成了50T全量数据同步
-
增量 Hive 分区表同步: 为了同步同一张 Hive 表的新增分区目录,我们可以加上 -update 参数,让 distcp 自己判断哪些新增目录需要同步。当然也可以在脚本中提前生成需要同步的日期,只同步新增的 Hive 分区目录
-
Hive 非分区表目录和用户目录: 通过 -update 参数同步
Hue
整个 Hadoop 生态相关的组件非常多,有负责存储、计算、任务编排、任务调度等,怎么和这些组件交互呢?

Cloudera 开源的 Hue 闪亮登场,它封装了大数据组件的 api ,并为用户提供了操作界面,我们可以通过它速览 HDFS 上的文件、通过 SQL 查询 Hive、Starrocks 数据等
Hue 之前我们一直用的是 CDH 原生集成的 3.9 版本,基于 Python 2.7 版本编译,界面如下

3.9 还是2015年的版本,非常久远,而且因为 Python 版本不能安装最新的 starrocks 连接器,使用 mysql 的适配器会有各种问题。于是决定顺带把 Hue 升级了
编译过程不是一帆风顺,问题大多数和 pip 依赖版本、django 配置有关,这里我把修复代码提交到了 smiecj/hue/branch-4.11.0,有需要可以拉取后执行 make install 安装

Hue 的元数据中需要迁移的只有用户执行过和保存的SQL,都在 desktop_document2 表中,升级后注意把这张表数据迁移即可
Jupyter
Jupyter 是访问大数据的另一个窗口,它作为交互式IDE,使用起来比 Hue 更灵活:可以在线编辑和运行 Python 代码,即时看到运行结果(包括通过 matplotlib 生成图片),并能够保存最近执行结果
我们提供的是 JupyterHub + JupyterLab + 集成常用的扩展插件的版本

Jupyter 需要迁移的主要是 Python 环境(包括 Jupyter 自己的环境和扩展的 Python 环境),以及所有用户目录。需要注意的是用户目录还包括一些隐藏目录的文件,这里有各个用户通过界面自定义的配置,还有手动安装的依赖
这里我们用 rsync 进行迁移,注意权限需要保持一致,示例:
rsync -apvhW -e 'ssh -p ssh_port' /opt/miniconda/envs/jupyter root@云下ip:/opt/miniconda/envs
Clickhouse
Clickhouse 的使用场景是为部分 Hive 宽表提供查询加速功能,并由 Superset 对接 Clickhouse 表提供视图展示。由于大部分表是分区表,因此迁移也分为全量和增量同步两部分工作。全量同步大概3天时间完成,后续的增量同步在一天内完成
数据迁移使用的是官方的迁移工具 Clickhouse copier,但是它只做数据传输这一件事,增量分区的筛选条件需要自己判断,写到配置文件,目标集群的 CK 表也需要自己先建好
因此即使我们的迁移不涉及比较复杂的 ReplicatedMergeTree 等类型,一张张表手动迁移肯定是不现实的,需要把迁移步骤封装好
最后我在 copy-cluster.sh 脚本中,实现了完整的迁移逻辑,可一键迁移所有表,使用方式:
# 集群迁移示例
# clickhouse_copier_zookeeper_nodes: copier 写入配置的 zookeeper 地址
# clickhouse_copier_source_server_nodes: 源 clickhouse ip 列表
# clickhouse_copier_target_server_nodes: 目标 clickhouse ip 列表
# clickhouse_copier_source_cluster_name: 源 clickhouse 集群名,需要和 server.xml 中的配置对应
# clickhouse_copier_target_cluster_name: 目标 clickhouse 集群名,需要和 server.xml 中的配置对应
# 增量同步参数: clickhouse_copier_enabled_partitions: 指定需要同步的分区名称,逗号分隔,如 20240714,20240715
clickhouse_copier_zookeeper_nodes=common1:2181 clickhouse_copier_source_server_nodes=core1,core2,core3 clickhouse_copier_target_server_nodes=newcore1,newcore2,newcore3 clickhouse_copier_source_cluster_name=source_cluster clickhouse_copier_target_cluster_name=target_cluster make clickhouse-copy-cluster
Starrocks
大数据实时数仓最初是基于 Impala + Kudu + Datalink(神州租车开源的数据同步框架),它在早期确实满足了我们公司的实时报表需求,但随着来自业务的实时报表需求越来越多,视图首次查询速度慢、不支持表结构变更、新增同步表需要大量人工操作等问题,就接踵而至。基于这套架构的二次改造也不太现实
于是从去年开始,我们将实时数仓体系逐渐往 Flink CDC + Starrocks 的框架迁移,Flink CDC 提供从 MySQL(和其他数据源) 实时同步数据的能力,Starrocks 提供存储和物化视图查询加速功能。基于这套框架,解决了上面的三个问题,目前为业务提供超过130个实时视图

Starrocks 的迁移也有新部署集群和原有集群迁移的两种方式。前者需要先部署新集群,然后把底表和物化视图等用户基本数据迁移过来(官方提供了跨集群迁移的工具 starrocks cluster sync 不过未开源 ),最后切换域名
后者则全程在同一个集群操作,先在云下部署相同的版本和配置,再依次将云下的fe和be上线,云下的fe和be下线,等待集群自动完成数据同步后,彻底停止云上服务
考虑到 Starrocks 数据基本来自 MySQL,即使迁移过程发现数据有缺失,完全可以从 MySQL 或者 TIDB 几分钟内就重新同步,所以这里采用了原有集群直接迁移的方式
相关指令如下:
# 添加 fe
ALTER SYSTEM ADD FOLLOWER "new_fe_host:9010";
# 添加 be
ALTER SYSTEM ADD BACKEND "new_be_host:9050";
# 删除原来的 fe
ALTER SYSTEM DROP FOLLOWER "old_fe_host:9010";
# 删除原来的 be
ALTER SYSTEM DROP BACKEND "old_be_host:9050";
# 检查所有 fe 和 be 状态,直到旧集群节点看不到了,表示下线完成
SHOW FRONTENDS;
SHOW BACKENDS;
除了迁移,我们还将集群版本升级到了 3.3,彻底解决了旧版SR的性能问题
3.3 之前的版本在数据写入和物化视图刷新的时候,都用到了库级别锁,一旦同个库在同时间有多张表并发写入,很容易就出现视图刷新超时和数据写入超时的报错,比如 "get database write lock timeout"。3.3 实现了更细粒度的元数据锁,解决了这个问题
和元数据锁的相关配置:
# 是否开启 lock manager
lock_manager_enabled = true
# 是否将元数据锁的粒度从库级别细化为表级别
lock_manager_enable_using_fine_granularity_lock = true
# 是否让 lock manager 自己解决可能出现的死锁情况,主动唤醒正在排队的锁
lock_manager_enable_resolve_deadlock = true
Azkaban
迁移 Azkaban 的具体任务,就是迁移700多个大数据离线任务。这些离线任务的作用是生成所有业务的离线报表,它们的重要性和实时报表类似,上层直接对接业务系统,对可用性和准确性要求很高。因此任务迁移是大数据迁移中最关键的一步,也是最后一步
任务迁移
Azkaban 服务本身的迁移很简单,主要是迁移数据库,但其背后的一个个任务迁移就没这么简单了
首先云下的机器是全新部署的,云下跑相同的任务,难免遇到因环境问题报错(最后主要是解决网络问题、缺少的中间件客户端、调优mapreduce参数等)
其次是迁移期间,业务仍在使用云上集群,可能会继续更新项目代码,如何让云下代码同步更新,避免手动更新也很关键
综上,Azkaban 的迁移分三个阶段:
两个月: 在云下部署相同的离线任务,替换可能影响云上报表的配置,进行双跑
一个月: 所有业务任务迁移
一个月: 云下任务执行结果观察、问题修复和云上任务下线

任务同步
接着前面提到的问题,如何让云上的任务代码和云下保持一致呢?
之前我们有一个 gitlab webhook 服务,负责将 gitlab 代码同步到 Azkaban,同个业务部门的数据开发都更新这一个 gitlab 仓库,即可同步更新 Azkaban 服务内存储的任务代码,避免多人上传代码到Azkaban时误操作相互覆盖

在这套服务基础上,我继续实现了支持同步两套环境的 webhook 的逻辑

相比之前多了执行 sed_项目名.sh 替换项目代码中的一些配置的操作,这是因为任务代码也包括了访问服务地址的配置文件,云上和云下的 Hive、Presto 等服务地址当然不同,只是为了配置文件搞两套代码又没必要,于是在云下代码上传前,加了配置替换特殊逻辑,保证任务代码还是同一套
至于云上和云下的调度(时间)要保持一致,这里用到了 azkaban-tools 脚本工具定期同步
正式迁移
谨慎起见,正式迁移我们选择在周末,留足时间迁移和验证
-
再次确认云上的调度时间和云下保持一致
-
验证所有云下任务是否正常运行
-
逐步停止云上的调度
-
确保后续任务正常运行
结尾
到这里终于可以宣布“完结撒花”了。整体来看还是比较顺利的迁移,离不开业务团队的配合和运维团队的支持
看着从原来在云上20几个节点跑的集群,到现在平稳跑在公司内部机房的集群,有些许成就感,当然还想感叹“大数据不仅是组件多,很多细节更是远比自己想象的要多”
也感叹负责其他项目的跨云迁移的同学,不是所有迁移都能大体顺利,他们可能会遇到更复杂的问题,也需要付出更多精力去定位和解决。对所有默默辛苦负责基建的同学表达 respect
最后的最后,今晚去吃什么呢?好像心中已经有了答案(

浙公网安备 33010602011771号