HBase权威指南

第一章 介绍  
HBase的历史和使用场景 
关系型数据库的问题 
  1.访问量过大必须主从分离 
  2.主写从读,写压力仍然很大前端只能加上缓存 
  3.水平分区 

一致性模型 
1.强一致性        所有的改变都会原子性的立刻生效  
2.顺序一致性      每个客户端都会看到对统一数据的顺序操作,但不一定是实时的 
3.因果关系一致性  对于存在因果关系的操作会看到相同的顺序,无因果关系的则会并行进行 
4.最终一致性      当没有数据更新时,所有的数据通过网络传播复制使得最终达到一致 
5.弱一致性        对于数据更新传播没有包含,使得各客户端看到的数据不一致 

Nosql的维度 
1.数据模型 
2.存储模型 
3.一致模型 
4.物理模型 
5.读写性能 
6.二级索引 
7.失败处理 
8.压缩 
9.负载均衡 
10.原子的读修改写 
11.锁等待和死锁 

构建块 
table,rows,columns,cell,类似这种结构: 
  SortedMap>>> 
自动分片,存储API 

HBase:Hadoop数据库 
hbase和bigtable对比 
HBase              Bigtable 
region             tablet 
regionserver       tablet server 
flush              minor compaction 
minor compaction   merging compaction 
major compaction   major compaction 
write-ahead log    commit log 
HDFS               GFS 
mapreduce          mapreduce 
memstore           memtable 
HFile              SSTable 
zookeeper          chubby 









第二章 安装  
需求  
  最好是商用pc,而不是桌面pc,内存要大,因为region节点需要大量内存,cpu最好4核以上 
  master和slave机器可以配置相同也可以不同,master要有更高的可靠性 
CPU 
  master 2.5G(4核) 
  slave  2.5G(4核) 
内存 
  namenode            8G 
  secondary namenode  8G 
  job tracker         2G 
  hbase master        4G 
  datanode            1G 
  task tracker        1G 
  region server       12G 
  zookeeper           1G 
  主从机器物理内存最好超过24G 
磁盘 
  master   4 * 1TB STAT,raid0+1 
  slave    6 * 1TB STAT,jbod 
  从IOPS考虑,可以将4*1TB换成8*500G,这样可以提高一倍的IOPS 
机架 
  master 1000M带宽,双PSU,1U或2U 
  slave  1000M带宽,单PSU,1U或2U 

操作系统 
  建议选择CentOS或Red hat 
文件系统 
  有ext3,ext4,XFS,ZFS,建议选择更高的ext4或XFS 

SSH可以不用安装 
域名服务器 ping -c 
时钟同步服务器NTP 
文件句柄上线 
  lsof -p region_server_pid 
datanode处理线程 
  dfs.datanode.max.xcievers   调整到4096 
调整交换分区 
  挂起进程可能会导致zookeeper超时,设置/etc/sysctl.conf 
  vm.swappiness=5 
  cat /proc/sys/vm/swappiness 

HBase的文件系统  
  本地文件系统 
  HDFS 
  S3 
  其他,如CloudStore,KFS 

安装选择  
  源码安装 
  mvn assembly:assembly 
  mvn -DskipTests assembly:assembly 

运行模式  
  独立模式 
  伪分布式 
  完全分布式 
  name:  hbase.rootdir    value:  hdfs://namenodeip:9000/hbase 
  name:  hbase.cluster.distributed   value:  true 

配置  
hbase-site.xml 
  优先hbase-site.xml 
  其次hbase-default.xml 
  再是hadoop相关xml 
hbase-env.sh 
regionservers 
log4j.properties 

部署  
  脚本部署 
  apache whirr 
  puppet和chef 










第三章 客户端API的基本操作  
这一章将要讨论的是HBase提供的客户端API。按照之前的介绍,HBase是用java语言编写的。但是这并不意味着必须用java客户端去访问HBase。事实上,在第六章我们将介绍如何用其他语言访问HBase。 

通用性介绍  
操作HBase的主要接口在org.apache.hadoop.hbase.client中,使用HTable类 
1.在一个客户端的生命周期中使用一个HTalbe使用,因为创建HTable花销比较大,会先扫描.META.表 
2.如果要在多线程中使用HTable,推荐使用HTablePool 
3.对每一行的更新操作都是原子的 

CURD操作  
1.Put  
用Put这个类做更新操作 
有一个工具累Bytes,可以将各种类型的值转换为byte[] 
Put#add(byte[] famliy,byte[] qualifier,long ts,byte[] value) 
  基本的add()操作 
  另外add()支持放入KeyValue这个对象 
KeyValue是HBase API中最低级别的类,这个类的数据格式,就是HBase中存储的字节格式,所以 
  如果对性能要求很高的话,可以直接对这个类进行操作 
has(byte[] family,byte[] qualifier) 
  这个类似迭代中的检查,检查某一个指定的cell是否存在 
Put的父类中,有一些API 
  getRow() 
  getRowLock() 
  getLockId() 
  getTimeStamp() 
  heapSize() 

通过Configuration创建一个默认配置实例,它会从classpath查找hbase-default.xml和 
   hbase-site.xml,使用Configuration.create(config)指定一个配置,这样优先级更高 
   HBaseConfiguration继承并兼容Configuration 
   可以手动指定一些属性,这样优先级最高,会覆盖配置文件中的属性 

KeyValue 
   字节级别的操作,比对象级别的操作更有效,这是HBase提供的可以访问数据格式内部的类 
   从构造函数就可以看出,是对底层KeyValue结构的一个封装,可以直接访问byte[] 
   提供了一些比较类(实现了Comparator接口) 
   toString()返回当前的KeyVlaue的元信息,格式如下: 
   /:/// 

Hbase有一个版本的概念,所有的版本都是按时间降序排列的,所以拿到的就是最新版本 
如有一个test表 
create 'test','name' 
put 'test','row1','name','value1' 
put 'test','row1','name','value2' 
scan 'test' 执行之后会发现只有一条数据,即第二个put将第一put的值覆盖了 
如果执行scan 'test',{VERSIONS=>3} 
就看以检索出两个数据,将'value1'和'value2'都检索出来 

客户端缓存 
HTable#setAutoFlush()可以设置缓存 
可以强制刷新缓存flushCommits() 
HBase客户端会将缓存的内容排序后,put到相应的region server上 
可以设置缓存大小: setWriteBufferSize() 
计算服务端的内存使用: 
    hbase.client.write.buffer * hbase.regionserver.handler.count * region server数量 
在没有刷新缓存之前,Htable#put()的内容都在内存中,此时如果去查找,则获取不到值 

Put多个值 
  put 操作 
  使用HTable#put(List) 这种方式提交,假设有4个Put对象,其中一个Put对象所对应 
的列不存在,则其他的3个Put对象是可以插入到表中的。 
  可以通过try-catch的方式捕获这些异常,然后在catch中使用flushCommits(),当然不使用 
flushCommits()也可以插入成功。 

原子更新 
    checkAndPut(byte[] row,byte[] family,byte[] qualifier,byte[] value,Put put) 
    服务端实现的原子操作 
    如果某一列不存在,则制定value为null即可 

2.Get  
  在0.94版本中构造函数 Get(byte[] row,RowLock lock)已经不存在了 
