ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Kylin3.10部署:Hadoop3.0+HBase2.0兼容与Cube构建

Kylin3.10部署:Hadoop3.0+HBase2.0兼容与Cube构建

最近因为有业务报表要跑多维分析,我接到一个比较折腾的任务:在 Hadoop 3.0 + HBase 2.0 这套看起来“不是官方推荐组合”的环境上,把 Kylin 3.10 完整搭起来,并且要能正常建 Cube、跑查询。 折腾几天下来,踩了不少坑,也把版本冲突、Jar 覆盖、Cube 构建这些关键点都理清了。 这篇就围绕 Kylin 3.10 的部署、Hadoop/HBase 环境适配、第一个 Cube 的完整构建过程来写,后续同样准备在 Hadoop 3.x 和 HBase 2.x 上部署 Kylin 的同学可以直接照着走。

1. 项目概述与环境选型

1.1 Kylin 在技术栈里的定位

Kylin 是一个分布式 OLAP 引擎,核心思想是“预计算”。 它提前把数据按照多维组合聚合好,生成 Cube 存储到 HBase 中,查询时直接扫描预计算结果,从而做到亚秒级响应。 你可以把它理解成“对查询的缓存”,但不是简单的缓存,而是针对固定维度和度量的离线聚合结果集。

Kylin 在架构上依赖几个东西:Hadoop 提供底层 HDFS 存储和 YARN 资源调度,Hive 负责管理数据表和 SQL 语义,HBase 负责存储构建好的 Cube 和 Kylin 的元数据。 所以搭建 Kylin 之前,Hadoop、HBase、Hive 这套底座必须可用。 而我们这次的基础版本是 Hadoop 3.0、HBase 2.0,Kylin 包的版本是 3.10。 单看版本,Kylin 3.x 更多是配合 Hadoop 2.x 和 HBase 1.x 使用,直接拿新版组合,主要是兼容性问题。

1.2 集群规划与版本确认

我这次用的环境是三台物理节点,角色分配如下。

节点主要角色部署进程
kylin-master主节点NameNode、ResourceManager、HMaster、Kylin、Hive Metastore、ZK
kylin-slave1从节点DataNode、NodeManager、RegionServer、ZK
kylin-slave2从节点DataNode、NodeManager、RegionServer、ZK

软件版本如下:

  • JDK:1.8.0_201(Kylin 3.x 必须 JDK 8,不要用 11)
  • Hadoop:3.0.3
  • HBase:2.0.2
  • Hive:3.0.0(用于读取表结构)
  • Zookeeper:3.4.13
  • Kylin:3.10(实际安装包可能标注为 apache-kylin-3.10-bin.tar.gz 之类,后面按这个版本名说明)

这里特别提醒:Hadoop 3.0 和 HBase 2.0 都不是 Kylin 官方最舒服的版本区间,所以在启动 Kylin 之前,必须先解决依赖兼容问题,不然会遇到各种 ClassNotFound 和 NoSuchMethodError。 这一点后面专门讲。

1.3 搭建前的基础准备

所有节点先做几项基础配置:

  • 配置 hosts:把三个节点的 IP 和主机名映射写进 /etc/hosts。
  • 关闭防火墙和 SELinux,避免端口访问异常。
  • 配置时间同步,大数据组件之间时间不一致会直接导致认证报错。
  • 创建统一用户,例如 bigdata,所有组件都跑在该用户下。
  • 配置 SSH 免密登录,从 kylin-master 免密到三个节点。

JDK 安装过程不多说,记得在所有节点设置 JAVA_HOME 并加入 PATH。 另外建议所有软件统一放在 /opt 下,目录清晰一些,后面覆盖 Jar 的时候也好管理。

2. 基础环境安装:Hadoop 3.0 + HBase 2.0

2.1 Hadoop 3.0 的安装配置

Hadoop 3.0.3 解压到 /opt/hadoop,主要修改四个配置文件。

core-site.xml:

<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://kylin-master:8020</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>

hdfs-site.xml:

<configuration> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/data/hadoop/nn</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/data/hadoop/dn</value> </property> <property> <name>dfs.namenode.http-address</name> <value>kylin-master:9870</value> </property> </configuration>

yarn-site.xml:

<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>kylin-master</value> </property> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property> </configuration>

