
简介面向 Ambari 2.7.5 编译场景这份 HBase 二进制发行包是本地构建流程中最值得提前获取的大包之一。官方源或第三方源下载缓慢时提前准备该包可避免构建中途卡死、反复重试也适合离线机房与企业内网。包内共有四百一十二个文件压缩后约二百一十一点五七兆一百九十四个归档包构成核心运行库一百五十八个脚本支持命令行交互十七个脚本处理服务启停与配置六份配置定义参数多份网页静态资源支撑自带管理界面。已有两千一百九十五人学习或下载说明该需求很普遍。拿到后可离线解压部署也可导入本地仓库加速后续编译包内包含常用启停、环境配置脚本和标准目录层级便于快速了解流程、调整配置或排查问题显著减少等待和带宽消耗。1. 这个tar.gz不是社区版先看懂版本号再往下动手如果你和我一样从某个镜像站拉下来一个叫 hbase-2.0.2.3.1.4.0-315-bin.tar.gz 的文件第一反应可能是“哦HBase 2.0.2 社区版”。真这么干会吃亏。这个版本号的构成是 Apache HBase 2.0.2 加某个发行版的内部版本 3.1.4.0-315它绑定了该发行版自己编译的依赖库和配置模板能解决下载源码自己编、第三方 HDFS 兼容性这两大痛点也引入了不少和社区版不一样的默认行为。我接下来按这个 tarball 实际部署会遇到的路走一遍从校验文件、配置三节点集群到用 PySpark 写 HBase再把这版本上最容易踩的 5 个坑摆出来。适合没有源码编译习惯、想离线快速起一套 HBase 做数据服务的开发和运维同学。2. 安装前四件事校验文件、解压、选目录、准备依赖2.1 先校验你的tar.gz别是半截文件运维里最怕的不是版本不兼容而是文件下到一半以为下完了。一个缺失的 tar 包解压时可能报gzip: invalid compressed data也可能正常解压但缺了 lib 下的某个 jar让 HBase 启动时抛ClassNotFound。所以拿到 hbase-2.0.2.3.1.4.0-315-bin.tar.gz 的第一件事不是解压而是校验。常见做法是下载发布方提供的 SHA256 校验文件然后用# 下载校验文件 wget https://your-mirror.example/hbase-2.0.2.3.1.4.0-315-bin.tar.gz.sha256 # 校验主包 sha256sum -c hbase-2.0.2.3.1.4.0-315-bin.tar.gz.sha256如果输出hbase-2.0.2.3.1.4.0-315-bin.tar.gz: OK说明文件完整。没有官方校验文件时你也可以临时用sha256sum hbase-2.0.2.3.1.4.0-315-bin.tar.gz自己计算一个值记录在案等同事从另一个内网源拉下来之后两份对比。这一步看似浪费时间但对一个接近 1.5GB 的二进制包来说能省下后面排错的两三个小时。有些发行版还会额外提供.asc的 GPG 签名文件用于验发布者的身份而不是只验文件完整性。内网部署时如果拿不到公钥可以跳过 GPG但 SHA256 一定要做。我自己遇到过把-bin.tar.gz和-src.tar.gz下混的情况文件名极其相似如果没有校验直接解压后面编译环境搭了就很难发现。2.2 解压与目录结构bin/ conf/ lib/ 都在里面装了什么我习惯把这类二进制分发包装在/data/service下用固定属主运行不直接放在/opt根目录里。先创建用户和目录再解压groupadd hbase useradd -g hbase -s /bin/bash hbase mkdir -p /data/service /data/hbase-data tar -zxvf hbase-2.0.2.3.1.4.0-315-bin.tar.gz -C /data/service ln -s /data/service/hbase-2.0.2.3.1.4.0-315 /opt/hbase chown -R hbase:hbase /data/service/hbase-2.0.2.3.1.4.0-315 /data/hbase-data软链到/opt/hbase是为了让配置脚本里的路径固定升级时只需改一次软链。解压后的关键路径和用途如下路径用途需要关注的点bin/hbase客户端与运维命令行入口所有hbase shell、hbase hbck都走它bin/start-hbase.sh启动整个集群会读regionservers文件做 SSH 分发bin/hbase-daemon.sh启停单个 Master/RegionServer常被集成到自研部署脚本conf/hbase-env.shJVM 与进程级环境变量必须改JAVA_HOME、堆大小conf/hbase-site.xmlHBase 全部运行时参数分布式模式的关键配置conf/regionserversRegionServer 主机名列表每行一个不能有空行lib/*.jar内置依赖含 Hadoop 客户端与 ZK 客户端不要用其他版本的 jar 混替换这个发行版在conf/目录下往往多放一个version.properties或RELEASE_NOTES文件里面写的真实 HBase 版本和补丁编号是可以当权威去读的。我之前就因为只看文件名里的2.0.2去查 Apache 社区版的 release note结果有几个配置项在社区版文档里根本不存在后来才发现是发行版自己加的。解压之后顺手检查一下 jar 包里是否包含日志依赖尤其是lib/下是否有slf4j-api和log4j-slf4j-impl。如果这个发行版自带的是log4j 1.x而你的系统里又有别的slf4j版本很容易在启动时出现SLF4J: Class path contains multiple SLF4J bindings的警告那不影响启动但会掩盖日志输出线上抓问题时会很难受。2.3 依赖环境JDK 8、ZooKeeper 3.4/3.5 的选择细节HBase 2.0.x 对 JDK 的要求比较硬官方支持 JDK 8实测用 JDK 11 启动也能跑但某些发行版的hbase-env.sh里有 JDK 版本判断用错版本会在日志里留下Unsupported major.minor version的异常。我一般固定JAVA_HOME指向 JDK 8 路径并写死在hbase-env.sh里不让 HBase 自动探测/usr/bin/java——自动探测很可能拿到系统默认的 JDK 17那几乎是必挂的。ZooKeeper 的选择更有说法。Apache HBase 2.0.2 自身带了一个hbase-zookeeper模块可以不用外部 ZK在单机开发时配一下就能自动起一个本地 ZK。但这个“bin”发行版默认面向生产集群我更倾向于使用独立部署的 ZooKeeper原因有两点一是 HBase、Kafka 等多套服务可以共用一套 ZK运维成本低二是外部 ZK 可以做独立的数据目录和权限管理HBase 节点挂掉时 ZK 还能继续服务其他业务。如果你选 ZooKeeper 3.5.x有个细节必须注意3.5 的 admin server 默认绑定 8080 端口跟 HBase Master Web UI 的常用端口冲突。所以要在zoo.cfg里改掉 admin server 端口# zoo.cfg 片段 tickTime2000 initLimit10 syncLimit5 clientPort2181 dataDir/data/zk-data admin.serverPort8081启动 ZK 之后用bin/zkCli.sh -server 10.0.0.11:2181 ls /验证能连通。集群通信端口 2888、3888 也需要在防火墙放行不只是 2181。HBase 本身只连 ZK 的 clientPort但 ZK 集群内部同步如果失败Master 和 RegionServer 的 session 状态会一直变HBase 就会频繁重连表现为集群起来了但表区域总在 RITRegions In Transition状态。把这三件套准备完整后再往下配置一个要素内存。HBase 是“吃内存”大户RegionServer 的 JVM 堆和操作系统的 page cache 之间要预留足够余量。如果测试机器只有 8GB 内存同时还要跑 NameNode、DataNode 和 ZooKeeper那建议先压缩规模只在一台机器上起 standalone 模式验证而不是强行起三节点伪分布式否则后面第 5 章的第一个坑会等着你。3. 配置并启动一个三节点HBase集群3.1 修改hbase-env.shJVM堆、GC、JAVA_HOME别用自动检测conf/hbase-env.sh是启动前必须改的。这个发行版默认带了大量注释掉的模板项其中HBASE_MANAGES_ZK是重点如果设为trueHBase 会在每个节点自己拉起一个 ZooKeeper多套 HBase 共用一个物理机时容易端口互踩。我统一设为false用外部 ZK。# conf/hbase-env.sh 关键行 export JAVA_HOME/usr/lib/jvm/jdk8u export HBASE_HEAPSIZE4G export HBASE_MASTER_OPTS-Xms4g -Xmx4g -XX:CMSInitiatingOccupancyFraction60 export HBASE_REGIONSERVER_OPTS-Xms8g -Xmx8g -XX:CMSInitiatingOccupancyFraction70 export HBASE_PID_DIR/data/hbase-pids export HBASE_LOG_DIR/data/hbase-logs export HBASE_MANAGES_ZKfalseHBASE_HEAPSIZE是全局默认堆大小但如果同时设置了HBASE_MASTER_OPTS和HBASE_REGIONSERVER_OPTS那后两者会覆盖前者。所以我通常把 Master 和 RegionServer 的堆分开写避免“一起调大”导致 RegionServer 吃满内存。堆大小设置要遵循一个原则Master 不是数据路径给 4G 足够RegionServer 的-Xmx建议不要超过物理内存的 1/3。原因是我们还需要给操作系统 page cache 留空间因为 HBase 读 HFile 时依赖 HDFS 客户端而 HDFS 客户端读 DataNode 时走本地文件系统page cache 命中率直接影响读性能。此外堆外内存还有hbase.client.write.buffer的分配、压缩库 native 内存等留少了会出现莫名其妙的OutOfMemoryError: Direct buffer memory。GC 方面HBase 2.0 时代 G1 在长期运行下还不太稳容易出现 Full GC 引起的长时间暂停而 CMS 配合CMSInitiatingOccupancyFraction70更可控。这个发行版在脚本里可能自带了一段针对 JDK 8 的 CMS 参数你只要确保-XX:UseConcMarkSweepGC出现在 RegionServer 的启动参数里即可。如果想观察 GC再追加-XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:/data/hbase-logs/gc-regionserver.log有了 GC 日志后面排查 RegionServer 卡顿会轻松很多。3.2 修改hbase-site.xmlDir与ZK端口参数对照表hbase-site.xml是整个集群的“总电门”。这个发行版和社区版最大的差异在于它自带的默认配置可能指向开发环境路径比如/usr/local/hbase权限不匹配就会在启动时抛Permission denied。我需要逐个检查的关键参数如下参数推荐值说明hbase.rootdirhdfs://nn01:8020/hbaseHBase 在 HDFS 上的根目录必须 hbase 用户可写hbase.zookeeper.quorumzk01,zk02,zk03外部 ZK 地址逗号分隔hbase.zookeeper.property.clientPort2181ZK 客户端端口hbase.cluster.distributedtrue分布式模式false 表示单机版hbase.master.info.port16010Master Web UI 端口hbase.regionserver.info.port16030RegionServer Web UI 端口hbase.client.write.buffer8388608客户端写缓冲 8MBhbase.hregion.max.filesize10737418240单个 HFile 达到 10G 触发分裂hbase.hregion.memstore.flush.size134217728MemStore 达到 128MB 刷写 HFile配置写在configuration标签内configuration property namehbase.rootdir/name valuehdfs://nn01:8020/hbase/value /property property namehbase.zookeeper.quorum/name valuezk01,zk02,zk03/value /property property namehbase.cluster.distributed/name valuetrue/value /property property namehbase.master.info.port/name value16010/value /property property namehbase.regionserver.info.port/name value16030/value /property /configuration端口清单是面试和排错都会问到的东西这里整理一份Master RPC 端口16000RegionServer RPC 端口16020Master Web UI16010RegionServer Web UI16030连接 ZK2181读 HDFS NameNode8020读 DataNode 数据流通常走9866。另外 HBase 客户端连接 Thrift2 时默认用9098不是旧的 9090。3.3 启动顺序与“假启动”验证分布式 HBase 的启动顺序是铁律先 ZooKeeper再 HDFS最后 HBase。很多人上来就start-hbase.sh然后 Master 起不来日志里全是Unable to connect to ZooKeeper。正确顺序# 在每台 ZK 节点上启动 ZK su - hbase -c /data/zk/bin/zkServer.sh start # 在 NameNode 节点启动 HDFS su - hdfs -c /opt/hadoop/sbin/start-dfs.sh # 同步 conf 到所有 RegionServer 节点后在 Master 节点启动 HBase for node in node01 node02 node03; do scp -r /data/service/hbase-2.0.2.3.1.4.0-315/conf hbase${node}:/data/service/hbase-2.0.2.3.1.4.0-315/ done su - hbase -c /opt/hbase/bin/start-hbase.shstart-hbase.sh会读conf/regionservers文件通过 SSH 到每台机器执行hbase-daemon.sh start regionserver。所以 hbase 用户必须配置了到所有 RegionServer 的 SSH 免密登录。如果没配好它只会启动本机 Master 和本机 RegionServer其他节点在日志里没有任何报错看起来一切正常。启动后不要只看jps出现HMaster和HRegionServer就宣布成功这一步可能是“假启动”。真正的验证是su - hbase -c /opt/hbase/bin/hbase shell status detailedstatus detailed会输出每个 RegionServer 的堆使用、请求数、在线 Region 列表。如果 web UI 的 “Regions in Transition” 数值长期不为 0说明有 Region 卡在迁移中。还可以用一行命令快速测试表操作echo create test_conn, cf | su - hbase -c /opt/hbase/bin/hbase shell echo put test_conn, row1, cf:a, v1 | su - hbase -c /opt/hbase/bin/hbase shell能正常 put 和 get 才算真正的连通。注意hbase hbck这个老牌检查工具在 2.0.2 版本中已经不建议在线上用于修复了它只能做只读检查具体原因后面第 5 章会提到。4. 数据写入与PySpark对接从Shell到API4.1 建表与Shell常用操作预分区和版本数hbase shell是熟悉数据模型最快的方式。这个发行版的 shell 和 Apache 2.0.2 基本一致只是连接地址默认走了hbase.zookeeper.quorum配置。建表时我会顺手做预分区让写入不再只压在一个 Region 上。比如按十六进制前缀预分裂create user_log, { NAME cf, VERSIONS 3, COMPRESSION SNAPPY }, { SPLITS [00,50,a0,f0] }SPLITS定义了 4 个 Region 边界前缀小于00的、00~50的、50~a0的、a0~f0的。如果你的 rowkey 是user001_20250101这样的风格写入会按第一个字节分桶。VERSIONS3表示同一 rowkey 保留最近 3 次覆盖记录能支持回溯历史COMPRESSIONSNAPPY比默认NONE省一半磁盘代价是多一点 CPU。常用的读写命令在这里# 写入一个 cell put user_log, user001_20250101, cf:total_time, 128 # 读取一个 rowkey 的所有版本 get user_log, user001_20250101, { COLUMN cf:total_time, VERSIONS 3 } # 前缀扫描 scan user_log, { STARTROW user001, LIMIT 100 } # 删除表必须先 disable disable user_log drop user_log注意put默认走客户端的 write buffershell 里一次 put 一条不会触发批量提交。想要真正体现“批量”优势要么用 Java API 的BufferedMutator要么用下面要说的 PySpark HappyBase 方案。4.2 让PySpark通过HappyBase批量写入HBase一线最常见的场景是清洗后的 DataFrame 要推到 HBase。用 PySpark 写 HBase 有三条路一是用org.apache.hadoop.hbase.spark这个 jar 在 2.0.2 的 lib 里没有内置自己编容易踩 Scala 版本冲突二是用 HBase 的 REST API吞吐不高三是用 Python 的 HappyBase 库在 RDD 的foreachPartition里复用连接批量 put。第三种最稳定面试中问到“PySpark 怎么写 HBase”这也是主流答案。# pip install happybase import happybase def write_to_hbase(iterator): # 每个分区建立一次连接不要在 foreach 里逐行建连 conn happybase.Connection(zk01, port9098) conn.open() table conn.table(user_log) batch table.batch(batch_size500) for row in iterator: rowkey {}#{}.format(row[user_id], row[day]) batch.put(rowkey, { cf:total_time: str(row[total_time]), cf:request_count: str(row[request_count]), }) batch.send() # 发送剩余不足一批的数据 conn.close() df.rdd.foreachPartition(write_to_hbase)这里有几个关键参数要理解。batch_size500控制一次 RPC 携带的行数500 在默认 8MB write buffer 下比较安全如果单行 value 很大比如超过 10KB就要把 batch_size 调小到 100否则可能触发BufferUnderflowException。happybase.Connection(zk01, port9098)中的端口是 Thrift2 的默认端口前提是 HBase 集群已经启动了 Thrift2 服务/opt/hbase/bin/hbase-daemon.sh start thrift2启动后日志里会看到ThriftServer.java开始监听 9098。记得别启动旧的thrift9090新版 HappyBase 走的是hbase.thrift.protocol和旧版不兼容。rowkey 设计也要配合表结构。示例中user_id # day是为了让扫描某个用户某一天的数据快但若建表时的预分区是00、50、a0、f0而user_id是数字前缀分布就不均匀。更稳的方案是在put前对user_id做一次散列把散列前缀拼到 rowkey 最前面这就是第 6 章要展开的预分区热点治理。4.3 写入内存参数写路径上的三个闸门遇到写 HBase 慢大多数不是网络问题而是写路径上的三个参数互相制约hbase.client.write.buffer客户端缓冲 8MBbuffer 满了才把数据发给 RegionServer。在 HappyBase 的 batch 里batch_size是行数闸门buffer 是字节数闸门谁先满谁触发发送。hbase.hregion.memstore.flush.sizeRegionServer 每个 Region 的 MemStore 达到 128MB 就刷成 HFile。写请求峰值超过刷写速度时线程会卡在 MemStore 上。hbase.hregion.memstore.block.multiplier默认 4表示 MemStore 达到128MB * 4 512MB时会阻塞写入。如果你想提升短时突发吞吐可以临时把 multiplier 调到 5 或 6但要保证 RegionServer 的 MemStore 总占用不超过堆的 40%否则会报Region too big。这三者其实决定了 HBase 单 Region 的突发写入上限。调整前先看 RegionServer Web UI 的 “MemStore Size” 指标如果长期超过堆的 35%说明刷写或分裂跟不上不是单纯调大 buffer 能解决的。常见的调优组合是堆 16G 时memstore.flush.size保持 128MBblock.multiplier保持 4然后靠预分区增加并行 Region 数来提高吞吐而不是靠压单个 Region。5. HBase 2.0.2部署的5个高频坑现象、原因、解法5.1 现象RegionServer 秒退日志只有一句内存不足现象执行start-hbase.sh后jps 能看到HRegionServer进程但十几秒后消失。查看/data/hbase-logs/hbase-hbase-regionserver-xxx.log末行只有一句Fatal error: Unable to construct memstore或者Cannot allocate memory。原因这个发行版默认的HBASE_REGIONSERVER_OPTS里-Xmx设得很大而测试机物理内存只有 8GB同时还在跑 HDFS、ZK操作系统的提交内存已经耗尽JVM 无法分配堆外或堆内空间进程直接被追 kill。解决先把-Xmx降到一个安全值比如 4G再看/etc/security/limits.conf里 hbase 用户的memlock和nofile限制写入hbase - memlock unlimited hbase - nofile 65536改完必须重新登录 hbase 用户或重启会话用ulimit -a确认值已生效。这个坑和 HBase 2.0.2 版本无关是纯环境问题但它最能让人怀疑人生——因为日志里没有明显异常。5.2 现象Shell能扫描写多后报 RowNotInRegion现象集群运行一天后写入时偶发org.apache.hadoop.hbase.NotServingRegionException异常详情写着Region ... is not online on ...重试后有时成功有时持续报错。原因HBase 2.0.2 默认的hbase.hregion.max.filesize为 10G高并发下 Region 分裂频繁。当 Region 在 Master 上重新分配时旧的 RegionServer 没来得及关闭该 Region客户端仍向旧地址发送请求于是抛出 NotServingRegionException。本质上这是 2.0 的 Assignment Manager 在旧版本上的已知缺陷。解决最彻底的是升级到该发行版的后续补丁版。如果你只能守着 2.0.2那就减少分裂频次把hbase.hregion.max.filesize调到 20G同时把hbase.client.retries.number从默认的 35 提高到 50让客户端在 Region 迁移期间多重试几轮。注意这是权宜之计当 Region 总数仍然增长到几千时问题还会回来最终还是要规划预分区规模。5.3 现象Master与RegionServer互相踢对方日志全是Unexpected zk session现象集群节点时间不一致某台 RegionServer 比 Master 慢 5 秒运行一段时间后Master 日志中频繁出现Unexpected zk session或RegionServer ... is dead的误判随后真 RegionServer 自己退出。原因HBase 使用 ZooKeeper 的 session 超时来感知节点存活默认zookeeper.session.timeout是 90 秒。节点间时钟偏差过大时Master 和 RegionServer 对 ZK 的临时节点事件处理顺序会出现不一致进而互相触发过期 session。解决所有 HBase 节点和 ZK 节点强制使用同样的 NTP 时间源并配置定时同步。同时在hbase-site.xml中调大 session timeoutproperty namezookeeper.session.timeout/name value120000/value /property注意session timeout必须大于等于tickTime的两倍tickTime 默认 2000ms也就是至少 4000ms。但线上建议给到 120000ms给网络抖动和时钟同步留足余量。5.4 现象端口被占用但 netstat 查不到监听现象启动 Master 时日志显示Failed to bind to 0.0.0.0:16010: Address already in use但执行netstat -tlnp | grep 16010毫无输出。原因netstat 默认只查 IPv4而这个发行版在纯 IPv6 主机或java.net.preferIPv4Stack未设置的情况下Master 可能占用了tcp6的 16010也可能是上一次进程异常退出留下了TIME_WAIT的 socket阻碍了立即重绑。解决改用ss -ltnp | grep 16010查 IPv6 socket看到占用进程后 kill 掉如果是 TIME_WAIT可以等待或直接在hbase-env.sh中加export HBASE_MASTER_OPTS$HBASE_MASTER_OPTS -Djava.net.preferIPv4Stacktrue强制使用 IPv4 后这类玄学端口占用问题会大幅减少。5.5 现象设置了 hbase.master.info.port 却不生效Web端口还是旧的现象把hbase-site.xml里的hbase.master.info.port改成 16888重启 Master 后访问 16888 无响应日志里仍显示绑定在 16010。原因这个发行版的bin/hbase启动脚本在读取配置时JAVA_OPTS里的系统属性优先级高于hbase-site.xml。如果你从历史脚本里复制了-Dhbase.master.info.port16010它会覆盖 XML 中的设置。解决检查hbase-env.sh和hbase-daemon.sh中所有-D开头的参数删掉对hbase.master.info.port的覆盖然后统一搜索grep -rn 16010 /opt/hbase/conf/确保没有环境变量、属性和脚本硬编码同时存在。这一个坑花了我一下午最后发现是旧的启动脚本里带了一串-D参数删掉后立刻生效。6. 进阶RowKey散列预分区让2.0.2集群不再热点HBase 的写入热点是 2.0.2 最常见的病预分区能挡掉一半另一半靠 rowkey 设计。这里给出一个我常用的散列预分区方案也当作对第 3 章建表语句的升级。常见错误是直接拿业务 ID 或时间戳当 rowkey 前缀比如20250101120000-userid这会让每秒的写入全部命中同一个 Region。正确做法是让 rowkey 的首字节尽量均匀。对整型业务键我会先做 MD5 再取两位十六进制作为前缀import hashlib def gen_rowkey(biz_id: int, ts: str) - str: # 取 MD5 的第一个字节相当于 256 个桶再转成两位十六进制 digest hashlib.md5(str(biz_id).encode(utf-8)).hexdigest()[:2] return {}_{}_{}.format(digest, biz_id, ts)配合建表时按 256 个预分区create metric, { NAME d, COMPRESSION SNAPPY, VERSIONS 1 }, { NUMREGIONS 256, SPLITALGO HexStringSplit }NUMREGIONS256配合HexStringSplit会把 rowkey 首字节00~ff切成 256 个 Region。这里有个关键参数要拿捏256 个 Region 对 6 台 RegionServer 来说偏多每台平均 40 多个 Region内存和线程都吃紧。建议按RegionServer 数 * 15来设比如 6 台就建 96 个 Region。HexStringSplit会根据总 Region 数自动切前缀区间不需要手工列 96 个 split。散列后的 rowkey 牺牲了“范围扫描”的效率你想查某用户某天的数据不能直接用STARTROW123_...前缀扫描必须先用同一个gen_rowkey算出前缀再发起查询。可在业务层做一个映射缓存或者在 HBase 里建一张前缀索引表。这是拿读的简单性换写的均匀性是否划算要看业务查询模型。验证是否热点最简便的办法是打开每个 RegionServer 的 Web UI16030查看 “Online Regions” 里每个 Region 的 request 数排序。也可以用一段简单的 PySpark 任务生成模拟 rowkey 并写入然后统计每台 RegionServer 的写请求数。如果某台机器是其他机器的 5 倍以上说明前缀分布失衡了。我现在养成的习惯是凡是要长期写入的表建立时一定把预分区、压缩编码DATA_BLOCK_ENCODINGFAST_DIFF一次性配好因为 2.0.2 的表即使支持alter改编码MemStore 里的历史数据也不会重新编码。等线上出现热点才去改 rowkey 设计相当于把表重灌一遍代价远大于建表时的设计成本。希望这个建议能帮到你少走我当年走过的弯路。本文还有配套的精品资源点击获取