Get类的其他方法 
  setFilter() 
  GetCacheBlocks() 
  numFamilies() 
Bytes工具类也提供了一些方法,可以将byte[]转换为具体的java类型 

Result类 
  提供了一些方法去检索键值对 
  KeyValue覆盖了toString()可以方便的dump 

Get多个值 
  和Put不同,当批量Get的时候,如果其中一个Get所对应的列不存在,则整个批量Get就执行失败,不会返回结果

涉及的检索方法 
exist() 
getRowOrBefore(byte[] row,byte[] family) 
  根据row key和family返回一个Result,如果指定的row key不存在,则返回这个key的前面的一个值 

3.Delete  
  deleteFamily(byte[] family) 
  deleteColumn(byte[] family,byte[] qualifier) 
  deleteColumns(byte[] family,byte[] qualifier) 
这些操作可以删除多个列,如果指定了时间戳,则会删除较老的时间戳的多个列 
如果指定一个时间戳,但是这个时间戳不存在,则什么都不会发生 

Delete多个值 
  使用HTable#delete(List) 这种方式删除,假设有4个Delete对象,其中一个Delete对象所对应 
的列不存在,则其他的3个Delete对象是可以从表中删除的。 
  可以通过try-catch的方式捕获这些异常 

原子删除 
  类似Put的原子更新,值必须存在才可以删除,如果删除的列不存在则抛出一个异常 


