Alluxio 在多级分布式缓存系统中的应用

做者:王冬前端

连接:https://www.infoq.cn/article/q58xAGoBIiOImqEEm-A9?utm_source=tuicool&utm_medium=referraljava

1. 前言

随着移动互联网的发展,愈来愈多的业务数据和日志数据须要用户处理。从而,用数据去驱动和迭代业务发展。数据处理主要包括:计算和查询。计算主要为离线计算、实时流计算、图计算、迭代计算等;查询主要包括 Ahdoc、OLAP、OLTP、KV、索引等。然而,在数据业务中,咱们时常听到数据需求方和数据开发方对性能慢的不满,因此,如何高效响应海量且迫切的数据需求,是大数据平台须要面对的一个关键问题,本文将介绍如何基于 Alluxio 建设分布式多级缓存系统对数据进行计算加速和查询加速。c++

2. 离线数据计算查询加速问题

对于加速组件,结合生态兼容性和系统成熟性的基础上,咱们选择 Alluxio,咱们知道,Alluxio 是经过 UFS 思想访问底层持久化的分布式数据。一般,咱们的数据主要存放在公司私有 HDFS 和 MySQL 上。那么,如何经过 UFS 思想访问到私有 HDFS 数据进行加速是咱们面对的主要问题。私有 HDFS 因为历史缘由,其基于的 HDFS 版本较低,加上公司对 HDFS 进行了部分改造,使得开源的计算和查询组件访问公司内部的离线数据较为困难。所以,如何打通 Alluxio 访问私有 HDFS 成为了系统的关键,后面的章节中,咱们会作相关介绍。web

3. 基于 Alluxio 的解决方案

总体上,咱们当前的多级缓存系统由私有 HDFS(PB 级别) + MEM(400G) + SSD(64T) 共 3 层组成。 示意以下:面试

系统会根据相似 LRU 思想对热点数据进行缓存。咱们主要存放热点部门核心数据。因为资源申请缘由,咱们的 Alluxio 在南方,UFS 在北方, 因此后面的测试数据均为跨地域性能数据 ,提供基于 Spark、Hive、 Presto、YARN、API 等方式访问数据。shell

对于多级分布式缓存系统,咱们实现的总体示意图以下:缓存

从上述方案中,咱们能够看出,若是经过 path 路径方式访问私有 HDFS 数据,直接使用 alluxio:// 协议路径便可;可是,若是要开源的 Hive 或者开源组件 (基于 Hive 桥接) 以数据表方式访问公司内部的私有 HDFS 数据,须要进行“表 schema 映射”,思路以下图:网络

基于上述方案,能够大体抽象出使用 Alluxio 的几个通常性步骤,以下:架构

下面,咱们会一一对每一个步骤进行相关说明及案例数据分析。并发

3.1 Alluxio Meta 数据同步 (load 和 sync)

因为 UFS 随时可能会有变更,致使 Alluxio Meta 和 UFS 的 Meta 不一致,那么,如何在 Alluxio 的 master 中同步 UFS 文件的 Meta 十分重要,因为 Alluxio Meta 的 load 和 sync 性能成本较高(对于 load 和 sync 区别,本文不赘述),官方不推荐过分频繁 load 和 sync Alluxio 的 Meta 数据。

3.1.1 同步方案

在咱们的集群中,咱们均采用了默认的配置,而对于 Aluxio Meta 和 UFS Meta 的状态主要有如下 3 种:

Meta 同步方式 说明
fs ls path 查看文件状态
fs checkConsistency -r path 检测 Alluxio Meta 和 UFS Meta 的一致性,并进行 repair 修复

若是经过上面 2 种方法,Meta 不管如何没法同步(你们应该会遇到这类状况),能够考虑 fs rm -R --alluxioOnly path 从 Alluxio 中删除数据 (仅删除 Alluxio 中的数据,不删除对应 UFS 上的数据),而后再 fs ls path 即可以让 Alluxio 中的 Meta 和 UFS 的真实 Meta 同步一致。

3.1.2 Meta 同步性能

咱们使用 Alluxio 自带的 fs ls 命令进行 Meta 同步,相关 Alluxio 设置以下:

 复制代码

alluxio.user.network.netty.timeout=600min
alluxio.user.network.netty.writer.close.timeout=600min
alluxio.user.network.socket.timeout=600min

上面的设置主要是为了解决网络超时,Meta 同步是很是耗时的操做。

数据同步性能数据以下(请忽略分区大小的合理性):

3.2 Alluxio 加载数据

3.2.1 数据加载方案

有了缓存系统,那么,咱们须要提早经常使用数据预加载到缓存系统中,如此,当用户使用时候,直接从缓存中读取,加快读取速度。数据预加载的方式有以下图的 3 种方式:

