Stargate 是 HBase REST API 的名称,它使数据可以通过 HTTP 进行读写。Stargate 公开来自与表结构匹配的 URL 的数据(例如,/access-logs/rk1 将从 access-logs 表中获取带有关键字 rk1 的行)。
HTTP 动词 GET、POST 和 DELETE 用于处理作为资源的数据,这给了 Stargate 一个很好的 RESTful 接口。您可以在 JSON 中处理行和单元格,但该应用编程接口的缺点是所有数据都表示为 Base64 字符串,这些字符串是从 HBase 中的原始字节数组编码而来的。如果您只想使用像 Postman 或 cURL 这样的 REST 客户端进行浏览,这将使应用编程接口变得很尴尬。
像节俭应用编程接口一样,星际之门是一个独立的服务,你可以从 hbase-daemon.sh 开始休息。默认情况下,它监听端口 8080(并且已经在 hbase-简洁地说是 Docker 映像上运行)。
在生产环境中,您可以在区域服务器上运行 Stargate,但是如果您想将它用作 HBase 的主要接口,您应该考虑使用单独的服务器进行负载平衡。
提示:在这篇博文中,我用 Nginx 构建了一个负载平衡反向代理。
您可以使用任何带有 HTTP 客户端的框架来与 Stargate 对话。在本章中,我们将使用 cURL 来查看原始的 HTTP 数据,并使用. NET 客户端库在更高的抽象级别上工作。
代码清单 48 显示了对根 Stargate URL 的 GET 请求(cURL 中的默认动词)。响应与 HBase Shell 中的列表命令相同:
48:用 cURL 列出表格
$ curl http://127.0.0.1:8080
access-logs
social-usage
HTTP GET 请求相当于 HBase 外壳中的 GET 命令。您可以添加一个接受头来指定您想要的响应格式,但是 Stargate 提供的数据量有一些限制。
如果您试图请求整个表,例如 http://127 . 0 . 0 . 1:8080/access-logs,您将得到一个错误响应,状态代码为 405,这意味着该方法不被允许。你不能在 HBase 中获取整个表,405 是 Stargate 的实现。
您可以通过在表名后添加行键来获取一整行,但是如果您的行格式中有任何对 HTTP 不友好的字符,您将需要在 URL 中对它们进行转义。您也不能获得一行的纯文本表示;您需要用像 JSON 这样的以数据为中心的格式发出请求。
代码清单 49 显示了从星际之门读取的一整行。请注意,行键中的管道字符已被转义为%7C,响应中的数据值(行键、列限定符和单元格值)都是 Base64 编码的字符串(我已经对响应应用了格式;星际之门没有返回空白)。
49:用 cURL 读取一行
$ curl -H accept:application/json http://127.0.0.1:8080/access-logs/elton%7Cjericho%7C201511
{
"Row": [{
"key": "ZWx0b258amVyaWNob3wyMDE1MTE=",
"Cell": [{
"column": "dDoxMTA2",
"timestamp": 1447228701460,
"$": "MTIw"
}, {
"column": "dDoxMTA3",
"timestamp": 1447228695240,
"$": "NjUw"
}]
}]
}
响应是一个包含行对象数组的 JSON 对象。每行都有一个关键字字段和一个单元格对象数组。每个单元格都有一个列限定符、一个单元格值(存储在$字段中)和一个时间戳。时间戳是 HBase 存储的唯一具有解释的值;它们是长整数,存储行更新时的 UNIX 时间戳。
其他值是 Base64 字符串,这意味着您需要解码 GET 响应中的字段。表 6 显示了响应中一列的解码值:
田 | 价值 | 解码值 |
---|---|---|
Row.key | zwx 0x 258 amvyawnob 3 wymde 1 mte = | 埃尔顿|杰里科|201511 |
单元格.列 | dDoxMTA2 | t:1106 |
手机。$ | MTIw | One hundred and twenty |
6:编码和解码的 Stargate 值
请注意,单元格中的列值是全名(列族加上限定符,用冒号分隔),数值单元格值实际上是字符串。
您还可以从 Stargate 获取一行中的单列族(使用 URL 格式/{ table }/{ row-key }/{ column-family }),或者单个单元格值。对于单个单元格,您可以以纯文本方式获取它们,Stargate 将在响应中解码该值,如错误!未找到参考源。:
代码清单 50:获取单个单元格值
$ curl http://127.0.0.1:8080/access-logs/elton%7Cjericho%7C201511/t:1106
120
星际之门的 put 请求的语义与 HBase Shell 中的 PUT 命令非常相似。您可以在请求中指定所需的结束状态,剩下的工作由 HBase 来完成—如果行或列不存在,则创建行或列,并设置值。
你必须使用数据格式通过星际之门进行更新;否则你会得到一个 415 错误,“不支持的媒体类型。”使用 JSON,您可以镜像 GET 响应的格式,因此您可以在一个请求中为多行发送多个单元格值。
网址格式仍然需要一个行键和一个表,但是使用 PUT,网址中的键被忽略,取而代之的是请求数据中的键。代码清单 51 显示了更新我的行中两个单元格的 PUT 请求:
51:用 Stargate 更新细胞
$ curl -X PUT -H "Content-Type: application/json" -d '{
"Row": [{
"key": "ZWx0b258amVyaWNob3wyMDE1MTE=",
"Cell": [{
"column": "dDoxMTA2",
"timestamp": 1447228701460,
"$": "MTMw"
}, {
"column": "dDoxMTA3",
"timestamp": 1447228695240,
"$": "NjYw"
}]
}]
}' 'http://127.0.0.1:8080/access-logs/FAKE-KEY'
提示:Stargate 对于临时请求非常方便,但是使用 Base64 可能会很困难。我在博客上写了一些简单的工具让它变得更简单。
该 PUT 请求增加了实际上是我的行中的字符串的数值。通过 Stargate 不能使用 incr 命令自动增加计数器列,所以如果你需要增加值,那么你必须先读取它们,然后进行更新。
您可以使用 cURL 做更多的事情,比如发送删除请求来删除数据,以及创建扫描仪来获取多行,但是语法变得很麻烦。在星际之门中使用 RESTful API 的包装器是一个更好的选择。
NuGet 是的包管理器。NET 应用,还有几个开源包是访问星际之门的包装器。微软有一个专门针对运行在 Azure 云上的 HBase 集群的包,还有一个来自作者“部落”的第三方包,用于一般地使用 Stargate。
这个包很好地抽象了星际之门的内部,让你可以直观地处理 HBase 数据。它是 IoC 感知的(默认情况下使用自动调整),因此您可以轻松地调整 HTTP 设置并构建一个数据访问层,您可以模拟出来进行测试。
将该包及其依赖项添加到。NET 应用中,您可以使用代码清单 52 中的 NuGet 包管理器控制台命令:
52:为 Stargate 添加一个 NuGet 引用
Install-Package "HBase.Stargate.Client.Autofac"
在本书的 GitHub 存储库中,有一个. NET 控制台应用,它使用部落的客户端连接到 Stargate,运行在简洁的 Docker 容器中。
要设置 Stargate 客户端,您需要配置服务器网址并构建容器。代码清单 53 展示了如何使用 Autofac 实现这一点:
53:配置 Stargate 客户端
var builder = new ContainerBuilder();
builder.RegisterModule(new StargateModule(new StargateOptions
{
ServerUrl = "http://127.0.0.1:8080"
}));
var container = builder.Build();
var stargate = container.Resolve<IStargate>();
星之门选项对象包含星之门(或代理)网址,星之门模块包含所有其他容器注册。从容器中获得的 IStargate 接口提供了对所有 Stargate 客户端操作的访问,具有简洁的抽象,并且所有数据项都编码为字符串。
星际之门客户端有两种读取数据的方法。最简单的是 ReadValue(),它获取一个特定的单元格值,将表名、行键、列族和限定符传递给它。这在功能上等同于带有包含表名、行键和列名的 URL 的 GET 请求,它返回编码为字符串的单个单元格值,如代码清单 54 所示:
54:用 IStargate 读取单元格
var value = stargate.ReadValue("access-logs", "elton|jericho|201511", "t", "1106");
//value is "120"
或者,可以使用 FindCells()方法获取 CellSet 对象,该方法返回行和单元格的集合。这就像对一整行或一行中的列族发出 GET 请求。CellSet 是一个可枚举的集合,您可以用 LINQ 查询它,如代码清单 55 所示:
55:查找带有 IStargate 的单元格
var cellSet = stargate.FindCells("access-logs", "elton|jericho|201511");
var value = cellSet
.First(x => x.Identifier.CellDescriptor.Qualifier == "1106").Value;
//value is "120"
注意,FindCells()调用向 Stargate 发出 GET 请求,Stargate 返回 CellSet 中的所有数据,LINQ 查询在内存中的 CellSet 上运行。NET 客户端。
ReadValue()调用将很快返回,因为它获取的是单个数据,FindCells()调用将很快为 Stargate 服务,但是如果有许多包含大量数据的单元格,客户端可能需要更长时间才能收到。
从 Stargate 获取数据的另一种方法是创建一个行扫描器,它类似于服务器端的游标,您可以使用它来读取多行,并且扫描器可以选择有一个过滤器来限制返回的单元格数量。
用 Stargate 扫描行有两个部分。首先,创建运行在服务器上的扫描仪。星际之门给你一个扫描仪的参考,你可以用它来获取行。在。NET 客户端,您可以使用 ScannerOptions 对象来指定扫描的开始和结束行。
代码清单 56 显示了如何创建一个扫描器,从 2015 年 10 月开始为一个系统检索一个用户的所有访问日志:
56:使用 IStargate 创建扫描仪
var options = new ScannerOptions
{
TableName = "access-logs",
StartRow = "elton|jericho|201510",
StopRow = "elton|jericho|x",
};
var scanner = stargate.CreateScanner(options);
当 Stargate 返回时,扫描器正在服务器上运行,您可以从开始到结束行键循环遍历行,使用 MoveNext()方法从 Stargate 获取下一组单元格,如代码清单 57 所示:
57:使用 IStargate 遍历扫描仪
var totalUsage = 0;
while (scanner.MoveNext())
{
var cells = scanner.Current;
foreach (var cell in cells)
{
totalUsage += int.Parse(cell.Value);
}
}
//totalUsage is 850
注意:当您通过扫描仪迭代时返回的单元格可能来自多行,因此不要假设 MoveNext(或其他客户端中的等效方法)移动到下一行—它会移动到下一组单元格,这些单元格可能来自多行。
按行键扫描是从 Stargate 读取数据的最快方法,但是如果需要通过列中的数据(限定符或单元格值)来额外限制结果,则可以在创建扫描仪时指定过滤器。
过滤器也在 Stargate 中运行服务器端,所以它比在客户端获取整行和提取某些列更快,但是它确实使用了额外的服务器资源(如果您在区域服务器上运行 Stargate,这很重要)。
星际之门应用编程接口有各种各样的过滤器类型,但最有用的有:
key only filter–仅返回扫描仪中的行键
qualifier filter–返回与指定列限定符匹配的单元格
column prefixfilter–返回列名与指定前缀匹配的单元格
在 access-logs 表中,行键中的句点指定使用记录的年和月,列限定符包含日和小时。在代码清单 58 中,我向扫描器添加了一个列前缀过滤器,它过滤结果,以便只返回列名以提供的前缀开头的单元格。在这种情况下,只有每月第 11 天的单元格才会包含在结果中:
58:使用 IStargate 创建过滤扫描仪
var options = new ScannerOptions
{
TableName = "access-logs",
StartRow = "elton|jericho|201510",
StopRow = "elton|jericho|x",
Filter = new ColumnPrefixFilter("11")
};
var scanner = stargate.CreateScanner(options);
IStargate 接口有两种写入数据的方法。最简单的是 WriteValue(),它相当于对一行中特定单元格的 PUT 请求。如果需要,Stargate 会创建行和/或列,并设置值,如代码清单 59 所示:
59:用 IStargate 更新单元格值
stargate.WriteValue("100", "access-logs", "elton|jericho|201510", "t", "2908");
//cell value is now "100"
一个更复杂更灵活的方法是 WriteCells(),它采用一个 CellSet 对象,可以通过一次 API 调用更新多个值。这种混合值可以包括不同行的更新和插入,但所有行必须在同一个表中。
代码清单 60 显示了对现有单元格值的更新,以及在对 WriteCells()的一次调用中插入一个新行:
60:用 IStargate 更新单元格值
var update = new Cell(new Identifier
{
Row = "elton|jericho|201510",
CellDescriptor = new HBaseCellDescriptor
{
Column = "t",
Qualifier = "2908"
}
}, "120");
var insert = new Cell(new Identifier
{
Row = "elijah|jericho|201511",
CellDescriptor = new HBaseCellDescriptor
{
Column = "t",
Qualifier = "1117"
}
}, "360");
var cells = new CellSet(new Cell[] { update, insert});
cells.Table = "access-logs";
stargate.WriteCells(cells);
星际之门 API 是无状态的(即使是扫描器也运行在 Region Server 上,Region Server 不一定是星际之门服务器),客户端也是无状态的,所以本地没有数据缓存,除非你自己在内存中保留单元格。每次调用 Stargate 客户端读取或写入数据都会导致对 Stargate 的 REST 调用。
在这一章中,我们看了星际之门,HBase 提供的 REST API。它将行中的数据作为资源公开,使用描述数据路径的 URL 格式,始终包括表名和行键,以及可选的列族和限定符。
该 API 支持不同的数据格式,包括 JSON 和 Google 的 Protocol Buffers,对于简单的读写,可以使用纯文本(虽然功能集比较有限)。星际之门通过了 cURL 测试——如果你能用一个带有 cURL 的 API,那么它就有一个可用的 RESTful 设计。
由于星际之门提供了一种访问数据的标准化方法,它可以很容易地打包到一个客户端库中,我们用. NET NuGet 包介绍了一个选项。Stargate 提供了其他客户端的大部分功能(包括我们没有空间的 DDL 函数,比如创建表),但是在编写本文时不支持的一个特性是递增计数器列。
现在,我们已经很好地了解了您可以存储在 HBase 中的内容以及访问它的客户端选项。在下一章中,我们将回顾一下 HBase 的体系结构。