批量操作  
Get,Delete,Put的父类Row,通过方法batch(List )支持多个不同的操作 
但需要注意这些操作之间可能会互相影响 
批量操作会返回四种结果: 
1.null 比如远程操作失败 
2.空结果 如Put和Delete操作成功 
3.Result对象,执行Get操作成功,如果没有查找到结果则返回空 
4.抛出一个客户端的异常 
有两个方法: 
batch(List
batch(List,Object[]) 
另外批量操作还支持回调 

行锁(0.94稳定版中已经没有这个类了)  
  put(),delete(),checkAndPut()都是一些排斥操作,可以显示的指定一个锁 
  RowLock,并在创建Delete,Put时指定这个锁 
  当多个客户端同时操作一行时,第一个使用锁的客户端就会占有这行,之后所有的客户端必须等待第一个操作完才可以 
    继续访问 
  锁的超时时间可以通过hbase-site.xml配置 
  Get也有一个锁,但实际上服务端使用 "多并发版本控制" 的方式去实现的 
  使用行锁要小心死锁的问题 

Scans  
  类似数据库的游标 
  有以下一些方法: 
  setStartRow(byte[] startRow) 
  setStopRow(byte[] stopRow) 
  setTimeRange(long minStamp, long maxStamp) 
  setFilter(Filter filter) 

ResultScanner  
  通过HTable#getScanner()可以获得一个ResultScanner对象,它包含三个方法 
  void close() 
  Result next() 
  result[] next(int nbRows)  返回nbRows个Result对象 
  Scanner可能会返回很多Result对象,操作这些对象的时候需要注意尽可能短的释放他们,调用close()或者在 
    hbase-site.xml中配置 

缓存和批处理 
  设置cache大了可以提高性能,但是设置过大,每一次调用next()都会获取很多数据,甚至会导致OOM 
  读取时间过长可能会超时异常,可以在客户端代码中设置 
  Configuration#setLong(HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY,num) 
  这个设置只对客户端有效,服务端需要修改hbase-site.xml才可生效 
  cache是针对行的,而batch是针对列的,比如有17列,batch设置为5,则依次返回5,5,5,2 四次 
  RPC次数 = (行 * 每行的列) / Min(每行的列,批处理大小) / 缓存数 
  如果没有设置批处理数,则返回的一个完整的行 


其他特性  
1.HTable工具方法  
  close() 
  getTalbeName() 
  getTableDescriptor() 
  getRegionLocatioin(Byte[] row) 
  getRegionsInfo() 

2.Bytes类  
提供了java类型到byte[]类型的转换,同时也提供了byte[]转换为java类型 
支持String,boolean,short,int,long,float,double 










第四章 客户端API的高级特性  
Filters  
通过客户端定以后的filter,经过RPC调用,在服务端执行 
接口Filter,抽象实现FilterBase 
有比较的Filter,专用的Filter,装饰的Filter,Filter列表几大类 

比较操作:(在类CompareFilter.CompareOp 中定义) 
1.LESS 
2.LESS_OR_EQUAL 
3.EQUAL 
4.NOT_EQUAL 
5.GREATER_OR_EQUAL 
6.EREATER 
7.NO_OP 

比较的实现类(继承自抽象类ByteArrayComparable) 
1.BinaryComparator 
2.BinaryPrefixComparator 
3.NullComparator 
4.BitComparator 
5.RegexStringComparator 
6.SubstringComparator 
  需要注意BitComparator,RegexStringComparator,SubstringComparator只能用于EQUAL或者NOT_EQUAL操作,用于其他操作会出错 


基于比较的Filters  
1.RowFilter 
可以用于之前的各种比较实现类,实现二进制比较,正则表达式,子串等 

2.FamilyFilter 
  基于列簇的比较 

3.QualifierFilter 
  基于限定符的比较 

4.ValueFilter 
  基于值的比较 

5.DependentColumnFilter 
  精确定位列簇和限定符 

专用的Filters  
1.SingleColumnValueFilter 
  可以设置setFilterIfMissing(true) 返回所有的列,还是返回只查找到的列 

2.SingleColumnValueExcludeFilter 
  和SingleColumnValueFilter类似,只是如果满足条件,则不返回指定的列(无论是返回多列还是单列) 

3.PrefixFilter 
  根据key的前缀查找 

4.PageFilter 
  可以返回指定个数的行,配合startRow可以达到分页的效果 

5.KeyOnlyFilter 
  只返回key,如果指定构造函数true,则返回value的length 

6.FirstKeyOnlyFilter 
  只返回第一列 

7.InclusiveStopFilter 
  通过和startRow配合使用,可以指定一个范围,当扫描到指定的filter就停止 

8.TimestampsFilter 
  限制timestampe范围,可以指定一个List,包括了需要检索的timestampe,Scanner可以指定检索的范围 

9.ColumnCountGetFilter 
  一次能检索的最大的列数 

10.ColumnPaginationFilter 
  可以从指定的偏移量开始,选择若limit个列,这个filter适合列非常多的表 

11.ColumnPrefixFilter 
  类似PrefixFilter,这个filter是取cloumn的前缀 

12.RandomRowFilter 
  内部使用java.util.Random#nextFloat(),返回一个随机的行 
  如果值为负数则不返回任何行,如果大于1.0则返回所有行 

Decpratomg Filters  
装饰filter,配合其他filter一起使用 
SkipFilter 
  如果创建ValueFilter(CompareOp.NOT_EQUAL,new BinaryComparator(Bytes.toBytes(0)) 
  SkipFilter包装了ValueFilter后,如果发现某一行不包含0,则全部跳过,而不是像VluaeFilter 
    那样,只是把对应的列跳过,SkipFilter跳过的是一整行 

WhileMatchFilter 
比如RoWFilter选择不匹配第五行,那么最终Scan会得到除第五行以外的其他行 
而whileMatchFilter会匹配到第四行之后,发现第五行不匹配就终止了 

FilterList  
可以包含多个Filter,可以传入List,如果传入的是ArrayList,就按照加入的顺序执行各个filter 
默认是MUST_PASS_ALL,还有一个是MUST_PASS_ONE,即至少返回一个结果 

自定义的Filter  
可以实现Filter接口或者继承FilterBase类 
内部枚举类RetrunCode定义了一些具体动作 
  1.INCLUDE 
  2.SKIP 
  3.NEXT_CLO              如TimestampFilter 
  4.NEXT_ROW              如RowFilter 
  5.SEEK_NEXT_USING_HINT  如ColumnPrefixFilter 

具体的一些执行方法:(按照执行先后顺序) 
  1.filterRowKey(byte[] buffer, int offset, int length) 
  2.filterKeyValue(KeyValue v) 
  3.filterRow(List kvs) 
  4.filterRow() 
  5.reset() 
  6.filterAllRemaining() 

首先会执行filterRowKey(),判断row是否满足,RowFilter就是按照这种逻辑去实现的 
如果不满足则执行FilterKeyValue(),这回返回一个RetrunCode类型,指明下一步需要的操作 
filterRow(List) 根据前面的结果再做进一步过滤 
filterRow()会根据结果判断是否停止执行, PageFilter就是用这个方法去实现的 
修改后的jar需要部署到服务端才可以执行,可以修改hbase-env.sh指定classpath,或者放到lib目录下 
修改后需要重启才能生效 

Counters  
  hbase提供的一种功能,可以原子的更新计数 
  可以用于广告,数据统计等 
  创建一张表后,计数器的语法为: 
    incr 'table','row','column',[increment-value] 
  获取方法: 
    get_counter 'table','row','column' 

incr可以使用三种值: 
  1.大于0,用于增加 
  2.等于0,类似get_counter,可用于检索 
  3.小于0,用于减去一个值 

注意,写操作是有锁保护的,但是读操作可能没有 
当多个counter更新相同的行可能会有问题 
单行counters 
  HTable#incrementColumnValue() 
多行counters 
  Increment 

Coprocessors  
类似关系数据库的存储过程,可以通过实现指定的接口完成任意代码 
有这么几种类型: 
Observer 
  1.RegionObserver 
  2.MasterObserver 
  3.WALObserver 
Endpoint 

Coprocesor有两个枚举类型,Priority和State 
Priority:(0.94版本做了一些修改,增加了最高和最低级别) 
  1.SYSTEM 
  2.USER 
系统级别会在用户级别前执行,相同优先级通过定义的数字大小按顺序执行 

Coprocessor包含start()和stop()方法,并且包含CoprocessorEnvironment实例 
Coprocessor.Stat包含以下状态: 
  1.UNINSTALLED 
  2.INSTALLED 
  3.STARTING 
  4.ACTIVE 
  5.STOPPING 
  6.STOPPED 
三个重要的类,Coprocessor,CoporcessorEnvironment,CoprocessorHost 

Coprocessor装载  
在hbase-site.xml中增加coprocessor相关配置: 
  1.hbase.coprocessor.region.classes    值就是自定义的class,中间用逗号分隔 
  2.hbase.coprocessor.master.classes    同上 
  3.hbase.coprocessor.wal.classes       同上 

加载表描述,用于每个region server,但是不能用户WAL和master 
格式为:(必须以COPROCESSOR开头) 
  || 
如: 
  alter 'testTable' METHOD=>'table_att', 
  'COPROCESSOR$1'=>'hdfs://ip:54310/myhbase/test.jar|test.coprocessor.Test|SYSTEM' 


RegionObserver class  
preGet()方法如下:  
  preGet(ObserverContext e,Get get,List results) 
RegionCoprocessorEnvironment 上下文可以获得当前运行时相关的表配置,表信息,RegionServer信息等 
更改配置后需要重启 

MasterObserver class  
类似RegionCoprocessor,也包含了MasterCoporcessorEnvironment 
类似数据库中的DDL,在DDL之前之后会有一些触发操作被回调 

Endpoint  
  RegionObserver是在单个server上执行的,也是单个region,但如果要计算表的行数,那么就需要依次对每个region
    都操作一遍,代价太大 
  Endpoint可以对表中的每个region执行一个操作并返回,这个操作是在服务端执行的,所以传输的数据就会小很多 
  Endpoint类似数据库中的sum()函数 
  具体部署方式和RegionObserver一样,也需要配置hbase-site.xml 
  客户端通过回调方式收集所有的region返回的结果,这个有点像微型的MapReduce 
  回调的接口在org.apache.hadoop.hbase.client.coprocessor.Batch中,是Batch的内部接口 

HTablePool  
  在高并发的环境中创建HTable是一个耗时的操作 
  HTable也不是线程安全的,最好在每个线程中使用一个HTable实例 
  HTablePool构造函数中最大数并不是控制最多可以同时获取多少个HTable实例,而是缓存中的HTable实例个数 
    如果超过了这个数,就新实例化一个并返回,一样可以使用 
  构造函数中提供了一个HTableInterfaceFactory,自定义的创建HTableInterface实例 
  注意:在0.94之后又提供了新的构造参数,一个枚举类型,指定池的类型,有三种: 
    1.Reusable 
    2.RoundRobin 
    3.ThreadLocal 

连接处理  
  很多连接都是会被缓存的,如访问zookeeper的连接,这样可以避免重复连接 
HTalbe的构造函数支持Configuration对象,这样就可以做到多个表共享连接了 
但是缺点就是连接不会主动释放,只有客户端退出了才会释放 
可以手动释放连接 









第五章 管理特性  
模式定义  
  HTableDescriptor 
  我们讨论的很多类都有一个无参的构造函数,因为这些类实现了Writable接口,这是为远程序列化考虑的 
  实现自定义的类需要保证如下: 
    1.实现Writable接口 
    2.提供一个无参数的构造函数 

表的属性 
  表的名字必须是拉丁字母的,用正则表达式表示为: 
    [a-zA-Z_0-9-.] 
  默认的文件大小是256M,超过就是执行分割 
  默认是非只读的,可以指定表为只读 
  memstore flush默认为64M 
  是否打开预写日志 

列簇 
  严格来说叫HColumnFamilyDescriptor更合适 
  family的名字必须是可打印的字符,而qualifier可以是任意字符 
  family不能重命名,只能创建一个新的 
  最大版本为3,可以查找到以前删除的历史 
  压缩类型 
    1.NONE 
    2.GZ (gzip) 
    3.LZO 
    4.SNAPPY 
  block大小,默认为64K,这个相当于缓存,hadoop的block大小是用指定单个文件大小 
  block缓存默认是开启的 
  支持一个版本的TTL,如果超时的话在块合并的时候会被删除 
  可以支持将列完全放入内存中,当达到JVM内存上限时会丢弃多余的数据 
  布隆过滤可以大幅度提高检索时间,但是也有误识别的缺点,默认是关闭的,可用key和key+(family+qualifier)的组合 
  复制范围,默认关闭为0,表示本地复制,设置为1表示集群复制 

HBaseAdmin  
  类似数据库的DML 

集群操作 
  flush() 
  compact() 
  majorCompact() 
  move() 
  blance() 

集群状态信息 
  通过HBaseAdmin获得ClusterStatus 
  ServerName   服务端机器信息 
  HServerLoad  服务状态信息 
  RegionLoad   region相关状态信息 
  WebUI上可以观察到这些信息 









第六章 可用的客户端  
交互式的客户端  
REST 
启动方式./hbase-daemon.sh start rest 
文本方式 
  curl -H "Accept:text/plain" http://IP:8080/ppp/aa1 
xml方式(默认格式) 
  curl http://IP:8080/ppp/aa1 
json方式 
  curl -H "Accept:application/json" http://IP:8080/ppp/aa1 
protocol buffer方式 
  curl -H "Accept:application/x-protobuf" http://IP:8080/ppp/aa1 | hexdump -c 
raw binary方式 
  curl -H "Accept:application/octet-stream" http://IP:8080/ppp/aa1 | hexdump -c 
REST java client 
  Cluster cluster = new Cluster(); 
  cluster.add("IP",8080); 
  Client client = new Client(cluster); 
  RemoteHTable table = new RemoteHTable(client,"test"); 
  //..之后的get,delete,put,scanner操作都和普通的方式一致 

Thrift 
  也是跨语言的,有thrift和thrift2两个版本,用C++编写的 
  启动方式./hbase-daemon.sh start thrift 
  模式文件定义在 $HBASE_HOME/src/main/resources/org/apache/hadoop/hbase/thrift/下 
  Hbase.thrift文件 
  生成php文件支持:(假设已经安装好thrift) 
  thrift -en php Hbase.thrift   之后产生一个gen-php目录 
  cp /lib/php/src $DOCUMENT_ROOT/thrift 
  mkdir $DOCUMENT_ROOT/thrift/packages 
  cp -r ~/thrift_scr/gen-pp/Hbase $DOCUMENT_ROOT/thrift/packages 
  HBase目录下的src/examples/thrift目录下有php的列子  

Avro 
  和thrift类似,也是跨语言的 
  启动方式./hbase-daemon.sh start avro 
  模式文件定义在 $HBASE_HOME/src/main/java/org/apache.hadoop/hbase/avro/hbase.avpr 

其他客户端 
  jruby 
  HBql 
  HBase-DSL 
  JPA/JPO 
  PyHBase 
  AsyncHBase 

批处理客户端  
  HIVE 
  PIG 
  Cascading 

创建和hbase管理的表 
create table hbase_table(key int,value string)stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties("hbase.columns.mapping"=":key,cf1:val") 
tableproperties("hbase.table.name"="hbase_table") 

关联已经存在的hbase表 
create external table hbase_table_2(key int,value string)stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties("hbase.columns.mapping"=":key,cf1:val") 
tableproperties("hbase.table.name"="hbase_table_2") 
关联外部表时,如果在hive中删除了这张表,外部表不会被删除 

Shell  
  开启debug, 查看是否开启debug? 
jruby脚本 
  org.apache.hadoop.hbase.util.Bytes.toInt("\x00\x01\x06[".to_java_bytes) 
  java.text.SimpleDateFormate.new(yyyy/MM/dd HH:mm:ss").parse("2012/12/21 
    20:56:29").getTime() 
  for i in 'a'..'z' do for j in 'a'..'z' do put 'test',"row-#{i}#{j}","colfam1:#{j}","#{j}" end end 
  require 'date' 
一个xx.rb脚本 ,运行方式./hbase org.jruby.Main xx.rb 
  include java 
  import org.apache.hadoop.hbase.HBaseConfiguration 
  import org.apache.hadoop.hbase.client.HBaseAdmin 
  conf = HBaseConfiguration.new 
  admin = HBaseAdmin.new(conf) 
  tables = admin.listTables() 
  tables.each {|table| put table.getNameAsString() } 

webUI  
  配置hbase-site.xml可以调整webUI端口 
  hbase.master.info.port 
  hbase.regionserver.info.port 
masterUI 和 regionUI 
通用功能 
Local logs 
Thread Dump 
Log Level 
Debug dump 









第七章 整合MapReduce  
map-reduce可以处理TB级别数据,将大任务分解为多个小任务到多台机器上,执行完结果后再汇总 
InputFormat 
  getSplits() 
  createRecordReader() 
  Hbase提供了TableInputFormatBase作为其扩展实现 
Mapper的每一个记录使用RecordReader处理map() 
  Hbase提供了TalbeMapper作为其扩展实现 
Reducer阶段汇总Mapper的数据 
  Hbase提供了TableReducer作为其扩展实现 
OutputFormat 最终的数据输出 
  Hbase提供TableOutputFormat作为其扩展实现,用TableRecordWriter写入到指定表中 
  TableOutputCommitter需要hadoop类是完成job工作 

使用TableMapReduceUtil设置map-reduce工作 

hdfs使用三副本的形式,map-reduce选择三台机器之一运行 
TableInputFormat#getSplits()等于所有region中的startKey和endKey之间数据,然后做切分 
之后TableRecordReader会迭代的对region的startKey和endKey的每行数据进行处理 

在MapReduce之上运行HBase 
静态导入 
  需要将hbase的jar导入到hadoop的classpath中,此外要配置mapre-site,需要重启节点 
动态导入 
  使用maven引入需要的jar,使用hadoop jar xx.jar的方式运行 
  注意guava等jar也需要引入到classpath中来 

Data Sink(下沉) 
实现Mapper接口,其setup()函数是只调用一次,map()是每行都会被触发调用一次 
最终调用TableOutputFormat,它会将map之后分解的数据写入到表中 
因为写入的不是中间文件而是hbase的表,所以结果是有序的,这样就不需要reduce了 

Data Source(来源) 
一个统计单词的例子,从Result中读取每个columns,然后解析作者名字,记录+1并设置到上下文中 
之后reduce过程对其+1 
最后汇总打印出来 

辅助工具类TableMapReduceUtil 
自定义过程 
  可以将输出写到两个不同的表中,在setup()函数中定义A和B两个表 
  在map()中判断key的内容,如果是aa开头则插入到A表,否则插入到B表 










第八章 架构  
查找和传输  
B+树 一个节点下包含了多个节点,这样可以降低IO读取的次数 
但是B+树一个节点超过限制了,就会拆分,从而引起父节点拆分,这样可能引发很多个拆分,而且不同节点可 

能分散在磁盘 
的不同地方,不是连续的,这样性能就差了 
B+树的优化就是将不连续的块重新写一遍,做到连续 

LSM(Log-structured merge-tree)是先将数据写入到日志文件中,日志文件是有序的,当日志文件改变时,先 

将改变的内容 
保存到内存中,优化查询,当内存满了就将数据写到磁盘中,此时内存的数据可以丢弃,经过多次写之后, 
会产生多个小文件,后台线程会将多个小文件合并成一个大文件,这样查询就被定位在几个文件中了 

存储  
当memstore大于hbase.hregion.preclose.flush.size(默认5M)就会刷新到磁盘上 
hdfs路径 /hbase/.logs 会包含对应的子region名字的目录,每个region就对应一个子目录,对于一个region 

目录是共享的 
日志文件大小为0是因为hdfs内置的append机制使用追加写导致的,只有文件达到一定大小才是可见的 
hbase.regionserver.logroll.period 设置日志滚动时间(默认60分钟) 
当数据被写入到磁盘后,就不需要日志文件了,这样的文件会被放到 /hbase/.oldlogs 目录下,也是一个 

region对应 
   一个目录 
参数hbase.master.logcleaner.ttl控制多久之后旧日志被删除(默认10分钟) 
参数hbase.master.cleaner.interval控制多长时间检查一次(默认1分钟) 

根级文件(在HDFS中/hbase目录下) 
  /hbase/hbase.id 和 /hbase/hbase.version 
      这两个文件包含集群的唯一ID和文件格式版本信息 
  /hbase/splitlog 和 /hbase/.corrupt 
      第一个是日志拆分产生的中间文件,第二个是损坏的日志 

表级文件 
  每个表都有自己的目录,每个表包含 .tableinfo 顶层文件和.tmp目录 
      第一个是用来存储表结构信息的,第二个是当新的.tableinfo生成的临时文件就放在.tmp目录下 
  region文件的总体结构: 
      //// 
      ncoded-regionname是 表名,起始key,启动时间,md5编码   这些组成的 
  // 这个目录下还有一个 .regioninfo文件 

拆分 
  在父region的splitlog目录下拆分log,然后关闭当前region,不接受请求 
  META表会更新父region,显示SPLIT=>true,之后会出现两个信息 
      column=info:splitA 和 column=info:splitB 
  当两个子region初始化好之后META表删除父region,并删除文件,可以由负载均衡将新region移动到其他机 

器上 
  整个过程都在zookeeper中进行跟踪 

合并 
  minor合并和major合并 
  minor合并 hbase.hstore.compaction.min(默认为3)设置的,这个值最小要大于等于2 
  minor合并可以处理的最大文数 hbase.hstore.compaction.max来配置(默认为10) 
  hbase.hstore.compaction.max.size 任何比这个值大的文件都会排除在外 
  hbase.hstore.compaction.min.size 它是一个阀值而不是限制,它包括任何小于限制的文件,直到每次压 

缩允许的 
        的总文件数量 
  hbase.hstore.compaction.ratio(默认为1.2即120%) 这个参数确保选择过程中尽可能的包含更多文件 
  主合并major由CompactionChecker类实现 
  周期由hbase.server.thread.wakefrequency参数控制(乘以 

hbase.server.htread.wakefrequency.multiplier, 
        设置为1000,使得执行不那么频繁) 
  除非强制指定 

HFile格式 
   
  Data格式: 
  ... 
  空的HFile格式为: 
   
  目前有V1和V2两种HFile格式,最新用的是V2格式,它支持多级索引 
  HFile中包含若干个块,每个块的大小默认是64K,建议设置到8K--1M之间,较大的块适合顺序访问但不适合 

随机访问, 
    较小的快适合随机访问但是会造成索引过多 
  HFile块对于HDFS来说是透明的,一个HFile可能会被写入到多个HDFS块中(一个HDFS块默认64M) 
    这两种块之间没有任何关系 
  使用命令查看HFile状态 
    ./hbase org.apache.hadoop.hbase.io.hfile.HFile 

KeyValue格式 
  Key长度,Vluae长度,Row长度,Row,column family长度,column family,column qualifer,timestamp,key 

type,value 

WAL  
  类似mysql的binlog,在主存储器出现意外的情况下作为恢复使用 
HLog类 
  所有的region都共享一个HLog,它使用追加写的方式 
HLogKey 
  使用region的编码名,表名,long类型的递增序列号,集群的UUID表示key 
WALEdit 
  每一个修改的实例都被封住到一个WALEdit中 
LogSyncer(最新版没有这个类) 
  延迟日志刷新默认为false,意味着每一编辑被发送到服务器时,都会调用写日志的sync(),但这意味着 
  一对N的管道写,datanode是写三分,管道的方式写入,只有最后一个写成功返回才算成功。这样会带来很  

  大的延迟。可以选择稍微延迟这个调用,但是可能有一定几率造成数据丢失 
  HDFS以后会支持多路写,即一次向多个datanode写入数据,只要等最慢的一个写入完成就算成功,不过这样 
  会给占用很多带宽 
  属性hbase.regionserver.optionallogflushinterval(默认1秒)配置多久之后调用sync() 
LogRoller(最新版没有这个类) 
  在特定的时间间隔内滚动日志,通过配置hbase.regionserver.logroll.period(默认1小时)来控制 
  hbase.regionserver.hlog.blocksize 设置文件系统的快大小(默认32M) 
  hbase.regioinserver.logroll.multiplier(默认为0.95)表示当日志大小达到块大小的95%会滚动日志 

日志回放 
  1.只有一份日志,跟bigtable类似,这是为性能考虑的,多个region共享一个日志文件 
  2.日志的拆分,之前是由master负责的,串行的回复每个日志,同时每个region都会被阻塞 
    现在使用分布式模式注册到zookeeper上,master指定某个日志是可以被处理的,region就会竞争这个 
    任务 
    可以通过hbase.master.distributed.log.splitting来设置关闭新的分布式日志拆分 
    在非分布式下写入是多线程的,这是通过hbase.regionserver.hlog.splitlog.writer.threads来控制的( 
    默认是3) 
    hbase.hlog.split.skip.errors(默认为false)表示当出现错误时是否跳过,不跳过抛出IOException 
    拆分中的日志被放在splitlog目录下 
    为了能和其他日志区分开来并发操作,日志路径包含了region名(散列值)和recovered.edits文件夹 
    错误的不能恢复的日志被放在.corrupt目录下 
  3.数据恢复 
    一旦检查到recovered.edits目录便开始 

持久性 
  底层的hadoop需要支持追加写,以前的hadoop是提供API向文件写入,写入之后才可以读取这个文件,并且 
  这个文件会变成只读,但是对于hbase可能会造成数据丢失 
  之后hadoop增加了追加写的功能,hbase调用syncFs()或hflush()管道的方式写入数据 


读路径  
  小合并,大合并,控制HFile文件数量 
  旧的数据作为KeyValue存储在磁盘上,新的数据被刷新后也会被存储,但是不会修改原始文件,而是存储在 

新文件中 
  删除的数据只是做一个墓碑标记,并不会真正删除,只有当合并的时候才会被删除 
  一个StoreScanner实例代表了一个Sotre,通过这个实例的next()扫描所有的数据并跳过被标记删除的数据 

Region查找  
  Root表-->meta表-->用户表 
  最坏的情况可能需要六次查找 

Region的生命周期  
  offline        region下线 
  pending open   打开region的请求已经被发送到服务器 
  opening        服务器已经打开region 
  open           region已经被打开并且完全可以使用 
  pending close  关闭region的请求被送到服务器 
  closing        服务器正在处理要关闭的region 
  closed         region服务器已经被关闭了 
  splitting      服务器开始切分region 
  split          region已经被切分了 

zookeeper  
  ./hbase zkcli 启动 
  ls /hbase 显示hbase的znode节点 
  get /hbase/hbaseid    HDFS上hbase.id的内容 
  /hbase/master         master节点内容 
  /hbase/root-region-root    root表所在的region机器 
  /hbase/rs             所有的region server 
  /hbase/shutdown       集群的启动时间 
  /hbase/splitlog       日志拆分,日志首先是unassigned状态然后被一个region服务器获取 
  /hbase/table          所有的表 
  /hbase/unassigned     未打开的region 

复制  
  类似Mysql的bin-log复制,使用异步方式 
LogEdit生命周期 
  1.每次的更新操作都会被记录到WAL中,另一个线程从日志中读取,当缓冲区满了或者到文件末尾了就将 
    内容发送到从集群 
  2.如果从集群没有反馈则重试若干次如果还是没有反馈则重新选择一台从集群备份 
内部机制 
  1.挑选需要复制的目标服务器(挑选的数目为从集群个数的10%) 
  2.每个从集群都有对应的znode,每个znode都包含HLog。文件在可用之前被添加到每个集群的znode中, 
    这样所有的更新操作都会复制到自己的集群中 
  3.默认情况下会过滤掉分为GLOBAL类的且不属于目录表日至项的KeyValue,之后是限制每个从集群的同步 
    大小,默认是64M,所以三个从集群就是192M 
  4.如果没有启用同步复制,master日志清理线程会按照TTL删除旧的日志,如果当前日志在队列中则不会 
    删除 
  5.所有的对等服务器都放在 
    当有服务器宕机了,其他服务器会竞争的创建一个lock的znode,并将这个服务器的内容转移到自己的 
      目录下 
    下面假设有3个region,从集群id为2,zonde名字就是HDFS的文件名 
    /hbase/replication/rs/ 
      1.1.1.1,60020.1234567890/ 
        peers/ 
              2/ 
                1.1.1.1,60020.123 
      1.1.1.2,60020.1234567890/ 
(lock) 
        peers/      
      2/ 
1.1.1.2,60020.1214 
      1.1.1.3,60020.1234567890/ 
        (lock) 
peers/ 
      2/ 
1.1.1.3,60020.1280 
将1.1.1.2的内容移到这里 










第九章 高级使用  
Key的设计  
                         KeyValue 
  row   ColumnFamily   ColumnQualifier   Timestamp   Value 
  越往后定位的性能就越差 
  每个column对应一个真实的文件,qualifier是和column存储在同一个文件中的,比如column为ff,quailfier为aa 
    则存储在实际的文件中的内容是ffaa 
  高窄的表 VS 短宽的表 
  1.假设e-mail的消息被放到了quailifer中,row key是用户id,这样如果用户不多,但是用户消息很多,会造成 
     行不多,但是单行的内容很多(有很多不同的qualifier),这样的设计很不好,因为HBase的split是按照行分割的, 
     qualifier过多,会造成这行内容过大(甚至超过了region大小),但HBase又不能对其split 
  2.如果将e-mail中的消息放到row key中,做成userId-message,这样每行的qualifier就是空的,每个row key就只有 
     一条数据了,但是行很多,这样的好处是HBase可以进行split 
  局部key扫描 
    key可以设计成这样的: 
        userid-date-messageId-attachmentId 
    因为timestamp是反序排列的,所以可以设计成: 
        Long.MAX_VALUE -  
  时间连续数据 
    假设有N个region server,设计key为: 
        byte prefix = (byte)(Long.hashCode(timestamp) %  
        byte[] rowkey = Bytes.add(Bytes.toBytes(prefix),Bytes.toBytes(timestamp); 
    那么key为:(假设有5个region server) 
        0myrowkey-1 
        4myrowkey-2 
        2myrowkey-3 
  这种设置的好处是分散了写的压力,可以让key分散到不同region server上,如果要加机器,客户端逻辑需要修改
    另外这种方式对读不是很好,尤其是scan需要遍历多个region,可以用多线程处理,这样可以提供IO效率 
  交换key 
    前面一个列子,将timestamp和互换,这样可以提高写效率 
    OpenTSDB采用类似的方式 这种格式作为key   
  随机key 
    byte [] rowkey = MD5(timestamp) 可以将key均衡的分散到多个region server上 
  对于写来说 
    顺序的key,按region取模分散key,时间顺序话-取摸的key,MD5随机化key    效率依次递减 
  对于写来说,正好相反,效率依次递增 
  时间有序 
    某个列index,可以对某个qualifier主题做降序排列,对某个qualifier发件人做升序排列 
    时间的降序排列: 
      Long.MAX_VALUE -    这样越早的时间值越大,就在前面了 

高级模式  
  跨语言的IDL(interface definition language) 
  avro 
  protocol buffers 

二级索引  
  客户端自己管理 
    1.管理多个表,很灵活,索引存放到另外一张表中,但这种方式可能会造成数据不一致的问题 
    2.基于列簇的方式,通过列的Qualifier,这样可以保证事务性 
      这种方式先扫描row key,然后根据qualifier再更小的范围,之后根据version找出结果 
  ITHBase 
  IHBase 
    这两种都是差不多的,扩展了服务端代码,客户端需要使用额外的代码来操作索引 
  Coporcessor 
    在服务端做扩展,和IHBase类似,但是不需要替换任何服务端和客户端的代码 

查询整合  
  客户端管理,facebook实现方式 
    1.每一行对应一条消息  
    2.列索引消息 
    3.版本是message id 
    4.值包含了附加信息,比如文档的位置 
  Lucene 
  HBasene 
    都是基于Lucene,存储的索引放在HBase中 
  Coprocessor 
    实现方式类似二级缓存 

事务  
  ITHBase扩展了服务端和客户端的代码,提供了事务功能 
  Cage也提供了多个lock的功能 
  zookeeper本身也有两阶段提交,父znode下包含了多个子znode,每个子znode会标记是否成功或失败,客户端可以监控 
    其状态 

Bloom filter  
  如果执行随机查找,在HFile发现key在数据索引中,则会执行一遍scan,发现没有再下一个HFile,一直到结束,可能会遍历多个HFile中的块,如果有bloom过滤器,可能只需要遍历很少几个HFile中的块即可 
  bloom过滤器需要原始文件的1/20大小,即文件1G,bloom过滤器占用50M空间 
  bloom有row和row+column两种类型,优先使用row过滤器 
  bloom会有判断错误率,默认1%,可以设置 
    即认为某个key在这些块中,但是实际上不存在的; 但如果认为key不存在,那么肯定是不存在 
  使用过程 
    1.判断cell的大小,如果小于阀值则不适用过滤器 
    2.如果cell数量超过阀值则使用row过滤器 
    3.检查读取模式如果是row则使用row模式,否则使用row+column模式 

版本  
  需要保证各个region server的时间一致,通过NTP(network time protocol)保证 
  如果各resion server时间不一致,某台机器时间比其他机器早一个小时,时间戳使用系统时间,当这台机器split,并 
    将一半的region移动到另一台机器B,之后又执行插入到机器B,此时新插入值的时间反而比旧值的时间晚,这样按照 
    时间排序取出的版本就是旧值的数据 
  默认的版本为3,最大版本为2^31-1. 如果一个cell的key,column,quailifer都一样,时间戳不同,那么会按照最新的三个 
    版本递减排序,最高的在最上面.插入6条数据(其他都一样,只有时间戳为1-6),那么1-3时间戳的数据不会被显示,但是 
    也不会被马上删除,如果查看硬盘上的HFile文件,数据还是存在的,当执行了一次major_compact之后,这些过期的数据 
    就会被真正删除 
  如果删除数据时没有指定版本,默认为当前时间,小于当前时间的所有值都会被删除,如果新增的数据时间戳小于当前 
    时间,就查询不到了,这样新增不就成功,flush,major_compact之后,新增的旧值就可以插入了 
  自定义的版本 
    1.facebook inbox search,根据时间戳排序,这样就可以取到最新的数据了 
    2.使用一个全局的递增版本 










第十章 集群监控  
Metrics框架 
继承自hadoop的metrics框架,将自身的信息发送给外部监控者 
上下文,记录,度量 
hbase提供了下列Context: 
  1.GangliaContext 
  2.FileContext 
  3.TimeStampingFileContext 
  4.CompositeContext 
  5.NullContext 
  6.NullContextWithUpdateThread 
完整的度量全限定名为: 
  .. 

度量框架包括以下类型 
  1.int型(IV) 
  2.long型(LV) 
  3.比率(R)  一段时间内的变化 
    a)比率计算是 操作数/花费时间 
    b)比率存储的是上一次的值 
    c)内部的计数器恢复到0 
    d)下一次的比率值才是当前值 
    e)计算后的比率值会返回给调用者 
  4.String型(S) 
  5.时间变化int型(TVI)  一段时间内的累计值 
  6.时间变化long型(TVL) 同上 
  7.时间变化比率(TVR) 计算一段时间完成的操作比列 
    a)操作个数    上一次执行后的总操作数 
    b)最小时间    一个时间完成的最短时间 
    c)最大时间    一个事件完成的最长时间 
    d)平均时间    事件完成的平均时间 
  8.持久的时间变化比率 
