HBase高级配置和调整(2)
七、配置列族的块缓存
? ? ? ?HBase支持使用块缓存来提高读性能。在进行扫描时,如果块缓存功能已启用并且仍有剩余的空间,从HDFS上的StoreFile中读取到的数据块就会被缓存在RegionServer的Java堆空间中,以便下一次访问同一块中的数据时可以直接访问缓存中的块。块缓存有助于减少数据检索时的磁盘I/O。
? ? ? ?块缓存可在表的列族一级进行配置。不同的列族可以有不同的缓存优先级,甚至还可以禁用块缓存。应用程序应根据数据规模和访问模式的不同而适当地利用这一缓存机制。
? ? ? ?查看该页面上的MemStore大小、块缓存大小、命中率等指标,从中可以发现一些有助于对集群进行调整的有用信息。如果块缓存的命中率非常低,可能就需要审查一下自己的表模式定义和数据访问模式,把那些总是同时被访问的列放在一起。使用Bloom Filter是另一种提高块缓存命中率的方法。如果出现了许多块驱逐(block eviction)的情形,那么就应该考虑增加块缓存的大小,以便可以存储更多的块。
?
九、客户端Scan类的设置? ? ? ?为了获得更好的读性能,除了服务器端调整之外,最重要的是调整客户端应用程序上Scan类的设置。正确的客户端Scan类设置会使Scan过程的效率得到大大的提高。而反过来说,错误的Scan类设置不仅会减缓Scan本身,而且会对整个RegionServer产生负面影响。因此,我们需要仔细配置客户端的Scan类设置。
? ? ? ?最重要的Scan类设置包括Scan缓存行数、Scan属性选择和Scan块缓存。
? ? ? ?1.为了在调用Scan类的next()方法时能读取到更多的行,需调高hbase.client.scanner.caching属性的值。
启动HBase Shellhbase(main):002:0> create 'table2', {NAME => 'f1'}, {NAME => 'f2', BLOOMFILTER => 'ROW'}, {NAME => 'f3', BLOOMFILTER => 'ROWCOL'}0 row(s) in 2.2160 secondshbase(main):003:0> describe 'table2'DESCRIPTION ENABLED true {NAME => 'table2', FAMILIES => [{NAME => 'f1', BLOOMFILTER => 'NONE', REPLICATION_SCOPE => '0', VERSIONS => '3', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => ' false', BLOCKCACHE => 'true'}, {NAME => 'f2', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => ' 3', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'fa lse', BLOCKCACHE => 'true'}, {NAME => 'f3', BLOOMFILTER => 'ROWCOL', REPLICATION_SCOPE => '0', VERSIONS => '3', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'f alse', BLOCKCACHE => 'true'}]} 1 row(s) in 0.0910 seconds? ? ? ?我们创建了一张表(table2),它带有三个列族(f1、f2和f3)。对于列族f1,我们未指定任何属性,所以其所有属性都是默认值。从上面的命令的结果可以看出,该列族的Bloom过滤器是禁用状态(BLOOMFILTER => 'NONE')。我们对f2指定了行级的Bloom过滤器(BLOOMFILTER => 'ROW'),对f3指定了行+列级的Bloom过滤器(BLOOMFILTER => 'ROWCOL')。
? ? ? ?如果启用了Bloom过滤器,HBase在创建StoreFile时就会给数据块添加Bloom过滤器。使用Bloom过滤器的目的是:使HBase能高效地找出一个StoreFile是否包含指定的行或单元格,而无需真正地加载该文件并扫描其数据块。Bloom过滤器有可能出现假阳性,这意味着一个查询虽然返回的是a row is contained in a file(某行包含在某个文件中),但实际上并没有包含。但Bloom过滤器不允许假阴性,因此如果一个查询返回a row is not in a file(某行不在某个文件中),那么该行就绝对不会在该文件中。
? ? ? ?在通常情况下,错误率是0.01(由io.storefile.bloom.error.rate设置来配置),因此Bloom过滤器报告某StoreFile包含某行但它实际并不包含的可能性是1%。若要减少错误率,需要使用更多的空间来存储Bloom过滤器。
? ? ? ?默认情况下,Bloom过滤器是禁用的,这意味着HBase在创建StoreFile时将不添加Bloom过滤器。Bloom过滤器要在列族级进行配置,可以启用行级或行+列级的Bloom过滤器。行级Bloom过滤器可以用来检查某行键是否包含在一个StoreFile中,而行+列级的Bloom过滤器可以告述HBase某个单元格否包含在一个StoreFile中。行+列级Bloom过滤器需要更多的磁盘空间,因为单元格的数量要远远大于行的数量。
? ? ? 即便是在启用了Bloom过滤器的时候,你可能也不会从各个不同的get操作上获得立竿见影的性能提升,因为HBase是并行读取数据的,其延迟来自于磁盘的I/O速度。然而,因为需加载的块数大大减少了,所以整体吞吐量会显著提高,特别是在重负载的集群上。
? ? ? ?使用Bloom过滤器的另一个优点是:它可以改善块缓存比。在启用了Bloom过滤器之后,HBase在读取客户端所请求的数据时需要加载的块数少了。因为无需加载不必要的数据块,所以那些含有客户端真正要查询的数据的数据块留在块缓存中的机会就会有更大。这就提升了整个集群的读性能。
? ? ? ?不足之处是:Bloom过滤器中的每个条目都要占用1字节的存储空间。如果单元格较小(例如,包括键/值信息开销在内20个字节),那么Bloom过滤器就将在文件中占用1/20。另一方面,如果平均单元格大小为1KB,Bloom过滤器也就只占文件大小的约1/1000。假设StoreFile为1GB,那么过滤器只需要1MB的存储空间。因此,建议在小型单元格列族中禁用Bloom过滤器,而在大中型单元格列族中一直启用Bloom过滤器。
? ? ? ?HBase支持行级和行+列级的Bloom过滤器。具体选择使用哪一种取决于你的数据访问模式。回过头来再看本例中的那个HStore,它只有一个StoreFile保存了row-D。在对row-D的单元格进行批处理更新后,就会出现这种情况。如果一行的大多数单元格都会在一起更新,那么行级过滤器就更适合。与此相反,就像例子中row-F,如果更新要分散在许多个StoreFile中,而且大多数StoreFile都包含有该行的部分信息,那么就建议使用行+列级的过滤器,因为它能够确定哪一个StoreFile包含了你所请求的该行的那一部分信息。但是,你还需要考虑数据读取的模式。很明显,如果你总是要读取整行的数据,那么行+列级过滤器就没有意义。例如:在加载整个row-F行时,RegionServer需要将所有四个StoreFile都加载进来。如果你的读取模式是只加载一行中的某几列(例如row-F在StoreFile 4中的那几列),那么行+列级过滤器就有用,因为RegionServer可以不用加载其他的StoreFile。
? ? ? ?需要注意的是:0.92之前版本的HBase的默认的HFile格式是HFile第1版,它对Bloom过滤器可容纳的最大元素数有限制。该最大值由io.storefile.bloom.max.keys属性来控制,默认是128M个键。如果StoreFile中的单元格太多,就可能会超过这个数量。为了减少Bloom过滤器中的键数,只能使用行级过滤器。
? ? ? ?Bloom过滤器是一种可提高集群整体性能的高效方法。行级过滤器在很多情况下都能发挥很好的作用,是你应该尝试的第一选择;只有在行级过滤器不适合你的使用方式时,才需要考虑行+列级过滤器。
? ? ? ?现有列族的Bloom Filter属性也可以在HBase Shell中通过alter命令来修改。该修改对此后创建的新StoreFile生效。
?