加载方式 数据类型 相关说明
Alluxio load 命令 path 类型数据 alluxio 文件系统的基础 shell 命令
Spark JAR path 类型数据 本身开发,基于分布式加载,利用 yarn 模式的 jar,传入 path 这个参数,来 count 文件的条数,以达到加载文件的目的。好处在于,能够经过配置 spark-submit 的相关参数来调整加载的速度
SQL 命令 Hive table 类型数据 对于 Hive 表的数据,能够直接利用 SELECT COUNT(*) FROM T WHERE condition 方式加载。

3.2.2 数据加载性能

咱们主要利用 Spark RDD count 方式来预加载数据,Spark 任务参数以下:

 复制代码

spark.executor.cores4
spark.executor.instances200
spark.executor.memory20g
spark.speculationtrue
spark.speculation.interval1000ms
spark.speculation.multiplier5
spark.speculation.quantile0.95

能够注意到上面开启了比较严格的探测执行,由于在实际应用中,咱们常常发现极少个别 part 的 load 很是慢。因此,在严格条件下开起探测执行,既保证了计算执行效率,又不太会影响到集群性能。

3.3 Alluxio 数据的读取

3.3.1 数据本地化

本地化数据,相信你们都比较清楚,使用本地数据能够有效地提到数据读取效率,具体能够将每一个 worker 节点的 alluxio.worker.hostname 设置为对应的 $HOSTNAME,熟悉 Spark 的同窗知道,这个设置相似 Spark 中的 SPARK_LOCAL_HOSTNAME 设置。

3.3.2 读取性能数据 1(私有 HDFS->Alluxio->Hive/Presto)

上图中,介词 through 和 on 的区别是,前者为首次从 UFS 上加载数据(即直接从私有 HDFS 上读取数据),后者为直接从 Alluxio 缓存中读取数据。

3.3.3 读取性能数据 2(私有 HDFS->Alluxio->Hive->Cube)

3.3.4 读取性能数据 3(私有 HDFS->Alluxio->Spark)

3.4 写入数据性能

3.4.1 经过 alluxio:// 写入

根据 Alluxio 官方介绍,写数据方式主要有 3 种:

Default write type when creating Alluxio files. Valid options are MUST_CACHE (write will only go to Alluxio and must be stored in Alluxio), CACHE_THROUGH (try to cache, write to UnderFS synchronously), THROUGH (no cache, write to UnderFS synchronously).

本文仅测试 CACHE_THROUGH, 数据为 150G,8000 个 part,因为性能不佳,推测主要因为 Meta 同步致使,因此后放弃此方法,因为任务结算结果数据一般不大, 改用 MUST_CACHE 或者直写 HDFS。

3.4.2 经过 hdfs:// 直接写入

当结果数据无需缓存到 Alluxio 时,咱们一样能够选择直接将数据写入到 HDFS,此方案也无需进行 Alluxio 和 UFS 以前的 Meta 同步。

4 Alluxio 集群建设

4.1 打通私有 HDFS

4.1.1 增长模块

因为公司内部的私有 HDFS 系统和开源最新版本的 HADOOP 生态难以直接融合,有些接口不支持,因而想到办法就是增长 1 个 UFS 存储支持。借鉴公司 Spark 对于私有 HDFS 访问思路,基于公司基础部门访问私有 HDFS 的动态库及 JNI 的思想,实现对私有 HDFS 的打通。

4.1.2 遇到的 libstdc++.so.6 及 libc.so.6 版本太低问题

关于 libstdc++.so.6 和 libc.so.6 的关系,本文不赘述。因为咱们增长的 UFS 是利用 java 经过 jni 调用 so 库,而使用的 so 文件依赖的 libstdc++.so.6 版本较高,提示错误以下:

 复制代码

java.lang.UnsatisfiedLinkError:/tmp/libxxx5420953064508929748.so:/usr/lib64/libstdc++.so.6:version`GLIBCXX_3.4.15' not found

或者

 复制代码

glibc/libc.so.6:version`GLIBC_2.14' not found (requiredby/usr/lib64/libstdc++.so.6)

可利用如:strings /usr/lib64/libstdc++.so.6 | grep "GLIB" 查看 libstdc++.so.6 和 libc.so.6 的符号库版本。

其本质缘由主要是,由于咱们环境使用的 java 目录内部的 so 库依赖的 libstdc++.so.6 的路径有问题,可经过命令 scanelf -F "%F %r" -BR $JAVA_HOME 中的 so 对于 libstdc++.so.6 的搜索路径,一样也能够利用命令 patchelf --set-interpreter 和 patchelf --force-rpath --set-rpath去修改优先搜索路径。

4.1.3 没法连通的问题

在测试连通公司私有 HDFS 集群的过程当中,咱们遇到了一个表现个比较奇怪的问题,就是启动 master 后,Alluxio 前端 web 页面菜单 "Browse" 点击无响应,debug 代码发现,某个 reentrantLock 的读计数没有正确降为 0(Master 启动过程当中出现,因此 debug 时候须要设置 suspend=y,同时可从 AlluxioMaster 的 main 函数开始入手),致使一直处于死锁状态,这个问题排查了好久,近乎把 Alluxio 启动代码逻辑都看完了,代码上没有发现问题,后来无心发现是由于各节点(master 和 workers)上没有安装 Agent,由于前文提到 JNI 使用的 so 库须要经过相似代理的方式先访问 Agent, 利用本地的 Agent 去访问私有 HDFS。