对于长时间运行的处理,可以通过配置 hbase.extendedperiod配置,默认是不过期,如设置一个小时则为3600 
master度量 
  1.集群请求(R) 所有region的请求和 
  2.重启后分割预写日志的时间(PTVR) 
  3.预写日志文件的总大小(PTVR) 

region server度量 
  1.块缓存度量    记录总数,大小,空闲,失效的度量,以及命中数和未命中数,以及命中比列 
  2.压缩度量      压缩大小,压缩时间,压缩队列大小 
  3.memstore度量  memstore大小度量,flush队列大小,flush时间 
  4.存储度量      所有存储文件的状态度量 
  5.I/O度量       读写等待时间度量 
  6.杂项度量      读请求数度量,写请求数度量,regionserver数度量 
压缩度量和memstore度量是在更新之间统计的,所以统计的值对于当前的值是有些延迟的 

RPC度量 
  master和region使用相同的度量 
  1.RPC处理时间 
  2.RPC队列时间,RPC将所有的处理放在队列中,在队列中等待直到被取出处理的时间 

JVM度量 
  1.内存使用度量    堆和非堆的使用情况 
  2.垃圾收集度量    垃圾收集时间,垃圾收集次数 
  3.线程度量        各种线程的状态 
  4.系统时间度量    各种子系统的日志信息,比如日志错误度量提供错误级别出现的时间 

