十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Hadoop+HBase+Spring Boot的分布式网盘系统架构与调优实践

基于Hadoop+HBase+Spring Boot的分布式网盘系统架构与调优实践 简介基于HadoopHBaseSpring Boot的分布式网盘系统毕业设计资源包面向计算机相关专业学生、毕设开发者及对大数据存储感兴趣的初学者旨在解决毕设选题无头绪、分布式存储系统搭建难的问题。资源包含完整项目源码、数据集与详细设计文档可帮助理解Hadoop与HBase在Web应用中的实际集成方式。包内共1154个文件压缩后约53.81MB主要涵盖Java/JSP后端逻辑、JS/HTML/CSS前端页面、PNG/GIF图片素材及数据库文件等按功能模块组织便于定位与二次开发。项目环境涉及Hadoop、HBase与Spring Boot适合作为毕设、课设或初期项目演示也适合新手学习大数据组件与业务代码的衔接。目前已有195人学习下载。该代码均经过测试运行成功文档包含系统架构、核心功能说明与使用指南读者可在此基础上扩展文件分享、权限管理、断点续传等能力或直接参考其分层设计快速完成自己的毕设项目。1. 用 Hadoop HBase Spring Boot 搭分布式网盘先想清楚一件事很多同学拿到“基于 Hadoop HBase Spring Boot 实现分布式网盘系统”这个题目第一反应是去搜源码、跑 demo、截图交差。但真正答辩或者面试被追问时往往卡在同一个问题上HDFS 到底存了什么HBase 又存了什么两边为什么不能互相替代如果只说“HDFS 存文件、HBase 存元数据”评委下一个问题就是“为什么不用 MySQL 存元数据”这一关很难过去。网盘系统本质上是两个存储诉求的叠加文件内容需要高吞吐、大容量、顺序读写的存储文件属性、目录树、分块索引、分享链接这类数据需要低延迟、高并发、支持范围扫描的存储。HDFS 负责前者HBase 负责后者Spring Boot 作为接入层把两者缝在一起这就是该标题背后真正的架构逻辑也是分布式网盘和单体网盘的分水岭。这篇博文不打算复述任何“源码包”里的代码而是按一线工程师的做法把这个系统从选型、建表、上传下载链路到部署调优完整走一遍。想要高分毕业设计的同学可以直接照做在职读者也能从中看到 HBase 在业务系统中的真实用法和边界。2. 分布式网盘的存储架构HDFS 管块HBase 管索引2.1 为什么网盘的元数据一定要单独拎出来先做一个假设一个网盘里有 10000 个用户每人平均 200 个文件那么文件总量是 200 万。如果元数据直接用小文件存在 HDFS 上NameNode 内存里就要维护 200 万个文件对象的块映射信息而每个文件对象在 NameNode 中占 150 字节的元数据再加上文件副本相关结构NameNode 的堆内存很快会被吃满。更麻烦的是目录树结构在 HDFS 上做“列出某个目录下的所有文件”这种操作需要从根目录逐层遍历延迟不可控。但网络云盘最核心的交互恰恰是“打开某个目录看一眼有哪些文件、大小多少、什么时候改的”这种操作天然适合列存储。HBase 的 RowKey 设计可以直接把文件路径“拍平”成前缀让同目录的文件连续存放一次 Scan 就能拿到整个目录的列表。这是 MySQL 和 HDFS 都做不到的平衡点MySQL 能查但单表数据量上来以后索引维护和分库分表成本高HDFS 能存但不适合高频小查询。所以这个系统的职责切分是固定的文件流走 HDFS文件索引走 HBase业务状态走 Spring Boot 应用层的内存与数据库。很多做得像样的网盘毕设连 MySQL 都不加HBase 里把文件属性和业务状态一起存了也能跑通但如果你想把项目往“分布式”方向拔高建议在 HBase 里只存文件和块索引剩下的用户信息、分享记录可以交给你熟悉的 MySQL反而是加分项。2.2 HDFS 上的文件切块策略与副本放置HDFS 默认块大小是 128MB这是针对大数据分析场景的。但网盘的文件来源五花八门大量小文件只有几 KB 到几 MB如果直接用默认块大小除了放大磁盘占用没有别的意义。HDFS 不会因为文件小于块大小就占用满一个块但小文件过多会让 NameNode 压力上升所以网盘系统上传入口一般会做两件套限制上传文件大小超限走分块上传每块控制在 8MB 到 64MB对小于块大小的文件按目录聚合或者直接原样存储不做额外合并因为网盘的读路径相对低频不值得为小文件合并引入额外的 LSM 复杂度。# hdfs-site.xml 中影响网盘存储的核心配置 property namedfs.blocksize/name value67108864/value !-- 64MB适配网盘的中等文件 -- description数据块大小默认128MB网盘场景调小到64MB可提升小文件读取效率/description /property property namedfs.replication/name value2/value !-- 伪分布式调成1即可集群模式建议2或3 -- description副本数毕设单机环境配1真正集群至少2/description /property块大小调成 64MB 之后写文件的逻辑变得更简单一个 50MB 的文件只占一个块HBase 里也只需要一条块记录一个 200MB 的文件占 4 个块上传时按顺序写HDFS 客户端会自动把文件切到不同 DataNode 上。副本数在单机伪分布式环境必须设成 1否则第二个副本无处可放会一直报NotReplicatedYetException这是最容易被忽略的一个配置。2.3 HBase 表设计一个存文件一个存块HBase 的表设计决定了整个网盘的查询性能这块建议做成两种风格文件信息主表和文件块索引表。文件信息主表的 RowKey 建议用反转用户名加拼接路径的方式比如用户alice的目录/docs/report.pdfRowKey 可以设计为alice_rev_docs_report.pdf。反转用户的目的是打散写入热点避免所有用户都写入同一个 Region。块索引表的 RowKey 则是文件 ID 加块序号例如file_20240901_0001_0000这样同一文件的所有块索引天然相邻下载时只需要一次 Scan。表名RowKey列族主要列典型查询netdisk_file反转用户名 路径cf属性fileName, size, type, parent, createTime目录列表、文件搜索netdisk_chunk文件ID 块号cf索引chunkIndex, blockSize, hdfsPath查某文件全部块位置列族最好只用一个cf不要为了“看着像设计”拆出三四个列族。HBase 一个列族对应一个 MemStore多个列族会导致一个 Region 里有多个 MemStore 同时刷写flush 和 compaction 的动作会变多运维成本直线上升。这是 HBase 官方明确建议过的原则网盘这种元数据系统一个列族完全够用。-- HBase Shell 建表语句对应上面的设计 create netdisk_file, {NAME cf, VERSIONS 1, COMPRESSION SNAPPY, BLOCKCACHE true} create netdisk_chunk, {NAME cf, VERSIONS 1, COMPRESSION SNAPPY, BLOCKCACHE true} -- 预分区可以安排在文件 ID 上做 Hash 前缀让 key 能按顺序散落到不同 region2.4 ZooKeeper 在中间扮演的角色HDFS 的 NameNode 高可用、HBase 的 RegionServer 心跳、Master 选举全都依赖 ZooKeeper。在这个项目里 ZooKeeper 不会出现在业务代码里但环境搭建时它是第一个要启动的进程它挂了整个系统不可用。整合的要点在于确认三个组件的 ZooKeeper 地址一致以及避免三个组件互相抢端口。# 在 hadoop-env.sh 中设置 export HADOOP_HOME/opt/hadoop export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop # hbase-site.xml 中 ZooKeeper 客户端端口 property namehbase.zookeeper.property.clientPort/name value2181/value /property property namehbase.zookeeper.quorum/name valuehadoop01,hadoop02,hadoop03/value /propertyZK 的 2181 端口是 HBase 的老朋友但这个端口也常被其他中间件占用例如 Dubbo 和 Kafka 各自注册中心可能冲突。启动 HBase 前先ss -lntp | grep 2181检查一遍能省不少排错时间。3. 用 Spring Boot 串起上传下载链路从 MultipartFile 到 HDFS3.1 环境准备伪分布式 Hadoop 与 HBase 的启动顺序无论是毕设还是本地自测先用单机伪分布式跑通是最高效的路线。启动顺序固定为ZooKeeper 集群单机也行→ HDFS → HBase。顺序错了容易出现 RegionServer 启动后报Cant initialize the zookeeper client的问题。# 启动 ZooKeeper单机模式 /opt/zookeeper/bin/zkServer.sh start # 启动 HDFS $HADOOP_HOME/sbin/start-dfs.sh jps # 检查 NameNode、DataNode、SecondaryNameNode 三个进程 # 启动 HBase $HBASE_HOME/bin/start-hbase.sh jps # 检查 HMaster 和 HRegionServer 是否也存在 hbase shell # 进入 HBase 命令行验证 status detailed伪分布式下要注意一点hbase.rootdir尽量不要沿用 Hadoop 的/user/hbase默认值建议设为hdfs://localhost:9000/hbase。不设置的情况下 HBase 默认写到本地临时目录重启后数据丢失最直接的体现是重启 HBase 后之前建的表没了于是又要从头导入一次数据集。3.2 Spring Boot 集成 HDFS 的依赖与配置Spring Boot 项目里不需要任何现成的“HDFS Starter”直接用 Hadoop 的客户端依赖即可。Hadoop 3.x 的hadoop-client包含 HDFS、YARN 等所有客户端类但没有必要全量引入用hadoop-hdfs-client一个模块就够了。要注意版本冲突Hadoop 的 Guava 版本在 3.x 里是 27.0而 Spring Boot 2.7 内置的 Guava 可能更低ClassCastException就是这么来的。dependency groupIdorg.apache.hadoop/groupId artifactIdhadoop-hdfs-client/artifactId version3.3.6/version exclusions exclusion groupIdcom.google.guava/groupId artifactIdguava/artifactId /exclusion exclusion groupIdorg.slf4j/groupId artifactIdslf4j-reload4j/artifactId /exclusion /exclusions /dependency dependency groupIdorg.apache.hbase/groupId artifactIdhbase-client/artifactId version2.5.8/version /dependency排除slf4j-reload4j也很重要Hadoop 自带的是 log4j1.x 桥接包不排除会出现日志警告甚至栈溢出。依赖引入完成后在application.yml里集中配置集群地址别把hdfs://前缀写死在代码里hadoop: hdfs-uri: hdfs://localhost:9000 user: hadoop # HDFS 客户端默认以本地系统用户访问会碰到权限问题这里显式指定 hbase: zookeeper-quorum: localhost:2181 zookeeper-property-client-port: 2181这里的user: hadoop等于在代码里通过UserGroupInformation.createRemoteUser(hadoop)伪装成 Hadoop 用户访问 HDFS避免手动 chown 改权限。伪分布式里这招很实用但集群环境下正式的方案应该是 Kerberos 认证毕设项目不需要走到那一步。3.3 上传文件时发生了什么一次写入两次记录网盘上传链路的关键动作如下Spring Boot 接收 MultipartFile生成全局唯一文件 ID把 MultipartFile 流转成 HDFS 文件在 HBase 写入文件元数据和块索引返回业务成功结果。Service public class FileService { private final FileSystem fs; private final Table netdiskTable; public String upload(MultipartFile file, String userId, String parentDir) throws IOException { // 1. 生成文件ID采用时间随机数避免并发重复 String fileId UUID.randomUUID().toString().replace(-, ); String fileName file.getOriginalFilename(); String hdfsPath String.format(/user/netdisk/%s/%s, userId, fileId); // 2. 写入HDFS覆盖已存在文件 Path path new Path(hdfsPath); try (FSDataOutputStream out fs.create(path, true)) { out.write(file.getBytes()); } // 3. 写HBase元数据 Put put new Put(Bytes.toBytes(reverseUserId(userId) _ parentDir / fileName)); put.addColumn(Bytes.toBytes(cf), Bytes.toBytes(fileId), Bytes.toBytes(fileId)); put.addColumn(Bytes.toBytes(cf), Bytes.toBytes(size), Bytes.toBytes(file.getSize())); netdiskTable.put(put); // 4. 写块索引单块策略每条块索引对应一个HDFS路径 Put chunkPut new Put(Bytes.toBytes(fileId _0000)); chunkPut.addColumn(Bytes.toBytes(cf), Bytes.toBytes(hdfsPath), Bytes.toBytes(hdfsPath)); chunkPut.addColumn(Bytes.toBytes(cf), Bytes.toBytes(chunkIndex), Bytes.toBytes(0)); netdiskTable.put(chunkPut); return fileId; } }这个实现把“一次写入两次记录”体现得很干净HDFS 负责落地文件内容HBase 记录业务元数据与块索引。参数上值得关注的是fs.create(path, true)里的布尔值它表示覆盖写如果网盘支持“秒传”同目录同名文件直接返回已有 fileId可以先查 HBase 再决定是否覆盖避免无意义地重写整个 HDFS 文件。3.4 下载的反向路径先查块再拼流下载是上传的逆过程第一步先根据用户请求的文件路径查 HBase拿到文件 ID 和块列表第二步按照块索引顺序从 HDFS 读取数据并写入响应流。块索引表存在的意义在这条链路上体现得尤其明显HBase 一次 Scan 能拿到一个文件的所有块记录且块顺序就是 RowKey 顺序省去了排序步骤。// 下载时根据文件ID查询块列表然后拼流输出 public void download(String fileId, HttpServletResponse response) throws IOException { Scan scan new Scan(); // RowKey 前缀是 fileId _范围扫描命中该文件所有块 scan.withStartRow(Bytes.toBytes(fileId _0000)); scan.withStopRow(Bytes.toBytes(fileId _9999)); ListString paths new ArrayList(); try (ResultScanner rs netdiskTable.getScanner(scan)) { for (Result r : rs) { paths.add(Bytes.toString(r.getValue(Bytes.toBytes(cf), Bytes.toBytes(hdfsPath)))); } } // 逐个块写入响应的OutputStream for (String p : paths) { try (FSDataInputStream in fs.open(new Path(p))) { IOUtils.copyBytes(in, response.getOutputStream(), 4096, false); } } }分块下载的最大价值在于应付“网络闪断”场景客户端只请求文件的后半段服务端只需要定位到对应块不必把整个文件读一遍再丢弃。这也是 HBase 作为块索引表比 MySQL 更好用的原因MySQL 的BETWEEN查询在块数多了以后同样有性能问题而 HBase 的 Range Scan 天然为这种场景做了优化。4. 元数据查询与索引设计的边界目录树、搜索和分页4.1 目录列表查询RowKey 前缀扫描网盘打开一个目录背后是一条 HBase Scan。以 RowKeyalice_rev_docs开头的所有记录即该目录下的一级子项。要严格限定“只查一层”不能只靠 HBase必须在列里把 parent 字段存好扫描后由 Spring Boot 过滤。这条过滤逻辑放在应用层代价可以接受因为目录深度一般不超过 10 层单层文件数一般是几百量级。-- HBase Shell 中模拟一次目录查询 scan netdisk_file, {STARTROW cirela_docs, STOPROW cirela_docu}但要注意一个细节文件名转成 RowKey 后是按字节排序的如果希望同一目录下文件按修改时间倒序排列RowKey 里就得设计时间戳前缀。常见的做法是 RowKey 拼上 Long.MAX_VALUE 减 createTime这样最新文件排在前面。这个术语叫“RowKey 设计”HBase 面试题里十有八九会问顺着这个场景答出来比背定义要有说服力得多。4.2 多条件搜索的落地思路HBase 的查询能力是很弱的它只能做 RowKey 精确查、RowKey 范围查以及基于 SingleColumnValueFilter 的扫表过滤。如果网盘需要“按文件类型查所有文件”“按文件名模糊搜索”正经的电商级做法是在前面加 Elasticsearch毕设和中小型项目用 HBase 的 Filter 也能糊弄过去但性能会随表 size 线性下降。如果只想用 HBase 扛住全部查询可以考虑牺牲写入灵活性把“类型”拼进 RowKey 的第二个字段。例如 RowKey 改为userId_rev fileType fileName这样“查某用户所有 pdf”就变成了一次 RowKey 范围扫描。缺点也很明显修改文件类型等于改 RowKeyHBase 没有 update 只有 put 新版本本质上是改一次删一次。我的建议是网盘元数据里只提供按目录浏览和按文件名前缀补全这两种交互这两种用 HBase 都能优雅解决覆盖了大多数搜索需求。4.3 分页在 HBase 里的实现方式HBase 的分页和 MySQL 完全不同。MySQL 可以直接用 LIMIT 加 OFFSETHBase 没有全局 OFFSET 的概念只能用 Scan 加 limit 参数控制条数配withStartRow从上一页的最后一条 RowKey 继续扫。这样做的代价是无法跳页只能逐页往下翻但这恰好和网盘“不断加载更多”的交互方式一致。// 第一页从目录前缀开始取 20 条 Scan pageScan new Scan(); pageScan.withStartRow(Bytes.toBytes(cirela_docs)); pageScan.setLimit(20); // 第二页把上一页最后一条RowKey作为这一页的起始行再取20条 pageScan.withStartRow(Bytes.toBytes(cirela_docs/report_20240901_0001)); pageScan.setLimit(20);这里用withStartRow而不是withStopRow来控制边界是本页和下一页的衔接关键。按 RowKey 前缀扫描时第一页拿到report_20240901_0001作为最后一行第二页从这个 RowKey 继续不会丢数据也不会重复。这个方案比“扫全表再丢前 N 条”效率好很多天然适配网盘无限滚动的体验。4.4 教材之外的避坑预分区与 RowKey 散列HBase 建表时如果不指定预分区所有数据会先写入同一个 Region直到该 Region 超过阈值才触发分裂。网盘这种写密集场景初始只有一个 Region 会形成写热点所以建表时最好直接把表拆成 8 个或 16 个 Region分区的边界用中文说明很难维护推荐的做法是给文件 ID 前缀一次散列再按 16 个前缀分区。# HBase Shell 建表并预分区前缀为 0-f 的 16 个分区 create netdisk_chunk, cf, {NUMREGIONS 16, SPLITALGO HexStringSplit}使用HexStringSplit是按 RowKey 字符串开头做字典序切分RowKey 先用文件 ID 的前缀来决定落入哪个分区同一个文件的所有块因为拥有同一个文件 ID 前缀会落在同一个 Region 里。这样设计之后一次下载文件的所有块查询不需要跨 Region 扫描性能直接受益。这部分的取舍也值得说透HexStringSplit适合 RowKey 是十六进制字符串的场景如果你的 RowKey 里字节不全是在 0-f 范围内split 出来的边界对不齐数据分布一样会歪。如果要追求绝对均匀最稳妥的方案还是给自己要造的 ID 加 Salt比如userHash % 16作为 RowKey 首字节这个前面在 2.3 里已经提过了实践下来比依赖 SPLITALGO 更可控。4.5 Region 高可用与 RegionServer 宕机的表象HBase 的高可用常以“RegionServer 宕机后 Region 自动迁移”为面试和运维热点。在这个网盘系统里体现得很直白某台 RegionServer 挂了它服务的 Region 会被 Master 重新分配到其他 RegionServer 上中间会有短暂的不可用窗口之后又能查到数据。# 查看 Region 在哪些 RegionServer 上 hbase hbck # 强制重启 Master 进程观察 Region 的重新分配过程 $HBASE_HOME/bin/hbase-daemon.sh stop master $HBASE_HOME/bin/hbase-daemon.sh start master第一次做这个实验会让你误以为数据丢了其实 Region 重新分配期间 HBase Shell 的查询会抛异常等 ZooKeeper 会话超时默认 90 秒后Region 上线恢复。这种表层的“小故障”反而是检验 HBase 集群健壮性的试金石。真正的坑在于RegionServer 宕机后 MemStore 数据尚未刷盘这块未落盘数据靠 HLogWAL回放才能恢复所以 HLog 所在的 HDFS 目录挂掉才是致命问题HBase 的双重依赖在这里体现出来。5. 数据导入演练用真实数据集压出系统的性能边界5.1 构造用于演示的文件目录一份可重复的幂等脚本网盘系统需要一个看起来真实的数据集。网上有很多公开的文本和日志数据集可以借用例如可以用 Linux 系统自带的/var/log日志文件或者用脚本生成一批带层次结构的模拟文件。构造数据集的方式和数据集本身相比后者更重要脚本应当可以重复执行而不产生脏数据。#!/bin/bash # 生成一个模拟用户的目录结构 for i in $(seq 1 10); do for j in $(seq 1 5); do mkdir -p /tmp/netdisk_data/user$i/docs$j for k in $(seq 1 20); do echo demo content $i-$j-$k $(date) /tmp/netdisk_data/user$i/docs$j/file_$k.txt done done done # 上传这些文件到 HDFS用 -put 批量操作比单个 put 快很多 hdfs dfs -mkdir -p /user/netdisk/batch1 hdfs dfs -put /tmp/netdisk_data/* /user/netdisk/batch1/ hdfs dfs -du -h /user/netdisk/batch1 | tail -20这个脚本会生成 1000 个小文件大小都在 1KB 左右刚好用来验证网盘系统对“海量小文件”的处理能力。HDFS 本身对小文件不友好靠 HBase 的元数据索引反而能在业务层规避部分性能问题这个矛盾本身就是很好的毕业设计切入点。5.2 毫秒级目录查询验证设计一个压测动作把数据导入后需要做一次看起来简单的验证打开一个目录看列表返回时间。这里的性能指标在伪分布式单机上不一定好看因为单机没有网络开销反而会导致 HDFS client 和 HBase client 在同一台机器上抢占 CPU个别请求会显得略慢。可以用一段简单的 Java 测试代码循环查询同一目录 100 次的平均耗时。# 查看 NameNode 的 RPC 处理线程数是否吃满 jstack $(jps | grep NameNode | awk {print $1}) | grep -c IPC Server如果IPC Server handler线程数长期为 20 以上说明单机伪分布式下 HDFS 的 RPC 处理是瓶颈这个结论写进论文里很出彩证明系统并非无缘无故地快而是瓶颈在手写协议的 IPC 层而不是逻辑代码。此时可以顺手调一下 HDFS 的dfs.namenode.handler.count参数从默认的 10 调到 32再对比一下目录查询延迟会得到一个漂亮的曲线。5.3 用量能饱和度视角看 HDFS 空间治理一个容易被忽略但很实用的技巧是因为 HDFS 底层是块存储网盘删除文件之后空间不一定马上释放需要通过hdfs balancer触发均衡或者hadoop fs -expunge清空回收站。空间总量用足了系统也不会有性能预警所以建议起一个定时检查 HDFS 快照的任务。# 查看整体空间使用率 hdfs dfsadmin -report | grep -E Configured Capacity|DFS Used|Non DFS Used # 属性命令快速定位超过100MB的大文件 hdfs dfs -du -h /user/netdisk/ | awk $1 ~ /G|T/ {print $2, $1}对于毕设项目数据总量一般不超过 10GB真实性能上限在这里体现不出来但展示一套可扩展的治理方法是加分项。能说出“大文件做快照”、“小文件做归档”这类运维思路就比对 HDFS 内部机制一无所知、只会上传下载的候选人高一截。5.4 JVM 调优的两个真实参数到了系统部署阶段真正拖垮网盘的不是 Hadoop 和 HBase而是 Spring Boot 应用和 HBase 客户端在同一个 JVM 里抢堆内存。HBase 的BufferedMutator或者Table.put(ListPut)会吃掉几十 MB 堆内存做写缓冲Spring Boot 默认的 256MB 堆很容易触发 Full GC。# Spring Boot 服务启动命令加上这些参数 java -Xms512m -Xmx1024m \ -XX:UseG1GC \ -XX:MaxGCPauseMillis200 \ -jar netdisk.jarG1 是推荐的选择MaxGCPauseMillis200让 GC 停顿控制在 200ms 内避免网盘交互时出现明显的卡顿。HBase 客户端的hbase.client.write.buffer也可以调小到 2MB 来压低 JVM 内存峰值代价是写 HBase 的 RPC 次数变多需要做一个小实验找出当前数据规模下的平衡点。6. 最后再补一刀用 HBase Shell 快速定位问题网盘系统运行中有一个容易忽略的验证技巧大多数时候你觉得“HBase 写不进去”其实都是因为 HBase 客户端拿到的 ZooKeeper 地址不对或者 Region 处于OPENING/CLOSING状态。与其翻日志不如直接用 HBase Shell 的这一组命令快速定位-- 查看某个表的 Region 分布检查是否有 Region 卡住 status detailed -- 查看表是否 disableddisabled 状态下读写都会报错 is_enabled netdisk_file -- 手动清空出问题的表再重新灌数据注意 truncate 会先 disable 再重新建表 truncate netdisk_chunkShell 里跑完这三条绝大多数表象问题都能定位。HBase 的status detailed会显示每个 RegionServer 上的 Region 数量如果某个 RegionServer 上堆积了大量 Region而你的 RowKey 又没做散列那就是写入热点这时候应该回头调整 RowKey 设计方案而不是傻傻重启集群。最后再强调一个 Spring Boot 层面的排查技巧HBase 客户端默认日志是 DEBUG 级别时会打出大量RpcRetryingCaller重试日志这会导致网盘接口变慢。生产环境把 HBase 相关的 logger 级别调到 WARN保留 HDFS 的 INFO 即可。logging: level: org.apache.hadoop.hbase.client: WARN org.apache.hadoop.hdfs: INFO org.apache.hadoop.ipc: WARN这样配置之后异常请求的重试信息会正常输出而正常的扫描日志不会刷屏排查的效率一下子就上来了。这套从环境搭建到调优的路径走完整个“Hadoop HBase Spring Boot 分布式网盘”就不再是看别人源码时的走马观花而是你自己也能顺手搭起来的一套完整系统论文里能写的数据粒度也完全不一样。本文还有配套的精品资源点击获取
返回列表