目录

RegionServer调整大小的经验法则

1.关于列族的数量

1.1.ColumnFamilies的基数

2.Rowkey设计

2.1.热点发现(Hotspotting)

2.2.单调增加行键/时间序列数据

2.3.尝试最小化行和列的大小

2.3.1.列族(Column Families)

2.3.2.属性(Attributes)

2.3.3.Rowkey Length

2.3.4.Byte Patterns

2.3.5.反向时间戳(Reverse Timestamps)

2.3.6.Rowkeys and ColumnFamilies

2.3.7.行键的不变性( Immutability of Rowkeys)

2.3.8.RowKey与区域分割之间的关系

2.4.版本数(Number of Versions)

2.4.1.最大版本数(Maximum Number of Versions)

2.4.2.最低版本数(Minimum Number of Versions)

2.5.支持的数据类型

2.5.1.Counters

2.6.Joins

2.7.生存时间Time To Live (TTL)

2.8.保留删除的单元格(Keeping Deleted Cells)

2.9.二级索引和备用查询路径

2.9.1.Filter Query

2.9.2.定期更新二级索引

2.9.3.双写二级索引

2.9.4.汇总表(Summary Tables)

2.9.5.协处理器二级索引(Coprocessor Secondary Index)

1.10.约束条件(Constraints)

1.11.模式设计案例研究

1.11.1.案例研究-日志数据和时间序列数据

1.11.3.Host In The Rowkey Lead Position

1.11.4.Timestamp, or Reverse Timestamp?

1.11.5.可变长度还是固定长度的行键?.

1.11.6.案例研究-类固醇的日志数据和时间序列数据

1.11.7.案例研究-Customer/Order

1.11.7.1.Single Table? Multiple Tables?

1.11.7.2.订单对象设计

1.11.8.案例研究-“Tall/Wide/Middle”模式设计

1.11.8.1.Rows vs. Versions

1.11.8.2.Rows vs. Columns

1.11.8.3.Rows as Columns

1.11.9.案例研究-列表数据

1.12.操作和性能配置选项

1.12.1.调整HBase服务器RPC处理

1.12.2.禁用Nagle for RPC

1.12.3.限制服务器故障影响

1.12.4.在服务器端进行优化以降低延迟

1.12.5.JVM调整.

1.12.5.1.调整JVM GC以降低收集延迟

1.12.5.2.操作系统级调整

1.13.特别案例

1.13.1.对于快速失败胜于等待的应用程序

1.13.2.对于可以容忍一些过时信息的应用程序

1.13.3.更多信息


RegionServer调整大小的经验法则

Lars Hofhansl撰写了一篇有关RegionServer内存大小调整的出色博客文章。 结果是您可能需要比您认为需要的更多的内存。 他探讨了区域大小,存储区大小,HDFS复制因子和其他要检查的因素的影响。

就我个人而言,除非您的工作负载非常繁重,否则我将把每台机器最多可与HBase一起使用的最大磁盘空间放在6T附近。 在这种情况下,Java堆应为32GB(20G区域,128M内存存储,其余为默认值)。— Lars Hofhanslhttp://hadoop-hbase.blogspot.com/2013/01/hbase-region-server-memory-sizing.html

1.关于列族的数量

HBase当前不能很好地处理超过两个或三个列族的任何事物,因此请保持架构中列族的数量少。 当前,刷新和压缩是在每个区域的基础上进行的,因此,如果一个列族承载着大量要进行刷新的数据,即使相邻族族携带的数据量很小,也将对其进行刷新。 当存在许多色谱柱系列时,冲洗和压实相互作用会导致大量不必要的 i/o(通过更改冲洗和压实以在每个色谱柱族的基础上解决)。 有关压缩的更多信息,请参见压缩(Compaction)。

如果可以,请尝试使用一个列族。 仅在数据访问通常是列范围的情况下才引入第二和第三列族。 也就是说,您查询一个列族或另一个列族,但通常一次都不查询。

1.1.ColumnFamilies的基数

在单个表中存在多个ColumnFamilies的地方,请注意基数(即行数)。 如果ColumnFamilyA有100万行,而ColumnFamilyB有10亿行,则ColumnFamilyA的数据可能会分布在许多地区(和RegionServers)。 这使得对ColumnFamilyA进行批量扫描的效率较低。

2.Rowkey设计

2.1.热点发现(Hotspotting)

HBase中的行按行键按字典顺序排序。 该设计针对扫描进行了优化,使您可以将相关行或将一起读取的行彼此靠近存储。 但是,设计不当的行键是引起热点的常见原因。 当大量客户端流量定向到群集的一个节点或仅几个节点时,就会发生热点。 此流量可能表示读取,写入或其他操作。 流量使负责托管该区域的单台计算机不堪重负,从而导致性能下降并可能导致区域不可用。 这也可能对由同一区域服务器托管的其他区域产生不利影响,因为该主机无法满足请求的负载。 设计数据访问模式非常重要,这样才能充分,均匀地利用群集。

为防止写入时出现热点,请设计行键,以使确实确实需要在同一区域中的行存在,但从更大的角度看,数据将被写入集群中的多个区域,而不是一次写入一个区域。 下面介绍了一些避免热点的常用技术,以及它们的一些优点和缺点。

Salting

从这种意义上讲,加盐与加密无关,而是指将随机数据添加到行密钥的开头。 在这种情况下,加盐是指在行键上添加一个随机分配的前缀,以使其排序不同于其他方式。 可能的前缀数量对应于您要分布数据的区域数量。 如果您在其他分布更均匀的行中反复出现一些“热”行键模式,则盐析会有所帮助。 考虑下面的示例,该示例表明加盐可以将写入负载分散到多个RegionServer上,并说明对读取的某些负面影响。

Example 11. Salting Example

假设您具有以下行键列表,并且对表进行了拆分,以使字母表中的每个字母都有一个区域。 前缀“ a”是一个区域,前缀“ b”是另一个区域。 在此表中,所有以'f'开头的行都在同一区域中。 本示例重点介绍具有以下键的行:

foo0001
foo0002
foo0003
foo0004

现在,假设您想将它们分布在四个不同的区域。 您决定使用四种不同的salts:a,b,c和d。 在这种情况下,这些字母前缀中的每一个都将位于不同的区域。 应用盐后,将改为使用以下行键。 由于您现在可以写入四个单独的区域,因此理论上您在写入时的吞吐量是所有写入相同区域时的吞吐量的四倍。

a-foo0003
b-foo0001
c-foo0004
d-foo0002

然后,如果您添加另一行,则会随机为其分配四个可能的salt值之一,并最终靠近现有行之一。

a-foo0003
b-foo0001
c-foo0003
c-foo0004
d-foo0002

由于此分配是随机的,因此,如果要按字典顺序检索行,则需要做更多的工作。 这样,盐化会尝试增加写入的吞吐量,但是会在读取期间增加成本。

Hashing

可以使用单向散列代替给定行,该散列将使给定的行始终使用相同的前缀“salted”,其方式是将负载分布在RegionServer上,但允许在读取过程中进行可预测性。 使用确定性哈希可以使客户端重建完整的行键,并使用Get操作正常检索该行。

