Hbase运维碎碎念宁海元 @NinGoohttp://NinGoo.netVer:0.22011年6月
Hbase运维碎碎念这是一个读书笔记,可能有大量的理解错误最后的参考文档比这个ppt更有价值后续对Hbase有更多的理解,随时会更新ppt你需要有基本的java概念和基本的Hbase概念
Hbase运维碎碎念AgendaJAVAHDFSHBase
Hbase运维碎碎念tmpwatch运行一段时间后,发现jps无法列举java进程了,崩溃。。。Why?Java需要将pid信息写入到 /tmp/hsperfdata_usernametmpwatch定期清理/tmp修改sudo vi /tmp/cron.daily/tmpwatch/usr/sbin/tmpwatch “$flags” -x /tmp/hsperfdata_* …
Hbase运维碎碎念JVM Heap图片出处:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html
Hbase运维碎碎念JVM Heap简单来说,Heap分为年轻代(Young)/年老代(Old/ Tenured)/持久代(Perm)-Xms: Heap初始尺寸-Xmx: Heap最大尺寸-Xmn: 年轻代尺寸-XX:NewRatio: 设置Young与Old的大小比例,-server时默认为1:2-XX:SurvivorRatio: 设置Eden与Survivor的比例,默认为32。-XX:MaxPermSize: 持久代大小,默认64M。-XX:NewSize: 年轻代大小-XX:MaxNewSize: 年轻代最大尺寸-Xss: 每个线程的stack尺寸-XX:MinHeapFreeRatio:空余堆内存小于40%时,JVM就会增大堆。 -XX:MaxHeapFreeRatio:空余堆内存大于70%时,JVM会减少堆。
Hbase运维碎碎念JVM Heap年轻代分为Eden,Survior 1, Survior2新对象在Eden区分配内存。GC时,将Eden和有对象的Survior区(From Space)的所有对象复制到另外一个Survior(To Space),然后清空Eden和原Sruvior。当一个对象在from和to之间复制的次数超过一定阀值(-XX:MaxTenuringThreshold)后,进入到年老代。如果是CMS GC,这个阀值默认为0,也就是经过一次copy后就进入年老代。 -XX:+PrintTenuringDistribution可以查看详细统计信息。持久代不GC,除非CMS GC且显式设置 XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
Hbase运维碎碎念JVM GCGC分为对Young的GC(minor)和同时对Young和Old的GC(Major)Serial GC,单线程GC,适合小Heap单CPU。-XX:+UseSerialGCParallel GC,也称Throughput GC。与第一种GC不同在于Young区是多线程的,但Old区仍然单线程。-XX:+UseParallelGC。Java 6.0已经支持Old区并行GC: -XX:+UseParallelOldGC。GC的线程数可以通过-XX:ParallelGCThreads=<N>调整。通过-XX:MaxGCPauseMillis=<N>可以提示最大GC暂停时间,设置此参数会导致JVM自动调整Heap大小和一些JVM相关参数,慎用。Concurrent GC,也称CMS GC,可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。该GC还可以开启增量模式-XX:+CMSIncrementalMode
Hbase运维碎碎念JVM GCConcurrent GC暂停所有线程,标记活跃对象的root,然后恢复线程访问使用一个或者多个CPU标记所有活跃对象,应用线程访问不受影响。使用一个CPU标记第2步过程中有修改的对象。暂停所有线程,标记前面2,3步过程中有修改的对象,然后恢复线程访问。使用一个CPU,并发的将非活跃对象清除,内存释放给free list。使用一个CPU,并发的重整heap大小,并准备下一轮GC需要的数据结构。
Hbase运维碎碎念JVM GCConcurrent GC并发GC更消耗CPU,假如有N个CPU,GC可使用1 <= K <= ceil(N/4) 。并发GC可能造成Heap碎片,Cloudera推出了MemStore-Local Allocation Buffers特性来改善碎片问题。如果并发GC进行中,有新对象要进入年老代会导致Concurrent Mode Failure,此时只能stop the world,改用串行Full GC。如果新的对象要进入年老代,但年老代没有足够大小的连续空间,会导致Promotion Failuer,此时只能stop the world,进行Full GC-XX:CMSInitiatingOccupancyFraction=<N> 可以控制启动CMC GC的阀值,N表示年老代的大小百分比。如果Concurrent Mode Failure频繁出现,可以考虑降低其值。
Hbase运维碎碎念JVM GC不管哪种GC,年轻代的GC都会阻塞线程。推荐年轻代使用Parallel New GC,年老代使用CMS GC-XX:+UseParNewGC –XX:+UseConcMarkSweepGC禁止程序显式GC-XX:+DisableExplicitGC打印GC Log-verbose:gc -Xloggc:filename -XX:+PrintGCDetails -XX:+PrintGCTimeStamps打印年老代FreeListSpace的状态 -XX:PrintFLSStatistics=1打印CMS的信息-XX:PrintCMSStatistics=1
Hbase运维碎碎念NUMA从JDK6u2开始,增加了-XX:+UseNUMA,在 UseParallelGC时,JVM会将年轻代根据节点数切分为不同的pool。cat /sys/devices/system/node/node0/meminfoNode 0 MemTotal:     12382196 kBNode 0 MemFree:       9739412 kBNode 0 MemUsed:       2642784 kBNode 0 Active:        1805868 kBNode 0 Inactive:       548076 kBNode 0 HighTotal:           0 kBNode 0 HighFree:            0 kBNode 0 LowTotal:     12382196 kBNode 0 LowFree:       9739412 kBNode 0 Dirty:             396 kBNode 0 Writeback:           0 kBNode 0 FilePages:     1765192 kBNode 0 Mapped:          23236 kBNode 0 AnonPages:      589204 kBNode 0 PageTables:       3672 kBNode 0 NFS_Unstable:        0 kBNode 0 Bounce:              0 kBNode 0 Slab:           141612 kBNode 0 HugePages_Total:     0Node 0 HugePages_Free:      0
Hbase运维碎碎念NUMA$ numastat                           node0           node1numa_hit              1675519925      1659271911numa_miss                      0               0numa_foreign                   0               0interleave_hit            110847          112840local_node            1675317828      1658259635other_node                202097         1012276
Hbase运维碎碎念NUMA图片出处:http://blogs.oracle.com/jonthecollector/entry/help_for_the_numa_weary
Hbase运维碎碎念NUMA关闭NUMA?vi /etc/grub.conf…Title Red Hat Enterprise Linux Server (2.6.18-164.el5)	root (hd0,0)	kernel /vmlinuz-2.6.18-164.el5 ro root=LABEL=/ numa=off console=tty0 console=ttyS1,115200 initrd /initrd-2.6.18-164.el5.img
Hbase运维碎碎念Large PageOS设置假设使用2G的大页面内存(2M页面)echo 1000 > /proc/sys/vm/nr_hugepagesecho 2147483647 > /proc/sys/kernel/shmmaxJVM设置-XX:+UseLargePages-Xmx整个JVM Heap必须全部使用大页内存,或者全部不用。
Hbase运维碎碎念AgendaJAVAHDFSHBase
Hbase运维碎碎念ulimitsudo vi /etc/security/limits.conf* soft nproc 65536* hard nproc 65536* soft nofile 65536* hard nofile 65536Swapecho 0 > /proc/sys/vm/swappiness
Hbase运维碎碎念SyncApache官方版本的0.20.x不支持sync(hflush),有较大存在数据丢失的可能性。如果作为Hbase的存储,需要使用CDH3版本或者自行编译Hadoopbranch-0.20-append分支。官方版本的HDFS只有在文件关闭后才能确保数据不丢失,如采用官方,可考虑加快Hlog的切换(hbase.regionserver.logroll.period),以尽量减少WAL日志的丢失,但会影响性能:产生更多的小文件,影响NameNode的管理效率更频繁的flush,Hlog超过一定数量(默认32)后会触发所有memstore的flush,影响regionserver的效率
Hbase运维碎碎念NameNodeNameNode目前的版本是单点,主要保存两类数据:1. Namespace通过Fsimage和Editlog持久化到硬盘2. BlocksMap纯内存三元组结构,重启后需要datanode做blockreport重构NameNode容灾需要确保Fsimage和Editlog写两份(通过NFS)NameNode重启的时间取决于Editlog的Apply时间和BlockReport的时间。
Hbase运维碎碎念Safemodedfs.safemode.threshold.pct默认0.999,也就是blockreport阶段NN需要收到99.9%的block的report信息才能退出安全模式dfs.safemode.min.datanodes退出safemode前存活的最小DN数,默认0,不限制dfs.safemode.extension达到阀值以后等待默认30000毫秒后才正式退出安全模式手工进入safemode$hadoopdfsadmin -safemode enter手工退出safemodehadoopdfsadmin -safemode leave
Hbase运维碎碎念DataNodedfs.datanode.max.xcievers默认256,建议至少4096+,太小可能导致频繁报错:hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXXXXXX_YYYYYYYY from any node: java.io.IOException: No live nodes contain current block.
Hbase运维碎碎念监控MetricsMetrics可以写到Ganglia,或者本地文件vi hadoop-metrics.properties#dfs.class=org.apache.hadoop.metrics.file.FileContextdfs.class=org.apache.hadoop.hbase.metrics.file.TimeStampingFileContextdfs.period=10dfs.fileName=/tmp/dfsmetrics.logdfs.class=org.apache.hadoop.metrics.ganglia.GangliaContext31dfs.period=10dfs.servers=localhost:8649注:Hadoop的FileContext没有记录timestamp,建议使用Hbase的TimeStampingFileContext
Hbase运维碎碎念监控MetricsMetrics也可以同时写到Ganglia和本地文件dfs.class=org.apache.hadoop.metrics.spi.CompositeContextdfs.arity=2dfs.period=10dfs.sub1.class=org.apache.hadoop.hbase.metrics.file.TimeStampingFileContextdfs.fileName=/tmp/metrics_hbase.logdfs.sub2.class=org.apache.hadoop.metrics.ganglia.GangliaContext31dfs.servers=localhost:8649
Hbase运维碎碎念AgendaJAVAHDFSHBase
Hbase运维碎碎念Flush/Compaction/Split图片出处:http://www.spnguru.com/?p=466
Hbase运维碎碎念Flush/Compaction/SplitCompactSplitThread.javalock.lock();try {  if(!this.server.isStopped()) {    // Don't interrupt us while we are working    byte [] midKey = r.compactStores();    if (r.getLastCompactInfo() != null) {  // compaction aborted?this.server.getMetrics().addCompaction(r.getLastCompactInfo());    }       if (shouldSplitRegion() && midKey != null &&          !this.server.isStopped()) {      split(r, midKey);    }     }   } finally {lock.unlock();}
Hbase运维碎碎念Flush/Compaction/Splithbase.hregion.memstore.flush.size默认64M,当一个region中所有MemStore总大小超过64M时,开始Flush。hbase.hregion.max.filesize默认256M,当一个StoreFile超过256M时,会启动split分裂为两个daughter region,分裂只是创建两个reference,不复制数据。hbase.hregion.memstore.block.multiplier默认2,当一个region所有memstore之和超过hbase.hregion.memstore.flush.size(默认64M)大小的2倍时,会强制阻塞写刷到磁盘。
Hbase运维碎碎念Flush/Compaction/Splithbase.regionserver.regionSplitLimit如果在线的region超过此数目,则不再split,默认int.MAX_VALUE(2147483647),设为1即可关闭自动split。hbase.hstore.compactionThreshold默认3,当一个store中的storefile超时3个时,触发compact。所以,将此值设置为int.MAX_VALUE可关闭自动compact。hbase.hstore.blockingStoreFiles默认7,当region中任一个store中的storefile超过7个时,会触发的compact,在compact完成之前,flush会延迟执行。如果此时更新较多,导致该region的memstore之和超过hbase.hregion.memstore.flush.size*hbase.hregion.memstore.block.multiplier,则会阻塞更新,直到Flush完成,或者hbase.hstore.blockingWaitTime(默认90s)超时,建议加大该值。
Hbase运维碎碎念Flush/Compaction/Splithbase.regionserver.maxlogs默认32,当Hlog的数量超过32个时会造成flush所有的region,不管它的memstore是否满。hbase.regionserver.global.memstore.upperLimit默认0.4,表示region server上所有的memstore占用的内存总和最多为MaxHeap的40%,超过则会加锁刷磁盘,一直要等到某个memstore刷到磁盘,且memstore总和下去了,才会继续, Flush是串行操作,所以对memstore多或写非常频繁的场景要特别注意。 hbase.regionserver.global.memstore.lowerLimit默认0.35,当所有MemStore的大小超过MaxHeap的35%时,开始持续Flush,以尽量避免到upperLimit导致锁。
Hbase运维碎碎念Minor CompactionMinor Compaction只合并StoreFile,不清理历史版本和删除记录hbase.hstore.compaction.max默认10,一次minor compaction最多只处理10个StoreFile
Hbase运维碎碎念Major CompactionMajor Compaction合并所有StoreFile,清理历史版本和删除记录hbase.hregion.majorcompaction默认86400000 毫秒=1天,同一个region两次major compaction操作的时间间隔。如果一次minor compaction选中的StoreFile是这个region的所有StoreFile,minor compaction会自动升级为major compaction手工触发:$hbase shellhbase(main):015:0> compact 'test'0 row(s) in 0.2220 secondshbase(main):016:0> major_compact 'test'0 row(s) in 0.3240 secondsSo,如果没有delete,major compaction可以不用太频繁的执行。
Hbase运维碎碎念Column Family每个CF都有一套MemStore+StoreFiless但是同一个table的所有CF的MemStore都会在同一时间Flush(未来或许会改善),会在同一时间split,从写的角度看,一个table最好不要设计太多的CF,各个CF之间的数据长度和更新频率尽量保持平衡,他们之间有太多的紧耦合。从读的角度看,读取频繁的列放到一个较小的CF较有利。CF的设计需要均衡考虑业务的读写模式。
Hbase运维碎碎念MSLABMemStore-Local Allocation Buffer 每个MemStore都有一个MemStoreLAB实例
MemStoreLAB有一个2MB的curChunk,其nextFreeOffset为0
 每次insert一个KV时,数据(byte[]数组)复制到curChunk,nextFreeOffset随之增长
curChunk满了以后,重新分配一个2MB的Chunk
 上述操作采用compare-and-swap,因此无需加锁优点: 原始插入的数据生命周期变短,就不用进入年老代可能进入年老代的Chunk是固定以2MB为大小,消除碎片的烦恼每个Chunk只可能属于一个MemStore当MemStore刷到磁盘,Heap释放的内存也是以2MB为单位。
Hbase运维碎碎念MSLABhbase.hregion.memstore.mslab.enabled是否启用MSLAB,默认truehbase.hregion.memstore.mslab.chunksizeChunk的尺寸,默认2MBhbase.hregion.memstore.mslab.max.allocationMSLAB中单次分配内存的最大尺寸,默认256K,超过该尺寸的内存直接在Heap上分配。
Hbase运维碎碎念Regionserverzookeeper.session.timeout默认3分钟,也就是rs超过3分钟没有给zk消息,Master就认为rs挂了。如果gc的过程中阻塞时间超过了3分钟,那就杯具了,so。。。hfile.block.cache.size默认0.2,全局公用的hfile的cache,最多占用MaxHeap的20%。当数据在memstore中读取不到时,就会从这个cache里获取,当从此cache中获取不到时,就需要读取文件。当cache的block达到了这个值的85%时,即会启动evict(日志中会出现“Block cache LRU eviction”),将cache清除到75%大小,可通过日志中的“LRU Stats: ”来观察cache的命中率
Hbase运维碎碎念Clienthbase.client.pause默认1000ms,客户端被阻塞或者失败后重试间隔,间隔为指数避让,即1,1,1,2,2,4,4,8,16,32,建议改下这个值,同时加大重试次数,避免split造成客户端响应时间过长以及失败率增加。hbase.client.retries.number默认为10次,决定了客户端的重试次数hbase.ipc.client.tcpnodelay默认tcp的no delay是false,建议修改为trueipc.ping.intervalRPC等待服务端响应的超时时间,默认为1分钟,有点太长了,建议改成3秒(3000)
Hbase运维碎碎念CompressLZO比默认的Gzip性能更好,但Gzip压缩比更高安装lzo-2.00以上版本:http://www.oberhumer.com/opensource/lzo/download/到http://code.google.com/p/hadoop-gpl-compression/下载lzo相关的native库io.compression.codecscom.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodecio.compression.codec.lzo.classcom.hadoop.compression.lzo.LzoCodec参考:http://wiki.apache.org/hadoop/UsingLzoCompression
Hbase运维碎碎念Replication是的,Hbase 0.90.0也开始支持replication了,不过目前版本bug较多。参考:http://koven2049.iteye.com/blog/983633图片出处:http://hbase.apache.org/docs/r0.89.20100726/replication.html
Hbase运维碎碎念监控Metricshbase.class=org.apache.hadoop.metrics.spi.CompositeContexthbase.arity=2hbase.period=10hbase.sub1.class=org.apache.hadoop.hbase.metrics.file.TimeStampingFileContexthbase.fileName=/tmp/metrics_hbase.loghbase.sub2.class=org.apache.hadoop.metrics.ganglia.GangliaContext31hbase.servers=localhost:8649
Hbase运维碎碎念备份恢复导出到本地或者HDFShbaseorg.apache.hadoop.hbase.mapreduce.Driver export  \Tablename/desctination导入回Hbasehbaseorg.apache.hadoop.hbase.mapreduce.Driver import  \Tablename /source导入TSV文件(以Tab分割的文本文件)hbaseorg.apache.hadoop.hbase.mapreduce.Driverimporttsv \ -Dimporttsv.columns=a,b,cTablename /source如果是csv文件,只需要加参数-Dimporttsv.separator=,即可
Hbase运维碎碎念备份恢复Hbase集群间CopyTablehbaseorg.apache.hadoop.hbase.mapreduce.CopyTable …或者hbaseorg.apache.hadoop.hbase.mapreduce.Drivercopytable …Hadoop集群间Copy文件hadoopdistcp -p -update "hdfs://A:8020/user/foo/bar" "hdfs://B:8020/user/foo/baz“Mozilla开发的Backup工具对运行的Hbase进行做distcp会导致不一致,Mozilla为此开发了一个Backup工具http://blog.mozilla.com/data/2011/02/04/migrating-hbase-in-the-trenches/
Hbase运维碎碎念压力测试 $ ./hbaseorg.apache.hadoop.hbase.PerformanceEvaluationUsage: java org.apache.hadoop.hbase.PerformanceEvaluation \  [--miniCluster] [--nomapred] [--rows=ROWS] <command> <nclients>Options:miniCluster     Run the test on an HBaseMiniClusternomapred        Run multiple clients using threads (rather than use mapreduce) rows            Rows each client runs. Default: One millionflushCommits    Used to determine if the test should flush the table.  Default: falsewriteToWAL      Set writeToWAL on puts. Default: TrueCommand:filterScan      Run scan test using a filter to find a specific row based on it's value (make sure to use --rows=20)randomRead      Run random read testrandomSeekScan  Run random seek and scan 100 testrandomWrite     Run random write test scan            Run scan test (read every row) scanRange10     Run random seek scan with both start and stop row (max 10 rows) scanRange100    Run random seek scan with both start and stop row (max 100 rows) scanRange1000   Run random seek scan with both start and stop row (max 1000 rows) scanRange10000  Run random seek scan with both start and stop row (max 10000 rows)sequentialRead  Run sequential read testsequentialWrite Run sequential write testArgs:nclients        Integer. Required. Total number of clients (and HRegionServers)                 running: 1 <= value <= 500Examples: To run a single evaluation client: $ bin/hbaseorg.apache.hadoop.hbase.PerformanceEvaluationsequentialWrite 1

Hbase运维碎碎念