第三个参数是我习惯性加上的,容器物理内存不足时,如果 YARN 做虚拟内存校准,很容易把 MR 任务杀掉。 大数据组件本来吃内存就厉害,关闭这个检查能少踩一个坑。

配置完成后,在 kylin-master 上执行 hdfs namenode -format,然后通过 start-dfs.sh 和 start-yarn.sh 启动集群。 启动后确认 Web UI 可访问,NameNode 的默认端口在 Hadoop 3.0 里是 9870,ResourceManager 是 8088。 第一次部署最好用 jps 检查进程,确认 DataNode 在从节点上正常注册。

2.2 HBase 2.0 安装配置

HBase 2.0.2 解压到 /opt/hbase,修改 hbase-env.sh,设置 JAVA_HOME,并关闭 HBase 自带的 Zookeeper:

export JAVA_HOME=/usr/local/jdk1.8.0_201 export HBASE_MANAGES_ZK=false

hbase-site.xml 如下:

<configuration> <property> <name>hbase.rootdir</name> <value>hdfs://kylin-master:8020/hbase</value> </property> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <property> <name>hbase.zookeeper.quorum</name> <value>kylin-master,kylin-slave1,kylin-slave2</value> </property> <property> <name>hbase.zookeeper.property.clientPort</name> <value>2181</value> </property> <property> <name>hbase.unsafe.stream.crash.ignore</name> <value>true</value> </property> </configuration>

HBase 2.0 的 HMaster 会自己创建 HDFS 上的根目录,启动顺序是 Zookeeper -> HDFS -> HBase。 我习惯用 start-hbase.sh 启动,然后执行 hbase shell,输入 status,看是否返回正常。

这里有个经验:HBase 2.0 对 Zookeeper 的版本比较敏感,我用了 3.4.13,如果是 3.5 及以上版本,连接会有 SessionExpired 问题,建议直接用 3.4.x。

2.3 Hive 3.0 与元数据库

Kylin 3.10 构建 Cube 的时候,需要从 Hive 获取表结构,所以 Hive 必须能正常跑起来。 我在 master 上安装 Hive 3.0,并使用 MySQL 存储元数据。

Hive 的配置点主要是 hive-site.xml,需要设置:

  • javax.jdo.option.ConnectionURL,指向 MySQL 中的 hive 元数据库。
  • hive.metastore.uris,设置为 thrift://kylin-master:9083。
  • hive.support.concurrency=true。
  • hive.zookeeper.quorum,指向 Zookeeper 节点。

初始化元数据时执行:

schematool -initSchema -dbType mysql

初始化成功后,单独启动 metastore:

nohup hive --service metastore > /data/logs/metastore.log 2>&1 &

Kylin 读取 Hive 表时会通过 metastore 服务,如果这个服务没起,你在 Kylin Web UI 里看不到任何表,而且日志里会报连接拒绝。

3. Kylin 3.10 部署与版本兼容处理

3.1 解压安装与环境变量

把 Kylin 3.10 的二进制包解压到 /opt/kylin,然后修改 /etc/profile,加入:

export KYLIN_HOME=/opt/kylin export HADOOP_HOME=/opt/hadoop export HBASE_HOME=/opt/hbase export HIVE_HOME=/opt/hive export PATH=$PATH:$KYLIN_HOME/bin:$HADOOP_HOME/bin:$HBASE_HOME/bin:$HIVE_HOME/bin

Kylin 的 check-env.sh 脚本会读取 HADOOP_HOME、HBASE_HOME、HIVE_HOME 这些变量,如果缺失,会直接告诉你环境不完整。 执行:

$KYLIN_HOME/bin/check-env.sh

正常情况会输出 Hadoop 和 HBase 客户端版本信息。 在我这套环境里,check-env.sh 能过,但后面启动 Kylin 时依然会报错,问题出在 Jar 包版本冲突。

3.2 替换 Kylin 的 Hadoop 和 HBase 相关 Jar

这是整套搭建里最关键的一步。 Kylin 3.10 默认带的是 Hadoop 2.x 和 HBase 1.x 的客户端依赖,直接对接 Hadoop 3.0 和 HBase 2.0,会出现多个不兼容类。 我遇到过的典型报错有:

  • java.lang.NoSuchMethodError: org.apache.hadoop.fs.FileSystem.create
  • java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/HTableDescriptor
  • java.lang.NoSuchMethodError: org.apache.hadoop.hbase.client.ConnectionFactory.createConnection