Example 12. Hashing Example

给定上面盐化示例中的相同情况,您可以改为应用单向哈希,这将导致键为foo0003的行始终且可预测地接收到前缀。 然后,要检索该行,您将已经知道密钥。 您还可以优化事物,例如使某些对密钥始终位于同一区域。

Reversing the Key

防止热点(hotspotting )的第三个常见技巧是反转固定宽度或数字行键,以便最频繁更改(最低有效数字)的部分位于第一位。 这有效地使行键随机化,但牺牲了行排序属性。

参见https://communities.intel.com/community/itpeernetwork/datastack/blog/2013/11/10/discussion-on-designing-hbase-tables,,以及有关Phoenix项目中的article on Salted Tables,以及 有关避免热点的更多信息,请参见 HBASE-11682的注释。

2.2.单调增加行键/时间序列数据

在汤姆·怀特(Tom White)的《 Hadoop:权威指南》(O'Reilly)的HBase一章中,有一个优化注意事项,用于注意一种现象,在该现象中,导入过程与所有客户齐心协力地敲击桌子的一个区域 (因此是单个节点),然后移到下一个区域,依此类推。随着单调增加行键(即使用时间戳),这种情况将会发生。 请参见IKai Lan的漫画,内容是为什么在像BigTable的数据存储区中单调递增的行键会出现问题:单调递增的值是不好的。 可以通过将输入记录随机化为不按排序顺序来缓解单调递增键在单个区域上的堆积,但是通常最好避免使用时间戳或序列(例如1、2、3) 作为行键。

如果确实需要将时间序列数据上传到HBase,则应学习OpenTSDB作为成功的示例。 它的页面描述了它在HBase中使用的架构。 OpenTSDB中的密钥格式实际上是[metric_type] [event_timestamp],乍一看与以前关于不使用时间戳作为密钥的建议相矛盾。 但是,不同之处在于时间戳不在密钥的领先位置,而设计假设是存在数十个或数百个(或更多)不同的度量标准类型。 因此,即使连续输入数据流混合使用各种度量标准类型,Put也会分布在表中区域的各个点上。

有关一些行键设计示例,请参见schema.casestudies研究。

2.3.尝试最小化行和列的大小

在HBase中,值总是随其坐标一起运送; 当单元格值通过系统时,将始终伴随其行,列名和时间戳。 如果行名和列名很大,尤其是与单元格值的大小相比,则可能会遇到一些有趣的情况。 Marc Limotte在HBASE-3551的尾部描述了这种情况(推荐!)。 其中,由于单元值坐标很大,保存在HBase存储文件(StoreFile (HFile))上以方便随机访问的索引可能最终会占用HBase分配的RAM的大块。 上面引用的注释中的Mark表示建议增大块大小,以便存储文件索引中的条目以较大的间隔发生或修改表模式,从而使行和列名更小。 压缩还将使索引更大。 请在用户邮件列表中查看有关问题storefileIndexSize的线程。

在大多数情况下,低效率并不重要。 不幸的是,这是他们这样做的情况。 无论为ColumnFamilies,属性和行键选择了哪种模式,它们都可以在数据中重复数十亿次。

有关HBase内部存储数据的更多信息,请参见 keyvalue,以了解为什么这很重要。

2.3.1.列族(Column Families)

尝试使ColumnFamily名称尽可能小,最好是一个字符(例如,“ d”表示data/default)。

有关HBase内部存储数据的更多信息,请参见 KeyValue,以了解为什么这很重要。

2.3.2.属性(Attributes)

尽管详细的属性名称(例如“ myVeryImportantAttribute”)更易于阅读,但更喜欢将较短的属性名称(例如“ via”)存储在HBase中。

有关HBase内部存储数据的更多信息,请参见keyvalue,以了解为什么这很重要。

2.3.3.Rowkey Length

请将它们尽可能短地保留,以使它们仍可用于必需的数据访问(例如,Get与Scan)。 对于数据访问无用的短键并不比具有更好的获取/扫描属性的长键更好。 设计行键时需要权衡取舍。

2.3.4.Byte Patterns

长为8个字节。 您可以在这八个字节中存储最多18,446,744,073,709,551,615个无符号数。 如果将此数字存储为字符串-(假定每个字符一个字节),则需要将近3倍的字节。

下面是一些示例代码,您可以自己运行。

// long
//
long l = 1234567890L;
byte[] lb = Bytes.toBytes(l);
System.out.println("long bytes length: " + lb.length);   // returns 8String s = String.valueOf(l);
byte[] sb = Bytes.toBytes(s);
System.out.println("long as string length: " + sb.length);    // returns 10// hash
//
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(Bytes.toBytes(s));
System.out.println("md5 digest bytes length: " + digest.length);    // returns 16String sDigest = new String(digest);
byte[] sbDigest = Bytes.toBytes(sDigest);
System.out.println("md5 digest as string length: " + sbDigest.length);    // returns 26

不幸的是,使用类型的二进制表示形式会使您的数据难以在代码外部读取。 例如,这是在增加值时在shell 中看到的内容:

hbase(main):001:0> incr 't', 'r', 'f:q', 1
COUNTER VALUE = 1hbase(main):002:0> get 't', 'r'
COLUMN                                        CELLf:q                                          timestamp=1369163040570, value=\x00\x00\x00\x00\x00\x00\x00\x01
1 row(s) in 0.0310 seconds

shell程序会尽力打印字符串,在这种情况下,它决定只打印十六进制。 区域名称内的行键也会发生同样的情况。 如果您知道要存储的内容,可以这样做,但是如果可以将任意数据放在相同的单元格中,则可能也无法读取。 这是主要的权衡。

2.3.5.反向时间戳(Reverse Timestamps)

反向扫描API
HBASE-4811实现了一个API,可以反向扫描表或表中的范围,从而减少了为正向或反向扫描而优化架构的需求。 HBase 0.98和更高版本中提供了此功能。 有关更多信息,请参见 Scan.setReversed()。

数据库处理中的一个常见问题是快速找到值的最新版本。 使用反向时间戳作为键的一部分的技术可以在此问题的特殊情况下极大地帮助您。 该技术还可以在汤姆·怀特(Tom White)的《 Hadoop:权威指南》(O'Reilly)的HBase一章中找到,该技术包括将(Long.MAX_VALUE-timestamp)附加到任何密钥的末尾,例如 [key] [reverse_timestamp]。

通过执行[key]扫描并获取第一条记录,可以找到表中[key]的最新值。 由于HBase键是按排序顺序排列的,因此此键在[key]的任何较旧的行键之前进行排序,因此是第一个。

将使用此技术代替使用“版本号”,以“forever”(或很长时间)保留所有版本,并同时使用相同的“扫描”技术快速获取对任何其他版本的访问权限。

2.3.6.Rowkeys and ColumnFamilies

行键的作用域为ColumnFamilies。 因此,相同的行键可以存在于表中的每个ColumnFamily中而不会发生冲突。

2.3.7.行键的不变性( Immutability of Rowkeys)

行键不能更改。 可以在表中“更改”它们的唯一方法是删除行然后将其重新插入。 这是HBase dist-list上的一个相当普遍的问题,因此在第一次(and/or在插入大量数据之前)正确获取行键是值得的。

2.3.8.RowKey与区域分割之间的关系

如果您预先分割了表格,那么了解行键如何在区域边界上分布至关重要。 作为说明为什么如此重要的示例,请考虑使用可显示的十六进制字符作为键的开头位置的示例(例如,“ 0000000000000000”到“ ffffffffffffffff”)。 通过Bytes.split(这是在Admin.createTable(byte [] startKey,byte [] endKey,numRegions)中创建区域时使用的拆分策略)来运行10个区域的键范围将生成以下拆分...

48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48                                // 0
54 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10                 // 6
61 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -68                 // =
68 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -126  // D
75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 72                                // K
82 18 18 18 18 18 18 18 18 18 18 18 18 18 18 14                                // R
88 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -44                 // X
95 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -102                // _
102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102                // f

(请注意:引导字节在右侧列为注释。)鉴于第一个分割为'0',最后一个分割为'f',一切都很好,对吗? 没那么快。

问题在于所有数据都将在前两个区域和最后一个区域堆积,从而造成“lumpy”(可能还有“hot”)区域问题。 要了解原因,请参考ASCII Table。 “ 0”是字节48,而“ f”是字节102,但是字节值(字节58至96)之间存在巨大差异,该间隙永远不会出现在此键空间中,因为唯一的值是[0-9]和[af ]。 因此,中间区域将永远不会被使用。 为了使此示例键空间能够进行预拆分,需要自定义拆分定义(即,不依赖于内置拆分方法)。

第1课:通常,最佳做法是预先分割表,但是您需要以能够在键空间中访问所有区域的方式预先分割表。 尽管此示例演示了十六进制键空间的问题,但任何键空间都可能发生相同的问题。 了解您的数据。

第2课:虽然通常不建议这样做,但只要在键空间中可访问所有创建的区域,使用十六进制键(更常见的是可显示的数据)仍可与预分割表一起使用。

总结这个例子,下面是一个例子,说明如何为十六进制键预先创建适当的分割:

public static boolean createTable(Admin admin, HTableDescriptor table, byte[][] splits)
throws IOException {try {admin.createTable( table, splits );return true;} catch (TableExistsException e) {logger.info("table " + table.getNameAsString() + " already exists");// the table already exists...return false;}
}public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) {byte[][] splits = new byte[numRegions-1][];BigInteger lowestKey = new BigInteger(startKey, 16);BigInteger highestKey = new BigInteger(endKey, 16);BigInteger range = highestKey.subtract(lowestKey);BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions));lowestKey = lowestKey.add(regionIncrement);for(int i=0; i < numRegions-1;i++) {BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i)));byte[] b = String.format("%016x", key).getBytes();splits[i] = b;}return splits;
}

