尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

HBase Shell命令全攻略:从建表、数据读写到运维实战

HBase Shell命令全攻略:从建表、数据读写到运维实战 做HBase开发或者运维的人应该都有过这种经历查资料看官方文档满屏的英文命令看得头晕要么就是上网搜教程结果搜出来的文章要么太浅只贴个命令不给解释要么太散东一块西一块根本串不起来。HBase的Shell命令看着简单真正用起来却有不少讲究比如为什么删表之前要先disable为什么get和scan都能查数据却有这么大差别这些细节不搞明白写脚本或者排查问题的时候就会踩坑。这篇博文我打算一次性把HBase Shell的常用命令讲透从启动方式、表管理、数据读写到运维辅助命令、实际操作演示、常见问题排查全部串起来。同时我会把每个命令背后的设计逻辑讲清楚比如HBase为什么需要保留多个版本的数据、filter过滤器能玩出什么花样、预分区为什么能救线上性能。不管你是刚入门HBase的开发者还是要做日常运维的工程师或者正在准备面试想系统梳理一遍这篇内容都能直接拿来用。1. HBase Shell整体思路与使用准备1.1 Shell在HBase生态里的定位很多人刚开始接触HBase的时候第一反应是上手Java API毕竟写代码才是正经开发。但实际工作中你会发现Shell命令的使用频率一点都不比Java API低。建表、加列族、看region分布、临时查一条数据、清理垃圾数据、做快照备份这些操作如果都要写一段Java代码去执行效率实在太低了。HBase Shell本质上是一个基于JRuby封装的交互式命令行工具它把HBase的Java API包装成了一个个可以直接敲的命令。你在Shell里执行的每一条命令底层都会转换成对应的客户端调用去访问HBase集群。所以Shell命令和Java API在功能上是对等的区别只是使用场景不同。日常开发调试、运维管理用Shell正式业务逻辑写入用Java API或者其他客户端两者配合起来才是完整的HBase使用姿势。1.2 启动Shell前的环境准备要进入Shell前提是HBase集群已经正常启动。这里有个容易忽略的点HBase Shell本身不需要额外安装什么客户端只要在一台能访问到HBase集群的机器上把HBase的bin目录加进PATH或者在HBase安装目录下直接执行命令就行。# 进入HBase安装目录 cd /opt/hbase/bin # 启动Shell ./hbase shell启动之后如果能看到类似下面的输出说明已经成功连上了集群HBase Shell Use help to get list of supported commands. Use exit to quit this interactive shell. For Reference, please visit: http://hbase.apache.org/2.0/book.html#shell Version 2.4.17, r2381a66c1d55b2f0e0d0c5e1b2a7e7a3f3f1d0e5, Tue Aug 9 18:41:12 PDT 2022 Took 0.0017 seconds如果你执行./hbase shell之后卡住了或者报Cant connect to ZooKeeper之类的错误先别急着怀疑集群挂了。多数情况下是三种原因一是ZooKeeper的地址配置不对检查hbase-site.xml里的hbase.zookeeper.quorum二是本机hostname解析问题HBase对hostname非常敏感机器上的/etc/hosts没有配好会出现各种奇怪的连接问题三是集群安全认证没通过如果是开启了Kerberos的环境需要先kinit拿到票据才能操作。在Shell里输入status命令能看到集群当前的运行概况比如RegionServer有几台、每个RegionServer负载如何。集群有问题先从这里看起。hbase:001:0 status 1 active master, 0 backup masters, 3 servers, 0 dead, 6.0000 average load Took 0.4192 seconds看到3 servers和0 dead说明三台RegionServer都活着没有节点挂掉这是最理想的状态。2. 表管理命令建表、查看、修改与删除的完整攻略2.1 创建表与预分区设置HBase建表命令是create语法非常灵活但也正因为灵活新手经常会被括号里的各种花括号弄晕。我来拆开讲一下。最简单的建表只指定表名和一个列族hbase:001:0 create user_info, base这条命令创建了一张名为user_info的表只有一个列族base。注意HBase建表的时候至少要有1个列族最多官方不建议超过5个列族太多会严重影响性能因为每个列族对应一个独立的存储文件HFile列族太多会导致写入放大的问题。稍微复杂一点的建表是指定列族属性hbase:002:0 create user_info, {NAME base, VERSIONS 3, TTL 86400}这条命令里的VERSIONS 3表示这个列族最多保留3个版本的数据TTL 86400表示数据存活时间是一天过期数据会被自动清理。生产环境建表的时候这两个参数几乎必设不设的话默认VERSIONS是1TTL是永久保留。VERSIONS设成1你会发现查不到历史版本TTL不设的话数据永远不会过期存储压力会越来越大。再来看预分区这个是真的能救性能的功能。HBase一张表默认只有一个region所有写入都打到这个region上数据量大了之后region会自动分裂但自动分裂会有性能抖动。比较稳妥的做法是建表时直接预分区。hbase:003:0 create user_log, {NAME info, VERSIONS 1}, SPLITS [100, 200, 300, 400]这条命令把user_log表在创建时就分成了5个region分别对应rowkey范围[-∞, 100)、[100, 200)、[200, 300)、[300, 400)、[400, ∞)。写入数据的时候根据rowkey的哈希值落到不同region就避免了单region热点问题。生产上我会用这种方式前提是rowkey设计有规律比如用用户ID前缀分桶。SPLITS_FILE也是常用参数适合region数量多、分界点多的场景hbase:004:0 create big_table, cf1, SPLITS_FILE /data/splits.txt文件里每行一个分界点HBase会按照文件内容自动切分region。我自己写脚本生成预分区文件时通常是按照数字前缀或者字符串前缀均匀分布去算的效果比手写靠谱。2.2 查看表结构list、describe与exists表建完之后怎么确认建对了用list命令查看当前namespace下有哪些表hbase:005:0 list TABLE big_table user_info user_log 3 row(s)如果namespace比较多可以指定查看某个namespace下的表hbase:006:0 list_namespace_tables default查看表详细结构用describe这是排查问题最常用的命令hbase:007:0 describe user_info Table user_info is ENABLED user_info COLUMN FAMILIES DESCRIPTION {NAME base, BLOOMFILTER ROW, VERSIONS 3, IN_MEMORY false, KEEP_DELETED_CELLS FALSE, DATA_BLOCK_ENCODING NONE, TTL 86400 SECONDS (1 DAY), COMPRESSION NONE, MIN_VERSIONS 0, BLOCKCACHE true, BLOCKSIZE 65536, REPLICATION_SCOPE 0} 1 row(s)describe输出里的ENABLED状态很重要。HBase表有两个状态ENABLED和DISABLED。ENABLED状态下才能读写数据DISABLED状态下不能读写。很多管理操作要求在DISABLED状态下才能执行后面讲删表的时候细说。还有一个命令是exists用来判断某张表是否存在。我在写自动化脚本的时候经常用它做前置判断避免重复建表报错。hbase:008:0 exists user_info Table user_info does exist Took 0.0138 seconds2.3 修改表结构alter的进阶玩法alter命令用来修改表结构比如增加列族、删除列族、修改属性。最常见的需求是给表加列族hbase:009:0 alter user_info, NAME address这条命令给user_info表增加了一个名为address的列族。和关系型数据库的ALTER TABLE不同HBase的alter操作不需要锁表可以在线执行所以生产环境加列族是很轻松的事情不用停机。修改列族属性也是一样的语法hbase:010:0 alter user_info, NAME base, VERSIONS 5把base列族的版本数从3改成5。注意这里的修改只影响之后写入的数据历史数据的版本还是按之前的配置保留。如果想把TTL改短比如原来一天改成10小时hbase:011:0 alter user_info, NAME base, TTL 36000TTL的单位是秒36000秒就是10小时。从实践角度看线上调整TTL是解决数据膨胀最快的手段比删数据跑Major Compaction要温和得多。删除列族同样用alterhbase:012:0 alter user_info, delete address执行这条命令要慎重列族删了之后里面的数据全部不可恢复而且这个操作在线上执行完之后表的存储文件会有一个大的变动如果表数据量很大可能会触发比较频繁的flush和compaction。2.4 禁用表、启用表与删除表删表绝对是新手重灾区。很多人上手就执行hbase:013:0 drop user_info结果报错ERROR: Table user_info is enabled, so cannot be dropped. Disable it first.HBase的删表流程是强制两步走先disable再drop。原因是HBase表在ENABLED状态下可能有客户端正在写入或读取直接删掉会出大问题。先把表禁用阻断所有读写请求再执行删除才能保证数据安全和操作一致。hbase:014:0 disable user_info hbase:015:0 drop user_infodisable命令执行之后表的每个region都会经历下线流程依次关闭这个过程如果region数量多或者负载高会持续几秒甚至更久。可以通过is_disabled命令确认状态hbase:016:0 is_disabled user_info true看到true说明表已经禁用成功可以放心drop。需要恢复一张被禁用的表用enable命令hbase:017:0 enable user_info执行enable之后表的region会重新分配上线。如果region数量特别多enable操作也会比较慢这是正常现象不要中途再执行其他alter操作去抢锁。3. 数据读写命令put、get、scan、delete的细节与技巧3.1 写入数据put命令的参数拆解HBase写数据用put一条put命令可以写入一个单元格的数据hbase:018:0 put user_info, rowkey_001, base:name, 张三这条命令的含义是向user_info表写入一行rowkey是rowkey_001列族base下的列name的值为张三。注意列名的写法是列族:列名冒号是必须的没有冒号就就不是一个合法的列。put命令还支持一次写多列hbase:019:0 put user_info, rowkey_001, base:age, 28 hbase:020:0 put user_info, rowkey_001, base:phone, 13800138000执行完这三条rowkey_001这一行就有了三个单元格。注意同一个rowkey的三次put实际上是三次独立的写入操作每次都会产生一个新的数据版本。如果你希望一次put操作写入多个列可以用Map方式hbase:021:0 put user_info, rowkey_002, { base:name 李四, base:age 32 }put命令还可以指定时间戳hbase:022:0 put user_info, rowkey_001, base:age, 29, 1700000000000最后一个参数是时间戳单位是毫秒。生产环境我几乎不会手动指定时间戳因为HBase默认会用客户端机器当前时间作为版本号手动指定容易搞乱数据版本只有做数据修复的时候才会用到。3.2 查询单行get命令的完整参数查询单行数据用get。最简单的获取整行hbase:023:0 get user_info, rowkey_001 COLUMN CELL base:age timestamp2023-11-20T10:30:00.123, value28 base:name timestamp2023-11-20T10:29:59.456, value张三 base:phone timestamp2023-11-20T10:30:00.789, value13800138000 3 row(s)只查某一列hbase:024:0 get user_info, rowkey_001, {COLUMN base:name}查多个列hbase:025:0 get user_info, rowkey_001, {COLUMN [base:name, base:age]}查指定版本数也就是把历史版本拉出来hbase:026:0 get user_info, rowkey_001, {COLUMN base:age, VERSIONS 5}这里能看到HBase的多版本特性。前提是建表时VERSIONS设置大于1如果建表时VERSIONS是1那这里就算指定VERSIONS 5也查不到多个版本因为写入时旧版本已经被覆盖了。还可以指定时间范围查询hbase:027:0 get user_info, rowkey_001, {TIMERANGE [1690000000000, 1700000000000]}TIMERANGE是一个左闭右开的区间即[start, stop)查询这个时间范围内的版本数据。3.3 批量扫描scan命令与过滤器scan是HBase最强大的查询命令。它是全表扫描所以性能上要小心使用生产环境没有加过滤条件的全表scan很容易把RegionServer拖垮。最简单的scan是扫全表hbase:028:0 scan user_info数据量小的时候没问题数据量大就要加限制了。先用LIMIT限制返回条数hbase:029:0 scan user_info, {LIMIT 10}指定列族扫描hbase:030:0 scan user_info, {COLUMN base}指定rowkey范围扫描。这个是最常用的操作因为HBase的rowkey是有序存储的范围扫描效率很高hbase:031:0 scan user_info, {STARTROW rowkey_001, ENDROW rowkey_010}注意STARTROW是包含的ENDROW是不包含的。也就是结果包含rowkey_001但不包含rowkey_010。如果想包含rowkey_010可以写成hbase:032:0 scan user_info, {STARTROW rowkey_001, ENDROW rowkey_010\x00}这里的\x00是一个比任何字符都小的终止符算是HBase Shell里的一个小技巧。scan配合过滤器才是完全体。HBase Shell里最常用的是ValueFilter和RowFilter。比如过滤出name等于张三的行hbase:033:0 scan user_info, {FILTER ValueFilter(, binary:张三)}过滤出age大于30的行hbase:034:0 scan user_info, {FILTER ValueFilter(, binary:30)}RowFilter配合正则表达式使用比如查询rowkey前缀为user_的行hbase:035:0 scan user_info, {FILTER RowFilter(, substring:user_)}substring:是HBase过滤器内置的比较器专门用来做包含匹配。还有PrefixFilter也可以实现前缀过滤hbase:036:0 scan user_info, {FILTER PrefixFilter(user_)}从性能角度看PrefixFilter底层会利用rowkey有序性跳过不匹配的region比ValueFilter效率高很多能用PrefixFilter就用PrefixFilter。3.4 删除数据delete、deleteall与清空表删除数据有delete和deleteall两个命令。delete删除一个单元格的指定版本hbase:037:0 delete user_info, rowkey_001, base:age这条命令删除rowkey_001这一行的base:age列。默认删除最新版本如果指定了时间戳就删除那个时间戳对应的版本hbase:038:0 delete user_info, rowkey_001, base:age, 1700000000000deleteall删除整行hbase:039:0 deleteall user_info, rowkey_001执行删除之后数据并不会立刻从磁盘上消失而是打上删除标记Tombstone后续Major Compaction的时候才会真正物理删除。这个特性解释了为什么HBase的删除操作很快但磁盘空间没有立刻返还。要清空表最稳妥的方式是先disable再drop再createhbase:040:0 disable user_info hbase:041:0 drop user_info hbase:042:0 create user_info, base还有一个truncate命令hbase:043:0 truncate user_infotruncate的内部实现其实就是disable → drop → create。执行之后表结构还在但数据全没了。在Shell里执行truncate会提示你确认非常贴心。4. 运维辅助命令状态查看、快照备份与Region管理4.1 集群状态与表状态监控日常运维里最先用的命令就是status。它能展示集群的整体健康度hbase:044:0 status detailed加上detailed参数能看到每个RegionServer上分配了哪些region每台机器的负载情况甚至能精确到region的状态是OPEN还是CLOSING。查看namespace列表和表列表hbase:045:0 list_namespace NAMESPACE default hbase 2 row(s)查看某张表被分配在哪些RegionServer上hbase:046:0 locate_region user_info, rowkey_001这个命令会告诉你rowkey_001这个rowkey落在哪个region以及这个region在哪个RegionServer上。排查数据热点、确认请求分发情况的时候非常有用。4.2 快照备份与恢复HBase快照是线上备份的利器。它的原理是记录表的元数据信息和HFile的文件引用信息创建快照本身几乎不复制数据所以非常快对线上影响极小。创建快照hbase:047:0 snapshot user_info, snap_user_info_20231120查看快照列表hbase:048:0 list_snapshots SNAPSHOT TABLE CREATION TIME snap_user_info_20231120 user_info (2023-11-20 10:00:00) 1 row(s)从快照恢复新表hbase:049:0 clone_snapshot snap_user_info_20231120, user_info_restoreclone_snapshot会基于快照数据创建一张新表。恢复完成后这张表和快照时点的数据完全一致。生产环境做数据误删恢复、把线上表克隆到测试环境用的都是这套方案。删除不再需要的快照hbase:050:0 delete_snapshot snap_user_info_20231120还有一个restore_snapshot命令可以把表恢复成快照时的状态。先禁用表再restorehbase:051:0 disable user_info hbase:052:0 restore_snapshot snap_user_info_20231120 hbase:053:0 enable user_inforestore_snapshot会覆盖当前表的数据危险程度极高操作前一定三思建议在生产环境外先做演练。4.3 Region管理与手动拆分合并HBase的region管理一般交给系统自动完成但某些场景需要人工介入。比如发现某个region数据量特别大成为热点可以手动拆分hbase:054:0 split user_info, rowkey_100这里rowkey_100是拆分点这条命令把包含rowkey_100的region从rowkey_100处一分为二。手动合并region更谨慎因为合并操作影响面大hbase:055:0 merge_region c9b9d1a2b4d6c7e8a0f9d8e7c6b5a4f3, c9b9d1a2b4d6c7e8a0f9d8e7c6b5a4f4merge_region需要传入两个region的编码ID可以从status detailed里查到对应的region名称。没有十足把握不建议在生产环境手动合并。4.4 其他高频辅助命令查看当前Shell用户是谁hbase:056:0 whoami查看表是否启用、是否可写hbase:057:0 is_enabled user_info查看HBase版本信息hbase:058:0 version统计表行数生产环境慎用会触发全表扫描hbase:059:0 count user_infocount命令可以加INTERVAL参数设置每扫描多少行打印一次进度还可以加CACHE参数控制每次扫描缓存的行数hbase:060:0 count user_info, INTERVAL 1000, CACHE 10005. 实操演练从建表到过滤查询的完整案例5.1 场景定义与建表设计下面用一个实际场景把前面讲的命令串起来。假设我们需要一张用户行为日志表记录用户对推荐内容的点击行为需要支持按用户维度的查询。表名reco_click_logrowkey设计为用户ID_时间戳反转。时间戳反转的意思是将Long.MaxValue减去当前时间戳这样同一用户的最新数据会排在前面适合查最近点击记录这类场景。列族设计为click列包括item_id内容ID、scene推荐场景、cost点击花费。hbase:061:0 create reco_click_log, {NAME click, VERSIONS 1, BLOCKCACHE true}, SPLITS [100, 200, 300]这里设置了VERSIONS为1因为点击行为的历史版本没有意义保留最新一条就行。SPLITS设置4个分区分别存储不同用户ID前缀的数据。5.2 写入数据与验证模拟写入几条数据hbase:062:0 put reco_click_log, 10001_9223372036854770000, click:item_id, A001 hbase:063:0 put reco_click_log, 10001_9223372036854770000, click:scene, homepage hbase:064:0 put reco_click_log, 10001_9223372036854770000, click:cost, 10 hbase:065:0 put reco_click_log, 20001_9223372036854770000, click:item_id, B002 hbase:066:0 put reco_click_log, 20001_9223372036854770000, click:scene, detail hbase:067:0 put reco_click_log, 20001_9223372036854770000, click:cost, 20验证写入hbase:068:0 get reco_click_log, 10001_9223372036854770000 COLUMN CELL click:cost timestamp2023-11-20T11:00:00.123, value10 click:item_id timestamp2023-11-20T11:00:00.000, valueA001 click:scene timestamp2023-11-20T11:00:00.045, valuehomepage 3 row(s)5.3 组合过滤查询演示查用户ID前缀为10001的最近点击记录hbase:069:0 scan reco_click_log, {FILTER PrefixFilter(10001_)}结果ROW COLUMNCELL 10001_9223372036854770000 columnclick:cost, timestamp..., value10 10001_9223372036854770000 columnclick:item_id, timestamp..., valueA001 10001_9223372036854770000 columnclick:scene, timestamp..., valuehomepage 1 row(s)查点击花费大于等于15的记录hbase:070:0 scan reco_click_log, {FILTER ValueFilter(, binary:15)}执行结果会返回20001_9223372036854770000这行的数据。注意这个过滤是在服务端做的但binary:15是字符串比较如果需要数值比较需要根据实际存储的数据格式去处理这是HBase过滤器比较隐晦的点。如果需要多个条件组合过滤用AND连接hbase:071:0 scan reco_click_log, {FILTER PrefixFilter(20001_) AND ValueFilter(, binary:15)}这条命令先按rowkey前缀过滤再按value过滤两个条件同时满足才会返回结果。5.4 快照备份的完整操作模拟线上备份流程。先创建快照hbase:072:0 snapshot reco_click_log, snap_reco_click_log_0320从快照克隆一个测试表hbase:073:0 clone_snapshot snap_reco_click_log_0320, reco_click_log_test扫描测试表确认数据正常hbase:074:0 scan reco_click_log_test, {LIMIT 5}测试完成后删除测试表hbase:075:0 disable reco_click_log_test hbase:076:0 drop reco_click_log_test这套流程就是我平时做数据迁移、测试环境准备的标准动作。省去了用export/import导数据的时间尤其适合大表场景。6. 常见问题与排查技巧实录6.1 Shell命令卡住或连接超时典型的报错是ERROR: Cant get master address from ZooKeeper; znode data is null排查思路是按顺序检查ZooKeeper服务是否正常、HBase Master进程是否存活、hbase-site.xml里的hbase.zookeeper.quorum是否配置正确、机器之间网络是否通。我碰到过最坑的一次是某台机器的时间不同步导致和集群的session频繁超时同步时间之后立刻恢复。6.2 删除表卡在DISABLED状态有时候执行disable之后表状态一直是DISABLING迟迟变不成DISABLED。这种情况通常是某些region的关闭流程卡住了。用status detailed定位卡住的region看看它所在的RegionServer日志有没有异常。一个快速恢复的办法是重启对应的RegionServer让region重新调度上线后再执行disable。6.3 scan全表导致RegionServer负载飙升这是最危险的误操作。线上生产表动辄几十GB甚至几TB一条scan big_table不带LIMIT可能会把集群CPU和内存打满。解决办法是第一日常查询务必带STARTROW和ENDROW第二非要过滤就用PrefixFilter这种高效的过滤器第三如果只是看数据结构用LIMIT 1先探路。6.4 获取的数据版本和预期不一致get命令查出来的数据版本比预期少先检查建表时VERSIONS的设置。如果建表时设了VERSIONS为1那写入两次同名数据后只能查到最新一条。如果需要保留历史版本必须先alter修改VERSIONS再执行put。这里有一个很容易踩的坑对已有数据执行alter修改VERSIONS之后已经被覆盖的旧版本数据并不会恢复只影响后续新写入的数据。6.5 常用命令速查表我把自己日常用的最多的命令整理成了一个速查表方便直接复制操作类型命令示例说明启动Shell./hbase shell进入HBase命令行查看状态status/status detailed查看集群和region状态建表create t1, cf1创建单列族表建表(预分区)create t1, cf1, SPLITS [10,20]按分界点预分区查看表结构describe t1显示列族和属性写数据put t1, r1, cf1:c1, v1写入单单元格查单行get t1, r1获取整行范围扫描scan t1, {STARTROW r1, ENDROW r2}按rowkey范围扫描条件过滤scan t1, {FILTER PrefixFilter(r1)}按前缀过滤删除列delete t1, r1, cf1:c1删除单元格删除行deleteall t1, r1删除整行禁用表disable t1删除表前的必要步骤启用表enable t1恢复表读写删除表drop t1删除表清空表truncate t1清空数据保留表结构修改表alter t1, NAME cf2, VERSIONS 3修改列族属性快照备份snapshot t1, snap1创建快照恢复快照restore_snapshot snap1恢复表到快照状态克隆快照clone_snapshot snap1, t2从快照生成新表最后再分享一个我自己的使用习惯。不要只在出问题的时候才打开Shell平时可以在Shell里写一些简单的脚本比如把status和disk_space的执行结果定期打出来作为日常巡检的一部分。HBase Shell是能直接执行脚本文件的你写好的命令集合可以存成.hb后缀的文件以后一行命令就能自动跑完一套巡检流程。HBase的Shell命令看似零散但只要理解了表管理、数据读写、运维操作这条主线再用快照和预分区这两个关键功能把实际场景串起来用起来就会非常顺手。
返回列表