1.1 提升写效率
1.1客户端调优
1.1.1 AutoFlush
参数值:setAutoFlush
解析:
autoflush=false的原理是当客户端提交delete或put请求时,将该请求在客户端缓存,直到数
据超过2M(hbase.client.write.buffer决定)或用户执行了hbase.flushcommits()时才向reg
ionserver提交请求。因此即使htable.put()执行返回成功,也并非说明请求真的成功了。假
如还没有达到该缓存而client崩溃,该部分数据将由于未发送到regionserver而丢失。这对于
零容忍的在线服务是不可接受的。
autoflush=true虽然会让写入速度下降2-
3倍,但是对于很多在线应用来说这都是必须打开的,也正是hbase为什么让它默认为true的原
因,每次请求都会发往regionserver,而regionserver接收到请求后第一件事情就是写HLOG。
因此对IO要求是非常高的,为了提高hbase的写入速度应该尽可能地提高IO吞吐量,比如增加
磁盘、使用raid卡、减少replication因子数等。
如何调优?
默认:true
经验设定:setAutoFlush=false
1.1.2 使用PutList方式提交请求
可以极大地提升写性能
val putList: util.ArrayList[Put] = new util.ArrayList[Put]()
1.2 Memstore相关
当regionserver(以下简称为RS)收到一个写请求,会将这个请求定位到某个特定的region。每
一个region存储了一系列的Row,每一个 Row
对应的数据分散在一个或多个ColumnFamily(以下简称为CF)。特定CF的数据都存储在对应的
store里面,而每个store都是由一个memstore和很多个storefile组成。memstore存储在RS的
内存中,而storefile则存储在HDFS上。当一个写请求到达RS的时候,该请求对应的数据首先
会被menstore存储,直到达到一定的临界条件,memstore里面的数据才会flush到storefile。
使用memstore的主要原因是为了使存储在HDFS上的数据是有序的(按Row)。HDFS设计为顺序
读写的,已有的文件不能被修改。这就意味着,因为hbase收到的写请求是无序的,所以如果
直接将这些数据写到HDFS上,以后再对文件里面的内容做排序就会是一件极其困难的事情;无
序的数据存储方式,又会大大影响后续的读请求性能。为了解决这种问题,hbase会将最近的
某些写请求放到内存中(也就是memstore),并将这些数据在flush到storefile之前做好排序
。
除了解决排序的问题,memstore还有其他好处,比如:
它能充当memcache的角色,缓存最近写入的数据。鉴于新数据的访问频率和几率都比旧数据高
很多,这就大大的提高客户端的读效率。
注意:每个memstore每次刷新时,都会给CF生产一个storefile。
剩下读取就非常容易了,hbase会检查数据是否在memstore里面,否则就去storefile读取,然
后返回给客户端。
1.2.1 根据 memstore 大小flush hfile
参数值:hbase.hregion.memstore.flush.size
参数解析:
在regionserver中,当写操作内存中存在超过 memstore.flush.size
大小的memstore,则MemstoreFlusher就启动flush操作将该memstore以hfile的形式写入对应
的store中。
如何调优?
默认:128M
A、如果Regionserver的内存充足,而且活跃Region数量也不是很多的时候,可以适当增大该
值,可以减少compaction的次数,有助于提升系统性能。
B、这种flush产生的时候,并不是紧急的flush,flush操作可能会有一定延迟,在延迟期间,
写操作还可以进行,Memstore还会继续增大,最大值 = “memstore.flush.size” *
"hbase.hregion.memstore.block.multiplier"。
hbase.hregion.memstore.block.multiplier 默认 4 , 4 * 128 = 512 M
C、当超过最大值时,将会阻塞写操作。适当增大“hbase.hregion.memstore.block.multiplie
r”可以减少阻塞,减少性能波动。
参数值:hbase.regionserver.global.memstore.size 默认:0.4
参数解析:
RegionServer中,负责flush操作的是MemStoreFlusher线程。该线程定期检查写操作内存,当
写操作占用内存总量达到阈值,MemStoreFlusher将启动flush操作,按照从大到小的顺序,fl
ush若干相对较大的memstore,直到所占用内存小于阈值。
阈值=“hbase.regionserver.global.memstore.size” *
"hbase.regionserver.global.memstore.size.lower.limit" * "Hbase_HEAPSIZE"
upperLimit说明:hbase.hregion.memstore.flush.size这个参数的作用是单个Region内所有
memstore大小总和,超过该指定值时,会flush该region的所有memstore。RegionServerd的fl
ush是通过将请求添加一个队列,模拟生产消费模式来异步处理的。那这里就有一个问题,当
队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发OOM(程序申
请内存过大,虚拟机无法满足我们,然后自杀)。
这个参数的作用是防止内存占用过大,当ReionServer内所有region的memstore所占用内存总
和达到heap的40%时,Hbase会强制block所有的更新并flush这些region以释放所有memstore占
用的内存。
lowerLimit说明:lowelimit在所有Region的memstore所占用内存达到Heap的40%时,不flush
所有的memstore。它会找一个memstore内存占用最大的region,做个别flush,此时写更新还
是会被block。lowerLimit算是一个在所有region强制flush导致性能降低前的补救措施。在日
志中,表现为“** Flush thread woke up with memory above low water.”
如何调优?
比如 Hbase_HEAPSIZE=8, 阈值= 0.4 * 0.95 * 8 = 3.04G
[[hbase.regionserver.global.memstore.size.lower.limit]]
*`hbase.regionserver.global.memstore.size.lower.limit`*::
+
.Description
Maximum size of all memstores in a region server before flushes are forced.
Defaults to 95% of hbase.regionserver.global.memstore.size.
A 100% value for this property causes the minimum possible flushing to occur when
updates are
blocked due to memstore limiting.
+
.Default
`0.95`
[[hbase.hregion.memstore.block.multiplier]]
*`hbase.hregion.memstore.block.multiplier`*::
+
.Description
Block updates if memstore has hbase.hregion.memstore.block.multiplier
times hbase.hregion.memstore.flush.size bytes. Useful preventing
runaway memstore during spikes in update traffic. Without an
upper-bound, memstore fills such that when it flushes the
resultant flush files take a long time to compact or split, or