这些本质都是因为 Kylin 内嵌的依赖版本太旧。 解决思路很简单:把 Kylin 自带的旧版本 Jar 替换成当前环境 Hadoop/HBase 对应的 Jar。

具体操作如下。

Hadoop 方面:

cd /opt/kylin/tomcat/lib # 将原先 hadoop-*.jar 移到一个 backup 目录 mkdir -p /opt/backup/kylin-hadoop-jars mv /opt/kylin/tomcat/lib/hadoop-*.jar /opt/backup/kylin-hadoop-jars/ # 把 Hadoop 客户端相关 jar 软链进来 ln -s /opt/hadoop/share/hadoop/common/*.jar /opt/kylin/tomcat/lib/ ln -s /opt/hadoop/share/hadoop/hdfs/*.jar /opt/kylin/tomcat/lib/ ln -s /opt/hadoop/share/hadoop/client/*.jar /opt/kylin/tomcat/lib/ ln -s /opt/hadoop/share/hadoop/mapreduce/*.jar /opt/kylin/tomcat/lib/ ln -s /opt/hadoop/share/hadoop/yarn/*.jar /opt/kylin/tomcat/lib/

HBase 方面:

# 同理,先备份旧 jar mv /opt/kylin/tomcat/lib/hbase-*.jar /opt/backup/kylin-hbase-jars/ # 引入 HBase 2.0 的 client 和 server jar ln -s /opt/hbase/lib/hbase-client-2.0.2.jar /opt/kylin/tomcat/lib/ ln -s /opt/hbase/lib/hbase-common-2.0.2.jar /opt/kylin/tomcat/lib/ ln -s /opt/hbase/lib/hbase-server-2.0.2.jar /opt/kylin/tomcat/lib/ ln -s /opt/hbase/lib/hbase-protocol-2.0.2.jar /opt/kylin/tomcat/lib/ ln -s /opt/hbase/lib/hbase-hadoop-compat-2.0.2.jar /opt/kylin/tomcat/lib/

这里有个细节:HBase 2.0 的 client 会依赖一些 Netty 和 Trace 相关类,如果发现运行时还是抱 ClassNotFound,把 HBase lib 目录下对应的 netty-*.jar 也一并软链过去。 我没做这一步之前,Kylin 启动时卡在 HBase 连接初始化上,改了之后才正常。

另外,Zookeeper jar 也要注意。 HBase 2.0 自带 ZK 3.4.13 的 client,而 Kylin 自带可能是 ZK 3.4.5 或者其他版本。 建议把 Kylin 的 zookeeper-.jar 也清理掉,软链到 /opt/hbase/lib/zookeeper-.jar,避免 Session 莫名其妙断开。

3.3 修改 Kylin 核心配置

Kylin 的配置文件是 $KYLIN_HOME/conf/kylin.properties。 我这次改动过的关键项如下:

kylin.server.mode=all kylin.metadata.url=kylin_metadata@hbase kylin.storage.hbase.region-cut-gb=5 kylin.engine.mr.lib-dir=/opt/kylin/lib kylin.job.concurrency=8 kylin.hbase.region.count.min=8 kylin.source.hive.enable=true

解释几个关键参数。

kylin.server.mode=all:本机既要跑查询,也要跑 Job。 如果拆成多节点,可以把 query 和 job 分开。

kylin.metadata.url:Kylin 的元数据默认存放在 HBase 里,这个配置会给 Kylin 自动创建一个名为 kylin_metadata 的 namespace/表。 第一次启动时会自动建表,不需要手动处理。

kylin.storage.hbase.region-cut-gb:单个 Region 超过 5GB 就触发切割,这会影响 Cube 构建时的 HBase 写入和查询性能。 除非数据量很小,否则不建议设太低,Region 切分频繁会导致构建任务变慢。

kylin.hbase.region.count.min:预分区数量下限。 如果维度组合比较多,建议把这个值调大,减少单 Region 热点问题。

3.4 启动 Kylin 并初始化元数据

所有基础服务就绪后,在 kylin-master 上执行:

$KYLIN_HOME/bin/start.sh