2.4.版本数(Number of Versions)

2.4.1.最大版本数(Maximum Number of Versions)

通过HColumnDescriptor为每个列系列配置了要存储的最大行版本数。 最大版本的默认值为1。这是一个重要的参数,因为如“Data Model”部分所述,HBase不会覆盖行值,而是按时间(和限定符)每行存储不同的值。 大型压缩期间将删除多余的版本。 取决于应用程序的需要,最大版本数可能需要增加或减少。

不建议将最大版本数设置为过高的级别(例如,数百个或更多),除非您非常喜欢那些旧值,因为这会大大增加StoreFile的大小。

2.4.2.最低版本数(Minimum Number of Versions)

与最大行版本数一样,通过HColumnDescriptor为每个列系列配置要保留的最小行版本数。 最低版本的默认值为0,这表示该功能已禁用。 最小行版本数参数与生存时间参数一起使用,并且可以与行版本数参数结合使用,以进行诸如“保留最后T分钟的数据,最多N个版本, 至少保留M个版本”(其中M是最小行版本数的值,M <N)。 仅当为列族启用生存时间时才应设置此参数,并且该参数必须小于行版本的数目。

2.5.支持的数据类型

HBase通过Put和Result支持“ bytes-in / bytes-out”接口,因此任何可以转换为字节数组的内容都可以存储为值。 输入可以是字符串,数字,复杂对象甚至是图像,只要它们可以呈现为字节即可。

值的大小有实际限制(例如,在HBase中存储10-50MB对象可能会要求太多); 在邮件列表中搜索有关此主题的对话。 HBase中的所有行均符合数据模型(Data Model),其中包括版本控制。 设计时要考虑到这一点,以及ColumnFamily的块大小。

2.5.1.Counters

需要特别提及的一种受支持的数据类型是“计数器(counters)”(即进行原子原子递增数字的能力)。 请参阅表中的Increment

计数器同步是在RegionServer上完成的,而不是在客户端上完成的。

2.6.Joins

如果您有多个表,请不要忘记将Joins纳入架构设计的可能性。

2.7.生存时间Time To Live (TTL)

ColumnFamilies可以设置以秒为单位的TTL长度,并且一旦达到到期时间,HBase将自动删除行。 这适用于一行的所有版本-甚至是当前版本。 在HBase中为该行编码的TTL时间以UTC指定。

较小的压缩会删除仅包含过期行的存储文件。 将hbase.store.delete.expired.storefile设置为false将禁用此功能。 将最小版本数设置为非0也会禁用此功能。

有关更多信息,请参见HColumnDescriptor。

HBase的最新版本还支持设置每个单元的生存时间。 有关更多信息,请参见HBASE-10560。 单元TTL使用Mutation#setTTL作为突变请求(追加,增量,放置等)的属性提交。 如果设置了TTL属性,它将应用于通过该操作在服务器上更新的所有单元。 单元TTL处理和ColumnFamily TTL之间有两个显着区别:

  • 单元TTL以毫秒为单位而不是秒。
  • 单元TTL无法将单元的有效寿命延长到ColumnFamily级别TTL设置之外。

2.8.保留删除的单元格(Keeping Deleted Cells)

默认情况下,删除标记可追溯到时间的开始。 因此,即使“获取”或“扫描”操作指示放置删除标记之前的时间范围,“获取”或“扫描”操作也不会看到已删除的单元格(行或列)。

ColumnFamilies可以选择保留已删除的单元格。 在这种情况下,只要这些操作指定的时间范围在影响该单元格的任何删除的时间戳记之前结束,仍可以检索已删除的单元格。 即使存在删除操作,这也可以进行时间点查询。

删除的单元格仍然受TTL的约束,并且删除的单元格永远不会超过“最大版本数”。 新的“原始”扫描选项将返回所有已删除的行和删除标记。

使用HBase Shell更改KEEP_DELETED_CELLS的值

hbase> hbase> alter ‘t1′, NAME => ‘f1′, KEEP_DELETED_CELLS => true

例13.使用API更改KEEP_DELETED_CELLS的值

...
HColumnDescriptor.setKeepDeletedCells(true);
...

让我们说明在表上设置KEEP_DELETED_CELLS属性的基本效果。

