Apache HBase 官方文档中文版

joesilver

贡献于2012-02-01

字数:0 关键词: 分布式/云计算/大数据 Apache

HBase 官方文档(中文版) Copyright © 2010 Apache Software Foundation,颜开(译) Revision History Revision 0.90.4 配置,数据模型使用入门 Abstract 这是 Apache HBase 的官方文档, Hbase 是一个分布式 ,版本化 (versioned),构建在 Apache Hadoop 和 Apache ZooKeeper 上的列数据库 . Table of Contents 序 1. 入门 1.1. 介绍 1.2. 快速开始 1.2.1. 下载解压最新版本 1.2.2. 启动 HBase 1.2.3. Shell 练习 1.2.4. 停止 HBase 1.2.5. 下一步该做什么 1.3. 慢速开始 (相对快速开始) 1.3.1. 需要的软件 1.3.2. HBase 运行模式:单机和分布式 1.3.3. 配置例子 2. 升级 2.1. 从 HBase 0.20.x or 0.89.x 升级到 HBase 0.90.x 3. 配置 3.1. hbase-site.xml 和 hbase-default.xml 3.1.1. HBase 默认配置 3.2. hbase-env.sh 3.3. log4j.properties 3.4. 重要的配置 3.5. 必须的配置 3.6. 推荐的配置 3.6.1. zookeeper.session.timeout 3.6.2. hbase.regionserver.handler.count 3.6.3. 大内存机器的配置 3.6.4. LZO 压缩 3.6.5. 更大的 Regions 3.6.6. 管理 Splitting 3.7. 连接 Hbase 集群的客户端配置和依赖 3.7.1. Java 客户端配置 4. The HBase Shell 4.1. 使用脚本 4.2. Shell 技巧 4.2.1. irbrc 4.2.2. LOG 时间转换 4.2.3. Debug 5. 构建 HBase 5.1. 将一个 HBase release 加入到 Apache's Maven Repository 6. Developers 6.1. IDEs 6.1.1. Eclipse 6.2. 单元测试 6.2.1. Mocito 7. HBase 和 MapReduce 7.1. 默认 HBase MapReduce 分割器(Splitter) 7.2. HBase Input MapReduce 例子 7.3. 在一个 MapReduce Job 中访问其他的 HBase Tables 7.4. 预测执行 8. HBase 的 Schema 设计 8.1. Schema 创建 8.2. column families 的数量 8.3. 单调递增 Row Keys/时序数据(log) 8.4. 尽量最小化 row 和 column 的大小 8.5. 版本的时间 9. Metrics 9.1. Metric 安装 9.2. RegionServer Metrics 9.2.1. hbase.regionserver.blockCacheCount 9.2.2. hbase.regionserver.blockCacheFree 9.2.3. hbase.regionserver.blockCacheHitRatio 9.2.4. hbase.regionserver.blockCacheSize 9.2.5. hbase.regionserver.compactionQueueSize 9.2.6. hbase.regionserver.fsReadLatency_avg_time 9.2.7. hbase.regionserver.fsReadLatency_num_ops 9.2.8. hbase.regionserver.fsSyncLatency_avg_time 9.2.9. hbase.regionserver.fsSyncLatency_num_ops 9.2.10. hbase.regionserver.fsWriteLatency_avg_time 9.2.11. hbase.regionserver.fsWriteLatency_num_ops 9.2.12. hbase.regionserver.memstoreSizeMB 9.2.13. hbase.regionserver.regions 9.2.14. hbase.regionserver.requests 9.2.15. hbase.regionserver.storeFileIndexSizeMB 9.2.16. hbase.regionserver.stores 9.2.17. hbase.regionserver.storeFiles 10. 跨集群复制 11. 数据模型 11.1. 概念视图 11.2. 物理视图 11.3. 表 11.4. 行 11.5. Column Family 11.6. Cells 11.7. 版本 11.7.1. Hbase 的操作(包含版本操作) 11.7.2. 现有的限制 12. 架构 12.1. 客户端 12.1.1. 连接 12.1.2. 写缓冲和批量操作 12.1.3. Filters 12.2. Daemons 12.2.1. Master 12.2.2. RegionServer 12.3. Regions 12.3.1. Region 大小 12.3.2. Region Splits 12.3.3. Region 负载均衡 12.3.4. Store 12.4. Write Ahead Log (WAL) 12.4.1. 目的 12.4.2. WAL Flushing 12.4.3. WAL Splitting 13. 性能调优 13.1. Java 13.1.1. 垃圾收集和 HBase 13.2. 配置 13.2.1. Regions 的数目 13.2.2. 管理压缩 13.2.3. 压缩 13.2.4. hbase.regionserver.handler.count 13.2.5. hfile.block.cache.size 13.2.6. hbase.regionserver.global.memstore.upperLimit 13.2.7. hbase.regionserver.global.memstore.lowerLimit 13.2.8. hbase.hstore.blockingStoreFiles 13.2.9. hbase.hregion.memstore.block.multiplier 13.3. Column Families 的数目 13.4. 数据聚集 13.5. 批量 Loading 13.5.1. Table 创建: 预创建 Regions 13.6. HBase 客户端 13.6.1. AutoFlush 13.6.2. Scan Caching 13.6.3. Scan 属性选择 13.6.4. 关闭 ResultScanners 13.6.5. 块缓存 13.6.6. Row Keys 的负载优化 14. Bloom Filters 14.1. 配置 14.1.1. HColumnDescriptor 配置 14.1.2. io.hfile.bloom.enabled 全局关闭开关 14.1.3. io.hfile.bloom.error.rate 14.1.4. io.hfile.bloom.max.fold 14.2. Bloom StoreFile footprint 14.2.1. StoreFile 中的 BloomFilter, FileInfo 数据结构 14.2.2. 在 StoreFile 元数据中的 BloomFilter entries 15. Hbase 的故障排除和 Debug 15.1. 一般准则 15.2. Logs 15.2.1. Log 位置 15.3. 工具 15.3.1. search-hadoop.com 15.3.2. tail 15.3.3. top 15.3.4. jps 15.3.5. jstack 15.3.6. OpenTSDB 15.3.7. clusterssh+top 15.4. 客户端 15.4.1. ScannerTimeoutException 15.5. RegionServer 15.5.1. 启动错误 15.5.2. 运行时错误 15.5.3. 终止错误 15.6. Master 15.6.1. 启动错误 15.6.2. 终止错误 A. 工具 A.1. HBase hbck A.2. HFile 工具 A.3. WAL Tools A.3.1. HLog 工具 A.4. 压缩工具 A.5. Node 下线 A.5.1. 依次重启 B. HBase 中的压缩 B.1. 测试压缩工具 B.2. hbase.regionserver.codecs B.3. LZO B.4. GZIP C. FAQ D. YCSB: 雅虎云服务 测试 和 Hbase Index List of Tables 11.1. 表 webtable 11.2. ColumnFamily anchor 11.3. ColumnFamily contents 序 这本书是 HBase 的官方指南。 版本为 0.90.4.可以在 Hbase 官网上找到它。也可以在 javadoc, JIRA 和 wiki 找到更多的资料。 此书正在编辑中。 可以向 HBase 官方提供补丁 JIRA. 这个版本系译者水平限制,没有理解清楚或不需要翻译的地方保留英文原文。 最前面的话 若这是你第一次踏入分布式计算的精彩世界,你会感到这是一个有趣的年代。分布式计算是 很难的,做一个分布式系统需要很多软硬件和网络的技能。你的集群可以会因为各式各样的 错误发生故障。比如 Hbase 本身的 Bug,错误的配置(包括操作系统),硬件的故障(网卡和磁 盘甚至内存) 如果你一直在写单机程序的话,你需要重新开始学习。这里就是一个好的起点: 分布式计算的谬论. Chapter 1. 入门 Table of Contents 1.1. 介绍 1.2. 快速开始 1.2.1. 下载解压最新版本 1.2.2. 启动 HBase 1.2.3. Shell 练习 1.2.4. 停止 HBase 1.2.5. 下一步该做什么 1.3. 慢速开始(相对快速开始) 1.3.1. 需要的软件 1.3.2. HBase 运行模式:单机和分布式 1.3.3. 配置例子 1.1. 介绍 Section 1.2, “快速开始”会介绍如何运行一个单机版的 Hbase.他运行在本地磁盘上。 Section 1.3, “慢速开始(相对快速开始)” 会介绍如何运行一个分布式的 Hbase。他运行在 HDFS 上 1.2. 快速开始 本指南介绍了在单机安装 Hbase 的方法。会引导你通过 shell 创建一个表,插入一行,然后 删除它,最后停止 Hbase。只要 10 分钟就可以完成以下的操作。 1.2.1. 下载解压最新版本 选择一个 Apache 下载镜像,下载 HBase Releases. 点击 stable 目录,然后下载后缀 为 .tar.gz 的文件; 例如 hbase-0.90.4.tar.gz. 解压缩,然后进入到那个要解压的目录. $ tar xfz hbase-0.90.4.tar.gz $ cd hbase-0.90.4 现在你已经可以启动 Hbase 了。但是你可能需要先编辑 conf/hbase-site.xml 去配置 hbase.rootdir,来选择 Hbase 将数据写到哪个目录 . hbase.rootdir file:///DIRECTORY/hbase 将 DIRECTORY 替换成你期望写文件的目录. 默认 hbase.rootdir 是指向 /tmp/hbase-${user.name} ,也就说你会在重启后丢失数据(重启的时候操作系统会清理/tmp 目录) 1.2.2. 启动 HBase 现在启动 Hbase: $ ./bin/start-hbase.sh starting Master, logging to logs/hbase-user-master-example.org.out 现在你运行的是单机模式的 Hbaes。所以的服务都运行在一个 JVM 上,包括 Hbase 和 Zookeeper。Hbase 的日志放在 logs 目录,当你启动出问题的时候,可以检查这个日志。 是否安装了 java ? 你需要确认安装了 Oracle 的 1.6 版本的 java.如果你在命令行键入 java 有反应说明你安装了 Java。如果没有装,你需要先安装,然后编辑 conf/hbase-env.sh,将其中的 JAVA_HOME 指 向到你 Java 的安装目录。 1.2.3. Shell 练习 用 shell 连接你的 Hbase $ ./bin/hbase shell HBase Shell; enter 'help' for list of supported commands. Type "exit" to leave the HBase Shell Version: 0.90.0, r1001068, Fri Sep 24 13:55:42 PDT 2010 hbase(main):001:0> 输入 help 然后 可以看到一列 shell 命令。这里的帮助很详细,要注意的是表 名,行和列需要加引号。 创建一个名为 test 的表,这个表只有一个 column family 为 cf。可以列出所有的表来检查 创建情况,然后插入些值。 hbase(main):003:0> create 'test', 'cf' 0 row(s) in 1.2200 seconds hbase(main):003:0> list 'table' test 1 row(s) in 0.0550 seconds hbase(main):004:0> put 'test', 'row1', 'cf:a', 'value1' 0 row(s) in 0.0560 seconds hbase(main):005:0> put 'test', 'row2', 'cf:b', 'value2' 0 row(s) in 0.0370 seconds hbase(main):006:0> put 'test', 'row3', 'cf:c', 'value3' 0 row(s) in 0.0450 seconds 以上我们分别插入了 3 行。第一个行 key 为 row1, 列为 cf:a, 值是 value1。Hbase 中的列 是由 column family 前缀和列的名字组成的,以冒号间隔。例如这一行的列名就是 a. 检查插入情况. Scan 这个表,操作如下 hbase(main):007:0> scan 'test' ROW COLUMN+CELL row1 column=cf:a, timestamp=1288380727188, value=value1 row2 column=cf:b, timestamp=1288380738440, value=value2 row3 column=cf:c, timestamp=1288380747365, value=value3 3 row(s) in 0.0590 seconds Get 一行,操作如下 hbase(main):008:0> get 'test', 'row1' COLUMN CELL cf:a timestamp=1288380727188, value=value1 1 row(s) in 0.0400 seconds disable 再 drop 这张表,可以清除你刚刚的操作 hbase(main):012:0> disable 'test' 0 row(s) in 1.0930 seconds hbase(main):013:0> drop 'test' 0 row(s) in 0.0770 seconds 关闭 shell hbase(main):014:0> exit 1.2.4. 停止 HBase 运行停止脚本来停止 HBase. $ ./bin/stop-hbase.sh stopping hbase............... 1.2.5. 下一步该做什么 以上步骤仅仅适用于实验和测试。接下来你可以看 Section 1.3, “慢速开始(相对快速开 始)” ,我们会介绍不同的 Hbase 运行模式,运行分布式 Hbase 中需要的软件 和如何配置。 1.3. 慢速开始(相对快速开始) 1.3.1. 需要的软件 Hbase 有如下需要,请仔细阅读本章节以确保所有的需要都被满足。如果需求没有能满足, 就有可能遇到莫名其妙的错误甚至丢失数据。 1.3.1.1. java 和 Hadoop 一样,Hbase 需要 Oracle 版本的 Java6.除了那个有问题的 u18 版本其他的都可以 用,最好用最新的。 1.3.1.2. hadoop 该版本的 Hbase 只可以运行在 Hadoop 0.20.x,不可以运行于 hadoop 0.21.x (0.22.x 也不行). HBase 运行在没有持久同步功能的 HDFS 上会丢失数据。 Hadoop 0.20.2 和 Hadoop 0.20.203.0 就没有这个功能。现在只有 branch-0.20-append 补丁有这个功能[1]. 现在官方的 发行版都没有这个功能,所以你要自己打这个补丁。推荐看 Michael Noll 写的详细的说明, Building an Hadoop 0.20.x version for HBase 0.90.2. 你还可以用 Cloudera's CDH3. CDH 打了这个补丁 (CDH3 betas 就可以满足; b2, b3, or b4). 因为 Hbase 建立在 Hadoop 之上,所以他用到了 hadoop.jar,这个 Jar 在 lib 里面。这个 jar 是 hbase 自己打了 branch-0.20-append 补丁的 hadoop.jar. Hadoop 使用的 hadoop.jar 和 Hbase 使 用的 必须 一致。所以你需要将 Hbase lib 目录下的 hadoop.jar 替换成 Hadoop 里面的那个, 防止版本冲突。比方说 CDH 的版本没有 HDFS-724 而 branch-0.20-append 里面有,这个 HDFS-724 补丁修改了 RPC 协议。如果不替换,就会有版本冲突,继而造成严重的出错, Hadoop 会看起来挂了。 我可以用 Hbase 里面的支持 sync 的 hadoop.jar 替代 Hadoop 里面的那个吗? 你可以这么干。详细可以参见这个邮件列表. Hadoop 安全性 HBase 运行在 Hadoop 0.20.x 上,就可以使用其中的安全特性 -- 只要你用这两个版本 0.20S 和 CDH3B3,然后把 hadoop.jar 替换掉就可以了. 1.3.1.3. ssh 必须安装 ssh , sshd 也必须运行,这样 Hadoop 的脚本才可以远程操控其他的 Hadoop 和 Hbase 进程。ssh 之间必须都打通,不用密码都可以登录,详细方法可以 Google 一下 ("ssh passwordless login"). 1.3.1.4. DNS HBase 使用本地 hostname 才获得 IP 地址. 正反向的 DNS 都是可以的. 如果你的机器有多个接口,Hbase 会使用 hostname 指向的主接口. 如果还不够,你可以设置 hbase.regionserver.dns.interface 来指定主接口。当然你的整个集群 的配置文件都必须一致,每个主机都使用相同的网络接口 还有一种方法是设置 hbase.regionserver.dns.nameserver 来指定 nameserver,不使用系统带的. 1.3.1.5. NTP 集群的时钟要保证基本的一致。稍有不一致是可以容忍的,但是很大的不一致会造成奇怪的 行为。 运行 NTP 或者其他什么东西来同步你的时间. 如果你查询的时候或者是遇到奇怪的故障,可以检查一下系统时间是否正确! 1.3.1.6. ulimit 和 nproc HBase 是数据库,会在同一时间使用很多的文件句柄。大多数 linux 系统使用的默认值 1024 是不能满足的,会导致 FAQ: Why do I see "java.io.IOException...(Too many open files)" in my logs?异常。还可能会发生这样的异常 2010-04-06 03:04:37,542 INFO org.apache.hadoop.hdfs.DFSClient: Exception increateBlockOutputStream java.io.EOFException 2010-04-06 03:04:37,542 INFO org.apache.hadoop.hdfs.DFSClient: Abandoning block blk_-6935524980745310745_1391901 所以你需要修改你的最大文件句柄限制。可以设置到 10k. 你还需要修改 hbase 用户的 nproc,如果过低会造成 OutOfMemoryError 异常。 [2] [3]. 需要澄清的,这两个设置是针对操作系统的,不是 Hbase 本身的。有一个常见的错误是 Hbase 运行的用户,和设置最大值的用户不是一个用户。在 Hbase 启动的时候,第一行日志会现在 ulimit 信息,所以你最好检查一下。 [4] 1.3.1.6.1. 在 Ubuntu 上设置 ulimit 如果你使用的是 Ubuntu,你可以这样设置: 在文件 /etc/security/limits.conf 添加一行,如: hadoop - nofile 32768 可以把 hadoop 替换成你运行 Hbase 和 Hadoop 的用户。如果你用两个用户,你就需要配两 个。还有配 nproc hard 和 soft limits. 如: hadoop soft/hard nproc 32000 . 在 /etc/pam.d/common-session 加上这一行: session required pam_limits.so 否则在 /etc/security/limits.conf 上的配置不会生效. 还有注销再登录,这些配置才能生效! 1.3.1.7. dfs.datanode.max.xcievers 一个 Hadoop HDFS Datanode 有一个同时处理文件的上限. 这个参数叫 xcievers (Hadoop 的 作者把这个单词拼错了). 在你加载之前,先确认下你有没有配置这个文件 conf/hdfs-site.xml 里面的 xceivers 参数,至少要有 4096: dfs.datanode.max.xcievers 4096 对于 HDFS 修改配置要记得重启. 如果没有这一项配置,你可能会遇到奇怪的失败。你会在 Datanode 的日志中看到 xcievers exceeded ,但是运行起来会报 missing blocks 错误。例如: 10/12/08 20:10:31 INFO hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXXXXXX_YYYYYYYY from any node: java.io.IOException: No live nodes contain current block. Will get new block locations from namenode and retry... [5] 1.3.1.8. Windows HBase 没有怎么在 Windows 下测试过。所以不推荐在 Windows 下运行. 如果你实在是想运行,需要安装 Cygwin 还虚拟一个 unix 环境.详情请看 Windows 安装指 导 . 或者 搜索邮件列表找找最近的关于 windows 的注意点 1.3.2. HBase 运行模式:单机和分布式 HBase 有两个运行模式: Section 1.3.2.1, “单机模式” 和 Section 1.3.2.2, “分布式模式”. 默 认是单机模式,如果要分布式模式你需要编辑 conf 文件夹中的配置文件. 不管是什么模式,你都需要编辑 conf/hbase-env.sh 来告知 Hbase java 的安装路径.在这个文 件里你还可以设置 Hbase 的运行环境,诸如 heapsize 和其他 JVM 有关的选项, 还有 Log 文 件地址,等等. 设置 J AVA _ H O M E 指向 java 安装的路径. 1.3.2.1. 单机模式 这是默认的模式,在 Section 1.2, “快速开始” 一章中介绍的就是这个模式. 在单机模式中, Hbase 使用本地文件系统,而不是 HDFS ,所以的服务和 zooKeeper 都运作在一个 JVM 中。 zookeep 监听一个端口,这样客户端就可以连接 Hbase 了。 1.3.2.2. 分布式模式 分布式模式分两种。伪分布式模式是把进程运行在一台机器上,但不是一个 JVM.而完全分 布式模式就是把整个服务被分布在各个节点上了 [6]. 分布式模式需要使用 Hadoop Distributed File System (HDFS).可以参见 HDFS 需求和指导来 获得关于安装 HDFS 的指导。在操作 Hbase 之前,你要确认 HDFS 可以正常运作。 在我们安装之后,你需要确认你的伪分布式模式或者 完全分布式模式的配置是否正确。这 两个模式可以使用同一个验证脚本 Section 1.3.2.3, “运行和确认你的安装”。 1.3.2.2.1. 伪分布式模式 伪分布式模式是一个相对简单的分布式模式。这个模式是用来测试的。不能把这个模式用于 生产环节,也不能用于测试性能。 你确认 HDFS 安装成功之后,就可以先编辑 conf/hbase-site.xml。在这个文件你可以加入自 己的配置,这个配置会覆盖 Section 3.1.1, “HBase 默认配置” and Section 1.3.2.2.2.3, “HDFS 客户端配置”. 运行 Hbase 需要设置 hbase.rootdir 属性.该属性是指 Hbase 在 HDFS 中使用的目录的位置。例如,要想 /hbase 目录,让 namenode 监听 locahost 的 9000 端口, 只有一份数据拷贝(HDFS 默认是 3 份拷贝)。可以在 hbase-site.xml 写上如下内容 ... hbase.rootdir hdfs://localhost:9000/hbase The directory shared by RegionServers. dfs.replication 1 The replication count for HLog & HFile storage. Should not be greater than HDFS datanode count. ... Note 让 Hbase 自己创建 hbase.rootdir 目录,如果你自己建这个目录,会有一个 warning,Hbase 会试图在里面进行 migration 操作,但是缺少必须的文件。 Note 上面我们绑定到 localhost. 也就是说除了本机,其他机器连不上 Hbase。所以你需要设置成 别的,才能使用它。 现在可以跳到 Section 1.3.2.3, “运行和确认你的安装” 来运行和确认你的伪分布式模式安 装了。 [7] 1.3.2.2.2. 完全分布式模式 要想运行完全分布式模式,你要进行如下配置,先在 hbase-site.xml, 加一个属性 hbase.cluster.distributed 设置为 true 然后把 hbase.rootdir 设置为 HDFS 的 NameNode 的位 置。 例如,你的namenode运行在namenode.example.org,端口是9000 你期望的目录是 /hbase, 使用如下的配置 ... hbase.rootdir hdfs://namenode.example.org:9000/hbase The directory shared by RegionServers. hbase.cluster.distributed true The mode the cluster will be in. Possible values are false: standalone and pseudo-distributed setups with managed Zookeeper true: fully-distributed with unmanaged Zookeeper Quorum (see hbase-env.sh) ... 1.3.2.2.2.1. regionservers 完全分布式模式的还需要修改 conf/regionservers. 在 Section 1.3.3.1.2, “regionservers” 列 出了你希望运行的全部 HRegionServer,一行写一个 host (就像 Hadoop 里面的 slaves 一样). 列在这里的 server 会随着集群的启动而启动,集群的停止而停止. 1.3.2.2.2.2. ZooKeeper 一个分布式运行的 Hbase 依赖一个 zookeeper 集群。所有的节点和客户端都必须能够访问 zookeeper。默认的情况下 Hbase 会管理一个 zookeep 集群。这个集群会随着 Hbase 的启动而 启动。当然,你也可以自己管理一个 zookeeper 集群,但需要配置 Hbase。你需要修改 conf/hbase-env.sh 里面的 HBASE_MANAGES_ZK 来切换。这个值默认是 true 的,作用是让 Hbase 启动的时候同时也启动 zookeeper. 当 Hbase 管理 zookeeper 的时候,你可以通过修改 zoo.cfg 来配置 zookeeper,一个更加简单 的方法是在 conf/hbase-site.xml 里面修改 zookeeper 的配置。Zookeep 的配置是作为 property 写在 hbase-site.xml 里面的。option 的名字是 hbase.zookeeper.property. 打个比方, clientPort 配置在 xml 里面的名字是 hbase.zookeeper.property.clientPort. 所有的默认值都是 Hbase 决定 的,包括 zookeeper, 参见 Section 3.1.1, “ HBase 默认配置”. 可以查找 hbase.zookeeper.property 前缀,找到关于 zookeeper 的配置。 [8] 对于 zookeepr 的配置,你至少要在 hbase-site.xml 中列出 zookeepr 的 ensemble servers,具 体 的字段是 hbase.zookeeper.quorum. 该这个字段的默认值是 localhost,这个值对于分布式应 用显然是不可以的. (远程连接无法使用). 我需要运行几个 zookeeper? 你运行一个 zookeeper 也是可以的,但是在生产环境中,你最好部署 3,5,7 个节点。部署 的越多,可靠性就越高,当然只能部署奇数个,偶数个是不可以的。你需要给每个 zookeeper 1G 左右的内存,如果可能的话,最好有独立的磁盘。 (独立磁盘可以确保 zookeeper 是高性 能的。).如果你的集群负载很重,不要把 Zookeeper 和 RegionServer 运行在同一台机器上面。 就像 DataNodes 和 TaskTrackers 一样 打个比方,Hbase 管理着的 ZooKeeper 集群在节点 rs{1,2,3,4,5}.example.com, 监听 2222 端 口(默认是 2181),并确保 conf/hbase-env.sh 文件中 HBASE_MANAGE_ZK 的值是 true ,再 编辑 conf/hbase-site.xml 设置 hbase.zookeeper.property.clientPort 和 hbase.zookeeper.quorum。你还可以设置 hbase.zookeeper.property.dataDir 属性来把 ZooKeeper 保存数据的目录地址改掉。默认值是 /tmp ,这里在重启的时候会被操作系统删掉,可以把 它修改到 /user/local/zookeeper. ... hbase.zookeeper.property.clientPort 2222 Property from ZooKeeper's config zoo.cfg. The port at which the clients will connect. hbase.zookeeper.quorum rs1.example.com,rs2.example.com,rs3.example.com,rs4.example.com,rs5.example.com Comma separated list of servers in the ZooKeeper Quorum. For example, "host1.mydomain.com,host2.mydomain.com,host3.mydomain.com". By default this is set to localhost for local and pseudo-distributed modes of operation. For a fully-distributed setup, this should be set to a full list of ZooKeeper quorum servers. If HBASE_MANAGES_ZK is set in hbase-env.sh this is the list of servers which we will start/stop ZooKeeper on. hbase.zookeeper.property.dataDir /usr/local/zookeeper Property from ZooKeeper's config zoo.cfg. The directory where the snapshot is stored. ... 1.3.2.2.2.2.1. 使用现有的 ZooKeeper 例子 让 Hbase 使用一个现有的不被 Hbase 托管的 Zookeep 集群,需要设置 conf/hbase-env.sh 文件 中的 HBASE_MANAGES_ZK 属性为 false ... # Tell HBase whether it should manage it's own instance of Zookeeper or not. export HBASE_MANAGES_ZK=false 接下来,指明 Zookeeper 的 host 和端口。可以在 hbase-site.xml 中设置, 也可以在 Hbase 的 CLASSPATH 下面加一个 zoo.cfg 配置文件。 HBase 会优先加载 zoo.cfg 里面的配置,把 hbase-site.xml 里面的覆盖掉. 当 Hbase 托管 ZooKeeper 的时候,Zookeeper 集群的启动是 Hbase 启动脚本的一部分。但现 在,你需要自己去运行。你可以这样做 ${HBASE_HOME}/bin/hbase-daemons.sh {start,stop} zookeeper 你可以用这条命令启动 ZooKeeper 而不启动 Hbase. HBASE_MANAGES_ZK 的值是 false, 如果你想在 Hbase 重启的时候不重启 ZooKeeper,你可以这样做 对于独立 Zoopkeeper 的问题,你可以在 Zookeeper 启动得到帮助. 1.3.2.2.2.3. HDFS 客户端配置 如果你希望 Hadoop 集群上做 HDFS 客户端配置 ,例如你的 HDFS 客户端的配置和服务端 的不一样。按照如下的方法配置,HBase 就能看到你的配置信息: 在 hbase-env.sh 里将 HBASE_CLASSPATH 环境变量加上 HADOOP_CONF_DIR 。 在${HBASE_HOME}/conf 下面加一个 hdfs-site.xml (或者 hadoop-site.xml) ,最好是软连接 如果你的 HDFS 客户端的配置不多的话,你可以把这些加到 hbase-site.xml 上面. 例如 HDFS 的配置 dfs.replication.你希望复制 5 份,而不是默认的 3 份。如果你不照上面的 做的话,Hbase 只会复制 3 份。 1.3.2.3. 运行和确认你的安装 首先确认你的 HDFS 是运行着的。你可以运行 HADOOP_HOME 中的 bin/start-hdfs.sh 来启 动 HDFS.你可以通过 put 命令来测试放一个文件,然后有 get 命令来读这个文件。通常情况 下 Hbase 是不会运行 mapreduce 的。所以比不需要检查这些。 如果你自己管理 ZooKeeper 集群,你需要确认它是运行着的。如果是 Hbase 托管,ZoopKeeper 会随 Hbase 启动。 用如下命令启动 Hbase: bin/start-hbase.sh 这个脚本在 HBASE_HOME 目录里面。 你现在已经启动 Hbase 了。Hbase 把 log 记在 logs 子目录里面. 当 Hbase 启动出问题的时候, 可以看看 Log. Hbase 也有一个界面,上面会列出重要的属性。默认是在 Master 的 60010 端口上 H (HBase RegionServers 会默认绑定 60020 端口,在端口 60030 上有一个展示信息的界面 ).如果 Master 运行在 master.example.org ,端口是默认的话,你可以用浏览器在 http://master.example.org:60010 看到主界面. . 一旦 Hbase 启动,参见 Section 1.2.3, “Shell 练习”可以看到如何建表,插入数据,scan 你 的表,还有 disable 这个表,最后把它删掉。 可以在 Hbase Shell 停止 Hbase $ ./bin/stop-hbase.sh stopping hbase............... 停止操作需要一些时间,你的集群越大,停的时间可能会越长。如果你正在运行一个分布式 的操作,要确认在 Hbase 彻底停止之前,Hadoop 不能停. 1.3.3. 配置例子 1.3.3.1. 简单的分布式 Hbase 安装 这里是一个 10 节点的 Hbase 的简单示例,这里的配置都是基本的,节点名为 example0, example1... 一直到 example9 . HBase Master 和 HDFS namenode 运作在同一个节点 example0 上. RegionServers 运行在节点 example1-example9. 一个 3-节点 ZooKeeper 集群 运行在 example1, example2, 和 example3,端口保持默认. ZooKeeper 的数据保存在目录 /export/zookeeper. 下面我们展示主要的配置文件-- hbase-site.xml, regionservers, 和 hbase-env.sh -- 这些文件可以在 conf 目录找到. 1.3.3.1.1. hbase-site.xml hbase.zookeeper.quorum example1,example2,example3 The directory shared by RegionServers. hbase.zookeeper.property.dataDir /export/zookeeper Property from ZooKeeper's config zoo.cfg. The directory where the snapshot is stored. hbase.rootdir hdfs://example0:9000/hbase The directory shared by RegionServers. hbase.cluster.distributed true The mode the cluster will be in. Possible values are false: standalone and pseudo-distributed setups with managed Zookeeper true: fully-distributed with unmanaged Zookeeper Quorum (see hbase-env.sh) 1.3.3.1.2. regionservers 这个文件把 RegionServer 的节点列了下来。在这个例子里面我们让所有的节点都运行 RegionServer,除了第一个节点 example1,它要运行 HBase Master 和 HDFS namenode example1 example3 example4 example5 example6 example7 example8 example9 1.3.3.1.3. hbase-env.sh 下面我们用 diff 命令来展示 hbase-env.sh 文件相比默认变化的部分. 我们把 Hbase 的堆内 存设置为 4G 而不是默认的 1G. $ git diff hbase-env.sh diff --git a/conf/hbase-env.sh b/conf/hbase-env.sh index e70ebc6..96f8c27 100644 --- a/conf/hbase-env.sh +++ b/conf/hbase-env.sh @@ -31,7 +31,7 @@ export JAVA_HOME=/usr/lib//jvm/java-6-sun/ # export HBASE_CLASSPATH= # The maximum amount of heap to use, in MB. Default is 1000. -# export HBASE_HEAPSIZE=1000 +export HBASE_HEAPSIZE=4096 # Extra Java runtime options. # Below are what we set by default. May only work with SUN JVM. 你可以使用 rsync 来同步 conf 文件夹到你的整个集群. [1] See CHANGES.txt in branch-0.20-append to see list of patches involved adding append on the Hadoop 0.20 branch. [2] See Jack Levin's major hdfs issues note up on the user list. [3] 这样的需求对于数据库应用来说是很常见的,例如 Oracle。 Setting Shell Limits for the Oracle User in Short Guide to install Oracle 10 on Linux. [4] A useful read setting config on you hadoop cluster is Aaron Kimballs' Configuration Parameters: What can you just ignore? [5] 参见 Hadoop HDFS: Deceived by Xciever for an informative rant on xceivering. [6] 这两个命名法来自于 Hadoop. [7] See Pseudo-distributed mode extras for notes on how to start extra Masters and RegionServers when running pseudo-distributed. [8] For the full list of ZooKeeper configurations, see ZooKeeper's zoo.cfg. HBase does not ship with a zoo.cfg so you will need to browse the conf directory in an appropriate ZooKeeper download. Chapter 2. 升级 Table of Contents 2.1. 从 HBase 0.20.x or 0.89.x 升级到 HBase 0.90.x 参见 Section 1.3.1, “需要的软件”, 需要特别注意有关 Hadoop 版本的信息. 2.1. 从 HBase 0.20.x or 0.89.x 升级到 HBase 0.90.x 0.90.x 版本的 HBase 可以在 HBase 0.20.x 或者 HBase 0.89.x 的数据上启动. 不需要转换数 据文件, HBase 0.89.x 和 0.90.x 的 region 目录名是不一样的 -- 老版本用 md5 hash 而不 是 jenkins hash 来命名 region-- 这就意味着,一旦启动,再也不能回退到 HBase 0.20.x. 在升级的时候,一定要将 hbase-default.xml 从你的 conf 目录删掉。 0.20.x 版本的配置对于 0.90.x HBase 不是最佳的. hbase-default.xml 现在已经被打包在 HBase jar 里面了. 如果你想 看看这个文件内容,你可以在 src 目录下 src/main/resources/hbase-default.xml 或者在 Section 3.1.1, “HBase 默认配置”看到. 最后,如果从 0.20.x 升级,需要在 shell 里检查 .META. schema . 过去,我们推荐用户使用 16KB 的 MEMSTORE_FLUSHSIZE. 在 shell 中运行 hbase> scan '-ROOT-'. 会显示当前 的.META. schema. 检查 MEMSTORE_FLUSHSIZE 的大小. 看看是不是 16KB (16384)? 如果是的话,你需要修改它( 默认的值是 64MB (67108864)) 运行脚本 bin/set_meta_memstore_size.rb. 这个脚本会修改 .META. schema. 如果不运行的话,集群会 比较慢[9] . [9] 参见 HBASE-3499 Users upgrading to 0.90.0 need to have their .META. table updated with the right MEMSTORE_SIZE Chapter 3. 配置 Table of Contents 3.1. hbase-site.xml 和 hbase-default.xml 3.1.1. HBase 默认配置 3.2. hbase-env.sh 3.3. log4j.properties 3.4. 重要的配置 3.5. 必须的配置 3.6. 推荐的配置 3.6.1. zookeeper.session.timeout 3.6.2. hbase.regionserver.handler.count 3.6.3. 大内存机器的配置 3.6.4. LZO 压缩 3.6.5. 更大的 Regions 3.6.6. 管理 Splitting 3.7. 连接 Hbase 集群的客户端配置和依赖 3.7.1. Java 客户端配置 Hbase 的配置系统和 Hadoop 一样。在 conf/hbase-env.sh 配置系统的部署信息和环境变量。 -- 这个配置会被启动 shell 使用 -- 然后在 XML 文件里配置信息,覆盖默认的配置。告知 Hbase 使用什么目录地址,ZooKeeper 的位置等等信息。 [10] . 当你使用分布式模式的时间,当你编辑完一个文件之后,记得要把这个文件复制到整个集群 的 conf 目录下。Hbase 不会帮你做这些,你得用 rsync. 3.1. hbase-site.xml 和 hbase-default.xml 正如 Hadoop 放置 HDFS 的配置文件 hdfs-site.xml,Hbase 的配置文件是 conf/hbase-site.xml. 你可以在 Section 3.1.1, “HBase 默认配置”找到配置的属性列表。你也可以看有代码里面 的 hbase-default.xml 文件,他在 src/main/resources 目录下。 不是所有的配置都在 hbase-default.xml 出现.只要改了代码,配置就有可能改变,所以唯一 了解这些被改过的配置的办法是读源代码本身。 要注意的是,要重启集群才能是配置生效。 3.1.1. HBase 默认配置 HBase 默认配置 该文档是用 hbase 默认配置文件生成的,文件源是 hbase-default.xml(因翻译需要,被译者修 改成中文注释). hbase.rootdir 这个目录是 region server 的共享目录,用来持久化 Hbase。URL 需要是'完全正确'的,还要 包含文件系统的 scheme 。例如,要表示 hdfs 中的'/hbase'目录,namenode 运行在 namenode.example.org 的 9090 端口。则需要设置为 hdfs://namenode.example.org:9000/hbase。 默认情况下 Hbase 是写到/tmp 的。不改这个配置,数据会在重启的时候丢失。 默认: file:///tmp/hbase-${user.name}/hbase hbase.master.port Hbase 的 Master 的端口. 默认: 60000 hbase.cluster.distributed Hbase 的运行模式。false 是单机模式,true 是分布式模式。若为 false,Hbase 和 Zookeeper 会 运行在同一个 JVM 里面。 默认: false hbase.tmp.dir 本地文件系统的临时文件夹。可以修改到一个更为持久的目录上。(/tmp 会在重启时清楚) 默认: /tmp/hbase-${user.name} hbase.master.info.port HBase Master web 界面端口. 设置为-1 意味着你不想让他运行。 默认: 60010 hbase.master.info.bindAddress HBase Master web 界面绑定的端口 默认: 0.0.0.0 hbase.client.write.buffer HTable 客户端的写缓冲的默认大小。这个值越大,需要消耗的内存越大。因为缓冲在客户 端和服务端都有实例,所以需要消耗客户端和服务端两个地方的内存。得到的好处是,可以 减少 RPC 的次数。可以这样估算服务器端被占用的内存: hbase.client.write.buffer * hbase.regionserver.handler.count 默认: 2097152 hbase.regionserver.port HBase RegionServer 绑定的端口 默认: 60020 hbase.regionserver.info.port HBase RegionServer web 界面绑定的端口 设置为 -1 意味这你不想与运行 RegionServer 界面. 默认: 60030 hbase.regionserver.info.port.auto Master 或 RegionServer 是否要动态搜一个可以用的端口来绑定界面。当 hbase.regionserver.info.port 已经被占用的时候,可以搜一个空闲的端口绑定。这个功能在测 试的时候很有用。默认关闭。 默认: false hbase.regionserver.info.bindAddress HBase RegionServer web 界面的 IP 地址 默认: 0.0.0.0 hbase.regionserver.class RegionServer 使用的接口。客户端打开代理来连接 region server 的时候会使用到。 默认: org.apache.hadoop.hbase.ipc.HRegionInterface hbase.client.pause 通常的客户端暂停时间。最多的用法是客户端在重试前的等待时间。比如失败的 get 操作和 region 查询操作等都很可能用到。 默认: 1000 hbase.client.retries.number 最大重试次数。例如 region 查询,Get 操作,Update 操作等等都可能发生错误,需要重试。 这是最大重试错误的值。 默认: 10 hbase.client.scanner.caching 当调用 Scanner 的 next 方法,而值又不在缓存里的时候,从服务端一次获取的行数。越大的 值意味着 Scanner 会快一些,但是会占用更多的内存。当缓冲被占满的时候,next 方法调用 会越来越慢。慢到一定程度,可能会导致超时。例如超过了 hbase.regionserver.lease.period。 默认: 1 hbase.client.keyvalue.maxsize 一个 KeyValue 实例的最大 size.这个是用来设置存储文件中的单个 entry 的大小上界。因为一 个 KeyValue 是不能分割的,所以可以避免因为数据过大导致 region 不可分割。明智的做法 是把它设为可以被最大 region size 整除的数。如果设置为 0 或者更小,就会禁用这个检查。 默认 10MB。 默认: 10485760 hbase.regionserver.lease.period 客户端租用 HRegion server 期限,即超时阀值。单位是毫秒。默认情况下,客户端必须在 这个时间内发一条信息,否则视为死掉。 默认: 60000 hbase.regionserver.handler.count RegionServers 受理的 RPC Server 实例数量。对于 Master 来说,这个属性是 Master 受理的 handler 数量 默认: 10 hbase.regionserver.msginterval RegionServer 发消息给 Master 时间间隔,单位是毫秒 默认: 3000 hbase.regionserver.optionallogflushinterval 将 Hlog 同步到 HDFS 的间隔。如果 Hlog 没有积累到一定的数量,到了时间,也会触发同 步。默认是 1 秒,单位毫秒。 默认: 1000 hbase.regionserver.regionSplitLimit region 的数量到了这个值后就不会在分裂了。这不是一个 region 数量的硬性限制。但是起到 了一定指导性的作用,到了这个值就该停止分裂了。默认是 MAX_INT.就是说不阻止分裂。 默认: 2147483647 hbase.regionserver.logroll.period 提交 commit log 的间隔,不管有没有写足够的值。 默认: 3600000 hbase.regionserver.hlog.reader.impl HLog file reader 的实现. 默认: org.apache.hadoop.hbase.regionserver.wal.SequenceFileLogReader hbase.regionserver.hlog.writer.impl HLog file writer 的实现. 默认: org.apache.hadoop.hbase.regionserver.wal.SequenceFileLogWriter hbase.regionserver.thread.splitcompactcheckfrequency region server 多久执行一次 split/compaction 检查. 默认: 20000 hbase.regionserver.nbreservationblocks 储备的内存 block 的数量(译者注:就像石油储备一样)。当发生 out of memory 异常的时候, 我们可以用这些内存在 RegionServer 停止之前做清理操作。 默认: 4 hbase.zookeeper.dns.interface 当使用 DNS 的时候,Zookeeper 用来上报的 IP 地址的网络接口名字。 默认: default hbase.zookeeper.dns.nameserver 当使用 DNS 的时候,Zookeepr 使用的 DNS 的域名或者 IP 地址,Zookeeper 用它来确定和 master 用来进行通讯的域名. 默认: default hbase.regionserver.dns.interface 当使用 DNS 的时候,RegionServer 用来上报的 IP 地址的网络接口名字。 默认: default hbase.regionserver.dns.nameserver 当使用 DNS 的时候,RegionServer 使用的 DNS 的域名或者 IP 地址,RegionServer 用它来 确定和 master 用来进行通讯的域名. 默认: default hbase.master.dns.interface 当使用 DNS 的时候,Master 用来上报的 IP 地址的网络接口名字。 默认: default hbase.master.dns.nameserver 当使用 DNS 的时候,RegionServer 使用的 DNS 的域名或者 IP 地址,Master 用它来确定用 来进行通讯的域名. 默认: default hbase.balancer.period Master 执行 region balancer 的间隔。 默认: 300000 hbase.regions.slop 当任一 regionserver 有 average + (average * slop)个 region 是会执行 Rebalance 默认: 0 hbase.master.logcleaner.ttl Hlog 存在于.oldlogdir 文件夹的最长时间, 超过了就会被 Master 的线程清理掉. 默认: 600000 hbase.master.logcleaner.plugins LogsCleaner 服务会执行的一组 LogCleanerDelegat。值用逗号间隔的文本表示。这些 WAL/HLog cleaners 会按顺序调用。可以把先调用的放在前面。你可以实现自己的 LogCleanerDelegat,加到 Classpath 下,然后在这里写下类的全称。一般都是加在默认值的 前面。 默认: org.apache.hadoop.hbase.master.TimeToLiveLogCleaner hbase.regionserver.global.memstore.upperLimit 单个 region server 的全部 memtores 的最大值。超过这个值,一个新的 update 操作会被挂起, 强制执行 flush 操作。 默认: 0.4 hbase.regionserver.global.memstore.lowerLimit 当强制执行 flush 操作的时候,当低于这个值的时候,flush 会停止。默认是堆大小的 35% . 如果这个值和 hbase.regionserver.global.memstore.upperLimit 相同就意味着当 update 操作因 为内存限制被挂起时,会尽量少的执行 flush(译者注:一旦执行 flush,值就会比下限要低, 不再执行) 默认: 0.35 hbase.server.thread.wakefrequency service 工作的 sleep 间隔,单位毫秒。 可以作为 service 线程的 sleep 间隔,比如 log roller. 默认: 10000 hbase.hregion.memstore.flush.size 当 memstore 的大小超过这个值的时候,会 flush 到磁盘。这个值被一个线程每隔 hbase.server.thread.wakefrequency 检查一下。 默认: 67108864 hbase.hregion.preclose.flush.size 当一个 region 中的 memstore 的大小大于这个值的时候,我们又触发了 close.会先运行 “pre-flush”操作,清理这个需要关闭的 memstore,然后将这个 region 下线。当一个 region 下线了,我们无法再进行任何写操作。如果一个 memstore 很大的时候,flush 操作会消耗很 多时间。"pre-flush"操作意味着在 region 下线之前,会先把 memstore 清空。这样在最终执行 close 操作的时候,flush 操作会很快。 默认: 5242880 hbase.hregion.memstore.block.multiplier 如果 memstore 有 hbase.hregion.memstore.block.multiplier 倍数的 hbase.hregion.flush.size 的大 小,就会阻塞 update 操作。这是为了预防在 update 高峰期会导致的失控。如果不设上界, flush 的时候会花很长的时间来合并或者分割,最坏的情况就是引发 out of memory 异常。(译 者注:内存操作的速度和磁盘不匹配,需要等一等。原文似乎有误) 默认: 2 hbase.hregion.memstore.mslab.enabled 体验特性:启用 memStore 分配本地缓冲区。这个特性是为了防止在大量写负载的时候堆的 碎片过多。这可以减少 GC 操作的频率。(GC 有可能会 Stop the world)(译者注:实现的原理 相当于预分配内存,而不是每一个值都要从堆里分配) 默认: false hbase.hregion.max.filesize 最大 HStoreFile 大小。若某个 Column families 的 HStoreFile 增长达到这个值,这个 Hegion 会被切割成两个。 Default: 256M. 默认: 268435456 hbase.hstore.compactionThreshold 当一个 HStore 含有多于这个值的 HStoreFiles(每一个 memstore flush 产生一个 HStoreFile)的 时候,会执行一个合并操作,把这 HStoreFiles 写成一个。这个值越大,需要合并的时间就 越长。 默认: 3 hbase.hstore.blockingStoreFiles 当一个 HStore 含有多于这个值的 HStoreFiles(每一个 memstore flush 产生一个 HStoreFile)的 时候,会执行一个合并操作,update 会阻塞直到合并完成,直到超过了 hbase.hstore.blockingWaitTime 的值 默认: 7 hbase.hstore.blockingWaitTime hbase.hstore.blockingStoreFiles 所限制的 StoreFile 数量会导致 update 阻塞,这个时间是来限 制阻塞时间的。当超过了这个时间,HRegion 会停止阻塞 update 操作,不过合并还有没有完 成。默认为 90s. 默认: 90000 hbase.hstore.compaction.max 每个“小”合并的 HStoreFiles 最大数量。 默认: 10 hbase.hregion.majorcompaction 一个 Region 中的所有 HStoreFile 的 major compactions 的时间间隔。默认是 1 天。 设置为 0 就是禁用这个功能。 默认: 86400000 hbase.mapreduce.hfileoutputformat.blocksize MapReduce 中 HFileOutputFormat 可以写 storefiles/hfiles. 这个值是 hfile 的 blocksize 的最小 值。通常在 Hbase 写 Hfile 的时候,bloocksize 是由 table schema(HColumnDescriptor)决定的, 但是在 mapreduce 写的时候,我们无法获取 schema 中 blocksize。这个值越小,你的索引就 越大,你随机访问需要获取的数据就越小。如果你的 cell 都很小,而且你需要更快的随机访 问,可以把这个值调低。 默认: 65536 hfile.block.cache.size 分配给 HFile/StoreFile 的 block cache 占最大堆(-Xmx setting)的比例。默认是 20%,设置为 0 就是不分配。 默认: 0.2 hbase.hash.type 哈希函数使用的哈希算法。可以选择两个值:: murmur (MurmurHash) 和 jenkins (JenkinsHash). 这个哈希是给 bloom filters 用的. 默认: murmur hbase.master.keytab.file HMaster server 验证登录使用的 kerberos keytab 文件路径。(译者注:Hbase 使用 Kerberos 实 现安全) 默认: hbase.master.kerberos.principal 例如. "hbase/_HOST@EXAMPLE.COM". HMaster 运行需要使用 kerberos principal name. principal name 可以在: user/hostname@DOMAIN 中获取. 如果 "_HOST" 被用做 hostname portion,需要使用实际运行的 hostname 来替代它。 默认: hbase.regionserver.keytab.file HRegionServer 验证登录使用的 kerberos keytab 文件路径。 默认: hbase.regionserver.kerberos.principal 例如. "hbase/_HOST@EXAMPLE.COM". HRegionServer 运行需要使用 kerberos principal name. principal name 可以在: user/hostname@DOMAIN 中获取. 如果 "_HOST" 被用做 hostname portion,需要使用实际运行的 hostname 来替代它。在这个文件中必须要有一个 entry 来描述 hbase.regionserver.keytab.file 默认: zookeeper.session.timeout ZooKeeper 会话超时.Hbase 把这个值传递改 zk 集群,向他推荐一个会话的最大超时时间。 详 见 http://hadoop.apache.org/zookeeper/docs/current/zookeeperProgrammers.html#ch_zkSessions "The client sends a requested timeout, the server responds with the timeout that it can give the client. "。 单位是毫秒 默认: 180000 zookeeper.znode.parent ZooKeeper 中的 Hbase 的根 ZNode。所有的 Hbase 的 ZooKeeper 会用这个目录配置相对路径。 默认情况下,所有的 Hbase 的 ZooKeeper 文件路径是用相对路径,所以他们会都去这个目录 下面。 默认: /hbase zookeeper.znode.rootserver ZNode 保存的 根 region 的路径. 这个值是由 Master 来写,client 和 regionserver 来读的。 如果设为一个相对地址,父目录就是 ${zookeeper.znode.parent}.默认情形下,意味着根 region 的路径存储在/hbase/root-region-server. 默认: root-region-server hbase.zookeeper.quorum Zookeeper 集群的地址列表,用逗号分割。例如: "host1.mydomain.com,host2.mydomain.com,host3.mydomain.com".默认是localhost,是给伪分布 式用的。要修改才能在完全分布式的情况下使用。如果在 hbase-env.sh 设置了 HBASE_MANAGES_ZK,这些 ZooKeeper 节点就会和 Hbase 一起启动。 默认: localhost hbase.zookeeper.peerport ZooKeeper 节点使用的端口。详细参见: http://hadoop.apache.org/zookeeper/docs/r3.1.1/zookeeperStarted.html#sc_RunningReplicatedZoo Keeper 默认: 2888 hbase.zookeeper.leaderport ZooKeeper 用来选择 Leader 的端口,详细参见: http://hadoop.apache.org/zookeeper/docs/r3.1.1/zookeeperStarted.html#sc_RunningReplicatedZoo Keeper 默认: 3888 hbase.zookeeper.property.initLimit ZooKeeper 的 zoo.conf 中的配置。 初始化 synchronization 阶段的 ticks 数量限制 默认: 10 hbase.zookeeper.property.syncLimit ZooKeeper 的 zoo.conf 中的配置。 发送一个请求到获得承认之间的 ticks 的数量限制 默认: 5 hbase.zookeeper.property.dataDir ZooKeeper 的 zoo.conf 中的配置。 快照的存储位置 默认: ${hbase.tmp.dir}/zookeeper hbase.zookeeper.property.clientPort ZooKeeper 的 zoo.conf 中的配置。 客户端连接的端口 默认: 2181 hbase.zookeeper.property.maxClientCnxns ZooKeeper 的 zoo.conf 中的配置。 ZooKeeper 集群中的单个节点接受的单个 Client(以 IP 区 分)的请求的并发数。这个值可以调高一点,防止在单机和伪分布式模式中出问题。 默认: 2000 hbase.rest.port HBase REST server 的端口 默认: 8080 hbase.rest.readonly 定义 REST server 的运行模式。可以设置成如下的值: false: 所有的 HTTP 请求都是被允许 的 - GET/PUT/POST/DELETE. true:只有 GET 请求是被允许的 默认: false 3.2. hbase-env.sh 在这个文件里面设置 HBase 环境变量。比如可以配置 JVM 启动的堆大小或者 GC 的参数。 你还可在这里配置 Hbase 的参数,如 Log 位置,niceness(译者注:优先级),ssh 参数还有 pid 文件的位置等等。打开文件 conf/hbase-env.sh 细读其中的内容。每个选项都是有详尽的注释 的。你可以在此添加自己的环境变量。 这个文件的改动系统 Hbase 重启才能生效。 3.3. log4j.properties 编辑这个文件可以改变 Hbase 的日志的级别,轮滚策略等等。 这个文件的改动系统 Hbase 重启才能生效。 日志级别的更改会影响到 HBase UI 3.4. 重要的配置 下面我们会列举重要 的配置. 这个章节讲述必须的配置和那些值得一看的配置。(译者注: 淘宝的博客也有本章节的内容,HBase 性能调优,很详尽)。 3.5. 必须的配置 参见 Section 1.3.1, “需要的软件”. 这里列举了运行 Hbase 至少两个必须的配置: i.e. Section 1.3.1.6, “ ulimit 和 nproc ” 和 Section 1.3.1.7, “dfs.datanode.max.xcievers”. 3.6. 推荐的配置 3.6.1. zookeeper.session.timeout 这个默认值是 3 分钟。这意味着一旦一个 server 宕掉了,Master 至少需要 3 分钟才能察觉到 宕机,开始恢复。你可能希望将这个超时调短,这样 Master 就能更快的察觉到了。在你调 这个值之前,你需要确认你的 JVM 的 GC 参数,否则一个长时间的 GC 操作就可能导致超 时。(当一个 RegionServer 在运行一个长时间的 GC 的时候,你可能想要重启并恢复它). 要想改变这个配置,可以编辑 hbase-site.xml, 将配置部署到全部集群,然后重启。 我们之所以把这个值调的很高,是因为我们不想一天到晚在论坛里回答新手的问题。“为什 么我在执行一个大规模数据导入的时候 Region Server 死掉啦”,通常这样的问题是因为长时 间的 GC 操作引起的,他们的 JVM 没有调优。我们是这样想的,如果一个人对 Hbase 不很 熟悉,不能期望他知道所有,打击他的自信心。等到他逐渐熟悉了,他就可以自己调这个参 数了。 3.6.2. hbase.regionserver.handler.count 这个设置决定了处理用户请求的线程数量。默认是 10,这个值设的比较小,主要是为了预 防用户用一个比较大的写缓冲,然后还有很多客户端并发,这样 region servers 会垮掉。有 经验的做法是,当请求内容很大(上 MB,如大 puts, 使用缓存的 scans)的时候,把这个值放 低。请求内容较小的时候(gets, 小 puts, ICVs, deletes),把这个值放大。 当客户端的请求内容很小的时候,把这个值设置的和最大客户端数量一样是很安全的。一个 典型的例子就是一个给网站服务的集群,put 操作一般不会缓冲,绝大多数的操作是 get 操作。 把这个值放大的危险之处在于,把所有的 Put 操作缓冲意味着对内存有很大的压力,甚至会 导致 OutOfMemory.一个运行在内存不足的机器的 RegionServer 会频繁的触发 GC 操作,渐 渐就能感受到停顿。(因为所有请求内容所占用的内存不管 GC 执行几遍也是不能回收的)。 一段时间后,集群也会受到影响,因为所有的指向这个 region 的请求都会变慢。这样就会 拖累集群,加剧了这个问题。 3.6.3. 大内存机器的配置 Hbase 有一个合理的保守的配置,这样可以运作在所有的机器上。如果你有台大内存的集群 -Hbase 有 8G 或者更大的 heap,接下来的配置可能会帮助你 TODO.(译者注:原文到此为止, 汗) 3.6.4. LZO 压缩 你可以考虑使用 Lzo 压缩,这个可以无缝集成,并且在大多数情况下可以提供性能。 Hbase 是 Apache 的协议,而 LZO 是 GPL 的协议。Hbase 不能自带 LZO,因此 LZO 需要在 安装 Hbase 之前安装。参见 使用 LZO 压缩介绍了如何在 Hbase 中使用 LZO 一个常见的问题是,用户在一开始使用 LZO 的时候会很好,但是数月过去,管理员在给集 群添加集群的时候,他们忘记了 LZO 的事情。在 0.90.0 版本之后,我们会运行失败,但也 有可能不。 请你要阅读这一段[11]. 还要在本书的尾部参见 Appendix B, HBase 中的压缩 . 3.6.5. 更大的 Regions 更大的 Region 可以使你集群上的 Region 的总数量较少。 一般来言,更少的 Region 可以使 你的集群运行更加流畅。(你可以自己随时手工将大 Region 切割,这样单个热点 Region 就 会被分布在集群的更多节点上)。默认情况下单个 Region 是 256MB.你可以设置为 1G。有些 人使用更大的,4G 甚至更多。可以调整 hbase-site.xml 中的 hbase.hregion.max.filesize 属性. 3.6.6. 管理 Splitting 除了让 Hbase 自动切割你的 Region,你也可以手动切割。 [12] 随着数据量的增大,splite 会 被持续执行。如果你需要知道你现在有几个 region,比如长时间的 debug 或者做调优,你需要 手动切割。通过跟踪日志来了解 region 级的问题是很难的,因为他在不停的切割和重命名。 data offlineing bug 和未知量的 region 会让你没有办法。如果一个 HLog 或者 StoreFile 由于 一个奇怪的 bug,Hbase 没有执行它。等到一天之后,你才发现这个问题,你可以确保现在 的 regions 和那个时候的一样,这样你就可以 restore 或者 replay 这些数据。你还可以调优你 的合并算法。如果数据是均匀的,随着数据增长,很容易导致 split / compaction 疯狂的运行。 因为所有的 region 都是差不多大的。用手的切割,你就可以交错执行定时的合并和切割操 作,降低 IO 负载。 为什么我关闭自动 split 呢?因为自动的 splite 是配置文件中的 hbase.hregion.max.filesize 决 定的. 你把它设置成 ILong.MAX_VALUE 是不推荐的做法,要是你忘记了手工切割怎么办. 推荐的做法是设置成 100GB,一旦到达这样的值,至少需要一个小时执行 major compactions。 那什么是最佳的在 pre-splite regions 的数量呢。这个决定于你的应用程序了。你可以先从低 的开始,比如每个 server10 个 pre-splite regions.然后花时间观察数据增长。有太少的 region 至少比出错好,你可以之后再 rolling split.一个更复杂的答案是这个值是取决于你的 region 中的最大的 storefile。随着数据的增大,这个也会跟着增大。 你可以当这个文件足够大的时 候,用一个定时的操作使用 Store 的合并选择算法(compact selection algorithm)来仅合并这一 个 HStore。如果你不这样做,这个算法会启动一个 major compactions,很多 region 会受到 影响,你的集群会疯狂的运行。需要注意的是,这样的疯狂合并操作是数据增长造成的,而 不是手动分割操作决定的。 如果你 pre-split 导致 regions 很小, 你可以通过配置 HConstants.MAJOR_COMPACTION_PERIOD 把你的 major compaction 参数调大 如果你的数据变得太大,可以使用 org.apache.hadoop.hbase.util.RegionSplitter 脚本来执行针 对全部集群的一个网络 IO 安全的 rolling split 操作。 3.7. 连接 Hbase 集群的客户端配置和依赖 因为 Hbase 的 Master 有可能转移,所有客户端需要访问 ZooKeeper 来获得现在的位置。 ZooKeeper 会保存这些值。因此客户端必须知道 Zookeeper 集群的地址,否则做不了任何事 情。通常这个地址存在 hbase-site.xml 里面,客户端可以从 CLASSPATH 取出这个文件. 如果你是使用一个 IDE 来运行 Hbase 客户端,你需要将 conf/放入你的 classpath,这样 hbase-site.xml 就可以找到了,(或者把 hbase-site.xml 放到 src/test/resources,这样测试的时 候可以使用). Hbase 客户端最小化的依赖是 hbase, hadoop, log4j, commons-logging, commons-lang, 和 ZooKeeper ,这些 jars 需要能在 CLASSPATH 中找到。 下面是一个基本的客户端 hbase-site.xml 例子: hbase.zookeeper.quorum example1,example2,example3 The directory shared by region servers. 3.7.1. Java 客户端配置 Java 是如何读到 hbase-site.xml 的内容的 Java 客户端使用的配置信息是被映射在一个 HBaseConfiguration 实例中. HBaseConfiguration 有一个工厂方法, HBaseConfiguration.create();,运行这个方法的时候,他 会去 CLASSPATH,下找 hbase-site.xml,读他发现的第一个配置文件的内容。 (这个方法还会 去找 hbase-default.xml ; hbase.X.X.X.jar 里面也会有一个 an hbase-default.xml). 不使用任何 hbase-site.xml 文件直接通过 Java 代码注入配置信息也是可以的。例如,你可以用编程的方 式设置 ZooKeeper 信息,只要这样做: Configuration config = HBaseConfiguration.create(); config.set("hbase.zookeeper.quorum", "localhost"); // Here we are running zookeeper locally 如果有多 ZooKeeper 实例,你可以使用逗号列表。(就像在 hbase-site.xml 文件中做得一样). 这个 Configuration 实例会被传递到 HTable, 之类的实例里面去. [10] Be careful editing XML. Make sure you close all elements. Run your file through xmllint or similar to ensure well-formedness of your document after an edit session. [11] 参见 Section B.2, “ hbase.regionserver.codecs ” 可以看到关于 LZO 安装的具体信息, 帮助你放在安装失败。 [12] What follows is taken from the javadoc at the head of the org.apache.hadoop.hbase.util.RegionSplitter tool added to HBase post-0.90.0 release. Chapter 4. The HBase Shell Table of Contents 4.1. 使用脚本 4.2. Shell 技巧 4.2.1. irbrc 4.2.2. LOG 时间转换 4.2.3. Debug Hbase Shell is 在(J)Ruby 的 IRB 的基础上加上了 HBase 的命令。任何你可以在 IRB 里做的 事情都可在在 Hbase Shell 中做。 你可以这样来运行 HBase Shell: $ ./bin/hbase shell 输入 help 就会返回 Shell 的命令列表和选项。可以看看在 Help 文档尾部的关于如何输入变 量和选项。尤其要注意的是表名,行,列名必须要加引号。 参见 Section 1.2.3, “Shell 练习”可以看到 Shell 的基本使用例子。 4.1. 使用脚本 如果要使用脚本,可以看 Hbase 的 bin 目录.在里面找到后缀为 *.rb 的脚本.要想运行这个脚 本,要这样 $ ./bin/hbase org.jruby.Main PATH_TO_SCRIPT 就可以了 4.2. Shell 技巧 4.2.1. irbrc 可以在你自己的 Home 目录下创建一个.irbrc 文件. 在这个文件里加入自定义的命令。有一 个有用的命令就是记录命令历史,这样你就可以把你的命令保存起来。 $ more .irbrc require 'irb/ext/save-history' IRB.conf[:SAVE_HISTORY] = 100 IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history" 可以参见 ruby 关于 .irbrc 的文档来学习更多的关于 IRB 的配置方法。 4.2.2. LOG 时间转换 可以将日期'08/08/16 20:56:29'从 hbase log 转换成一个 timestamp, 操作如下: hbase(main):021:0> import java.text.SimpleDateFormat hbase(main):022:0> import java.text.ParsePosition hbase(main):023:0> SimpleDateFormat.new("yy/MM/dd HH:mm:ss").parse("08/08/16 20:56:29", ParsePosition.new(0)).getTime() => 1218920189000 也可以逆过来操作。 hbase(main):021:0> import java.util.Date hbase(main):022:0> Date.new(1218920189000).toString() => "Sat Aug 16 20:56:29 UTC 2008" 要想把日期格式和 Hbase log 格式完全相同,可以参见文档 SimpleDateFormat. 4.2.3. Debug 4.2.3.1. Shell 切换成 debug 模式 你可以将 shell 切换成 debug 模式。这样可以看到更多的信息。 -- 例如可以看到命令异常的 stack trace: hbase> debug 4.2.3.2. DEBUG log level 想要在 shell 中看到 DEBUG 级别的 logging ,可以在启动的时候加上 -d 参数. $ ./bin/hbase shell -d Chapter 5. 构建 HBase Table of Contents 5.1. 将一个 HBase release 加入到 Apache's Maven Repository 5.1. 将一个 HBase release 加入到 Apache's Maven Repository 可以参考 发布 Maven Artifacts 的信息.要想让所有的组件正确运行,关键在于配置好 mvn release plugin。确保你在运行 mvn release:perform 之前使用的是正确的分支版本。这点非常 的重要,要手写${HBASE_HOME}下的 release.properties 文件,然后执行 release:perform.。 你需要编辑它,这样才能将他指向一个正确的 SVN 地址。(译者注:可以使用 cloudera) 如果你出现了如下的问题,是因为你需要在 pom.xml 里编辑版本然后加上 -SNAPSHOT 。 [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'release'. [INFO] ------------------------------------------------------------------------ [INFO] Building HBase [INFO] task-segment: [release:prepare] (aggregator-style) [INFO] ------------------------------------------------------------------------ [INFO] [release:prepare {execution: default-cli}] [INFO] ------------------------------------------------------------------------ [ERROR] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] You don't have a SNAPSHOT project in the reactor projects list. [INFO] ------------------------------------------------------------------------ [INFO] For more information, run Maven with the -e switch [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3 seconds [INFO] Finished at: Sat Mar 26 18:11:07 PDT 2011 [INFO] Final Memory: 35M/423M [INFO] ----------------------------------------------------------------------- Chapter 6. Developers Table of Contents 6.1. IDEs 6.1.1. Eclipse 6.2. 单元测试 6.2.1. Mocito 6.1. IDEs 6.1.1. Eclipse 参见 HBASE-3678 Add Eclipse-based Apache Formatter to HBase Wiki 可以看到一个 eclipse 的格式化文件,可以帮你把编码转换成符合 Hbase 的格式。 这个 issue 还包含有使用这个 formatter 的指导。 6.2. 单元测试 我们在 Hbase 中使用 JUnit 4. 如果你希望跑一个最小化的 HDFS, ZooKeeper, HBase, 或者 MapReduce 测试,可以 checkoutHBaseTestingUtility. Alex Baranau of Sematext 阐述了怎么使 用它 HBase Case-Study: Using HBaseTestingUtility for Local Testing and Development (2010). 6.2.1. Mocito 有些时候你不需要运行一个完全的 running server 单元测试。比如一些操作 org.apache.hadoop.hbase.Server 实例的方法或者使用 org.apache.hadoop.hbase.master.MasterServices 接口而不是 org.apache.hadoop.hbase.master.HMaster 类的应用. 这些情况下,你可以不必使用 mocked Server 实例. 比如: (译者注:原文到此为止) Chapter 7. HBase 和 MapReduce Table of Contents 7.1. 默认 HBase MapReduce 分割器(Splitter) 7.2. HBase Input MapReduce 例子 7.3. 在一个 MapReduce Job 中访问其他的 HBase Tables 7.4. 预测执行 关于 HBase 和 MapReduce 详见 javadocs. 下面是一些附加的帮助文档. 7.1. 默认 HBase MapReduce 分割器(Splitter) 当 MapReduce job 的 HBase table 使用 TableInputFormat 为数据源格式的时候,他的 splitter 会给这个 table 的每个 region 一个 map。因此,如果一个 table 有 100 个 region,就有 100 个 map-tasks,不论需要 scan 多少个 column families 。 7.2. HBase Input MapReduce 例子 要想使 HBase 作为 MapReduce 的 source,Job 需要使用 TableMapReduceUtil 来配置,如下所 示... Job job = ...; Scan scan = new Scan(); scan.setCaching(500); // 1 is the default in Scan, which will be bad for MapReduce jobs scan.setCacheBlocks(false); // Now set other scan attrs ... TableMapReduceUtil.initTableMapperJob( tableName, // input HBase table name scan, // Scan instance to control CF and attribute selection MyMapper.class, // mapper Text.class, // reducer key LongWritable.class, // reducer value job // job instance ); ...mapper 需要继承于 TableMapper... public class MyMapper extends TableMapper { public void map(ImmutableBytesWritable row, Result value, Context context) throws InterruptedException, IOException { // process data for the row from the Result instance. 7.3. 在一个 MapReduce Job 中访问其他的 HBase Tables 尽管现有的框架允许一个 HBase table 作为一个 MapReduce job 的输入,其他的 Hbase table 可以同时作为普通的表被访问。例如在一个 MapReduce 的 job 中,可以在 Mapper 的 setup 方法中创建 HTable 实例。 public class MyMapper extends TableMapper { private HTable myOtherTable; @Override public void setup(Context context) { myOtherTable = new HTable("myOtherTable"); } 7.4. 预测执行 通常建议关掉针对 HBase 的 MapReduce job 的预测执行(speculative execution)功能。这个功 能也可以用每个 Job 的配置来完成。对于整个集群,使用预测执行意味着双倍的运算量。这 可不是你所希望的。 Chapter 8. HBase 的 Schema 设计 Table of Contents 8.1. Schema 创建 8.2. column families 的数量 8.3. 单调递增 Row Keys/时序数据(log) 8.4. 尽量最小化 row 和 column 的大小 8.5. 版本的时间 有一个关于 NSQL 数据库的优点和确定的介绍, No Relation: The Mixed Blessings of Non-Relational Databases. 推荐看一看. 8.1. Schema 创建 可以使用 HBaseAdmin 或者 Chapter 4, The HBase Shell 来创建和编辑 Hbase 的 schemas 8.2. column families 的数量 现在 Hbase 并不能很好的处理两个或者三个以上的 column families,所以尽量让你的 column families 数量少一些。目前,flush 和 compaction 操作是针对一个 Region。所以当一个 column family 操作大量数据的时候会引发一个 flush。那些不相关的 column families 也有进行 flush 操作,尽管他们没有操作多少数据。Compaction 操作现在是根据一个 column family 下的全 部文件的数量触发的,而不是根据文件大小触发的。当很多的 column families 在 flush 和 compaction 时,会造成很多没用的 I/O 负载(要想解决这个问题,需要将 flush 和 compaction 操作只针对一个 column family) 尽量在你的应用中使用一个 Column family。只有你的所有查询操作只访问一个 column family 的时候,可以引入第二个和第三个 column family.例如,你有两个 column family,但你 查询的时候总是访问其中的一个,从来不会两个一起访问。 8.3. 单调递增 Row Keys/时序数据(log) 在 Tom White 的 Hadoop: The Definitive Guide 一书中,有一个章节描述了一个值得注意的问 题:在一个集群中,一个导入数据的进程一动不动,所以的 client 都在等待一个 region(就是 一个节点),过了一会后,变成了下一个 region...如果使用了单调递增或者时序的 key 就会造 成这样的问题。详情可以参见 IKai 画的漫画 monotonically increasing values are bad。使用了 顺序的 key 会将本没有顺序的数据变得有顺序,把负载压在一台机器上。所以要尽量避免时 间戳或者(e.g. 1, 2, 3)这样的 key。 如果你需要导入时间顺序的文件(如 log)到 Hbase 中,可以学习 OpenTSDB 的做法。他有一 个页面来描述他的 schema.OpenTSDB 的 Key 的格式是[metric_type][event_timestamp],乍一 看,似乎违背了不将 timestamp 做 key 的建议,但是他并没有将 timestamp 作为 key 的一个 关键位置,有成百上千的 metric_type 就足够将压力分散到各个 region 了。 8.4. 尽量最小化 row 和 column 的大小 在 Hbase 中,值是作为一个 cell 保存在系统的中的,要定位一个 cell,需要 row,column name 和 timestamp.通常情况下,如果你的 row 和 column 的名字要是太大(甚至比 value 的大小还 要大) 的话,你可能会遇到一些有趣的情况。例如 Marc Limotte 在 HBASE-3551(recommended!)尾部提到的现象。在 Hbase 的存储文件 Section 12.3.4.2, “StoreFile (HFile)”中,有一个索引用来方便 value 的随机访问,但是访问一个 cell 的坐标 要是太大的话,会占用很大的内存,这个索引会被用尽。所以要想解决,可以设置一个更大 的 block size,当然也可以使用更小的 column name ` 8.5. 版本的时间 行的版本的数量是 HColumnDescriptor 设置的,每个 column family 可以单独设置,默认是 3.这个设置是很重要的,在 Chapter 11, 数据模型有描述,因为 Hbase 是不会去覆盖一个值 的,他只会在后面在追加写,用 timestamp 来区分、过早的版本会在执行 major compaction 的时候删除。这个版本的值可以根据具体的应用增加减少。 Chapter 9. Metrics Table of Contents 9.1. Metric 安装 9.2. RegionServer Metrics 9.2.1. hbase.regionserver.blockCacheCount 9.2.2. hbase.regionserver.blockCacheFree 9.2.3. hbase.regionserver.blockCacheHitRatio 9.2.4. hbase.regionserver.blockCacheSize 9.2.5. hbase.regionserver.compactionQueueSize 9.2.6. hbase.regionserver.fsReadLatency_avg_time 9.2.7. hbase.regionserver.fsReadLatency_num_ops 9.2.8. hbase.regionserver.fsSyncLatency_avg_time 9.2.9. hbase.regionserver.fsSyncLatency_num_ops 9.2.10. hbase.regionserver.fsWriteLatency_avg_time 9.2.11. hbase.regionserver.fsWriteLatency_num_ops 9.2.12. hbase.regionserver.memstoreSizeMB 9.2.13. hbase.regionserver.regions 9.2.14. hbase.regionserver.requests 9.2.15. hbase.regionserver.storeFileIndexSizeMB 9.2.16. hbase.regionserver.stores 9.2.17. hbase.regionserver.storeFiles 9.1. Metric 安装 参见 Metrics 可以获得一个 enable Metrics emission 的指导。 9.2. RegionServer Metrics 9.2.1. hbase.regionserver.blockCacheCount 内存中的 Block cache item 数量。这个是存储文件(HFiles)的缓存中的数量。 9.2.2. hbase.regionserver.blockCacheFree 内存中的 Block cache memory 剩余 (单位 bytes). 9.2.3. hbase.regionserver.blockCacheHitRatio Block cache 命中率(0 到 100). TODO: 描述当 cacheBlocks=false 时对这个值得影响 9.2.4. hbase.regionserver.blockCacheSize 内存中的 Block cache 大小 (单位 bytes) 9.2.5. hbase.regionserver.compactionQueueSize compaction 队列的大小. 这个值是需要进行 compaction 的 region 数目 9.2.6. hbase.regionserver.fsReadLatency_avg_time 文件系统延迟 (ms). 这个值是平均读 HDFS 的延迟时间 9.2.7. hbase.regionserver.fsReadLatency_num_ops TODO 9.2.8. hbase.regionserver.fsSyncLatency_avg_time 文件系统同步延迟(ms) 9.2.9. hbase.regionserver.fsSyncLatency_num_ops TODO 9.2.10. hbase.regionserver.fsWriteLatency_avg_time 文件系统写延迟(ms) 9.2.11. hbase.regionserver.fsWriteLatency_num_ops TODO 9.2.12. hbase.regionserver.memstoreSizeMB 所有的 RegionServer 的 memstore 大小 (MB) 9.2.13. hbase.regionserver.regions RegionServer 服务的 regions 数量 9.2.14. hbase.regionserver.requests 读写请求的全部数量。请求是指 RegionServer 的 RPC 数量,因此一次 Get 一个情况,一个 带缓存的 Scan 也是一个请求。一个批量 load 是一个 Hfile 一个请求。 9.2.15. hbase.regionserver.storeFileIndexSizeMB 当前 RegionServer 的 storefile 索引的总大小(MB) 9.2.16. hbase.regionserver.stores RegionServer 打开的 stores 数量。一个 stores 对应一个 column family。例如,一个表有 3 个 region 在这个 RegionServer 上,对应一个 column family 就会有 3 个 store. 9.2.17. hbase.regionserver.storeFiles RegionServer 打开的存储文件(HFile)数量。这个值一定大于等于 store 的数量。 Chapter 10. 跨集群复制 参见 跨集群复制. Chapter 11. 数据模型 Table of Contents 11.1. 概念视图 11.2. 物理视图 11.3. 表 11.4. 行 11.5. Column Family 11.6. Cells 11.7. 版本 11.7.1. Hbase 的操作(包含版本操作) 11.7.2. 现有的限制 简单来说,应用程序是以表的方式在 Hbase 存储数据的。表是由行和列构成的,所以的列是 从属于某一个 column family 的。行和列的交叉点称之为 cell,cell 是版本化的。cell 的内容是 不可分割的字节数组。 表的 row key 也是一段字节数组,所以任何东西都可以保存进去,不论是字符串或者数字。 Hbase 的表是按 key 排序的,排序方式之针对字节的。所以的表都必须要有主键-key. 11.1. 概念视图 下面 是根据 BigTable 论文稍加修改的例子。 有一个名为 webtable 的表,包含两个 column family : contents 和 anchor. 在这个例子里面,anchor 有两个列 (anchor:cssnsi.com, anchor:my.look.ca),contents 仅有一列(contents:html) 列名 一个列名是有它的 column family 前缀和 qualifier 连接而成。例如列 contents:html 是 column family contents 加冒号(:)加 qualifier html 组成的。 Table 11.1. 表 webtable Row Key Time Stamp ColumnFamily contents ColumnFamily anchor "com.cnn.www" t9 anchor:cnnsi.com = "CNN" "com.cnn.www" t8 anchor:my.look.ca = "CNN.com" "com.cnn.www" t6 contents:html = "..." "com.cnn.www" t5 contents:html = "..." "com.cnn.www" t3 contents:html = "..." 11.2. 物理视图 尽管在概念视图里,表可以被看成是一个稀疏的行的集合。但在物理上,它的是区分 column family 存储的。新的 columns 可以不经过声明直接加入一个 column family. Table 11.2. ColumnFamily anchor Row Key Time Stamp Column Family anchor "com.cnn.www" t9 anchor:cnnsi.com = "CNN" "com.cnn.www" t8 anchor:my.look.ca = "CNN.com" Table 11.3. ColumnFamily contents Row Key Time Stamp ColumnFamily "contents:" "com.cnn.www" t6 contents:html = "..." "com.cnn.www" t5 contents:html = "..." "com.cnn.www" t3 contents:html = "..." 值得注意的是在上面的概念视图中空白 cell 在物理上是不存储的,因为根本没有必要存储。 因此若一个请求为要获取 t8 时间的 contents:html,他的结果就是空。相似的,若请求为获取 t9 时间的 anchor:my.look.ca,结果也是空。但是,如果不指明时间,将会返回最新时间的行, 每个最新的都会返回。例如,如果请求为获取 row key 为"com.cnn.www",没有指明时间戳 的话,活动的结果是 t6 下的 contents:html,t9 下的 anchor:cnnsi.com 和 t8 下 anchor:my.look.ca。 11.3. 表 表是在 schema 声明的时候定义的。 11.4. 行 row key 是不可分割的字节数组。行是按字典排序由低到高存储在表中的。一个空的数组是 用来标识表空间的起始或者结尾。 11.5. Column Family 在 Hbase 是 column family 一些列的集合。一个 column family 所有列成员是有着相同的前缀。 比如,列 courses:history 和 courses:math 都是 column family courses 的成员.冒号(:)是 column family 的分隔符,用来区分前缀和列名。column 前缀必须是可打印的字符,剩下的部分(称 为 qualify),可以又任意字节数组组成。column family 必须在表建立的时候声明。column 就不 需要了,随时可以新建。 在物理上,一个的 column family 成员在文件系统上都是存储在一起。因为存储优化都是针 对 column family 级别的,这就意味着,一个 colimn family 的所有成员的是用相同的方式访 问的。 11.6. Cells A {row, column, version} 元组就是一个 Hbase 中的一个 cell。Cell 的内容是不可分割的字节 数组。 11.7. 版本 一个 {row, column, version} 元组是 Hbase 中的一个 cell .但是有可能会有很多的 cell 的 row 和 column 是相同的,可以使用 version 来区分不同的 cell. rows 和 column key 是用字节数组表示的,version 则是用一个长整型表示。这个 long 的值使 用 java.util.Date.getTime() 或者 System.currentTimeMillis()产生的。这就意味着他的含义是 “当前时间和 1970-01-01 UTC 的时间差,单位毫秒。” 在 Hbase 中,版本是按倒序排列的,因此当读取这个文件的时候,最先找到的是最近的版本。 有些人不是很理解 Hbase 的 cell 意思。一个常见的问题是: 如果有多个包含版本写操作同时发起,Hbase 会保存全部还是会保持最新的一个?[13] 可以发起包含版本的写操作,但是他们的版本顺序和操作顺序相反吗?[14] 下面我们介绍下在 Hbase 中版本是如何工作的。[15]. 11.7.1. Hbase 的操作(包含版本操作) 在这一章我们来仔细看看在 Hbase 的各个主要操作中版本起到了什么作用。 11.7.1.1. Get/Scan Gets 实在 Scan 的基础上实现的。可以详细参见下面的讨论 Get 同样可以用 Scan 来描述. 默认情况下,如果你没有指定版本,当你使用 Get 操作的时候,会返回最近版本的 Cell(该 Cell 可能是最新写入的,但不能保证)。默认的操作可以这样修改: 如果想要返回返回两个以上的把版本,参见 Get.setMaxVersions() 如果想要返回的版本不只是最近的,参见 Get.setTimeRange() 要向查询的最新版本要小于或等于给定的这个值,这就意味着给定的'最近'的值可以是某一 个时间点。可以使用 0 到你想要的时间来设置,还要把 max versions 设置为 1. 11.7.1.2. 默认 Get 例子 下面的 Get 操作会只获得最新的一个版本。 Get get = new Get(Bytes.toBytes("row1")); Result r = htable.get(get); byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns current version of value 11.7.1.3. 含有的版本的 Get 例子 下面的 Get 操作会获得最近的 3 个版本。 Get get = new Get(Bytes.toBytes("row1")); get.setMaxVersions(3); // will return last 3 versions of row Result r = htable.get(get); byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns current version of value List kv = r.getColumn(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns all versions of this column 11.7.1.4. Put 一个 Put 操作会给一个 cell,创建一个版本,默认使用当前时间戳,当然你也可以自己设置时 间戳。这就意味着你可以把时间设置在过去或者未来,或者随意使用一个 Long 值。 要想覆盖一个现有的值,就意味着你的 row,column 和版本必须完全相等。 11.7.1.4.1. 不指明版本的例子 下面的 Put 操作不指明版本,所以 Hbase 会用当前时间作为版本。 Put put = new Put(Bytes.toBytes(row)); put.add(Bytes.toBytes("cf"), Bytes.toBytes("attr1"), Bytes.toBytes( data)); htable.put(put); 11.7.1.4.2. 指明版本的例子 下面的 Put 操作,指明了版本。 Put put = new Put( Bytes.toBytes(row )); long explicitTimeInMs = 555; // just an example put.add(Bytes.toBytes("cf"), Bytes.toBytes("attr1"), explicitTimeInMs, Bytes.toBytes(data)); htable.put(put); 11.7.1.5. Delete 当你进行 delete 操作的是,有两种方式来确定要删除的版本。 删除所有比当前早的版本。 删除指定的版本。 一个删除操作可以删除一行,也可以是一个 column family,或者仅仅删除一个 column。你 也可以删除指明的一个版本。若你没有指明,默认情况下是删除比当前时间早的版本。 删除操作的实现是创建一个删除标记。例如,我们想要删除一个版本,或者默认是 currentTimeMillis。就意味着“删除比这个版本更早的所有版本”.Hbase 不会去改那些数据, 数据不会立即从文件中删除。他使用删除标记来屏蔽掉这些值。[16]若你知道的版本比数据 中的版本晚,就意味着这一行中的所有数据都会被删除。 11.7.2. 现有的限制 关于版本还有一些 bug(或者称之为未实现的功能),计划在下个版本实现。 11.7.2.1. 删除标记误删 Puts 删除标记操作可能会标记之后 put 的数据。[17].需要值得注意的是,当写下一个删除标记后, 只有下一个 major compaction 操作发起之后,这个删除标记才会消失。设想一下,当你写下 一个删除标记-“删除所有<= 时间 T 的数据”。但之后,你又执行了一个 Put 操作,版本<= T。 这样就算这个 Put 发生在删除之后,他的数据也算是打上了删除标记。这个 Put 并不会失败, 但是你需要注意的是这个操作没有任何作用。只有一个 major compaction 执行只有,一切才 会恢复正常。如果你的 Put 操作一直使用升序的版本,这个错误就不会发生。但是也有可能 出现这样的情况,你删除之后, 11.7.2.2. Major compactions 改变查询的结果 “设想一下,你一个 cell 有三个版本 t1,t2 和 t3。你 的 maximun-version 设置是 2.当你请求获 取全部版本的时候,只会返回两个,t2 和 t3。如果你将 t2 和 t3 删除,就会返回 t1。但是如 果在删除之前,发生了 major compaction 操作,那么什么值都不好返回了。[18]” [13] 目前,只有最新的那个是可以获取到的。. [14] 可以 [15] See HBASE-2406 for discussion of HBase versions. Bending time in HBase makes for a good read on the version, or time, dimension in HBase. It has more detail on versioning than is provided here. As of this writing, the limiitation Overwriting values at existing timestamps mentioned in the article no longer holds in HBase. This section is basically a synopsis of this article by Bruno Dumon. [16] 当 Hbase 执行一次 major compaction,标记删除的数据会被实际的删除,删除标记也会被 删除。 [17] HBASE-2256 [18] See Garbage Collection in Bending time in HBase Chapter 12. 架构 Table of Contents 12.1. 客户端 12.1.1. 连接 12.1.2. 写缓冲和批量操作 12.1.3. Filters 12.2. Daemons 12.2.1. Master 12.2.2. RegionServer 12.3. Regions 12.3.1. Region 大小 12.3.2. Region Splits 12.3.3. Region 负载均衡 12.3.4. Store 12.4. Write Ahead Log (WAL) 12.4.1. 目的 12.4.2. WAL Flushing 12.4.3. WAL Splitting 12.1. 客户端 Hbase 客户端的 HTable 类负责寻找相应的 RegionServers 来处理行。他是先查询 .META. 和 -ROOT 目录表。然后再确定 region 的位置。定位到所需要的区域后,客户端会直接 去访 问相应的 region(不经过 master),发起读写请求。这些信息会缓存在客户端,这样就不用每 发起一个请求就去查一下。如果一个 region 已经废弃(原因可能是 master load balance 或者 RegionServer 死了),客户端就会重新进行这个步骤,决定要去访问的新的地址。 管理集群操作是经由 HBaseAdmin 发起的 12.1.1. 连接 关于连接的配置信息,参见 Section 3.7, “连接 Hbase 集群的客户端配置和依赖”. HTable 不是线程安全的。建议使用同一个 HBaseConfiguration 实例来创建 HTable 实例。这 样可以共享 ZooKeeper 和 socket 实例。例如,最好这样做: HBaseConfiguration conf = HBaseConfiguration.create(); HTable table1 = new HTable(conf, "myTable"); HTable table2 = new HTable(conf, "myTable"); 而不是这样: HBaseConfiguration conf1 = HBaseConfiguration.create(); HTable table1 = new HTable(conf1, "myTable"); HBaseConfiguration conf2 = HBaseConfiguration.create(); HTable table2 = new HTable(conf2, "myTable"); 如果你想知道的更多的关于 Hbase 客户端 connection 的知识,可以参照: HConnectionManager. 12.1.2. 写缓冲和批量操作 若关闭了 HTable 中的 Section 13.6.1, “AutoFlush”,Put 操作会在写缓冲填满的时候向 RegionServer 发起请求。默认情况下,写缓冲是 2MB.在 Htable 被废弃之前,要调用 close(), flushCommits()操作,这样写缓冲就不会丢失。 要想更好的细粒度控制 Put 或 Delete 的批量操作,可以参考 Htable 中的 batch 方法. 12.1.3. Filters Get 和 Scan 实例可以使用 filters,这个过滤操作是运行在 RegionServer 上的。 12.2. Daemons 12.2.1. Master 12.2.2. RegionServer 12.3. Regions 本章节都是再讲 Regions. Note Regions 是由每个 Column Family 的 Store 组成。 12.3.1. Region 大小 Region 的大小是一个棘手的问题,需要考量如下几个因素。 Regions 是可用性和分布式的最基本单位 HBase 通过将 region 切分在许多机器上实现分布式。也就是说,你如果有 16GB 的数据,只 分了 2 个 region, 你却有 20 台机器,有 18 台就浪费了。 region 数目太多就会造成性能下降,现在比以前好多了。但是对于同样大小的数据,700 个 region 比 3000 个要好。 region 数目太少就会妨碍可扩展性,降低并行能力。有的时候导致压力不够分散。这就是为 什么,你向一个 10 节点的 Hbase 集群导入 200MB 的数据,大部分的节点是 idle 的。 RegionServer 中 1 个 region 和 10 个 region 索引需要的内存量没有太多的差别。 最好是使用默认的配置,可以把热的表配小一点(或者受到 split 热点的 region 把压力分散到 集群中)。如果你的 cell 的大小比较大(100KB 或更大),就可以把 region 的大小调到 1GB。 12.3.2. Region Splits RegionServer 的 Splits 操作是不可见的,因为 Master 不会参与其中。RegionServer 切割 region 的步骤是,先将该 region 下线,然后切割,将其子 region 加入到元信息中,再将他们加入 到原本的 RegionServer 中,最后汇报 Master.参见 Section 3.6.6, “管理 Splitting”来手动管 理切割操作。 12.3.3. Region 负载均衡 当没有任何 region 在进行转换的时候,Hbase 会定期执行一个 load balance。他会将移动 region 进行集群的负载均衡。可以配置运行时间间隔。 12.3.4. Store 一个 Store 包含了一个 MemStore 和若干个 StoreFile(HFile).一个 Store 可以定位到一个 column family 中的一个 region. 12.3.4.1. MemStore MemStores 是 Store 中的内存 Store,可以进行修改操作。修改的内容是 KeyValues。当 flush 的是,现有的 memstore 会生成快照,然后清空。在执行快照的时候,Hbase 会继续接收修 改操作,保存在 memstore 外面,直到快照完成。 12.3.4.2. StoreFile (HFile) 12.3.4.2.1. HFile Format hfile 文件格式是基于 BigTable [2006]论文中的 SSTable。构建在 Hadoop 的 tfile 上面(直接使 用了 tfile 的单元测试和压缩工具)。 Schubert Zhang's 的博客 HFile: A Block-Indexed File Format to Store Sorted Key-Value Pairs 详细介绍了 Hbases 的 hfile。Matteo Bertozzi 也做了详 细的介绍 HBase I/O: HFile。 12.3.4.2.2. HFile 工具 要想看到 hfile 内容的文本化版本,你可以使用 org.apache.hadoop.hbase.io.hfile.HFile 工具。 可以这样用: $ ${HBASE_HOME}/bin/hbase org.apache.hadoop.hbase.io.hfile.HFile 例如,你想看文件 hdfs://10.81.47.41:9000/hbase/TEST/1418428042/DSMP/4759508618286845475 的内容, 就执 行如下的命令: $ ${HBASE_HOME}/bin/hbase org.apache.hadoop.hbase.io.hfile.HFile -v -f hdfs://10.81.47.41:9000/hbase/TEST/1418428042/DSMP/4759508618286845475 如果你没有输入-v,就仅仅能看到一个 hfile 的汇总信息。其他功能的用法可以看 HFile 的文 档。 12.3.4.3. 压缩 有两种类型的压缩:minor 和 major。minor 压缩通常会将数个小的相邻的文件合并成一个大 的。Minor 不会删除打上删除标记的数据,也不会删除过期的数据,Major 压缩会删除过期 的数据。有些时候 minor 压缩就会将一个 store 中的全部文件压缩,实际上这个时候他本身 就是一个 major 压缩。对于一个 minor 压缩是如何压缩的,可以参见 ascii diagram in the Store source code. 在执行一个 major 压缩之后,一个 store 只会有一个 sotrefile,通常情况下这样可以提供性能。 注意:major 压缩将会将 store 中的数据全部重写,在一个负载很大的系统中,这个操作是很 伤的。所以在大型系统中,通常会自己 Section 3.6.6, “管理 Splitting”。 12.4. Write Ahead Log (WAL) 12.4.1. 目的 每个 RegionServer 会将更新(Puts, Deletes) 先记录到 Write Ahead Log 中(WAL),然后将其更 新在 Section 12.3.4, “Store”的 Section 12.3.4.1, “MemStore”里面。这样就保证了 Hbase 的写的可靠性。如果没有 WAL,当 RegionServer 宕掉的时候,MemStore 还没有 flush,StoreFile 还没有保存,数据就会丢失。HLog 是 Hbase 的一个 WAL 实现,一个 RegionServer 有一个 HLog 实例。 WAL 保存在 HDFS 的 /hbase/.logs/ 里面,每个 region 一个文件。 要想知道更多的信息,可以访问维基百科 Write-Ahead Log 的文章. 12.4.2. WAL Flushing TODO (describe). 12.4.3. WAL Splitting 12.4.3.1. 当 RegionServer 宕掉的时候,如何恢复 TODO 12.4.3.2. hbase.hlog.split.skip.errors 默认设置为 true,在 split 执行中发生的任何错误会被记录,有问题的 WAL 会被移动到 Hbase rootdir 目录下的.corrupt 目录,接着进行处理。如果设置为 false,异常会被抛出,split 会记 录错误。[19] 12.4.3.3. 如果处理一个发生在当 RegionServers' WALs 分割时候的 EOFExceptions 异常 如果我们在分割日志的时候发生 EOF,就是 hbase.hlog.split.skip.errors 设置为 false,我们也会 进行处理。一个 EOF 会发生在一行一行读取 Log,但是 Log 中最后一行似乎只写了一半就 停止了。如果在处理过程中发生了 EOF,我们还会继续处理,除非这个文件是要处理的最 后一个文件。[20] [19] See HBASE-2958 When hbase.hlog.split.skip.errors is set to false, we fail the split but thats it. We need to do more than just fail split if this flag is set. [20] 要想知道背景知识, 参见 HBASE-2643 Figure how to deal with eof splitting logs Chapter 13. 性能调优 Table of Contents 13.1. Java 13.1.1. 垃圾收集和 HBase 13.2. 配置 13.2.1. Regions 的数目 13.2.2. 管理压缩 13.2.3. 压缩 13.2.4. hbase.regionserver.handler.count 13.2.5. hfile.block.cache.size 13.2.6. hbase.regionserver.global.memstore.upperLimit 13.2.7. hbase.regionserver.global.memstore.lowerLimit 13.2.8. hbase.hstore.blockingStoreFiles 13.2.9. hbase.hregion.memstore.block.multiplier 13.3. Column Families 的数目 13.4. 数据聚集 13.5. 批量 Loading 13.5.1. Table 创建: 预创建 Regions 13.6. HBase 客户端 13.6.1. AutoFlush 13.6.2. Scan Caching 13.6.3. Scan 属性选择 13.6.4. 关闭 ResultScanners 13.6.5. 块缓存 13.6.6. Row Keys 的负载优化 可以从 wiki Performance Tuning 看起。这个文档讲了一些主要的影响性能的方面:RAM, 压 缩, JVM 设置, 等等。然后,可以看看下面的补充内容。 打开 RPC-level 日志 在 RegionServer 打开 RPC-level 的日志对于深度的优化是有好处的。一旦打开,日志将喷涌 而出。所以不建议长时间打开,只能看一小段时间。要想启用 RPC-level 的职责,可以使用 RegionServer UI 点击 Log Level。将 org.apache.hadoop.ipc 的日志级别设为 DEBUG。然后 tail RegionServer 的日志,进行分析。 要想关闭,只要把日志级别设为 INFO 就可以了. 13.1. Java 13.1.1. 垃圾收集和 HBase 13.1.1.1. 长时间 GC 停顿 在这个 PPT Avoiding Full GCs with MemStore-Local Allocation Buffers, Todd Lipcon 描述列在 Hbase 中常见的两种 stop-the-world 的 GC 操作,尤其是在 loading 的时候。一种是 CMS 失 败的模式(译者注:CMS 是一种 GC 的算法),另一种是老一代的堆碎片导致的。要想定位第 一种,只要将 CMS 执行的时间提前就可以了,加入-XX:CMSInitiatingOccupancyFraction 参 数,把值调低。可以先从 60%和 70%开始(这个值调的越低,触发的 GC 次数就越多,消耗 的 CPU 时间就越长)。要想定位第二种错误,Todd 加入了一个实验性的功能,在 Hbase 0.90.x 中这个是要明确指定的(在 0.92.x 中,这个是默认项),将你的 Configuration 中的 hbase.hregion.memstore.mslab.enabled 设置为 true。详细信息,可以看这个 PPT. 13.2. 配置 参见 Section 3.6, “推荐的配置”. 13.2.1. Regions 的数目 Hbase 中 region 的数目可以根据 Section 3.6.5, “更大的 Regions”调整.也可以参见 Section 12.3.1, “Region 大小” 13.2.2. 管理压缩 对于大型的系统,你需要考虑管理压缩和分割 13.2.3. 压缩 生产环境中的系统需要在 column family 的定义中使用 Section 3.6.4, “LZO 压缩”之类的 压缩。 13.2.4. hbase.regionserver.handler.count 参见 hbase.regionserver.handler.count.这个参数的本质是设置一个 RegsionServer 可以同时处 理多少请求。 如果定的太高,吞吐量反而会降低;如果定的太低,请求会被阻塞,得不到响 应。你可以打开 RPC-level 日志读 Log,来决定对于你的集群什么值是合适的。(请求队列也 是会消耗内存的) 13.2.5. hfile.block.cache.size 参见 hfile.block.cache.size. 对于 RegionServer 进程的内存设置。 13.2.6. hbase.regionserver.global.memstore.upperLimit 参见 hbase.regionserver.global.memstore.upperLimit. 这个内存设置是根据 RegionServer 的需 要来设定。 13.2.7. hbase.regionserver.global.memstore.lowerLimit 参见 hbase.regionserver.global.memstore.lowerLimit. 这个内存设置是根据 RegionServer 的需 要来设定。 13.2.8. hbase.hstore.blockingStoreFiles 参见 hbase.hstore.blockingStoreFiles. 如果在 RegionServer 的 Log 中 block,提高这个值是有帮 助的。 13.2.9. hbase.hregion.memstore.block.multiplier 参见 hbase.hregion.memstore.block.multiplier. 如果有足够的 RAM,提高这个值。 13.3. Column Families 的数目 参见 Section 8.2, “ column families 的数量 ”. 13.4. 数据聚集 如果你的数据总是往一个 region 写。你可以再看看处理时序数据 这一章. 13.5. 批量 Loading 如果可以的话,尽量使用批量导入工具,参见 Bulk Loads.否则就要详细看看下面的内容。 13.5.1. Table 创建: 预创建 Regions 默认情况下 Hbase 创建 Table 会新建一个 region。执行批量导入,意味着所有的 client 会写 入这个 region,直到这个 region 足够大,以至于分裂。一个有效的提高批量导入的性能的方 式,是预创建空的 region。最好稍保守一点,因为过多的 region 会实实在在的降低性能。下 面是一个预创建 region 的例子。 (注意:这个例子里需要根据应用的 key 进行调整。): public static boolean createTable(HBaseAdmin admin, HTableDescriptor table, byte[][] splits) throws IOException { try { admin.createTable( table, splits ); return true; } catch (TableExistsException e) { logger.info("table " + table.getNameAsString() + " already exists"); // the table already exists... return false; } } public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) { byte[][] splits = new byte[numRegions-1][]; BigInteger lowestKey = new BigInteger(startKey, 16); BigInteger highestKey = new BigInteger(endKey, 16); BigInteger range = highestKey.subtract(lowestKey); BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions)); lowestKey = lowestKey.add(regionIncrement); for(int i=0; i < numRegions-1;i++) { BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i))); byte[] b = String.format("%016x", key).getBytes(); splits[i] = b; } return splits; } 13.6. HBase 客户端 13.6.1. AutoFlush 当你进行大量的 Put 的时候,要确认你的 HTable 的 setAutoFlush 是关闭着的。否则的话, 每执行一个 Put 就要想 RegionServer 发一个请求。通过 htable.add(Put) 和 htable.add( Put)来将 Put 添加到写缓冲中。如果 autoFlush = false,要等到写缓冲都填满的时候才会发起 请求。要想显式的发起请求,可以调用 flushCommits。在 HTable 实例上进行的 close 操作也 会发起 flushCommits 13.6.2. Scan Caching 如果 Hbase 的输入源是一个 MapReduce Job,要确保输入的 Scan 的 setCaching 值要比默认 值 0 要大。使用默认值就意味着 map-task 每一行都会去请求一下 region-server。可以把这个 值设为 500,这样就可以一次传输 500 行。当然这也是需要权衡的,过大的值会同时消耗客 户端和服务端很大的内存,不是越大越好。 13.6.3. Scan 属性选择 当 Scan 用来处理大量的行的时候(尤其是作为 MapReduce 的输入),要注意的是选择了什么 字段。如果调用了 scan.addFamily,这个 column family 的所有属性都会返回。如果只是想 过滤其中的一小部分,就指定那几个 column,否则就会造成很大浪费,影响性能。 13.6.4. 关闭 ResultScanners 这与其说是提高性能,倒不如说是避免发生性能问题。如果你忘记了关闭 ResultScanners, 会导致 RegionServer 出现问题。所以一定要把 ResultScanner 包含在 try/catch 块中... Scan scan = new Scan(); // set attrs... ResultScanner rs = htable.getScanner(scan); try { for (Result r = rs.next(); r != null; r = rs.next()) { // process result... } finally { rs.close(); // always close the ResultScanner! } htable.close(); 13.6.5. 块缓存 Scan 实例可以在 RegionServer 中使用块缓存,可以由 setCacheBlocks 方法控制。如果 Scan 是 MapReduce 的输入源,要将这个值设置为 false。对于经常读到的行,就建议使用块缓冲。 13.6.6. Row Keys 的负载优化 当 scan 一个表的时候, 如果仅仅需要 row key(不需要 no families, qualifiers, values 和 timestamps),在加入 FilterList 的时候,要使用 Scanner 的 setFilter 方法的时候,要填上 MUST_PASS_ALL 操作参数(译者注:相当于 And 操作符)。一个 FilterList 要包含一个 FirstKeyOnlyFilter 和一个 KeyOnlyFilter.通过这样的 filter 组合,就算在最坏的情况下, RegionServer 只会从磁盘读一个值,同时最小化客户端的网络带宽占用。 Chapter 14. Bloom Filters Table of Contents 14.1. 配置 14.1.1. HColumnDescriptor 配置 14.1.2. io.hfile.bloom.enabled 全局关闭开关 14.1.3. io.hfile.bloom.error.rate 14.1.4. io.hfile.bloom.max.fold 14.2. Bloom StoreFile footprint 14.2.1. StoreFile 中的 BloomFilter, FileInfo 数据结构 14.2.2. 在 StoreFile 元数据中的 BloomFilter entries Bloom filters 是在 HBase-1200 Add bloomfilters 上面开发的.[21][22] (译者注:Bloom Filter 是一个算法,可以用来快速确认一个 Row Key 或者值是否在一个 Hfile 里面。) 14.1. 配置 可以在 column family 的选项的配置 Blooms.可以通过 Hbase Shell,也可以用 Java 代码操作 org.apache.hadoop.hbase.HColumnDescriptor. 14.1.1. HColumnDescriptor 配置 使用 HColumnDescriptor.setBloomFilterType(NONE | ROW | ROWCOL)来控制每个 column family 的 Blooms 这种。默认值是 NONE ,如果值是 ROW,就会在插入的时候去 Hash 这 个 row,加入到 Bloom 中去。如果值是 ROWCOL,就 Hash 这个 row,column family 和 column family qualifer。(译者注,ROW 是哈希 row key) 14.1.2. io.hfile.bloom.enabled 全局关闭开关 当有些东西出错的时候,Configuration 中的 io.hfile.bloom.enabled 是一个关闭的开关。 默认 是 true. 14.1.3. io.hfile.bloom.error.rate io.hfile.bloom.error.rate = 平均错误率。默认是 1%.减少一半(如 .5%),就意味着每个 bloom entry 加一个 bit. 14.1.4. io.hfile.bloom.max.fold io.hfile.bloom.max.fold = 保证最低的 fold 率。大多数人不该修改这个值,默认是 7,就是说 可以折叠到原本大小的 1/128。参见 Development Process 中的文档 BloomFilters in HBase 获得更多关于这个配置的信息。 14.2. Bloom StoreFile footprint Bloom filters 在 StoreFile 加入了一个 entry.包括 一般的 FileInfo 数据结构和两个额外 entries 到 StoreFile 的元数据部分中。 14.2.1. StoreFile 中的 BloomFilter, FileInfo 数据结构 14.2.1.1. BLOOM_FILTER_TYPE FileInfo 有一个 BLOOM_FILTER_TYPE entry ,可以被设置为 NONE, ROW 或者 ROWCOL. 14.2.2. 在 StoreFile 元数据中的 BloomFilter entries 14.2.2.1. BLOOM_FILTER_META BLOOM_FILTER_META 保存了 Bloom 的大小,使用的 Hash 算法等信息。他的大小的很小。 StoreFile.Reader 加载的时候会缓存进去。 14.2.2.2. BLOOM_FILTER_DATA BLOOM_FILTER_DATA 是实际的 bloomfiter 数据。按需获取,保存在 LRU 缓存中(如果缓 存是开启的,默认开启)。 [21] For description of the development process -- why static blooms rather than dynamic -- and for an overview of the unique properties that pertain to blooms in HBase, as well as possible future directions, see the Development Process section of the document BloomFilters in HBase attached to HBase-1200. [22] The bloom filters described here are actually version two of blooms in HBase. In versions up to 0.19.x, HBase had a dynamic bloom option based on work done by the European Commission One-Lab Project 034819. The core of the HBase bloom work was later pulled up into Hadoop to implement org.apache.hadoop.io.BloomMapFile. Version 1 of HBase blooms never worked that well. Version 2 is a rewrite from scratch though again it starts with the one-lab work. Chapter 15. Hbase 的故障排除和 Debug Table of Contents 15.1. 一般准则 15.2. Logs 15.2.1. Log 位置 15.3. 工具 15.3.1. search-hadoop.com 15.3.2. tail 15.3.3. top 15.3.4. jps 15.3.5. jstack 15.3.6. OpenTSDB 15.3.7. clusterssh+top 15.4. 客户端 15.4.1. ScannerTimeoutException 15.5. RegionServer 15.5.1. 启动错误 15.5.2. 运行时错误 15.5.3. 终止错误 15.6. Master 15.6.1. 启动错误 15.6.2. 终止错误 15.1. 一般准则 首先可以看看 master 的 log。通常情况下,他总是一行一行的重复信息。如果不是这样,说 明有问题,可以 Google 或是用 search-hadoop.com 来搜索遇到的 exception。 一个错误通常不是单独出现在 Hbase 中的,通常是某一个地方发生了异常,然后对其他的地 方发生影响。到处都是 exception 和 stack straces。遇到这样的错误,最好的办法是查日志, 找到最初的异常。例如 Region 会在 abort 的时候打印一下信息。Grep 这个 Dump 就有可能 找到最初的异常信息。 RegionServer 的自杀是很“正常”的。当一些事情发生错误的,他们就会自杀。如果 ulimit 和 xcievers(最重要的两个设定,详见 Section 1.3.1.6, “ ulimit 和 nproc ”)没有修改,HDFS 将无法运转正常,在 HBase 看来,HDFS 死掉了。假想一下,你的 MySQL 突然无法访问它 的文件系统,他会怎么做。同样的事情会发生在 Hbase 和 HDFS 上。还有一个造成 RegionServer 切腹(译者注:竟然用日文词)自杀的常见的原因是,他们执行了一个长时间的 GC 操作,这个时间超过了 ZooKeeper 的 session timeout。关于 GC 停顿的详细信息,参见 Todd Lipcon 的 3 part blog post by Todd Lipcon 和上面的 Section 13.1.1.1, “长时间 GC 停 顿”. 15.2. Logs 重要日志的位置( 是启动服务的用户, 是机器的名字) NameNode: $HADOOP_HOME/logs/hadoop--namenode-.log DataNode: $HADOOP_HOME/logs/hadoop--datanode-.log JobTracker: $HADOOP_HOME/logs/hadoop--jobtracker-.log TaskTracker: $HADOOP_HOME/logs/hadoop--jobtracker-.log HMaster: $HBASE_HOME/logs/hbase--master-.log RegionServer: $HBASE_HOME/logs/hbase--regionserver-.log ZooKeeper: TODO 15.2.1. Log 位置 对于单节点模式,Log 都会在一台机器上,但是对于生产环境,都会运行在一个集群上。 15.2.1.1. NameNode NameNode 的日志在 NameNode server 上。HBase Master 通常也运行在 NameNode server 上, ZooKeeper 通常也是这样。 对于小一点的机器,JobTracker 也通常运行在 NameNode server 上面。 15.2.1.2. DataNode 每一台 DataNode server 有一个 HDFS 的日志,Region 有一个 Hbase 日志。 每个 DataNode server 还有一份 TaskTracker 的日志,来记录 MapReduce 的 Task 信息。 15.3. 工具 15.3.1. search-hadoop.com search-hadoop.com 将所有的 mailing lists 和 JIRA 建立了索引。用它来找 Hadoop/HBase 的 问题很方便。 15.3.2. tail tail 是一个命令行工具,可以用来看日志的尾巴。加入的"-f"参数后,就会在数据更新的时候 自己刷新。用它来看日志很方便。例如,一个机器需要花很多时间来启动或关闭,你可以 tail 他的 master log(也可以是 region server 的 log)。 15.3.3. top top 是一个很重要的工具来看你的机器各个进程的资源占用情况。下面是一个生产环境的例 子: top - 14:46:59 up 39 days, 11:55, 1 user, load average: 3.75, 3.57, 3.84 Tasks: 309 total, 1 running, 308 sleeping, 0 stopped, 0 zombie Cpu(s): 4.5%us, 1.6%sy, 0.0%ni, 91.7%id, 1.4%wa, 0.1%hi, 0.6%si, 0.0%st Mem: 24414432k total, 24296956k used, 117476k free, 7196k buffers Swap: 16008732k total, 14348k used, 15994384k free, 11106908k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 15558 hadoop 18 -2 3292m 2.4g 3556 S 79 10.4 6523:52 java 13268 hadoop 18 -2 8967m 8.2g 4104 S 21 35.1 5170:30 java 8895 hadoop 18 -2 1581m 497m 3420 S 11 2.1 4002:32 java … 这里你可以看到系统的 load average 在最近 5 分钟是 3.75,意思就是说这 5 分钟里面平均有 3.75 个线程在 CPU 时间的等待队列里面。通常来说,最完美的情况是这个值和 CPU 和核数 相等,比这个值低意味着资源闲置,比这个值高就是过载了。这是一个重要的概念,要想理 解的更多,可以看这篇文章 http://www.linuxjournal.com/article/9001. 处理负载,我们可以看到系统已经几乎使用了他的全部 RAM,其中大部分都是用于 OS cache(这是一件好事).Swap 只使用了一点点 KB,这正是我们期望的,如果数值很高的话,就 意味着在进行交换,这对 Java 程序的性能是致命的。另一种检测交换的方法是看 Load average 是否过高(load average 过高还可能是磁盘损坏或者其它什么原因导致的)。 默认情况下进程列表不是很有用,我们可以看到 3 个 Java 进程使用了 111%的 CPU。要 想 知 道哪个进程是什么,可以输入"c",每一行就会扩展信息。输入“1”可以显示 CPU 的每个 核的具体状况。 15.3.4. jps jps 是 JDK 集成的一个工具,可以用来看当前用户的 Java 进程 id。(如果是 root,可以看到所 有用户的 id),例如: hadoop@sv4borg12:~$ jps 1322 TaskTracker 17789 HRegionServer 27862 Child 1158 DataNode 25115 HQuorumPeer 2950 Jps 19750 ThriftServer 18776 jmx 按顺序看 Hadoop TaskTracker,管理本地的 Task HBase RegionServer,提供 region 的服务 Child, 一个 MapReduce task,无法看出详细类型 Hadoop DataNode, 管理 blocks HQuorumPeer, ZooKeeper 集群的成员 Jps, 就是这个进程 ThriftServer, 当 thrif 启动后,就会有这个进程 jmx, 这个是本地监控平台的进程。你可以不用这个。 你可以看到这个进程启动是全部命令行信息。 hadoop@sv4borg12:~$ ps aux | grep HRegionServer hadoop 17789 155 35.2 9067824 8604364 ? S (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQu euedSynchronizer.java:1963) at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:395) at org.apache.hadoop.hbase.regionserver.HRegionServer.run(HRegionServer.java:647) at java.lang.Thread.run(Thread.java:619) The MemStore flusher thread that is currently flushing to a file: "regionserver60020.cacheFlusher" daemon prio=10 tid=0x0000000040f4e000 nid=0x45eb in Object.wait() [0x00007f16b5b86000..0x00007f16b5b87af0] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:485) at org.apache.hadoop.ipc.Client.call(Client.java:803) - locked <0x00007f16cb14b3a8> (a org.apache.hadoop.ipc.Client$Call) at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:221) at $Proxy1.complete(Unknown Source) at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:8 2) at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:59) at $Proxy1.complete(Unknown Source) at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.closeInternal(DFSClient.java:3390) - locked <0x00007f16cb14b470> (a org.apache.hadoop.hdfs.DFSClient$DFSOutputStream) at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.close(DFSClient.java:3304) at org.apache.hadoop.fs.FSDataOutputStream$PositionCache.close(FSDataOutputStream.java:61) at org.apache.hadoop.fs.FSDataOutputStream.close(FSDataOutputStream.java:86) at org.apache.hadoop.hbase.io.hfile.HFile$Writer.close(HFile.java:650) at org.apache.hadoop.hbase.regionserver.StoreFile$Writer.close(StoreFile.java:853) at org.apache.hadoop.hbase.regionserver.Store.internalFlushCache(Store.java:467) - locked <0x00007f16d00e6f08> (a java.lang.Object) at org.apache.hadoop.hbase.regionserver.Store.flushCache(Store.java:427) at org.apache.hadoop.hbase.regionserver.Store.access$100(Store.java:80) at org.apache.hadoop.hbase.regionserver.Store$StoreFlusherImpl.flushCache(Store.java:1359) at org.apache.hadoop.hbase.regionserver.HRegion.internalFlushcache(HRegion.java:907) at org.apache.hadoop.hbase.regionserver.HRegion.internalFlushcache(HRegion.java:834) at org.apache.hadoop.hbase.regionserver.HRegion.flushcache(HRegion.java:786) at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.flushRegion(MemStoreFlusher.java:250) at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.flushRegion(MemStoreFlusher.java:224) at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.run(MemStoreFlusher.java:146) 一个处理线程是在等一些东西(例如 put, delete, scan...): "IPC Server handler 16 on 60020" daemon prio=10 tid=0x00007f16b011d800 nid=0x4a5e waiting on condition [0x00007f16afefd000..0x00007f16afefd9f0] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00007f16cd3f8dd8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedS ynchronizer.java:1925) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:358) at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1013) 有一个线程正在忙,在递增一个 counter(这个阶段是正在创建一个 scanner 来读最新的值): "IPC Server handler 66 on 60020" daemon prio=10 tid=0x00007f16b006e800 nid=0x4a90 runnable [0x00007f16acb77000..0x00007f16acb77cf0] java.lang.Thread.State: RUNNABLE at org.apache.hadoop.hbase.regionserver.KeyValueHeap.(KeyValueHeap.java:56) at org.apache.hadoop.hbase.regionserver.StoreScanner.(StoreScanner.java:79) at org.apache.hadoop.hbase.regionserver.Store.getScanner(Store.java:1202) at org.apache.hadoop.hbase.regionserver.HRegion$RegionScanner.(HRegion.java:2209) at org.apache.hadoop.hbase.regionserver.HRegion.instantiateInternalScanner(HRegion.java:1063) at org.apache.hadoop.hbase.regionserver.HRegion.getScanner(HRegion.java:1055) at org.apache.hadoop.hbase.regionserver.HRegion.getScanner(HRegion.java:1039) at org.apache.hadoop.hbase.regionserver.HRegion.getLastIncrement(HRegion.java:2875) at org.apache.hadoop.hbase.regionserver.HRegion.incrementColumnValue(HRegion.java:2978) at org.apache.hadoop.hbase.regionserver.HRegionServer.incrementColumnValue(HRegionServer.jav a:2433) at sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.hadoop.hbase.ipc.HBaseRPC$Server.call(HBaseRPC.java:560) at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1027) 还有一个线程在从 HDFS 获取数据。 "IPC Client (47) connection to sv4borg9/10.4.24.40:9000 from hadoop" daemon prio=10 tid=0x00007f16a02d0000 nid=0x4fa3 runnable [0x00007f16b517d000..0x00007f16b517dbf0] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:215) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69) - locked <0x00007f17d5b68c00> (a sun.nio.ch.Util$1) - locked <0x00007f17d5b68be8> (a java.util.Collections$UnmodifiableSet) - locked <0x00007f1877959b50> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80) at org.apache.hadoop.net.SocketIOWithTimeout$SelectorPool.select(SocketIOWithTimeout.java:33 2) at org.apache.hadoop.net.SocketIOWithTimeout.doIO(SocketIOWithTimeout.java:157) at org.apache.hadoop.net.SocketInputStream.read(SocketInputStream.java:155) at org.apache.hadoop.net.SocketInputStream.read(SocketInputStream.java:128) at java.io.FilterInputStream.read(FilterInputStream.java:116) at org.apache.hadoop.ipc.Client$Connection$PingInputStream.read(Client.java:304) at java.io.BufferedInputStream.fill(BufferedInputStream.java:218) at java.io.BufferedInputStream.read(BufferedInputStream.java:237) - locked <0x00007f1808539178> (a java.io.BufferedInputStream) at java.io.DataInputStream.readInt(DataInputStream.java:370) at org.apache.hadoop.ipc.Client$Connection.receiveResponse(Client.java:569) at org.apache.hadoop.ipc.Client$Connection.run(Client.java:477) 这里是一个 RegionServer 死了,master 正在试着恢复。 "LeaseChecker" daemon prio=10 tid=0x00000000407ef800 nid=0x76cd waiting on condition [0x00007f6d0eae2000..0x00007f6d0eae2a70] -- java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:485) at org.apache.hadoop.ipc.Client.call(Client.java:726) - locked <0x00007f6d1cd28f80> (a org.apache.hadoop.ipc.Client$Call) at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:220) at $Proxy1.recoverBlock(Unknown Source) at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.processDatanodeError(DFSClient.java:263 6) at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.(DFSClient.java:2832) at org.apache.hadoop.hdfs.DFSClient.append(DFSClient.java:529) at org.apache.hadoop.hdfs.DistributedFileSystem.append(DistributedFileSystem.java:186) at org.apache.hadoop.fs.FileSystem.append(FileSystem.java:530) at org.apache.hadoop.hbase.util.FSUtils.recoverFileLease(FSUtils.java:619) at org.apache.hadoop.hbase.regionserver.wal.HLog.splitLog(HLog.java:1322) at org.apache.hadoop.hbase.regionserver.wal.HLog.splitLog(HLog.java:1210) at org.apache.hadoop.hbase.master.HMaster.splitLogAfterStartup(HMaster.java:648) at org.apache.hadoop.hbase.master.HMaster.joinCluster(HMaster.java:572) at org.apache.hadoop.hbase.master.HMaster.run(HMaster.java:503) 15.3.6. OpenTSDB OpenTSDB 是一个 Ganglia 的很好的替代品,因为他使用 Hbase 来存储所有的时序而不需要 采样。使用 OpenTSDB 来监控你的 Hbase 是一个很好的实践 这里有一个例子,集群正在同时进行上百个 compaction,严重影响了 IO 性能。(TODO: 在 这里插入 compactionQueueSize 的图片)(译者注:囧) 给集群构建一个图表监控是一个很好的实践。包括集群和每台机器。这样就可以快速定位到 问题。例如,在 StumbleUpon,每个机器有一个图表监控,包括 OS 和 Hbase,涵盖所有的 重要的信息。你也可以登录到机器上,获取更多的信息。 15.3.7. clusterssh+top clusterssh+top,感觉是一个穷人用的监控系统,但是他确实很有效,当你只有几台机器的是, 很好设置。启动 clusterssh 后,你就会每台机器有个终端,还有一个终端,你在这个终端的 操作都会反应到其他的每一个终端上。 这就意味着,你在一天机器执行“top”,集群中的所 有机器都会给你全部的 top 信息。你还可以这样 tail 全部的 log,等等。 15.4. 客户端 15.4.1. ScannerTimeoutException 当从客户端到 RegionServer 的 RPC 请求超时。例如如果 Scan.setCacheing 的值设置为 500, RPC 请求就要去获取 500 行的数据,每 500 次.next()操作获取一次。因为数据是以大块的形 式传到客户端的,就可能造成超时。将这个 serCacheing 的值调小是一个解决办法,但是这 个值要是设的太小就会影响性能。 15.5. RegionServer 15.5.1. 启动错误 15.5.1.1. 压缩链接错误 因为 LZO 压缩算法需要在集群中的每台机器都要安装,这是一个启动失败的常见错误。如 果你获得了如下信息 11/02/20 01:32:15 ERROR lzo.GPLNativeCodeLoader: Could not load native gpl library java.lang.UnsatisfiedLinkError: no gplcompression in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734) at java.lang.Runtime.loadLibrary0(Runtime.java:823) at java.lang.System.loadLibrary(System.java:1028) 就意味着你的压缩库出现了问题。参见配置章节的 LZO compression configuration. 15.5.2. 运行时错误 15.5.2.1. java.io.IOException...(Too many open files) 参见快速入门的章节 ulimit and nproc configuration. 15.5.2.2. xceiverCount 258 exceeds the limit of concurrent xcievers 256 这个时常会出现在 DataNode 的日志中。 参见快速入门章节的 xceivers configuration. 15.5.2.3. 系统不稳定,DataNode 或者其他系统进程有 "java.lang.OutOfMemoryError: unable to create new native thread in exceptions"的错误 参见快速入门章节的 ulimit and nproc configuration. 15.5.2.4. DFS 不稳定或者 RegionServer 租期超时 如果你收到了如下的消息 2009-02-24 10:01:33,516 WARN org.apache.hadoop.hbase.util.Sleeper: We slept xxx ms, ten times longer than scheduled: 10000 2009-02-24 10:01:33,516 WARN org.apache.hadoop.hbase.util.Sleeper: We slept xxx ms, ten times longer than scheduled: 15000 2009-02-24 10:01:36,472 WARN org.apache.hadoop.hbase.regionserver.HRegionServer: unable to report to master for xxx milliseconds - retrying 或者看到了全 GC 压缩操作,你可能正在执行一个全 GC。 15.5.2.5. "No live nodes contain current block" and/or YouAreDeadException 这个错误有可能是 OS 的文件句柄溢出,也可能是网络故障导致节点无法访问。 参见快速入门章节 ulimit and nproc configuration,检查你的网络。 15.5.3. 终止错误 15.6. Master 15.6.1. 启动错误 15.6.2. 终止错误 Appendix A. 工具 Table of Contents A.1. HBase hbck A.2. HFile 工具 A.3. WAL Tools A.3.1. HLog 工具 A.4. 压缩工具 A.5. Node 下线 A.5.1. 依次重启 这里我们列举一些 Hbase 管理,分析,修理和 Debug 的工具。 A.1. HBase hbck 用于 Hbase 安装的 fsck 在 Hbase 集群上运行 hbck $ ./bin/hbase hbck 这个命令的输出是 OK 或者 INCONSISTENCY. 如果你的集群汇报 inconsistencies,加上 -details 看更多的详细信息。如果 inconsistencies,多运行 hbck 几次,因为 inconsistencies 可能是暂时的。 (集群正在启动或者 region 正在 split)。加 上 -fix 可以修复 inconsistency(这是 一个实验性的功能) A.2. HFile 工具 参见 Section 12.3.4.2.2, “HFile 工具”. A.3. WAL Tools A.3.1. HLog 工具 HLog 的 main 方法提供了手动 切割和 dump 的方法。会把 WALs 或者 splite 的结果的内容 保存在 recovered.edits 目录下 你可以使用 $ ./bin/hbase org.apache.hadoop.hbase.regionserver.wal.HLog --dump hdfs://example.org:9000/hbase/.logs/example.org,60020,1283516293161/10.10.21.10%3A60020. 1283973724012 来获得一个 WAL 文件内容的文本化的 Dump。如果返回码部位 0,说明文件有错误,所有 你可以用这个命令来看文件是否健康,将命令重定向到/dev/null,检查返回码就可以了。 相似的,你可以将一个 log 切割,运行如下命令: $ ./bin/hbase org.apache.hadoop.hbase.regionserver.wal.HLog --split hdfs://example.org:9000/hbase/.logs/example.org,60020,1283516293161/ A.4. 压缩工具 参见 Section A.4, “压缩工具”. A.5. Node 下线 你可以在 Hbase 的特定的节点上运行下面的脚本来停止 RegionServer: $ ./bin/hbase-daemon.sh stop regionserver RegionServer 会首先关闭所有的 region 然后把它自己关闭,在停止的过程中,RegionServer 的会向 Zookeeper 报告说他已经过期了。master 会发现 RegionServer 已经死了,会把它当作 崩溃的 server 来处理。他会将 region 分配到其他的节点上去。 在下线节点之前要停止 Load Balancer 如果在运行 load balancer 的时候,一个节点要关闭, 则 Load Balancer 和 Master 的 recovery 可能会争夺这个要下线的 Regionserver。为了避免这个问题,先将 load balancer 停止,参见 下面的 Load Balancer. RegionServer 下线有一个缺点就是其中的 Region 会有好一会离线。Regions 是被按顺序关闭 的。如果一个 server 上有很多 region,从第一个 region 会被下线,到最后一个 region 被关闭, 并且 Master 确认他已经死了,该 region 才可以上线,整个过程要花很长时间。在 Hbase 0.90.2 中,我们加入了一个功能,可以让节点逐渐的摆脱他的负载,最后关闭。HBase 0.90.2 加入 了 graceful_stop.sh 脚本,可以这样用, $ ./bin/graceful_stop.sh Usage: graceful_stop.sh [--config &conf-dir>] [--restart] [--reload] [--thrift] [--rest] &hostname> thrift If we should stop/start thrift before/after the hbase stop/start rest If we should stop/start rest before/after the hbase stop/start restart If we should restart after graceful stop reload Move offloaded regions back on to the stopped server debug Move offloaded regions back on to the stopped server hostname Hostname of server we are to stop 要下线一台 RegionServer 可以这样做 $ ./bin/graceful_stop.sh HOSTNAME 这里的 HOSTNAME 是 RegionServer 的 host you would decommission. On HOSTNAME 传递到 graceful_stop.sh 的 HOSTNAME 必须和 hbase 使用的 hostname 一致,hbase 用它来区 分 RegionServers。可以用 master 的 UI 来检查 RegionServers 的 id。通常是 hostname,也可能 是 FQDN。不管 Hbase 使用的哪一个,你可以将它传到 graceful_stop.sh 脚本中去,目前他 还不支持使用 IP 地址来推断 hostname。所以使用 IP 就会发现 server 不在运行,也没有办法 下线了。 graceful_stop.sh 脚本会一个一个将 region 从 RegionServer 中移除出去,以减少改 RegionServer 的负载。他会先移除一个 region,然后再将这个 region 安置到一个新的地方,再 移除下一个,直到全部移除。最后 graceful_stop.sh 脚本会让 RegionServer stop.,Master 会注 意到 RegionServer 已经下线了,这个时候所有的 region 已经重新部署好。RegionServer 就可 以干干净净的结束,没有 WAL 日志需要分割。 Load Balancer 当执行 graceful_stop 脚本的时候,要将 Region Load Balancer 关掉(否则 balancer 和下线脚本 会在 region 部署的问题上存在冲突): hbase(main):001:0> balance_switch false true 0 row(s) in 0.3590 seconds 上面是将 balancer 关掉,要想开启: hbase(main):001:0> balance_switch true false 0 row(s) in 0.3590 seconds A.5.1. 依次重启 你还可以让这个脚本重启一个 RegionServer,不改变上面的 Region 的位置。要想保留数据的 位置,你可以依次重启(Rolling Restart),就像这样: $ for i in `cat conf/regionservers|sort`; do ./bin/graceful_stop.sh --restart --reload --debug $i; done &> /tmp/log.txt & Tail /tmp/log.txt 来看脚本的运行过程.上面的脚本只对 RegionServer 进行操作。要确认 load balancer 已经关掉。还需要在之前更新 master。下面是一段依次重启的伪脚本,你可以借鉴它: 确认你的版本,保证配置已经 rsync 到整个集群中。如果版本是 0.90.2,需要打上 HBASE-3744 和 HBASE-3756 两个补丁。 运行 hbck 确保你的集群是一致的 $ ./bin/hbase hbck 当发现不一致的时候,可以修复他。 重启 Master: $ ./bin/hbase-daemon.sh stop master; ./bin/hbase-daemon.sh start master 关闭 region balancer: $ echo "balance_switch false" | ./bin/hbase 在每个 RegionServer 上运行 graceful_stop.sh: $ for i in `cat conf/regionservers|sort`; do ./bin/graceful_stop.sh --restart --reload --debug $i; done &> /tmp/log.txt & 如果你在 RegionServer 还开起来 thrift 和 rest server。还需要加上--thrift or --rest 选项 (参见 graceful_stop.sh 脚本的用法). 再次重启 Master.这会把已经死亡的 server 列表清空,重新开启 balancer. 运行 hbck 保证集群是一直的 Appendix B. HBase 中的压缩 Table of Contents B.1. 测试压缩工具 B.2. hbase.regionserver.codecs B.3. LZO B.4. GZIP B.1. 测试压缩工具 HBase 有一个用来测试压缩新的工具。要想运行它,输入/bin/hbase org.apache.hadoop.hbase.util.CompressionTest. 就会有提示这个工具的具体用法 B.2. hbase.regionserver.codecs 如果你的安装错误,就会测试不成功,或者无法启动。可以在你的 hbase-site.xml 加上配置 hbase.regionserver.codecs 值你需要的 codecs。例如,如果 hbase.regionserver.codecs 的值是 lzo,gz 同时 lzo 不存在或者没有正确安装, RegionServer 在启动的时候会提示配置错误。 当一台新机器加入到集群中的时候,管理员一定要注意,这台新机器有可能要安装特定的压 缩解码器。 B.3. LZO 参见上面的 Section 3.6.4, “LZO 压缩” B.4. GZIP 相对于 LZO,GZIP 的压缩率更高但是速度更慢。在某些特定情况下,压缩率是优先考量的。 Java 会使用 Java 自带的 GZIP,除非 Hadoop 的本地库在 CLASSPATH 中。在这种情况下, 最好使用本地压缩器。(如果本地库不存在,可以在 Log 看到很多 Got brand-new compressor。 参见 Q: ) Appendix C. FAQ C.1. 一般问题 Hbase 还有其他的 FAQs 吗? HBase 支持 SQL 吗? HBase 是如何工作在 HDFS 上的? 为什么日志的最后一行是'2011-01-10 12:40:48,407 INFO org.apache.hadoop.io.compress.CodecPool: Got brand-new compressor'? C.2. EC2 为什么我的连接 EC2 上的集群的远程 Java 连接不能工作? C.3. 构建 HBase 当我 build 的时候,为什么遇到 Unable to find resource 'VM_global_library.vm'? C.4. Runtime 为什么我在 Hbase loading 的是看到了停顿 为什么我的 RegionServer 会突然挂住? 为什么我看到 RegionServer 的数量是实际的两倍。一半使用域名,一半使用 IP。 C.5. 我如何在 Hbase 中建立 二级索引? C.1. 一般问题 Hbase 还有其他的 FAQs 吗? HBase 支持 SQL 吗? HBase 是如何工作在 HDFS 上的? 为什么日志的最后一行是'2011-01-10 12:40:48,407 INFO org.apache.hadoop.io.compress.CodecPool: Got brand-new compressor'? Hbase 还有其他的 FAQs 吗? 可以在 Hbase 的 wiki HBase Wiki FAQ 和 Troubleshooting 看到更多的 FAQ. HBase 支持 SQL 吗? 不支持。可以通过 Hive 的 SQL-ish 来支持,该功能还在开发中。但是 Hive 是基于 MapReduce 的,对于低延迟的应用并不适合。参见 Chapter 11, 数据模型,可以看到 Hbase 客户端的例 子。 HBase 是如何工作在 HDFS 上的? HDFS 是一个为大文件设计的分布式文件系统。他的文档明确说了,它不是一个通用的文件 系统,文件不支持快速的记录查找。另一方面,HBase 是建立在 HDFS 之上,并且支持大表 快速记录查找(更新)。这有时候会混淆概念。参见 Chapter 11, 数据模型 和 Chapter 12, 架 构,来了解更多 Hbase 的目标。 为什么日志的最后一行是'2011-01-10 12:40:48,407 INFO org.apache.hadoop.io.compress.CodecPool: Got brand-new compressor'? 因为我们没有使用本地的压缩类库。参见 HBASE-1900 Put back native support when hadoop 0.21 is released.将 Hadoop 的本地类库拷贝到 Hbase 下面(或者做软链接)就可以了 C.2. EC2 为什么我的连接 EC2 上的集群的远程 Java 连接不能工作? 为什么我的连接 EC2 上的集群的远程 Java 连接不能工作? 根据用户列表,参见: Remote Java client connection into EC2 instance. C.3. 构建 HBase 当我 build 的时候,为什么遇到 Unable to find resource 'VM_global_library.vm'? 当我 build 的时候,为什么遇到 Unable to find resource 'VM_global_library.vm'? 忽略他。这不是一个错误。这是 officially ugly . C.4. Runtime 为什么我在 Hbase loading 的是看到了停顿 为什么我的 RegionServer 会突然挂住? 为什么我看到 RegionServer 的数量是实际的两倍。一半使用域名,一半使用 IP。 为什么我在 Hbase loading 的是看到了停顿 如果启用了压缩,参见用户列表 Long client pauses with compression. 为什么我的 RegionServer 会突然挂住? 如果你使用了一个老式的 JVM (< 1.6.0_u21?)?你可以看看 thread dump,是不是线程都 BLOCKED 但是没有一个 hold 着锁。参见 HBASE 3622 Deadlock in HBaseServer (JVM bug?). 在 Hbase 的 conf/hbase-env.sh 中的 HBASE_OPTS 加上 -XX:+UseMembar 来修复它。 为什么我看到 RegionServer 的数量是实际的两倍。一半使用域名,一半使用 IP。 修正你的 DNS。在 Hbase 0.92.x 之前的版本,反向 DNS 和正向 DNS 需要返回一致。参见 HBASE 3431 Regionserver is not using the name given it by the master; double entry in master listing of servers 获得详细信息. C.5. 我如何在 Hbase 中建立 二级索引? 二级索引? 对于在 Hbase 中维护一个二级索引的问题,有一个用户的指导。参见 David Butler 在 HBase, mail # user - Stargate+hbase 的信息。 Appendix D. YCSB: 雅虎云服务 测试 和 Hbase TODO: YCSB 不能很多的增加集群负载. TODO: 如果给 Hbase 安装 Ted Dunning 重做了 YCSV,这个是用 maven 管理了,加入了核实工作量的功能。参见 Ted Dunning's YCSB. Index C Cells, Cells Column Family, Column Family H Hadoop, hadoop L LZO, LZO 压缩 N nproc, ulimit 和 nproc U ulimit, ulimit 和 nproc V Versions, 版本 X xcievers, dfs.datanode.max.xcievers Z ZooKeeper, ZooKeeper

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享文档获得金币 ] 23 人已下载

下载文档

相关文档