# HBase 中的 Protobuf

## 179\. Protobuf

HBase 使用 Google 的 [protobufs](https://developers.google.com/protocol-buffers/) ，无论它在哪里持久存储元数据 - 在 hfiles 或 HBase 写入系统 hbase：meta 表格中，或者当 HBase 将 znodes 写入 zookeeper 等时 - 以及当它将对象传递给制丝 [RPCs](#hbase.rpc) 。 HBase 使用 protobufs 来描述我们向客户端公开的 RPC 接口（服务），例如 RegionServer 字段的`Admin`和`Client`接口，或指定开发人员通过我们的[协处理器端点](#cp)添加的任意扩展机制。

在本章中，我们将详细介绍那些希望更好地了解它的工作原理的开发人员。本章特别适用于那些修改或扩展 HBase 功能的人。

使用 protobuf，您可以在`.protos`文件中描述序列化和服务。然后，您将这些描述符提供给 protobuf 工具（`protoc`二进制文件），以生成可以编组和解组所描述的序列化并对指定的服务进行字段处理的类。

有关如何基于每个模块运行类生成的详细信息，请参阅 HBase 子模块中的`README.txt`;例如请参阅`hbase-protocol/README.txt`了解如何在 hbase 协议模块中生成 protobuf 类。

在 HBase 中，`.proto`文件位于`hbase-protocol`模块中;一个专用于托管公共 proto 文件的模块和 HBase 使用内部序列化元数据的 protoc 生成的类。对于 hbase 的扩展，例如需要自己的描述符的 REST 或协处理器端点;他们的 protos 位于函数的托管模块内：例如`hbase-rest`是 REST 原型文件的主页，`hbase-rsgroup`表分组协处理器端点具有与表分组有关的所有原型。

Protos 由使用它们的模块托管。虽然这使得 protobuf 类的生成分布式，按模块完成，我们这样做，因此模块封装了它们带给 hbase 的功能。

扩展是否 REST 或协处理器端点将使用在 hbase 协议模块中找到的核心 HBase 原型。当他们想要序列化 Cell 或 Put 时，或者通过 ServerName 等引用特定节点时，他们将使用这些核心 protos，作为提供 CPEP 服务的一部分。展望未来，在 hbase-2.0.0 发布之后，这种做法需要向前推进。我们将在后面的 [hbase-2.0.0](#shaded.protobuf) 部分解释原因。

### 179.1。 hbase-2.0.0 和 protobufs 的阴影（HBASE-15638）

从 hbase-2.0.0 开始，我们的 protobuf 使用情况变得更加复杂。 HBase 核心 protobuf 引用被抵消，以便引用私有的捆绑 protobuf。核心在 com.google.protobuf 中停止引用 protobuf 类。 _ 而是在 HBase 特定的偏移量 org.apache.hadoop.hbase.shaded.com.google.protobuf 上引用 protobuf。_ 。我们这样做是间接的，因此 hbase 核心可以独立于我们的依赖关系所依赖的方式发展其 protobuf 版本。例如，HDFS 使用 protobuf 序列化。 HDFS 在我们的 CLASSPATH 上。如果没有上述间接，我们的 protobuf 版本必须对齐。在 HDFS 决定升级之前，HBase 将停留在 HDFS protobuf 版本上。 HBase 和 HDFS 版本将捆绑在一起。

我们不得不继续使用 protobuf-2.5.0，因为我们需要在 protobuf-3.1.0 中添加设施;特别是能够保存副本并避免在序列化/反序列化时使用 protobufs。

在 hbase-2.0.0 中，我们引入了一个新模块`hbase-protocol-shaded`，其中包含了与 protobuf 及其后续重定位/着色相关的所有内容。这个模块本质上是许多旧`hbase-protocol`的副本，但有一个额外的着色/重定位步骤。核心被转移到依赖这个新模块。

也就是说，协处理器端点（CPEP）出现了复杂问题。 CPEP 依赖于明确引用`com.google.protobuf.*`的 protobuf 类的公共 HBase API。例如，在我们的表格接口中，我们使用以下内容作为获取 CPEP 服务以对其进行调用的方式：

```
...
  <T extends com.google.protobuf.Service,R> Map<byte[],R> coprocessorService(
   Class<T> service, byte[] startKey, byte[] endKey,
     org.apache.hadoop.hbase.client.coprocessor.Batch.Call<T,R> callable)
  throws com.google.protobuf.ServiceException, Throwable 
```

现有的 CPEP 将参考指定 ServerNames 或携带 Mutations 的核心 HBase protobufs。为了能够在升级到 hbase-2.0.0 及更高版本的过程中继续为 CPEP 及其对`com.google.protobuf.` **的引用提供服务，HBase 需要能够处理`com.google.protobuf.`** 引用及其内部偏移`org.apache.hadoop.hbase.shaded.com.google.protobuf.*` protobufs。

`hbase-protocol-shaded`模块托管 HBase 核心使用的所有 protobufs。

但是对于退化的 CPEP 参考`hbase-protocol`的（非阴影）内容，我们保留了这个模块的大部分内容，因此它可供 CPEP 使用。保留`hbase-protocol`的大部分会产生重叠的“重复”原型实例，其中一些存在于其旧模块位置中的非阴影/非重定位，但也存在于新位置，在`hbase-protocol-shaded`下阴影。换句话说，在 hbase 协议中有一个生成的 protobuf 类`org.apache.hadoop.hbase.protobuf.generated.ServerName`的实例，并且在所有方面都有相同的生成实例，除了它的 protobuf 引用是`org.apache.hadoop.hbase.shaded.protobuf.generated.ServerName`的内部着色版本（注意'阴影' '在包名称中间添加）。

如果在`hbase-protocol-shaded`中扩展原型供内部使用，请考虑在`hbase-protocol`中扩展它（并重新生成）。

展望未来，我们将提供 CPEP 使用的常见类型的新模块，它们将像我们的公共 API 一样具有相同的变更保证。去做。