首先,没有:

create 'test', {NAME=>'e', VERSIONS=>2147483647}
put 'test', 'r1', 'e:c1', 'value', 10
put 'test', 'r1', 'e:c1', 'value', 12
put 'test', 'r1', 'e:c1', 'value', 14
delete 'test', 'r1', 'e:c1',  11hbase(main):017:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                              COLUMN+CELLr1                                              column=e:c1, timestamp=14, value=valuer1                                              column=e:c1, timestamp=12, value=valuer1                                              column=e:c1, timestamp=11, type=DeleteColumnr1                                              column=e:c1, timestamp=10, value=value
1 row(s) in 0.0120 secondshbase(main):018:0> flush 'test'
0 row(s) in 0.0350 secondshbase(main):019:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                              COLUMN+CELLr1                                              column=e:c1, timestamp=14, value=valuer1                                              column=e:c1, timestamp=12, value=valuer1                                              column=e:c1, timestamp=11, type=DeleteColumn
1 row(s) in 0.0120 secondshbase(main):020:0> major_compact 'test'
0 row(s) in 0.0260 secondshbase(main):021:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                              COLUMN+CELLr1                                              column=e:c1, timestamp=14, value=valuer1                                              column=e:c1, timestamp=12, value=value
1 row(s) in 0.0120 seconds

注意如何释放删除单元格。

现在,仅在表上设置了KEEP_DELETED_CELLS的情况下运行相同的测试(您可以进行表或每个列的家庭):

hbase(main):005:0> create 'test', {NAME=>'e', VERSIONS=>2147483647, KEEP_DELETED_CELLS => true}
0 row(s) in 0.2160 seconds=> Hbase::Table - test
hbase(main):006:0> put 'test', 'r1', 'e:c1', 'value', 10
0 row(s) in 0.1070 secondshbase(main):007:0> put 'test', 'r1', 'e:c1', 'value', 12
0 row(s) in 0.0140 secondshbase(main):008:0> put 'test', 'r1', 'e:c1', 'value', 14
0 row(s) in 0.0160 secondshbase(main):009:0> delete 'test', 'r1', 'e:c1',  11
0 row(s) in 0.0290 secondshbase(main):010:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                                                                          COLUMN+CELLr1                                                                                          column=e:c1, timestamp=14, value=valuer1                                                                                          column=e:c1, timestamp=12, value=valuer1                                                                                          column=e:c1, timestamp=11, type=DeleteColumnr1                                                                                          column=e:c1, timestamp=10, value=value
1 row(s) in 0.0550 secondshbase(main):011:0> flush 'test'
0 row(s) in 0.2780 secondshbase(main):012:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                                                                          COLUMN+CELLr1                                                                                          column=e:c1, timestamp=14, value=valuer1                                                                                          column=e:c1, timestamp=12, value=valuer1                                                                                          column=e:c1, timestamp=11, type=DeleteColumnr1                                                                                          column=e:c1, timestamp=10, value=value
1 row(s) in 0.0620 secondshbase(main):013:0> major_compact 'test'
0 row(s) in 0.0530 secondshbase(main):014:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                                                                          COLUMN+CELLr1                                                                                          column=e:c1, timestamp=14, value=valuer1                                                                                          column=e:c1, timestamp=12, value=valuer1                                                                                          column=e:c1, timestamp=11, type=DeleteColumnr1                                                                                          column=e:c1, timestamp=10, value=value
1 row(s) in 0.0650 seconds

KEEP_DELETED_CELLS是避免将单元格从HBase删除的唯一原因是删除标记。 因此,启用KEEP_DELETED_CELLS后,如果您编写的版本超过配置的最大值,或者您拥有TTL并且单元格超出配置的超时时间,则删除的单元格将被删除。

2.9.二级索引和备用查询路径

该部分的标题也可能是“如果我的表行键看起来像这样,但我也想像这样查询我的表该怎么办”。 dist列表上的一个常见示例是其中行键的格式为“ user-timestamp”,但是对于特定时间范围内的用户活动有报告要求。 因此,由用户进行选择很容易,因为它处于键的引导位置,而时间却不然。

解决这个问题的最佳方法没有一个答案,因为这取决于...

  • 用户数
  • 数据大小和数据到达率
  • 报表要求的灵活性(例如,完全临时的日期选择与预先配置的范围)
  • 所需的查询执行速度(例如,对于某些临时报告,90秒对于某些人来说可能是合理的,而对于另一些报告则可能太长)

解决方案还受群集大小以及必须在解决方案上投入多少处理能力的影响。 常见技术在下面的小节中。 这是方法的综合列表,但并不详尽。

二级索引需要额外的群集空间和处理也就不足为奇了。 这正是RDBMS中发生的情况,因为创建备用索引的操作需要空间和处理周期来进行更新。 RDBMS产品在这方面更先进,可以立即处理替代索引管理。 但是,HBase在较大数据量时可更好地扩展,因此这是一个功能折衷。

实施任何一种方法时,请注意Apache HBase Performance Tuning。

此外,请在此dist-list线程HBase中查看David Butler的响应,邮件 HBase, mail # user - Stargate+hbase

2.9.1.Filter Query

根据情况,使用客户端请求过滤器可能是合适的。 在这种情况下,不会创建二级索引。 但是,请勿尝试从应用程序(即单线程客户端)对大型表进行完全扫描。

2.9.2.定期更新二级索引

可以在另一个表中创建二级索引,该表通过MapReduce作业定期更新。 该作业可以在一天之内执行,但是根据负载策略,它仍可能与主数据表不同步。

有关更多信息,请参见mapreduce.example.readwrite。

2.9.3.双写二级索引

另一种策略是在将数据发布到集群时构建辅助索引(例如,写入数据表,写入索引表)。 如果在已存在数据表之后采用这种方法,则对于具有MapReduce作业的辅助索引,将需要进行引导(请参见secondary.indexes.periodic)。

2.9.4.汇总表(Summary Tables)

在时间范围很广的地方(例如,长达一年的报告),并且数据量很大,因此汇总表是一种常见的方法。 这些将通过MapReduce作业生成到另一个表中。

有关更多信息,请参见mapreduce.example.summary。

2.9.5.协处理器二级索引(Coprocessor Secondary Index)

协处理器的行为类似于RDBMS触发器。 这些以0.92添加。 有关更多信息,请参见协处理器(coprocessors)。

1.10.约束条件(Constraints)

HBase当前在传统(SQL)数据库中支持“约束”。 约束的建议用法是针对表中的属性执行业务规则(例如,确保值在1到10的范围内)。 约束也可以用于强制执行参照完整性,但是强烈建议不要这样做,因为它将大大降低启用完整性检查的表的写吞吐量。 从0.94版开始,可以在Constraint上找到有关使用 Constraint的大量文档。

1.11.模式设计案例研究

面将描述一些使用HBase的典型数据摄取用例,以及如何进行行键设计和构造。 注意:这仅是潜在方法的说明,而不是详尽的清单。 了解您的数据,并了解您的处理要求。