4.1.4 recoverLease 函数

因为私有 HDFS 和和最新 HDFS 的差别,不存在 recoverLease, 这个函数主要在 XXXUnderFileSystem.java 中,主要用户当 Alluxio 的 journal 文件非正常关闭下进行恢复。目前,因为时间比较紧,这个功能暂时被跳过。

4.2 集群部署

相关机器配置和组件版本以下:

 复制代码

CPU56core、MEM192G、SSD1.6T、Disk XT
CentOS6.3
Alluxio1.8
hadoop-2.6.0-cdh5.14.0
spark-2.3.2-bin-hadoop2.7

4.2.1 用户

Alluxio 集群使用 alluxio 用户建立,便于迁移及维护。若是是 root 帐户部署,可能会减小很多权限问题,可是和 root 帐号耦合度过高。因此,不推荐直接用 root 帐号安装 Alluxio。

4.2.2 部署常见问题

4.2.2.1 日志显示

Alluxio 启动 (bin/alluxio-start.sh)、关闭 (bin/alluxio-top.sh) 等脚本中的日志显示不够友好,都是用 echo 方式显示,它的启动关闭日志没有日期,对于新手来讲,安装部署问题不少,而日志又没有时间,形成没法区分日志对应哪次操做,形成效率低下。

4.2.2.2 集群启动

目前的./bin/alluxio-start.sh [workers|master|all] [NoMount|SudoMount],它会默认不给任何提示,先杀死进程后再启动进程,并且不是相似 hadoop,提示进程运行中,须要先人肉杀死再启动,咱们进行了改造。否则,对于缓存在内存中的数据丢失。

4.2.2.3 RAM 内存申请

为了保证速度,咱们可能设置 MEM 做为一级缓存以下

 复制代码

alluxio.worker.tieredstore.level0.alias=MEM
alluxio.worker.tieredstore.level0.dirs.path=/mnt/ramdisk
alluxio.worker.tieredstore.level0.dirs.quota=${alluxio.worker.memory.size}
alluxio.worker.tieredstore.level0.reserved.ratio=0.1

那么在执行./bin/start-alluxio.sh workers SudoMount 时会提示出错,由于申请内存申请没有权限,解决方案,能够在 /etc/sudoers 文件中增长一行: alluxio ALL=(ALL) ALL

5 将来计划

5.1 更多应用场景

本文中的多级缓存系统(BigCache)除了能够加速访问热数据外,还变相起到了桥接做用。

让本来没法直接访问公司存储系统数据的新生代开源计算查询组件,能够经过访问 alluxio 协议变相访问私有 HDFS 数据,从 0 到 1 开启了访问公司私有 HDFS 数据的可能!

另外,多级缓存系统不但在离线数据加工方面能有效加速,同时它亦可在对象存储系统中获得较好的应用潜力。

5.2 Hive 表映射自动探测更新

如上面第 3 章节提到,如今咱们若是要让一些开源组件(基于 Hive 访问数据)访问到公司内部 Hive(私有 HDFS) 的数据,咱们须要人工建设表的 schema 进行映射,而后利用脚本进行表的 partition 加载,这一类通用工做,后续计划 web 化、自动化。

5.3 HA 的支持

这个问题在整个新增 UFS 模块开发中,耽误了很是多的时间,主要缘由是由于咱们底层是经过 JNI 利用公司基础部门的.so 动态库访问公司底层的私有 HDFS,在咱们配置了 HA 后,重启过程当中,会出现 core dump,参考了公司相关 wiki,定位成本比较高,因此后续须要对 core 的问题进行进一步排查,支持系统的 HA。

5.4 容器化部署

近年来,公司物理机器的配置愈来愈好,不少机器上都配置有 SSD 硬盘,而不少线上服务可能只用到了 HD 部分,对 SSD 的需求不大,因此若是可以经过混部的方式,将各台机器的 SSD 利用起来,造成一个巨大的多级缓存池,用来加速离线数据计算和查询,带来时效提升收益的同时,也大大提升了机器的利用率,下降成本。

5.5 易用性与性能

如上文一些章节提到,目前易用性还须要进一步提升,好比对于 In Alluxio Data 的搜索,某些数据缓存过时时间的设置,集群的维护等等都较为不便,同时,对于 Meta 同步、数据加载、数据读取等性能提升也有较大需求。

若是对Java微服务、分布式、高并发、高可用、大型互联网架构技术、面试经验交流感兴趣的。

能够加我架构圈子群:834-962-734 领取资料,群内天天更新资料,免费领取。

相关文章
相关标签/搜索