Info度量 
  提供各种内部值 
  1.date         Hbase build时间 
  2.version      hbase版本 
  3.revision     仓库的构建修订版 
  4.url          仓库的url 
  5.user         构建hbase的user 
  6.hdfsDate     HDFS的构建时间 
  7.hdfsVersion  当前使用的hdfs版本 
  8.hdfsRevision 仓库的修订版构建的hdfs 
  9.hdfsUrl      hdfs仓库url 
  10.hdfsUser    构建hdfs的user 

Ganglia 
  Ganglia monitoring daemon(gmond) 每个机器都运行一个 
  Ganglia meta daemon(gmetad) master机器运行 
  Ganglia PHP web frontend web前端 
  安装好之后需要设置hadoop-metrics.properties 

JMX 
  在hbase-env.sh中开启 
  配置hadoop-metrics.properties 
  hbase.class=org.apache.hadoop.metrics.spi.NullConetextWithUpdateThread 
  MBean地址: 
  hadoop:service=,name= 
  如: 
    hadoop:service=Master,name=MasterStatistics 
    hadoop:serivce=HBase,name=RPCStatistics- 

JConsole 
JMX 远程API 
   git clone git://github/larsgeorge/jmxtoolkit.git 
   运行: 
   java -cp build/hbase-jmxtoolkit.jar org.apache.hadoop.hbase.jmxtoolkit.JMXToolkit -h 
   可以整合Cacti 