强烈建议您在阅读这些案例研究之前,先阅读HBase and Schema Design的其余部分。

描述了以下案例研究:

  • Log Data / Timeseries Data
  • Log Data / Timeseries on Steroids
  • Customer/Order
  • Tall/Wide/Middle Schema Design
  • List Data

1.11.1.案例研究-日志数据和时间序列数据

假设正在收集以下数据元素。

  • Hostname
  • Timestamp
  • Log event
  • Value/message

我们可以将它们存储在名为LOG_DATA的HBase表中,但是行键是什么? 从这些属性中,行键将是主机名,时间戳和日志事件的某种组合-但是具体是什么?

1.11.2.Rowkey引导位置的时间戳

所述rowkey[时间戳] [主机名] [登录事件]从单调递增行键/时间序列资料中描述的单调递增rowkey问题的困扰。

通过在时间戳上执行mod操作,在dist列表中经常提到另一种关于“存储桶”时间戳的模式。 如果面向时间的扫描很重要,那么这可能是一种有用的方法。 必须注意存储桶的数量,因为这将需要相同数量的扫描才能返回结果。

long bucket = timestamp % numBuckets;

构造:

[bucket][timestamp][hostname][log-event]

如上所述,要为特定时间范围选择数据,将需要为每个存储桶执行一次扫描。 例如,100个存储桶将在键空间中提供广泛的分布,但是需要100次扫描才能获取单个时间戳的数据,因此需要权衡取舍。

1.11.3.Host In The Rowkey Lead Position

如果有大量主机在键空间上分布写操作和读操作,则行键[hostname] [log-event] [timestamp]是候选对象。 如果按主机名扫描是优先级,则此方法将很有用。

1.11.4.Timestamp, or Reverse Timestamp?

如果最重要的访问路径是提取最新事件,则将时间戳存储为反向时间戳(例如,时间戳= Long.MAX_VALUE –时间戳)将创建能够对[hostname] [log- 事件],以获取最近捕获的事件。

两种方法都没有错,仅取决于最适合这种情况的方法。

反向扫描API
HBASE-4811实现了一个API,可以反向扫描表或表中的范围,从而减少了为正向或反向扫描而优化架构的需求。 HBase 0.98和更高版本中提供了此功能。 有关更多信息,请参见 Scan.setReversed()。

1.11.5.可变长度还是固定长度的行键?.

重要的是要记住,行键标记在HBase的每一列上。 如果主机名是a并且事件类型是e1,则结果行键将非常小。 但是,如果提取的主机名是myserver1.mycompany.com,事件类型是com.package1.subpackage2.subsubpackage3.ImportantService,该怎么办?

在行键中使用某些替换可能很有意义。 至少有两种方法:散列和数字。 在“ Rowkey Lead Position中的主机名”示例中,可能看起来像这样:

带有哈希的复合行键:

  • [MD5 hash of hostname] = 16 bytes
  • [MD5 hash of event-type] = 16 bytes
  • [timestamp] = 8 bytes

带有数字替换的复合行键:

对于这种方法,除了LOG_DATA外,还需要另一个查询表,称为LOG_TYPES。 LOG_TYPES的行键为:

  • [type] (e.g., byte indicating hostname vs. event-type)

  • [bytes] variable length bytes for raw hostname or event-type.

此行键的列可以是带有指定数字的长整数,可以通过使用HBase计数器获得该数字

因此,生成的复合行键将为:

  • [substituted long for hostname] = 8 bytes
  • [substituted long for event type] = 8 bytes
  • [timestamp] = 8 bytes

在散列或数字替换方法中,主机名和事件类型的原始值可以存储为列。

1.11.6.案例研究-类固醇的日志数据和时间序列数据

这实际上是OpenTSDB方法。 OpenTSDB所做的是重写数据并将行在某些时间段内打包到列中。 有关详细说明,请参见: http://opentsdb.net/schema.html,以及Lessons Learned from OpenTSDB中获得的经验教训。

但这就是一般概念的工作原理:例如以这种方式摄取数据...

[hostname][log-event][timestamp1]
[hostname][log-event][timestamp2]
[hostname][log-event][timestamp3]

每个详细事件都有单独的行键,但是像这样重写...

[hostname][log-event][timerange]

并将上述每个事件转换为以相对于开始时间范围的时间偏移(例如每5分钟)存储的列。 这显然是一种非常先进的处理技术,但是HBase使这成为可能。

1.11.7.案例研究-Customer/Order

假定HBase用于存储客户和订单信息。 提取了两种核心记录类型:客户记录类型和订单记录类型。

客户记录类型将包括您通常期望的所有内容:

  • Customer number
  • Customer name
  • Address (e.g., city, state, zip)
  • Phone numbers, etc.

订单记录类型将包括以下内容:

  • Customer number
  • Order number
  • Sales date
  • A series of nested objects for shipping locations and line-items (see Order Object Design for details)

假设客户编号和销售订单的组合唯一地标识了一个订单,那么这两个属性将组成行键,特别是一个组合键,例如:

[customer number][order number]

用于ORDER表。 但是,还有更多的设计决策:原始值是行键的最佳选择吗?

日志数据用例中的相同设计问题在这里也面临着我们。 客户编号的键空间是什么,格式是什么(例如,数字?字母数字?),因为在HBase中使用固定长度的键以及可以在键空间中支持合理分布的键是有利的,类似 选项出现:

带有哈希的复合行键:

  • [MD5 of customer number] = 16 bytes
  • [MD5 of order number] = 16 bytes

复合数字/哈希组合行键:

  • [substituted long for customer number] = 8 bytes
  • [MD5 of order number] = 16 bytes

1.11.7.1.Single Table? Multiple Tables?

传统的设计方法将为客户和销售提供单独的表格。 另一种选择是将多种记录类型打包到一个表中(例如CUSTOMER ++)。

客户记录类型行键:

  • [customer-id]
  • [type] = type indicating `1' for customer record type

订单记录类型行键:

  • [customer-id]
  • [type] = type indicating `2' for order record type
  • [order]

这种特定的CUSTOMER ++方法的优点是,可以通过客户ID组织许多不同的记录类型(例如,一次扫描可以为您提供有关该客户的所有信息)。 缺点是扫描特定记录类型不那么容易。

1.11.7.2.订单对象设计

现在我们需要解决如何对Order对象建模。 假定类结构如下:

Order

一个订单可以有多个发运地点

LineItem

一个ShippingLocation可以有多个LineItem

存储此数据有多种选择。

完全规范化

通过这种方法,有将是订单,SHIPPING_LOCATION和LINE_ITEM单独的表。

上面介绍了ORDER表的行键:schema.casestudies.custorder

SHIPPING_LOCATION的复合行键如下所示:

  • [order-rowkey]

  • [shipping location number] (e.g., 1st location, 2nd, etc.)

LINE_ITEM表的复合行键如下所示:

  • [order-rowkey]

  • [shipping location number] (e.g., 1st location, 2nd, etc.)

  • [line item number] (e.g., 1st lineitem, 2nd, etc.)

