网易视频云:HBase GC的前生今世 – 演进篇
- 格式:docx
- 大小:236.24 KB
- 文档页数:6
hbase参数HBase 是一个分布式、面向列的开源数据库系统,建立在Apache Hadoop 上。
HBase 的性能和行为可以通过配置多个参数进行调整。
以下是一些常见的HBase 配置参数及其简要说明:1. .port:-描述: Master 的信息端口。
-默认值: 16010。
2. hbase.regionserver.global.memstore.upperLimit:-描述: RegionServer 上所有MemStore 的全局内存使用上限。
-默认值: 0.4。
3. hbase.hregion.memstore.flush.size:-描述: 单个Region 的MemStore 刷新阈值。
-默认值: 134217728(128MB)。
4. hbase.hregion.max.filesize:-描述: 单个HFile 的最大大小。
-默认值: 10737418240(10GB)。
5. hbase.hstore.flusher.count:-描述: 每个RegionServer 上的MemStore Flush 线程数量。
-默认值: 1。
6. paction.max.size:-描述: 每次compaction 的最大数据大小。
-默认值: 9223372036854775807(Long.MAX_VALUE)。
7. hbase.hregion.majorcompaction:-描述: Region 是否允许执行major compaction。
-默认值: true。
8. hbase.client.scanner.timeout.period:-描述: 客户端扫描操作的超时时间。
-默认值: 60000 毫秒(1 分钟)。
9. hbase.client.retries.number:-描述: 客户端操作的重试次数。
-默认值: 35。
10. hbase.rpc.timeout:-描述: RPC 请求的超时时间。
hbase的应用场景
HBase是一个分布式的非关系型数据库,其应用场景主要包括以下几个方面:
1. 大数据存储和处理:HBase可以存储PB级别的海量数据,并且支持快速的数据读写操作,可以作为大数据存储和处理平台的重要组成部分,例如企业级数据仓库、日志分析、搜索引擎等。
2. 实时数据处理:HBase可以实现实时的数据存储和查询,在实时数据处理场景下可以作为数据缓存和实时计算的基础组件,例如实时监控和分析系统、智能推荐系统等。
3. 协同过滤和推荐系统:HBase支持随机访问和列存储,可以快速查询和计算用户之间的相似度和兴趣偏好,可以作为协同过滤和推荐系统的底层存储和计算引擎。
4. 地理信息系统:HBase支持空间数据类型和空间索引,可以存储和查询大规模的地理空间数据,可以作为地理信息系统的底层存储和查询引擎。
5. 时序数据存储和分析:HBase支持时间戳的存储和查询,可以存储和查询大规模的时序数据,例如物联网数据、传感器数据、日志数据等。
总之,HBase适用于大规模数据存储和处理场景,具有高可靠性、高可扩展性和高性能的特点,是企业级大数据应用的重要组成部分。
- 1 -。
HBASE架构中各组件的功能作⽤⼀、HBASE结构图⼆、HBase架构中的客户端Client客户端有以下⼏点作⽤:1. 整个HBase集群的访问⼊⼝;2. 使⽤HBase RPC机制与HMaster和HRegionServer进⾏通信;3. 使⽤HMaster进⾏通信进⾏管理类操作;4. 与HRegionServer进⾏数据读写类操作;5. 包含访问HBase的接⼝,并维护cache来加快对HBase的访问。
三、协调服务组件ZookeeperZookeeper的作⽤如下:1. 保证任何时候,集群中只有⼀个HMaster;2. 存储所有的HRegion的寻址⼊⼝;3. 实时监控HRegionServer的上线和下线信息,并实时通知给HMaster;4. 存储HBase的schema和table元数据;5. Zookeeper Quorum存储-ROOT-表地址、HMaster地址。
四、主节点HMasterHMaster的主要功能如下:1. HMaster没有单节点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有⼀个Master在运⾏,主要负责Table和Region的管理⼯作。
如何启动多个HMaster?通过hbase-daemons.sh启动,步骤如下:1)在hbase/conf⽬录下编辑backup-masters;2)编辑内容为⾃⼰的主机名;3)保存后,执⾏如下命令:bin/hbase-daemons.sh start master-backup。
2. 管理⽤户对表的增删改查操作;3. 管理HRegionServer的负载均衡,调整Region分布(在命令⾏⾥⾯有⼀个tools,tools这个分组命令其实全部都是Master做的事情);4. Region Split后,负责新Region的分布;5. 在HRegionServer停机后,负责失效HRegionServer上Region迁移⼯作。
HBase使用例子(中文翻译)通过编码(java)的形式对HBase进行一系列的管理涉及到对表的管理、数据的操作等。
1、对表的创建、删除、显示以及修改等,可以用HBaseAdmin,一旦创建了表,那么可以通过HTable的实例来访问表,每次可以往表里增加数据。
2、插入数据创建一个Put对象,在这个Put对象里可以指定要给哪个列增加数据,以及当前的时间戳等值,然后通过调用HTable.put(Put)来提交操作,子猴在这里提请注意的是:在创建Put对象的时候,你必须指定一个行(Row)值,在构造Put对象的时候作为参数传入。
3、获取数据要获取数据,使用Get对象,Get对象同Put对象一样有好几个构造函数,通常在构造的时候传入行值,表示取第几行的数据,通过HTable.get(Get)来调用。
4、浏览每一行通过Scan可以对表中的行进行浏览,得到每一行的信息,比如列名,时间戳等,Scan相当于一个游标,通过next()来浏览下一个,通过调用HTable.getScanner(Scan)来返回一个ResultScanner对象。
HTable.get(Get)和HTable.getScanner(Scan)都是返回一个Result。
Result是一个KeyValue的链表,5、删除使用Delete来删除记录,通过调用HTable.delete(Delete)来执行删除操作。
(注:删除这里有些特别,也就是删除并不是马上将数据从表中删除。
)6、锁7、新增、获取、删除在操作过程中会对所操作的行加一个锁,而浏览却不会。
8、簇(cluster)的访问客户端代码通过ZooKeeper来访问找到簇,也就是说ZooKeeper quorum将被使用,那么相关的类(包)应该在客户端的类(classes)目录下,即客户端一定要找到文件hbase- site.xml。
下面是一个例子,假定你已经创建了一个表:myTable,还有一个column family(这个找不到合适的翻译词语):myColumnFamily:HBase是Hadoop的一个子项目,HBase采用了Google BigTable的稀疏的,面向列的数据库实现方式的理论,建立在hadoop的hdfs上,一方面里用了hdfs的高可靠性和可伸缩行,另外一方面里用了BigTable的高效数据组织形式.可以说HBase为海量数据的real-time相应提供了很好的一个开源解决方案.据说在某运营商中使用类似于BigTable(个人猜测应该就是HBase)的技术可以在两秒时间内从2TB数据中查找到某条话费记录.而这是原来该运营商使用Oracle数据库所无法解决的问题.对于HBase使用的类似与BigTable的技术我们这里就不仔细描述,可以参考google的论文以及网上的一些相关资料.另外,HBase的配置在HBase的官方文档中有很详细的描述.可以参见相关文档.HBase提供了一个类似于mysql等关系型数据库的shell.通过该shell我们可以对HBase的内的相关表以及列族进行控制和处理.HBase shell的help命令比较详细的列出了HBase所支持的命令.具体使用方法可以参见其文档.这里我们用一个学生成绩表作为例子,对HBase的基本操作和基本概念进行讲解:下面是学生的成绩表:name grad course:math course:artTom 1 87 97Jerry 2 100 80这里grad对于表来说是一个列,course对于表来说是一个列族,这个列族由两个列组成:math和art,当然我们可以根据我们的需要在course中建立更多的列族,如computer,physics等相应的列添加入course列族.有了上面的想法和需求,我们就可以在HBase中建立相应的数据表啦!1, 建立一个表格 scores 具有两个列族grad 和couresehbase(main):002:0> create 'scores', 'grade', 'course'0 row(s) in 4.1610 seconds2,查看当先HBase中具有哪些表hbase(main):003:0> listscores1 row(s) in 0.0210 seconds3,查看表的构造hbase(main):004:0> describe 'scores'{NAME => 'scores', IS_ROOT => 'false', IS_META => 'false', FAMILIES => [{NAME => 'course', BLOOMFILTER => 'false',IN_MEMORY => 'false', LENGTH => '2147483647', BLOCKCACHE => 'false', VERSIONS => '3', TTL => '-1', COMPRESSION => 'NONE'}, {NAME => 'grade', BLOOMFILTER => 'false', IN_MEMORY => 'false', LENGTH => '2147483647', BLOCKCACHE => 'false', VERSIONS => '3', TTL => '-1', COMPRESSION => 'NONE'}]}1 row(s) in 0.0130 seconds4, 加入一行数据,行名称为 Tom 列族grad的列名为””值位1hbase(main):005:0> put 'scores', 'Tom', 'grade:', '1'0 row(s) in 0.0070 seconds5,给Tom这一行的数据的列族添加一列 <math,87>hbase(main):006:0> put 'scores', 'Tom', 'course:math', '87'0 row(s) in 0.0040 seconds6,给Tom这一行的数据的列族添加一列 <art,97>hbase(main):007:0> put 'scores', 'Tom', 'course:art', '97'0 row(s) in 0.0030 seconds7, 加入一行数据,行名称为 Jerry 列族grad的列名为””值位2hbase(main):008:0> put 'scores', 'Jerry', 'grade:', '2'0 row(s) in 0.0040 seconds8,给Jerry这一行的数据的列族添加一列 <math,100>hbase(main):009:0> put 'scores', 'Jerry', 'course:math', '100'0 row(s) in 0.0030 seconds9,给Jerry这一行的数据的列族添加一列 <art,80>hbase(main):010:0> put 'scores', 'Jerry', 'course:art', '80' 0 row(s) in 0.0050 seconds10,查看scores表中Tom的相关数据hbase(main):011:0> get 'scores', 'Tom'COLUMN CELLcourse:art timestamp=1224726394286,value=97course:math timestamp=1224726377027,value=87grade: timestamp=1224726360727,value=13 row(s) in 0.0070 seconds11,查看scores表中所有数据hbase(main):012:0> scan 'scores'ROW COLUMN+CELLTom column=course:art,timestamp=1224726394286, value=97Tom column=course:math,timestamp=1224726377027, value=87Tom column=grade:,timestamp=1224726360727, value=1Jerry column=course:art,timestamp=1224726424967, value=80Jerry column=course:math,timestamp=1224726416145, value=100Jerry column=grade:,timestamp=1224726404965, value=26 row(s) in 0.0410 seconds12,查看scores表中所有数据courses列族的所有数据hbase(main):013:0> scan 'scores', ['course:']ROW COLUMN+CELLTom column=course:art,timestamp=1224726394286, value=97Tom column=course:math,timestamp=1224726377027, value=87Jerry column=course:art,timestamp=1224726424967, value=80Jerry column=course:math,timestamp=1224726416145, value=1004 row(s) in 0.0200 seconds上面就是HBase的基本shell操作的一个例子,可以看出,hbase的shell还是比较简单易用的,从中也可以看出HBase shell缺少很多传统sql 中的一些类似于like等相关操作,当然,HBase作为BigTable的一个开源实现,而BigTable是作为google业务的支持模型,很多sql语句中的一些东西可能还真的不需要.当然,通过程序我们也可以对HBase进行相关的操作.下面的程序就完成了上面shell操作的内容:import java.io.IOException;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.ByteArrayInputStream;import java.io.DataInputStream;import java.util.Map;import org.apache.hadoop.io.Writable;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.hbase.HBaseConfiguration;import org.apache.hadoop.hbase.HTableDescriptor;import org.apache.hadoop.hbase.HColumnDescriptor;import org.apache.hadoop.hbase.client.HBaseAdmin;import org.apache.hadoop.hbase.client.HTable;import org.apache.hadoop.hbase.io.BatchUpdate;import org.apache.hadoop.hbase.io.RowResult;import org.apache.hadoop.hbase.io.Cell;import org.apache.hadoop.hbase.util.Writables;public class HBaseBasic {public static void main(String[] args) throws Exception {HBaseConfiguration config = new HBaseConfiguration();HBaseAdmin admin = new HBaseAdmin(config);if (admin.tableExists("scores")) {System.out.println("drop table");admin.disableTable("scores");admin.deleteTable("scores");}System.out.println("create table");HTableDescriptor tableDescripter= newHTableDescriptor("scores".getBytes());tableDescripter.addFamily(newHColumnDescriptor("grade:")); tableDescripter.addFamily(newHColumnDescriptor("course:")) ;admin.createTable(tableDescripter);HTable table = new HTable(config, "scores");System.out.println("add Tom's data");BatchUpdate tomUpdate = new BatchUpdate("Tom");tomUpdate.put("grade:",Writables.getBytes(newIntWritable(1)));tomUpdate.put("course:math",Writables.getBytes(newIntWritable(87)));tomUpdate.put("course:art",Writables.getBytes(newIntWritable(97)));mit(tomUpdate);System.out.println("add Jerry's data");BatchUpdate jerryUpdate = new BatchUpdate("Jerry");jerryUpdate.put("grade:",Writables.getBytes(newIntWritable(2)));jerryUpdate.put("course:math",Writables.getBytes(newIntWritable(100)));jerryUpdate.put("course:art",Writables.getBytes(newIntWritable(80)));mit(jerryUpdate);for (RowResult row : table.getScanner(new String[] {"course:" })) {System.out.format("ROW\t%s\n", newString(row.getRow()) );for (Map.Entry<byte[], Cell> entry : row.entrySet()) { String column = new String(entry.getKey());Cell cell = entry.getValue();IntWritable value = new IntWritable();Writables.copyWritable(cell.getValue(), value);System.out.format(" COLUMN\t%s\t%d\n", column, value.get());}}}}输出如下:drop table09/07/11 08:51:59 INFO client.HBaseAdmin: Disabled scores 09/07/11 08:51:59 INFO client.HBaseAdmin: Deleted scores create tableadd Tom's dataadd Jerry's dataROW TomCOLUMN course:art 97COLUMN course:math 87ROW JerryCOLUMN course:art 80COLUMN course:math 100。
什么是HBase?HBase 介绍⼀、什么是HBase?1.HBase – Hadoop Database,是⼀个⾼可靠性、⾼性能、⾯向列、可伸缩、实时读写的分布式数据库2. HBASE是Google Bigtable的开源实现,但是也有很多不同之处。
⽐如:Google Bigtable使⽤GFS作为其⽂件存储系统,HBASE利⽤Hadoop HDFS作为其⽂件存储系统;Google运⾏MAPREDUCE来处理Bigtable中的海量数据,HBASE同样利⽤Hadoop MapReduce来处理HBASE中的海量数据;Google Bigtable利⽤Chubby作为协同服务,HBASE利⽤Zookeeper作为协同服务。
3.HBase是⼀个分布式存储、数据库引擎,可以⽀持千万的QPS、PB级别的存储,这些都已经在⽣产环境验证,并且在⼴⼤的公司已经验证。
特别是阿⾥(淘宝、天猫、蚂蚁⾦服)、⼩⽶⽶聊、⼩⽶云、⼩⽶推送服务)、京东、滴滴内部都有数千、上万台的HBase集群。
Hbase PMC。
阿⾥1个。
Hbase Committer。
阿⾥4个,⼩⽶4个。
2016年双11,HBase承载访问量达到了上百GB/秒(写⼊)与上百GB/秒(读取),相当于全国⼈民⼀秒收发⼀条短信,在业务记录、安全风控、实时计算、⽇志监控、消息聊天等多个场景发挥重要价值。
⼆、哪些是HBase的特点?1.存储数据量⼤:⼀个表可以有上亿⾏,上百万列。
2.⾯向列:⾯向列表(簇)的存储和权限控制,列(簇)独⽴检索。
3.稀疏:对于为空(NULL)的列,并不占⽤存储空间,因此,表可以设计的⾮常稀疏。
4.⽆模式:每⼀⾏都有⼀个可以排序的主键和任意多的列,列可以根据需要动态增加,同⼀张表中不同的⾏可以有截然不同的列。
5.数据多版本:每个单元中的数据可以有多个版本,默认情况下,版本号⾃动分配,版本号就是单元格插⼊时的时间戳。
6.数据类型单⼀:HBase中的数据都是字符串,没有类型。
Hbase的安装(详细步骤)Hbase的安装(详细步骤)1、前提条件1、得安装的有hdfs系统2、得安装zookeeper集群2、准备安装包下载安装包并上传到node01服务器安装包下载地址:将安装包上传到node01服务器/hc/softwares路径下,并进⾏解压[hadoop@node01 ~]$ cd /hc/soft/[hadoop@node01 soft]$ tar -zxvf hbase-2.2.6-bin.tar.gz -C /hc/install/3、修改Hbase配置⽂件3.1、修改hbase-env.sh⽂件修改⽂件[hadoop@node01 softwares]$ cd /hc/install/hbase-2.2.6/conf[hadoop@node01 conf]$ vim hbase-env.sh修改如下两项内容,值如下export JAVA_HOME=/hc/install/jdk1.8.0_141export HBASE_MANAGES_ZK=false3.2、修改hbase-site.xml⽂件修改⽂件[hadoop@node01 conf]$ vim hbase-site.xml内容如下<configuration><!-- 指定hbase在HDFS上存储的路径 --><property><name>hbase.rootdir</name><value>hdfs://node01:8020/hbase</value></property><!-- 指定hbase是否分布式运⾏ --><property><name>hbase.cluster.distributed</name><value>true</value></property><!-- 指定zookeeper的地址,多个⽤“,”分割 --><property><name>hbase.zookeeper.quorum</name><value>node01,node02,node03:2181</value></property><!--指定hbase管理页⾯--><property><name>.port</name><value>60010</value></property><!-- 在分布式的情况下⼀定要设置,不然容易出现Hmaster起不来的情况 --><property><name>hbase.unsafe.stream.capability.enforce</name><value>false</value></property></configuration>3.3、修改regionservers⽂件修改⽂件[hadoop@node01 conf]$ vim regionservers指定HBase集群的从节点;原内容清空,添加如下三⾏node01node02node033.4、修改back-masters⽂件创建back-masters配置⽂件,⾥边包含备份HMaster节点的主机名,每个机器独占⼀⾏,实现HMaster的⾼可⽤[hadoop@node01 conf]$ vim backup-masters将node02作为备份的HMaster节点,问价内容如下node024、分发安装包将 node01上的HBase安装包,拷贝到其他机器上[hadoop@node01 conf]$ cd /hc/install[hadoop@node01 install]$ scp -r hbase-2.2.6/ node02:/hc/install[hadoop@node01 install]$ scp -r hbase-2.2.6/ node03:/hc/install5、创建软连接注意:三台机器均做如下操作因为HBase集群需要读取hadoop的core-site.xml、hdfs-site.xml的配置⽂件信息,所以我们三台机器都要执⾏以下命令,在相应的⽬录创建这两个配置⽂件的软连接ln -s /hc/install/hadoop-3.1.4/etc/hadoop/core-site.xml /hc/install/hbase-2.2.6/conf/core-site.xmlln -s /hc/install/hadoop-3.1.4/etc/hadoop/hdfs-site.xml /hc/install/hbase-2.2.6/conf/hdfs-site.xml执⾏完后,出现如下效果,以node01为例6、添加HBase环境变量注意:三台机器均执⾏以下命令,添加环境变量sudo vim /etc/profile⽂件末尾添加如下内容export HBASE_HOME=/hc/install/hbase-2.2.6export PATH=$PATH:$HBASE_HOME/bin重新编译/etc/profile,让环境变量⽣效source /etc/profile7、HBase的启动与停⽌需要提前启动HDFS及ZooKeeper集群如果没开启hdfs,请在node01运⾏start-dfs.sh命令如果没开启zookeeper,请在3个节点分别运⾏zkServer.sh start命令第⼀台机器node01(HBase主节点)执⾏以下命令,启动HBase集群[hadoop@node01 ~]$ start-hbase.sh启动完后,jps查看HBase相关进程node01、node02上有进程HMaster、HRegionServernode03上有进程HRegionServer警告提⽰:HBase启动的时候会产⽣⼀个警告,这是因为jdk7与jdk8的问题导致的,如果linux服务器安装jdk8就会产⽣这样的⼀个警告可以注释掉所有机器的hbase-env.sh当中的“HBASE_MASTER_OPTS”和“HBASE_REGIONSERVER_OPTS”配置来解决这个问题。
目录1、前言........................................................................................ 错误!未定义书签。
2、Hbase的体系结构................................................................. 错误!未定义书签。
2.1 HBase的服务器体系结构......................................... 错误!未定义书签。
2.1.1 HBase的服务器的构架.................................. 错误!未定义书签。
2.1.2 数据的更新...................................................... 错误!未定义书签。
2、2 HRegion和HMaster的关系 .................................. 错误!未定义书签。
2.2.1 HMaster的主要任务....................................... 错误!未定义书签。
2.2.2 HMaster的管理............................................... 错误!未定义书签。
2.3逻辑视图........................................................................ 错误!未定义书签。
2.3.1 Row Key .......................................................... 错误!未定义书签。
2.3.2 列族.................................................................. 错误!未定义书签。
vcloud.163.com
网易视频云:HBase GC的前生今世–演进篇
网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技
术,为客户提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频
的PaaS服务。在线教育、远程医疗、娱乐秀场、在线金融等各行业及企业用户只需经过简
单的开发即可打造在线音视频平台。现在,网易视频云与大家分享一下HBase GC的前生
今世–演进篇。
最原始的HBase CMS GC相当严重,经常会因为碎片过多导致Promotion Failure,严重影
响业务的读写请求。幸运的是,HBase并没有止步不前,很多优化方案相继被提出并贡献
给社区,本文要介绍的就是几个比较重要的核心优化,分别是针对Memstore所作的两个优
化:Thread-Local Allocation Buffer和MemStore Chunk Pool 以及针对BlockCache所作
的优化:BuckctCache方案。在详细介绍这几个优化之前有必要简单介绍一下HBase GC
优化的目标,很直观的,第一是要尽量避免长时间的Full GC,避免影响用户的读写请求;
第二是尽量减少GC时间,提高读写性能;接着分别来看HBase针对GC所做的各种优化:
MemStore GC优化一- Thread-Local Allocation Buffer
HBase数据写入操作实际上并没有直接将数据写入磁盘,而是先写入内存并顺序写入HLog,
之后等待满足某个特定条件后统一将内存中的数据刷新到磁盘。一个RegionServer通常由
多个Region组成,每张Region通常包含一张表的多个列族,而每个列族对应一块内存区
域,这块内存被称为MemStore,很显然,一个RegionServer会由多个Region构成,一
个Region会由多个MemStore构成。
最原始的HBase版本存在很严重的内存碎片,经常会导致长时间的Full GC,其中最核心
的问题就出在MemStore这里。因为一个RegionServer由多个Region构成,不同Region
的数据写入到对应Memstore,在JVM看来其实是混合在一起写入Heap的,此时假如
Region1上对应的所有MemStore执行落盘操作,就会出现下图所示场景:
vcloud.163.com
为了优化这种内存碎片可能导致的Full GC,HBase借鉴了Arena Allocation内存管理方式,
它通过顺序化分配内存、内存数据分块等特性使得内存碎片更加粗粒度,有效改善Full GC
情况;
具体实现原理如下:
1. 每个MemStore会实例化出来一个MemStoreLAB
2. MemStoreLAB会申请一个2M大小的Chunk数组和一个Chunk偏移量,初始值为0
3. 当一个KeyValue值插入MemStore后,MemStoreLAB会首先通过KeyValue.getBuffer()
取得data数组,并将data数组复制到Chunk数组中,之后再将Chunk偏移量往前移动
data.length
4. 如果当前Chunk满了之后,再调用new byte[ 2 * 1024 * 1024]申请一个新的Chunk
很显然,通过申请2M大小的Chunk可以使得内存碎片更加粗粒度,官方在优化前后通过
设置 -xx:PrintFLSStatistics = 1 统计了老生代的Max Chunk Size分别随时间的变化曲线,
如下图所示:
vcloud.163.com
由上图可以看出,未优化前碎片会大量出现导致频繁的Full GC,优化后虽然依然会产生大
量碎片,但是最大碎片大小一直会维持在1e+08左右,极大地降低了Full GC频率。
MemStore GC优化二 – MemStore Chunk Pool
然而一旦一个Chunk写满之后,系统就会重新申请一个新的Chunk,这些Chunk大部分都
会经过多次YGC之后晋升到老生代,如果某个Chunk再没有被引用就会被JVM垃圾回收。
很显然,不断申请新的Chunk会导致YGC频率不断增多,YGC频率增加必然会导致晋升
到老生代的Chunk增多,进而增加CMS GC发生的频率。如果这些Chunk能够被循环利
用,系统就不需要申请新的Chunk,这样就会使得YGC频率降低,晋升到老生代的Chunk
就会减少,CMS GC发生的频率就会降低。这就是MemStore Chunk Pool的核心思想,具
体实现如下:
vcloud.163.com
1. 系统会创建一个Chunk Pool来管理所有未被引用的chunks,这些chunk就不会再被
JVM当作垃圾回收掉了
2. 如果一个Chunk没有再被引用,将其放入Chunk Pool
3. 如果当前Chunk Pool已经达到了容量最大值,就不会再接纳新的Chunk
4. 如果需要申请新的Chunk来存储KeyValue,首先从Chunk Pool中获取,如果能够获取
得到就重复利用,如果为null就重新申请一个新的Chunk
官方针对该优化也进行了简单的测试,使用jstat -gcutil对优化前后的JVM GC情况进行了
统计,具体的测试条件和测试结果如下所示:
很显然,经过优化后YGC时间降低了40+%左右,FGC的次数以及时间更是大幅下降。
BlockCache优化-BuckctCache方案
对于需要深入了解HBase针对BlockCache所做的GC优化的朋友,强烈建议首先阅读之
前的3篇BlockCache系列博文:part1 , part2 和 part3。文中重点介绍了BlockCache的
两种实现方案:LRUBlockCache和BucketCache。
其中LRUBlockCache是目前HBase的默认方案,这种方案会将内存区分为3个部分:
single-access区、mutil-access区以及in-memory区,一个Block块从HDFS中加载出来
之后首先放入signle区,后续如果有多次请求访问到这块数据的话,就会将这块数据移到
mutil-access区。随着Block数据从single-access区晋升到mutil-access区,基本就伴随
着对应的内存对象从young区到old区,晋升到old区的Block被淘汰后会变为内存垃圾,
vcloud.163.com
最终由CMS回收掉,CMS回收之后必然会产生大量的内存碎片,碎片空间一直累计就会
产生臭名昭著的Full GC。
为了减少频繁 CMS GC 产生的碎片问题,社区采纳了阿里开发者的新方案:BucketCache。
这种方案还是采用“将小碎片整理为大碎片”的思路,由程序在初始化的时候就申请了很多大
小为2M的Bucket,数据Block的Get/Cache动作只是对这片空间的访问/覆写,CMS碎
片会自然大大降低。BucketCache有三种工作模式:heap、offheap以及file,其中heap
模式表示将数据存储在JVM堆内存,offheap模式表示将数据Block存储到操作系统内存,
file模式表示将数据Block存储到类似于SSD的外部高速缓存上;很显然,offheap模式和
file模式根本没有将数据Block存在JVM堆内存,所以几乎不会出现Full GC,而heap模
式即使数据存储在JVM堆内存,也会因为内存由程序独立管理大大降低内存碎片。
针对BlockCache的两种实现方案,分别简单地对内存碎片产生情况和GC情况进行了统计,
结果如下:
从结果可以看出,BucketCache大大减少了碎片的产生,而且YGC和FGC时间也极大地
得到了改善。需要注意的是,此结论是在部分缓存未命中的情况下得出的,缓存全部命中的
场景结果会有所不同。
总结
vcloud.163.com
所有构建在JVM上的应用或多或少都会受到GC的影响,尤其对于大内存系统更是如此,
HBase也不例外。针对GC问题,一方面我们期待JVM能够做出更多地改进和优化,另一
方面,我们也可以从内存管理方面进行更多地探索,不断优化内存的使用。HBase在0.98
之后的版本还不断针对GC进行着优化,后续再进行补充!