Nagios 
   配合JMXToolkit脚本一起使用 










第十一章 性能调优  
垃圾收集  
GC调优使用CMS垃圾收集器,可以调整垃圾收集的出现阀值(比如70%) 
打印详细的日志输出 
注意block cache(处理读)和memstore cache(处理写)的大小比列 

memstore-local allocation buffer  
MSLAB的实现原理(对照Arena Allocation,HBase实现细节): 
创建一个2M(默认)的Chunk数组和一个chunk偏移量,默认值为0。 
当Memstore有新的KeyValue被插入时,通过KeyValue.getBuffer()取得data bytes数组。将data复制到Chunk数组起始位置为chunk偏移量处,并增加偏移量=偏移量+data.length。 
当一个chunk满了以后,再创建一个chunk。 
所有操作lock free,基于CMS原语。 
    优势: 
KeyValue原始数据在minor gc时被销毁。 
数据存放在2m大小的chunk中,chunk归属于memstore。 
flush时,只需要释放多个2m的chunks,chunk未满也强制释放,从而为Heap腾出了多个2M大小的内存区间,减少碎片密集程度。 
开启MSLAB 
hbase.hregion.memstore.mslab.enabled=true // 开启MSALB 
hbase.hregion.memstore.mslab.chunksize=2m // chunk的大小,越大内存连续性越好,但内存平均利用率会降低,要比插入的单元格的数据大一些。 
hbase.hregion.memstore.mslab.max.allocation=256K // 通过MSLAB分配的对象不能超过256K,否则直接在Heap上分配,256K够大了。 