这种标准化的模型可能是RDBMS的方法,但这并不是HBase的唯一选择。 这种方法的缺点是要检索有关任何订单的信息,您将需要:

  • 进入订单的ORDER表
  • 在SHIPPING_LOCATION表上扫描该订单以获取ShippingLocation实例
  • 在LINE_ITEM上扫描每个送货地点

当然,这是RDBMS会在后台进行的操作,但是由于HBase中没有联接,因此您只需要了解这一事实。

具有记录类型的单表

使用这种方法,将存在一个单个表ORDER,其中包含

订单行键已在上面进行了描述:schema.casestudies.custorder

  • [order-rowkey]

  • [ORDER record type]

ShippingLocation复合行键将如下所示:

  • [order-rowkey]

  • [SHIPPING record type]

  • [shipping location number] (e.g., 1st location, 2nd, etc.)

LineItem复合行键将如下所示:

  • [order-rowkey]

  • [LINE record type]

  • [shipping location number] (e.g., 1st location, 2nd, etc.)

  • [line item number] (e.g., 1st lineitem, 2nd, etc.)

非正规化

“带有记录类型的单表”方法的一种变体是对某些对象层次结构进行规范化和扁平化,例如将ShippingLocation属性折叠到每个LineItem实例上。

LineItem复合行键将如下所示:

  • [order-rowkey]

  • [LINE record type]

  • [line item number] (e.g., 1st lineitem, 2nd, etc., care must be taken that there are unique across the entire order)

而LineItem列将如下所示:

  • itemNumber

  • quantity

  • price

  • shipToLine1 (denormalized from ShippingLocation)

  • shipToLine2 (denormalized from ShippingLocation)

  • shipToCity (denormalized from ShippingLocation)

  • shipToState (denormalized from ShippingLocation)

  • shipToZip (denormalized from ShippingLocation)

这种方法的优点是对象层次结构不太复杂,但是缺点之一是万一这些信息发生更改,更新就会变得更加复杂。

Object BLOB

过这种方法,整个Order对象图以一种或另一种方式被视为BLOB。例如,上面描述了ORDER表的行键:schema.casestudies.custorder,以及称为“ order”的单个列将包含可以反序列化的对象,其中包含容器Order,ShippingLocations和LineItems。

这里有很多选项:JSON,XML,Java序列化,Avro,Hadoop可写文件等。它们都是相同方法的变体:将对象图编码为字节数组。如果对象模型发生更改,以确保仍可以从HBase中读取较旧的持久化结构,则应谨慎使用此方法以确保向后兼容。

专业人士能够以最少的I / O管理复杂的对象图(例如,在此示例中为单个“每个订单获取HBase Get”),但缺点包括上述警告,说明了序列化的向后兼容性,序列化的语言依赖性(例如Java序列化)仅适用于Java客户端),必须对整个对象进行反序列化以在BLOB中获取任何信息这一事实,以及使诸如Hive之类的框架无法与此类自定义对象一起使用的困难。

1.11.8.案例研究-“Tall/Wide/Middle”模式设计

本节将描述出现在dist列表中的其他模式设计问题,特别是关于高表和宽表的问题这些是一般的指导方针,而不是法律——每个申请都必须考虑到自己的需要。

1.11.8.1.Rows vs. Versions

一个常见的问题是,应该选择行还是HBase的内置版本控制上下文通常是要保留行的“a lot”版本(例如,它明显高于hbase默认的最大版本数1)。rows方法需要在rowkey的某些部分存储时间戳,这样它们就不会在每次连续更新时被覆盖。

首选项:Rows (一般来说)。

1.11.8.2.Rows vs. Columns

另一个常见的问题是一个人应该更喜欢行还是列上下文通常是在宽表的极端情况下出现的,例如有1行有100万个属性,或者有100万行有1列。

首选项:Rows(一般来说)要清楚的是,这条准则是在非常广泛的情况下使用的,而不是在需要存储几十列或几百列的标准用例中使用的。但在这两个选项之间也有一个中间路径,那就是“Rows as Columns”

1.11.8.3.Rows as Columns

行与列之间的中间路径是将某些行的单独行打包到列中opentsdb是这种情况的最佳示例,其中一行表示定义的时间范围,然后将离散事件视为列。这种方法通常更复杂,并且可能需要重新编写数据的附加复杂性,但具有I/O高效的优点。有关此方法的概述,请参见schema.casestudies.log-steroids。

1.11.9.案例研究-列表数据

下面是用户dist列表中关于一个相当常见的问题的交换:如何在apache hbase中处理每个用户的列表数据。

  • QUESTION *

我们正在研究如何在hbase中存储大量(每个用户)列表数据,并试图找出最合理的访问模式。一种选择是将大部分数据存储在一个密钥中,这样我们就可以得到如下内容:

<FixedWidthUserName><FixedWidthValueId1>:"" (no value)
<FixedWidthUserName><FixedWidthValueId2>:"" (no value)
<FixedWidthUserName><FixedWidthValueId3>:"" (no value)

我们的另一个选择是完全使用:

<FixedWidthUserName><FixedWidthPageNum0>:<FixedWidthLength><FixedIdNextPageNum><ValueId1><ValueId2><ValueId3>...
<FixedWidthUserName><FixedWidthPageNum1>:<FixedWidthLength><FixedIdNextPageNum><ValueId1><ValueId2><ValueId3>...

其中每一行将包含多个值。因此,在一个案例中,读取前30个值将是:

scan { STARTROW => 'FixedWidthUsername' LIMIT => 30}

在第二种情况下

get 'FixedWidthUserName\x00\x00\x00\x00'

通常的使用模式是只读取这些列表的前30个值,而很少的访问会更深入地读取列表。在这些列表中,某些用户的总价值为30英镑,而某些用户的百万价值(即幂律分布)

单值格式似乎会在HBase上占用更多空间,但会提供一些改进的检索/分页灵活性。通过获取进行分页与通过扫描进行分页是否会有任何显着的性能优势?

我最初的理解是,如果我们的分页大小未知(并且缓存设置适当),则扫描应该更快,但是如果我们始终需要相同的页面大小,则扫描应该更快。我最终听到不同的人告诉我有关性能的相反的话。我假设页面大小相对一致,因此对于大多数用例,我们可以保证在固定页面长度的情况下只需要一页数据。我还假设我们不会进行频繁的更新,但是可能会在这些列表的中间插入(这意味着我们需要更新所有后续行)。

感谢您的帮助/建议/后续问题。

  • ANSWER *

如果我对您的理解正确,那么您最终将尝试以“用户,valueid,值”的形式存储三元组,对吗? 例如:

"user123, firstname, Paul",
"user234, lastname, Smith"

(但是用户名是固定宽度,而valueid是固定宽度)。

而且,您的访问模式如下:“对于用户X,列出接下来的30个值,以valueid Y开头”。那正确吗?而这些值应该按valueid排序返回?

tl; dr版本是,您应该每个用户+值只包含一行,并且除非您确实确定需要,否则不要自己构建复杂的行内分页方案。