启动时需要等待几十秒,日志在 $KYLIN_HOME/logs/kylin.log。 第一次启动会初始化 HBase 元数据,如果看到:

New metadata store created: kylin_metadata@hbase

说明元数据库初始化成功。

访问 http://kylin-master:7070/kylin,默认账号 ADMIN / KYLIN。 登录后进入 “System” 页面,可以看到 Hadoop 3.0.3、HBase 2.0.2 这些版本信息。 如果这里显示的不是 2.0.2 而是 1.x,说明 Jar 没有替换干净,回 3.2 节继续处理。

启动 Kylin 前,最好先确认 Hive Metastore 也在运行。 很多同学会漏掉这一步,导致 Kylin 界面的 “Data Source” 里加载不到表。

4. 实操演示:第一个 Cube 构建与查询

4.1 准备 Hive 测试数据

先建一个简单的销售事实表,模拟线上的订单记录。

CREATE DATABASE test_db; CREATE TABLE test_db.fact_sales ( order_id string, product_id string, category string, amount double, order_date string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ','; LOAD DATA LOCAL INPATH '/data/sales.csv' INTO TABLE test_db.fact_sales;

sales.csv 内容类似:

1001,P001,手机,2999.0,2024-01-01 1002,P002,电脑,5999.0,2024-01-02 1003,P001,手机,2999.0,2024-01-03 1004,P003,耳机,399.0,2024-01-03

数据量很小,但流程和真实场景一致。 后面构建 Cube 时,Kylin 会跑到 YARN 上执行 MapReduce,这需要 Hadoop 集群本身正常。

4.2 创建 Model 和 Cube

进入 Kylin Web UI,先建 Project,名称随便,比如 sale_analysis。 然后在 Data Source 里加载 Hive 表,选择 test_db.fact_sales 即可。

Model 创建时,我需要指定:

  • 事实表:fact_sales。
  • 维度字段:category、product_id、order_date。
  • 度量字段:amount,聚合方式为 SUM。

Cube 创建时,我重点讲几个容易被忽略的配置。

Rowkeys 的选择顺序直接影响 HBase 的查询效率。 建议把高基数的维度放前面,比如 product_id 放第一,order_date 第二,category 放最后。 如果维度基数相差很大,还可以开启 Mandatory Dimension 和 Hierarchy Dimension 来剪枝,减少 Cube 膨胀。

聚合组也很关键。 比如 order_date 按天、按月、按年分别聚合,可以配置成 Hierarchy 关系,否则 Kylin 会生成大量多余的 Cuboid,造成 Cube 体积爆炸。 我之前在另一个项目里没做裁剪,几千万行的数据直接生成几百万个 Cuboid,构建时间从半小时变成十几小时,非常痛苦。

度量可以选 SUM(amount),也可以加一个 COUNT_DISTINCT(order_id) 来算订单数。 需要注意 COUNT_DISTINCT 会占用更多存储,而且构建比 SUM 慢,不是必需就不用。

4.3 构建 Cube

在 Cube 页面点击 “Action -> Build”,选择全量构建。 我这次数据量小,选择 “Refresh” 和 “Build” 都可以。 点击后,Kylin 会提交一个 MR Job 到 YARN 上,日志里会显示 job ID。

Build 过程一般包括:

  1. 从 Hive 抽取原始数据。
  2. 基于维度组合做 Cube 预计算。
  3. 将结果写入 HBase。
  4. 在 HBase 中生成 HTable 并注册 Coprocessor。

如果前面 Jar 替换有问题,这一步最容易暴露,比如 hbase coprocessor 相关类错误。 我在 HBase 2.0 上遇到过一个典型问题:Coprocessor 加载失败导致 RegionServer 直接卡死。 后来发现是 Kylin 的 hbase-server jar 版本太老,替换成 HBase 2.0.2 的 jar 后,才能正常构建。

构建完成的状态是 GREEN。 如果失败,点进去看 MapReduce 日志,基本都能定位到具体异常。

4.4 SQL 查询

构建完成后,在 Kylin Web UI 的 “Insight” 页面写 SQL:

SELECT category, SUM(amount), COUNT(DISTINCT order_id) FROM test_db.fact_sales GROUP BY category;

Kylin 会把这条 SQL 重新路由到已经构建好的 Cube 上,而不是去扫 Hive 表。 我第一次跑这条查询时,因为数据量很小,几乎 1 秒内就返回了。 如果直接跑 Hive,需要提交一个 MR 任务,快则几秒,慢则几十秒。 这就是 Kylin 的核心价值:复杂维度聚合,提前算好,查询时只做 HBase 扫描。

5. 常见问题速查与实战避坑

5.1 启动与依赖问题

Kylin 启动时报 Hadoop/HBase 类无法加载:基本都是因为 Kylin 自带的 Jar 与环境版本不一致。 按 3.2 节的替换方法处理。 替换后最好重启 Kylin,而不是热加载。

check-env.sh 提示 HADOOP_HOME 未设置:确认 /etc/profile 已配置,并且当前 shell 执行过 source /etc/profile。 Kylin 脚本不会主动读取 /etc/profile,需要你在启动前手动 export,或者放到启动脚本里。

HBase RegionServer 崩溃,日志出现 coprocessor 相关异常:把 Kylin tomcat lib 下的 hbase-server-*.jar 换成 HBase 2.0.2 的版本,同时检查 Kylin 的 coprocessor 注册是否在构建后生效。

5.2 构建 Cube 的问题

构建任务卡住不动:先看 YARN ResourceManager 是否有任务;再查看 Kylin 日志,看是否卡在 Hive 抽取阶段。 多数是 Hive Metastore 没启动,或者 Hive 连接超时。

维度组合过多导致 Cube 膨胀:构建后的 HDFS 存储可能比原表大几十倍。 合理设计聚合组、启用 Mandatory 和 Hierarchy 维度、必要时用聚合组里的“联合维度”。 这是一开始就要想清楚的,而不是等构建完了再改。

构建后查询结果不对:检查 Model 的时间维度。 如果你用了增量构建,时间字段格式必须和 Hive 表一致,否则会丢数据。

5.3 查询慢的问题

查询响应突然变慢:先看 HBase 是否有 Region 热点。 如果单个 Region 太大,会降低并行扫描能力。 调大 kylin.storage.hbase.region-cut-gb 不合理,应该把预分区数量增加,或者优化 Rowkey 顺序。

SQL 没有命中 Cube:Kylin 不是所有 SQL 都能跑。 如果你的查询维度组合不在 Cube 的 Cuboid 列表里,Kylin 会扫描进度增大的 Cuboid,速度变慢。 打开 SQL 的 “Query Result” 能看到命中的 Cuboid 信息,拿这个作为优化依据。

5.4 问题速查表

现象可能原因处理方式
登录 Kylin 后加载数据源为空Hive Metastore 未启动启动 Hive metastore
启动 Kylin 报 NoClassDefFoundErrorJar 版本冲突替换 Kylin tomcat/lib 下的 Hadoop/HBase jar
构建 Cube 时 MR Job 失败HBase 客户端依赖缺失软链 HBase 2.0 全部依赖 jar 到 Kylin lib
RegionServer 崩溃HBase Coprocessor 类加载失败替换 hbase-server jar 并重启组件
查询结果不准确增量构建时间配置错误检查 Model 的时间范围和 Hive 时间格式
Cube 构建后体积过大Cuboid 裁剪不到位启用聚合组、强制维度、层次维度

最后聊点体会

这套环境组合,Hadoop 3.0 + HBase 2.0 + Kylin 3.10,不是装完就能用的,核心工作量大多花在依赖兼容上。 我个人的建议是:不要一上来就做 Cube 调优,先把 Kylin 元数据初始化、Web UI 登录、数据源加载、Cube 构建这条链路跑通,再去考虑维度裁剪和查询性能。 版本兼容问题,优先通过替换 Jar 解决,而不是改代码。

另外,HBase 2.0 的稳定性和 Hadoop 3.0 的 ResourceManager 都还有不少内存问题,建议严格控制 YARN 容器内存大小,并给 Kylin 单独预留 JVM 堆。 我们团队后来为 Kylin 加了独立节点,和 HBase 的 RegionServer 分开部署,内存压力就缓解了很多。

如果你也是要在新版本 Hadoop/HBase 上跑 Kylin,最好先把 Kylin 官方包里自带的依赖清单导出来,再和当前环境做 diff。 这个步骤看起来麻烦,却能省下后面排查问题的大量时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进