压缩  
GZIP,LZO,Zippy/Snappy 
GZIP最慢,Snappy最快 

校验压缩是否安装成功 
./hbase org.apache.hadoop.hbase.util.CompressionTest  
配置hbase-site.xml 
 
    hbase.regionserver.codecs 
    snappy,lzo 
 

启用压缩 
create 'testtable',{NAME=>'clof1',COMPRESS=>'GZ'} 
启用压缩后并不是马上生效,因为数据还在buffer中,除非手动触发major_compact 

优化切分和压缩  
hbase.hregion.max.filesize  单个region的大小(整个集群范围) 
或者可以指定某个column 
预创建regions 
  ./hbase org.apache.hadoop.hbase.util.RegionSplitter  
或者用命令行 
  create 'testtable' 'colf',{SPLITS=>['row-100','row-200','row-300']} 

负载均衡 
将各个机器上的region数量平衡 
hbase.balancer.period 多长时间间隔执行一次,默认是5分钟 
hbase.balancer.max.balancing  每次执行多长时间,默认是上面参数的一般,也就是2分30秒 
可以通过HBaseAdmin#balanceSwitch()来控制开关,可以通过shell命令控制 

region的合并 
  ./hbase org.apache.hadoop.hbase.util.Merge  

客户端API最佳实践 
  1.关闭自动flush 
  2.使用scanner缓存 
  3.设置scanner的范围 
  4.关闭ResultScanners 
  5.使用块缓存 
  6.优化需要加载的key(如使用KeyOnlyFilter) 
  7.关闭WAL(预写日志) 