您的两个选择反映了人们在设计HBase模式时遇到的一个常见问题:我应该“高”还是“宽”?您的第一个架构是“高层”:每一行代表一个用户一个值,因此表中有很多行针对每个用户;行键是用户+ valueid,并且(大概)将有一个单列限定符,表示“值”。如果您要按行键按排序顺序扫描行(这是我上面的问题,关于这些ID是否正确排序),这很好。您可以在任何用户名+值id处开始扫描,然后读取下一个30,然后完成扫描。您要放弃的是能够为一位用户在所有行上拥有交易担保,但这听起来并不是您需要的。通常建议以这种方式进行操作(请参见此处https://hbase.apache.org/book.html#schema.smackdown)。

您的第二个选项是“宽”:使用不同的限定词(其中的限定词是valueid)将一堆值存储在一行中。这样做的简单方法是只将一个用户的所有值存储在一行中。我猜您跳到了“分页”版本,因为您假设在单行中存储数百万列会降低性能,这可能是正确的,也可能不是正确的。只要您不想在单个请求中尝试执行太多操作,或者执行诸如扫描并返回该行中所有单元格之类的操作,从根本上讲,这应该不会更糟。客户端具有允许您获取特定列列的方法。

请注意,两种情况从根本上都不比另一种情况使用更多的磁盘空间。您只是将标识信息的一部分“左移”(左移(在选项一中,移到行键中)或右)(移入选项2的列限定符中)。在幕后,每个键/值仍存储整个行键和列族名称。 (如果这有点令人困惑,请花一个小时,观看Lars George的精彩视频,内容涉及了解HBase架构设计: http://www.youtube.com/watch?v=_HLoH_PgrLk)。

如您所注意到的,手动分页版本具有更多的复杂性,例如必须跟踪每个页面中有多少东西,如果插入新值则需要重新排序等等。这似乎要复杂得多。在极高的吞吐量下,它可能具有一些轻微的速度优势(或劣势!),要真正知道这一点,唯一的方法就是尝试一下。如果您没有时间进行双向构建和比较,我的建议是从最简单的选项开始(每个用户+值一行)。从简单开始并进行迭代! :)

1.12.操作和性能配置选项

1.12.1.调整HBase服务器RPC处理

  • 设置hbase.regionserver.handler.count(在HBase的-site.xml中)到核心X主轴并发。
  • (可选)将呼叫队列分为不同的读取和写入队列以区分服务。参数hbase.ipc.server.callqueue.handler.factor指定呼叫队列的数量:
    • 0表示单个共享队列
    • 1表示每个处理程序一个队列。
    • 0到1之间的值与处理程序的数量成比例地分配队列的数量。例如,值.5在每两个处理程序之间共享一个队列。
  • 使用hbase.ipc.server.callqueue.read.ratio(0.98中的hbase.ipc.server.callqueue.read.share)将调用队列拆分为读写队列:
    • 0.5表示将有相同数量的读写队列
    • <0.5表示读写多
    • > 0.5表示写入比读取更多
  • 设置hbase.ipc.server.callqueue.scan.ratio(HBase 1.0+)以将读取的呼叫队列拆分为小读取和长读取队列:
    • 0.5表示短读和长读队列的数目相同
    • <0.5可获得更多短读
    • > 0.5可获得更长的阅读时间

1.12.2.禁用Nagle for RPC

停用Nagle的算法。 延迟的ACK可能会使RPC往返时间增加约200毫秒。 设置以下参数:

  • 在Hadoop的core-site.xml中:

    • ipc.server.tcpnodelay = true
    • ipc.client.tcpnodelay = true
  • 在HBase的hbase-site.xml中:
    • hbase.ipc.client.tcpnodelay = true
    • hbase.ipc.server.tcpnodelay = true

1.12.3.限制服务器故障影响

尽快检测到区域服务器故障。 设置以下参数:

  • 在hbase-site.xml中,将zookeeper.session.timeout设置为30秒或更短以进行绑定故障检测(20-30秒是一个好的开始)。

    • 注意:Zookeeper的sessionTimeout限制在tickTime的2到20倍之间(ZooKeeper使用的基本时间单位为毫秒,默认值为2000ms,用于进行心跳,最小会话超时将是tickTime的两倍) 。
  • 检测并避免不健康或故障的HDFS数据节点:在hdfs-site.xml和hbase-site.xml中,设置以下参数:
    • dfs.namenode.avoid.read.stale.datanode=true
    • dfs.namenode.avoid.write.stale.datanode=true

1.12.4.在服务器端进行优化以降低延迟

当RegionServer通过利用HDFS的“Short-Circuit Local Reads”功能从HDFS读取数据时,跳过网络上的本地块。 请注意如何在连接的数据节点和dfsclient端(即在RegionServer上)都必须完成设置,以及两端如何都需要加载hadoop本机.so库。 在配置好hadoop之后,将dfs.client.read.shortcircuit设置为true,并配置dfs.domain.socket.path数据节点和dfsclient共享并重新启动的路径,接下来配置regionserver / dfsclient端。

  • 在hbase-site.xml中,设置以下参数:

    • dfs.client.read.shortcircuit=true
    • dfs.client.read.shortcircuit.skip.checksum = true,因此我们不会将校验和加倍(HBase自己执行校验和以保存在i / os上。有关更多信息,请参见hbase.regionserver.checksum.verify
    • dfs.domain.socket.path匹配为数据节点设置的内容。
    • dfs.client.read.shortcircuit.buffer.size = 131072要避免OOME,请务必注意-如果未设置hbase的默认值,请参见hbase.dfs.client.read.shortcircuit.buffer.size; 其默认值为131072。
  • 确保数据局部性。 在hbase-site.xml中,将hbase.hstore.min.locality.to.skip.major.compact设置为0.7(意味着0.7 <= n <= 1)
  • 确保DataNode具有足够的处理程序以进行块传输。 在hdfs-site.xml中,设置以下参数:
    • dfs.datanode.max.xcievers> = 8192
    • dfs.datanode.handler.count =主轴数

重新启动后检查RegionServer日志。 如果配置错误,您应该只会看到投诉。 否则,短路读取将在后台安静地运行。 它没有提供度量标准,因此没有光学手段可以证明它的有效性,但是读取延迟应该显示出明显的改善,尤其是如果良好的数据局部性,大量的随机读取以及数据集大于可用缓存时。

您可能会使用的其他高级配置,尤其是在日志中抱怨短路功能的情况下,包括dfs.client.read.shortcircuit.streams.cache.size和dfs.client.socketcache.capacity。 这些选项的文档很少。 您必须阅读源代码。

有关短路读物的更多信息,请参阅Colin推出的旧博客,《改进的短路本地读物如何为Hadoop带来更好的性能和安全性》。HDFS-347问题也引起了有趣的阅读,显示了HDFS社区处于最佳状态(有一些评论)。

1.12.5.JVM调整.

1.12.5.1.调整JVM GC以降低收集延迟

  • 使用CMS收集器:-XX:+UseConcMarkSweepGC
  • 保持伊甸园空间尽可能小,以最小化平均收集时间。 例:
    • -XX:CMSInitiatingOccupancyFraction = 70
  • 针对低收集延迟而不是吞吐量进行优化:-Xmn512m
  • 并行收集eden:-XX:+ UseParNewGC
  • 避免在压力下收集:-XX:+仅使用CMSInitiatingOccupancy
  • 按请求限制扫描器结果的大小,使所有内容都适合幸存者的空间,但没有使用期限。 在hbase-site.xml中,将hbase.client.scanner.max.result.size设置为eden空间的1/8(使用-Xmn512m时约为51MB)

1.12.5.2.操作系统级调整

  • Turn transparent huge pages (THP) off:

    echo never > /sys/kernel/mm/transparent_hugepage/enabled
    echo never > /sys/kernel/mm/transparent_hugepage/defrag
  • Set vm.swappiness = 0

  • Set vm.min_free_kbytes to at least 1GB (8GB on larger memory systems)

  • Disable NUMA zone reclaim with vm.zone_reclaim_mode = 0

1.13.特别案例

1.13.1.对于快速失败胜于等待的应用程序

  • 在客户端的hbase-site.xml中,设置以下参数:

    • 设置hbase.client.pause = 1000
    • 设置hbase.client.retries.number = 3
    • 如果要遍历拆分和区域移动,请大幅增加hbase.client.retries.number(> = 20)
    • 设置RecoverableZookeeper重试计数:zookeeper.recovery.retry = 1(不重试)
  • 在服务器端的hbase-site.xml中,设置Zookeeper会话超时以检测服务器故障:zookeeper.session.timeout⇐30秒(20-30很好)。

1.13.2.对于可以容忍一些过时信息的应用程序

HBase时间线一致性(HBASE-10070)启用只读副本后,区域(副本)的只读副本将分布在群集上。 一个RegionServer服务于默认副本或主副本,这是唯一可以服务于写操作的副本。 其他RegionServer服务于辅助副本,跟在主要RegionServer之后,并且仅查看已提交的更新。 辅助副本是只读的,但可以在主副本进行故障转移时立即为读取提供服务,从而将读取可用性的时间从几秒钟缩短到了几毫秒。 自4.4.0起,Phoenix支持时间轴一致性。

  • 部署HBase 1.0.0或更高版本。
  • 在服务器端启用时间轴一致的副本。
  • 使用以下方法之一设置时间轴一致性:
    • 使用ALTER SESSION SET CONSISTENCY ='TIMELINE'
    • 在JDBC连接字符串中将连接属性Consistency设置为时间轴

1.13.3.更多信息

有关操作和性能模式设计选项的更多信息,请参见“性能”部分perf.schema ,例如Bloom Filters,Table配置的regionsize,压缩和blockizes。

Apache HBase【从无到有从有到无】【AH8】RegionServer调整大小的经验法则相关推荐

  1. Apache HBase【从无到有从有到无】【AH4】Apache HBase配置

    目录 1.Apache HBase配置 1.1.配置文件 1.2.基本先决条件 1.2.1.操作系统实用程序 1.2.2.Hadoop 1.2.2.1.dfs.datan

  2. Apache HBase

    Apahce HBase 1.简介 2.特性 3.应用场景 4.优缺点 5.与Hadoop/HDFS的区别与关系 6.HBase的基本概念 7.概念视图 8.物理视图 9.数据模型的主要操作 10.命 ...

  3. 移动云使用 JuiceFS 支持 Apache HBase 增效降本的探索

    作者简介: 陈海峰,移动云数据库 Apache HBase 开发人员,对 Apache HBase.RBF.Apache Spark 有浓厚兴趣. 背景 Apache HBase 是 Apache H ...

  4. 七年磨一剑:Apache HBase 1.0正式发布

    Apache HBase是一个高性能.面向列.可伸缩的开源分布式NoSQL数据库,它是Google Bigtable的开源实现.HBase构建在Hadoop基础设施之上,用户使用它能够在廉价PC Se ...

  5. Apache HBase快照介绍

    转自 http://www.importnew.com/4966.html CDH是Cloudera的完全开源分布式Apache Hadoop及相关项目(包括Apache HBase).CDH的当前版 ...

  6. 【翻译】Apache Hbase新特性--MOB支持(一)

    2019独角兽企业重金招聘Python工程师标准>>> 原文链接:http://blog.cloudera.com/blog/2015/06/inside-apache-hbases ...

  7. apache karaf_Apache Karaf遇到Apache HBase

    apache karaf 介绍 Apache HBase是一个以Google Bigtable为蓝本的开源,分布式,版本化,面向列的商店. 如果您是普通读者,那么您可能已经知道Apache Karaf ...

  8. Apache Karaf遇到Apache HBase

    介绍 Apache HBase是模仿Google Bigtable的开源,分布式,版本化,面向列的商店. 如果您是普通读者,那么您可能已经知道Apache Karaf是什么,但是对于那些不是的读者:A ...

  9. apache hbase的region 分割与合并

    原文地址:APACHE HBASE REGION SPLITTING AND MERGING  本文我们将深入探讨hbase的核心领域之一:region分割与合并. 具体来说,我们将详细讨论hbase ...

最新文章

  1. matlab中实时脚本与纯代码脚本
  2. Ext.Net学习笔记18:Ext.Net 可编辑的GridPanel
  3. 【bzoj3224】 Tyvj1728—普通平衡树
  4. 虚拟机ping不通开发板如何解决
  5. 了解情况的 飞鸽传书官方网站 时候
  6. Adobe illustrator 导出可编辑文本 - 连载 18
  7. 一个好的桌面图标的网站
  8. 形态学操作之提取水平与垂直直线
  9. 生成[1,2,,3,4,5,6,7,8,9]的随机数组?
  10. 华硕触摸板驱动ASUS PTP Driver安装失败解决办法
  11. 计算KL散度与JS散度的MATLAB程序
  12. python实现bt下载器_使用Python实现BT种子和磁力链接的相互转换
  13. c语言pi算法程序,C语言计算圆周率PI
  14. arm体系结构:arm920t
  15. 网页中直接跳转相应页面方法
  16. SpingMVC文件下载,ie浏览器提示无法打开该Internet站点.请求的站点不可用,或找不到.请以后再试.
  17. 显示器固件测试软件,【安全工具】固件可视化分析-工具篇
  18. 100+份项目管理模板和工具免费下载,包含项目管理各个流程都该用到哪些工具和方法!
  19. 服务器域共享文件夹,访问域共享文件夹
  20. SQL语句:where条件后写上1=1是为了什么

热门文章

  1. Django基于admin的stark组件创建(一)
  2. RCNN、Fast RCNN、Faster RCNN算法详细介绍
  3. 玩客云家庭媒体共享中心使用说明
  4. 玩客云 虚拟服务器设置,玩客云刷 Linux 系统后遇到的问题和设置固定 IP
  5. 多传感器数据融合学习笔记
  6. CentOS服务器密匙登录
  7. eclipse 打开pom.xml文件很慢 设置pom.xml打开方式
  8. 01时态(1):疑问句
  9. 自己总结的wireshark抓包技巧
  10. 快速学习四步法:如何用20小时,快速学习?