如何设计hbase table

How to design hbase table

我打算为 JSON 数据设计 Hbase table。

因为我不太了解 Hbase 的概念,所以我想知道为下面提到的 JSON 类型设计 table 的最佳方法是什么。

虚线是Json数据中的逻辑分区: 这意味着 A 记录有一个 rowkey 是 uid,然后有粗体的请求部分,斜体和分类的响应部分。在分类下有一个类似数组的结构。 我正在考虑为每个逻辑组创建 3 个列族。但是如何将类似数组的结构 ("Problem Reasons") 存储到 HBASE table。除了二进制之外,hbase 是否有任何特定的数据类型??

{
        "uid": "abc2342",
-----------------------------------

        "req1": sometext,
        "res1": sometext,
        "matter": "point1",
        "body": "point2",
-------------------------------------
        "response": null,
                "validity": null
---------------------------------------

    "classification": "Problems",
        "Problem reasons": [
            "Address Not found",
            "Invalid Phone Number",
            "Invalid Email"
        ]
    },

HBase 只有二进制。您将不得不自己序列化和反序列化数据。 HBase Bytes class 可以帮助你(例如 Bytes.toBytes((short) 5))。对于数组,考虑到您计划如何查询它,您将不得不找出最适合您的格式。存储字符串数组的一种简单方法是使用字符串本身不允许的分隔符连接它们。您也可以将其转储为 JSON.

schema is the key 的另一个重要考虑因素。通常你会想要一个统一的随机密钥,这样你就不会得到会降低性能的热点。一个简单的方法是散列你的字符串键并使用散列的字节。

对于column families

Physically, all column family members are stored together on the filesystem. Because tunings and storage specifications are done at the column family level, it is advised that all column family members have the same general access pattern and size characteristics.

IBM 有很好的 document 一些经验法则:

An HBase table is made of column families which are the logical and physical grouping of columns. The columns in one family are stored separately from the columns in another family. If you have data that is not often queried, assign that data to a separate column family.

The column family and column qualifier names are repeated for each row. Therefore, keep the names as short as possible to reduce the amount of data that HBase stores and reads. For example, use f:q instead of mycolumnfamily:mycolumnqualifier.

Because column families are stored in separate HFiles, keep the number of column families as small as possible. You also want to reduce the number of column families to reduce the frequency of MemStore flushes, and the frequency of compactions. And, by using the smallest number of column families possible, you can improve the LOAD time and reduce disk consumption.

我假设您的结构是每个用户有一个请求、一个响应和几个问题。

如果是这样,只需将 UID 设置为行键即可。 Rowkey设计是HBase模式设计中最重要的部分。这是因为 HBase 根据 rowkey 对数据进行分片,它控制着您查找数据的方式。为避免热点,您可能需要将 UID 的哈希值添加到密钥的前面。例如,您可以使密钥看起来像这样 hash(UID):UIDf97h23:user123.

现在开始你的下一个问题。 HBase 只存储字节。它不关心那些字节是什么。由您的程序决定您存储的字节的含义。 HBase 不知道除计数器之外的数据类型,但我们将在这里忽略它们。

这个 table 看起来相当简单,所以我将其余的 JSON 字段分别放入一列中。对于数组,我在列中做了一些分隔列表,即 Address Not found,Invalid Phone Number,Invalid Email。任何时候你使用这样的方案,一定要使数据中的定界字符非法,或者使用转义方案。

在大多数情况下,我认为没有理由使用单独的列族。看起来你每行的数据量很小,而且你没有提到不同的访问模式,这让我假设你在查询 UID 时大多只是获取每个字段。如果确实如此,您甚至可以用一列 "JSON" 来存储上面的 json 字符串。这样做的缺点是需要序列化和反序列化 JSON.

有关您的用例的更多信息将有助于指导设计。 像这样的东西:

  • 您能大致描述一下您正在使用这个数据库解决什么问题吗?

  • 您总是阅读所有专栏,还是只阅读部分专栏?

  • 您希望总共有多少行?

  • 您通常是追加新记录,还是更新现有记录?

  • 读写的混合是什么?

  • 性能要求是什么?

HBase 是一个愚蠢的野兽,你必须这样对待它。这只是低级别的索引存储。

您应该遵循一条规则 - 您的模式应该以一种可以访问的方式存储,而不是存储。 根据其他评论,您应该使用 req1 生成行键。

但请注意! req1 必须分布良好,而不是二进制顺序值。如果必须,请使用种子。

如果您使用 rowkey 访问整个 JSON 对象 - 然后只需将所有内容转储到二进制字符串中,BSON 或某些序列化程序就足够了。如果更新不是并发的,那么更新的数量并不重要。

如果您希望能够同时使用一个键或 adding/changing 个值来引用数据的一个子集,那么您应该将它们分开。


根据您的示例,您可以轻松地将值拆分为 3 个列族:

  1. 请求(列如 req:req1req:uid 等)
  2. 响应(列如 res:validity 等等)
  3. 分类

在分类列族中,您可以将值拆分到最低级别:

  • 列cl:classification可以识别分类类型
  • 如果你的分类列表合理且有限,那么你可以按分类命名列族-列族问题
  • 然后您可以添加数组值作为列值或列名:
    • 问题:1 => "Address Not found"
    • problem:addressnotfound => 1 - 这种方法的主要好处是它可以很好地处理并发更新。
    • cl:reason1 => "Address Not found"