配置 
  1.减少zookeeper超时时间 
  2.增加处理线程hbase.regionserver.handler.count 
  3.增加堆大小(hbase-env.sh) 
  4.启用压缩 
  5.增加region大小(hbase.hregion.max.filesize) 
  6.调整block缓存大小(perf.hfile.block.cache.size),是一个浮点数(如0.2) 
  7.调整memstore大上限(hbase.regionserver.global.memstore.upperLimit)默认0.4, 
           hbase.regionserver.global.memstore.lowerLimit 默认0.35 
  8.增加blocking存储文件 hbase.hstore.blockingStoreFiles(多余这个数量的hfile时才会合并) 
  9.增加block multplier hbase.hregion.memstore.block.multiplier 
           如果memstore有hbase.hregion.memstore.block.multiplier倍数的 
           hbase.hregion.flush.size的大小,就会阻塞update操作 
    hbase.hregion.flush.size这个参数的作用是当单个Region内所有的memstore大小总和超过指定值时, 
    flush该region的所有memstore 

负载测试 
hbase自带的测试工具 
    ./hbase org.apache.hadoop.hbase.PerformanceEvaluation 

YCSB 
  yahoo cloud serving benchmark 
  java -cp build/ycsb.jar:db/hbase/lib* com.yahoo.ycsb.Client 










第十二章 集群管理 
操作任务 
关闭一个region server 
./hbase-daemon.sh stop regionserver 
但是这样做不好,应当使用如下方式: 
首先关闭bleance 
./hbase shell blance_switch false 
之后执行 
./graceful_stop.sh HOSTNAME 

重启一个region server 
./graceful_stop.sh --restart --reload --debug HOSTNAME 

增加一个region server 
在master机器的conf文件中增加机器的hostname 
可以在master机器上执行start-hbase.sh,它会跳过所有已经启动的机器,并启动新增加的机器 
或者新增加的机器上单独执行脚本: 
./hbase-daemon.sh start regionserver 

增加一个备份master(和原先的master在一台机器上,可以创建多个备份) 
./local-master-backup.sh start 1 
在不同机器上创建备份 
./hbase-daemon.sh start master --backup 
还可以调用master-backup.sh 脚本完成备份 

连接zookeeper,./hbase zkcli 可以观察到已经增加到备份znode上的机器 
ls /hbase/backup-masters 

数据任务 
可以用.hadoop jar直接运行hbase-xxx.jar,运行前需要将$HBASE_HOME/lib下的一些jar拷贝到$HADOOP_HOME/lib下 
zookeeper-xxx.jar 
guava-xxx.jar 
protobuf-java-xxx.jar 
如下面一段是将testtable备份到hdfs的/hbase-backup目录下 
./hadoop jar $HBASE_HOME/hbase.jar export testtable /hbase-backup/test-table 
导入命令如下: 
./hadoop jar $HBASE_HOME/hbase.jar import mybak /hbase-backup/test-table 
直接运行./hadoop jar $HBASE_HOME/hbase.jar export/import 会有些更详细的参数 
export和import是用mapreduce执行的,所以可以通过-D导入一些mapreduce参数 
另外export支持start time,end time,prefix,regexp等参数 
需要注意,import时指定的表必须先创建,否则会提示找不到表 

使用hadoop的命令./hadoop distcp,将一个集群中的数据拷贝到另一个集群中 
但是只能用停机备份,运行时备份会有问题 

./hadoop jar $HBASE_HOME/hbase.jar  copytable --new.name=new-tab old-tab 
类似上面两个命令的整合,可以将一个旧表的数据导入新表中,同时还支持集群间的拷贝, 
可以将旧表的数据拷贝到其他集群中,注意拷贝时候新指定的表必须存在 

importtsv和completebulkload 这两个可以命令可以完成大量数据导入,比直接用API快一个数量级 
importtsv可以直接导入,也可以分两步导入,先用importtsv导入到hdfs的临时目录中,生成内部的HFile格式,再用 
completebulkload命令move到目标表中,completebulkload只是本地磁盘拷贝非常快 
这两个命令需要用到mapreduce,如果没有配置mapred-site.xml则默认使用本地mapreduce,运行时会有问题 
  在mapred-site.xml中加一段:(注意端口不能和hdfs中定义的port一样) 
      mapred.job.tracker 
      hdfs://ip:54311 
  定义hadoop-env.sh,将hbase.jar,zookeeper.jar,guava.jar,protobuf.jar引入到HADOOP_CLASSPATH中 
执行命令 
./hadoop jar hbase.jar importtsv -Dimporttsv.bulk.output=/hbase-tmp -Dimporttsv.columns=HBASE_ROW_KEY,col_name 

table_name /xx.txt 
xx.txt中的数据格式如下:(默认是按\t分割的),可以通过-D参数指定 
key-1   xxxxxxxxxx 
key-2   xxxxxxxxxx 
key-3   xxxxxxxxxx 
运行之后/hbase-tmp目录下就有数据了,查看新表已经创建了,但是里面还没有数据,用completebulkload导入 
./hadoop jar hbase.jar completebulkload /hbase-tmp table_name 
导入很快,导入完成之后表中就有数据了,如果导入数据很大,原表中就有region,导入时候会执行切分工作 
可能需要将hbase-site.xml放入hadoop-conf变量中,但我测试的时候没导入也成功了 

Replication 
  需要在hbase-site.xml中增加一个配置hbase.replication=true 
  通过shell脚本增加一个对等集群(对等集群的规模可以和原集群不同) 
  add_peer '1','IP-2:2181:/hbase' 
  启动复制 start_replication 
验证复制 
  ./hadoop jar hbase.jar verifyrep 
  可以比较两个集群的两个表数据是否相等,可以基于时间增量比较 

附加的任务 
共存的集群 
  只能用于测试目的 
  需要修改hbase-site.xml中的下列属性: 
  hbase.rootdir 
  hbase.tmp.dir 
  zookeeper.znode.parent 
  hbase.master.port 
  hbase.master.info.port 
  hbase.regionserver.port 
  hbase.regionserver.info.port 
  conf目录和log目录需要另外拷贝一份 
  启动: $HBASE_HOME_CONF_DIR=conf.2 ./start-hbase.sh 

故障排查 
日志级别默认是DEBUG,在conf/log4j.properties中调整 
./hbase hbck 
  首先是做一致性检查,检查.META.表中的数据是否对应到具体regionserver中 
  之后是完整性检查,如果加上了-fix会做一些修正工作,比如将未分配的region分配出去 
    或者重新分配region等 

  通过ulimit -n 可以查看datanode当前的处理上线 
    cat /proc//limits 
  启用LZO压缩,需要单独安装LZO包,否则会报找不到类错误 
  zookeeper问题 
  1.因为页面换入换出导致处理响应变慢,zookeeper超时 
    通过vmstat 20 和free -m查看 
  2.GC时间过长导致的超时问题 
  3.机器负载过高导致超时问题(zookeeper可能和regionserver部署在相同物理机器上) 
  4.IO压力高导致超时问题 


你可能感兴趣的:(HBase权威指南)