Skip to content

中文使用手册

中文 README · English documentation · 场景示例 / Cookbook

本手册面向首次接入和准备迁移的使用者。README 提供快速开始;这里解释数据如何组织、怎样连接、不同操作的返回值,以及实际接入时容易踩到的边界。文档描述当前仓库实现,不代表 Apache HBase 或 Java Client 的全部能力。

按任务查找

你要做什么 对应文档
安装、第一次读写 本页;详细安装入门
设计行键、存中文或 JSON 本页;数据模型与编码
连接远程或 Docker 集群 本页;配置与连接生命周期
前缀查询、条件过滤、分页 可执行场景示例、高级用法
批量导入、计数、条件修改 可执行场景示例、API 参考
建表、改列族、快照管理 管理指南
接口存在但行为不符合预期 当前限制、故障排查
从 Java/Thrift/HappyBase 迁移 迁移检查表、HappyBase 迁移
测性能或参与开发 性能指南、开发环境、测试指南
维护示例、理解 PyPI 文档入口 文档维护

英文专题页包含更多接口细节;Cookbook 每个场景带中英文标题、前提条件和断言,可直接对应实际业务需求。

1. 安装:直接 pip 即可

客户不需要克隆仓库、启动 Docker 或创建 venv 才能安装:

python -m pip install hbase-driver
python -c "import hbasedriver; print('安装成功')"

venv 是可选的依赖隔离方式,不是必需步骤。如果使用系统管理的 Python,环境本身可能限制直接安装;可以选择已有应用环境或虚拟环境。安装会自动带上 kazoo 和 protobuf。

需要修改源码时,再在源码目录使用:

python -m pip install -e .
python -m pip install -r requirements.txt

建议使用 Python 3.10+,项目当前验证环境为 Python 3.11 / HBase 2.6.1。能成功 import 只代表包已安装,不代表能够访问集群或全部功能已验证。

2. 连接的不是 Thrift

客户端先访问 ZooKeeper,再连接它返回的 Master 和 RegionServer 地址。因此,Python 进程必须能解析并访问这些主机名和端口,只转发 ZooKeeper 的 2181 端口通常不够。

import os

from hbasedriver.client.client import Client
from hbasedriver.hbase_constants import HConstants

config = {
    HConstants.ZOOKEEPER_QUORUM: os.getenv("HBASE_ZK", "127.0.0.1:2181"),
}

这里由示例程序读取环境变量,再交给 Client;驱动不会自动读取 HBASE_ZK。

  • 在本项目 hbase_dev 内:hbase-zk:2181。
  • 在本机访问本机 HBase:通常为 127.0.0.1:2181,还要确保广播地址可达。
  • 远程集群:使用管理员提供的 host:port,多个地址以英文逗号分隔。
  • 当前启动路径按默认 /hbase znode 和简单认证实现,不能宣称已完整支持自定义 znode、Kerberos/SASL/TLS 或 Java 式自动故障恢复。

3. 先理解字节串与表结构

例如 default:users:

  • default 是命名空间,users 是表名。
  • b"user:000001" 是行键,按字节顺序排列。
  • b"cf" 是建表时定义的列族。
  • b"name" 是列限定符,写入时可以增加,不需要先定义每个列名。
  • 值由应用编码,例如 "张三".encode("utf-8")。

行键中数字的字符串排序不同于数值排序:b"10" < b"2"。固定宽度的非负整数编码可保持指定范围内的顺序,例如 f"{42:06d}".encode("ascii")。键格式应在写入前确定;变更格式意味着迁移已有数据。

Row.kv 是 {列族: {列限定符: 值}},不是 HappyBase 的扁平字典。不存在的行返回 None;不存在的列返回 None;b"" 是实际存在的空值,不能混为一谈。

4. 读写中文与 JSON

前提:已存在且启用 default:users 表,包含 cf 列族。此示例写入数据并保留,应用到真实表之前请更换示例行键或使用临时表。

import json
import os

from hbasedriver.client.client import Client
from hbasedriver.hbase_constants import HConstants
from hbasedriver.operations.get import Get
from hbasedriver.operations.put import Put

config = {HConstants.ZOOKEEPER_QUORUM: os.getenv("HBASE_ZK", "127.0.0.1:2181")}
with Client(config) as client:
    with client.get_table(b"default", b"users") as table:
        profile = {"name": "张三", "active": True}
        table.put(
            Put(b"user:000001")
            .add_column(b"cf", b"name", profile["name"].encode("utf-8"))
            .add_column(
                b"cf", b"profile",
                json.dumps(profile, ensure_ascii=False).encode("utf-8"),
            )
        )
        row = table.get(Get(b"user:000001"))
        if row is not None:
            value = row.get(b"cf", b"profile")
            if value is not None:
                print(json.loads(value.decode("utf-8")))

HBase 不会自动按 JSON 字段过滤。需要独立查询的业务字段,应单独存为 qualifier,再用相应过滤器。

5. 扫描、过滤与分页

以下片段假定已经打开带有 cf 的 table:

from hbasedriver.filter import PrefixFilter
from hbasedriver.operations.scan import Scan

scan = (
    Scan(start_row=b"user:")
    .with_end_row(b"user;", inclusive=False)
    .add_family(b"cf")
    .set_filter(PrefixFilter(b"user:"))
)
with table.scan(scan) as scanner:
    rows = scanner.next_batch(100)
for row in rows:
    print(row.rowkey, row.kv)

这段代码读取至多 100 行后关闭 scanner,不是遍历整个表。当前 set_limit() 没有在扫描路径中形成全局行数限制,不能用它代替这里的读取上限。

分页使用 table.scan_page(scan, page_size),返回 (rows, resume_key)。下页通过 scan.with_start_row(resume_key, inclusive=False) 排除上一页最后一行,保留同样的过滤器和结束边界;直到返回空 rows 才结束。非空的最后一页仍可能带 resume_key。

注意:

  • Scan 构造器的起止边界默认都包含;需要半开区间时显式设置结束边界不包含。
  • 不支持在构造器传 include_start_row=False。
  • Scan.add_column() 当前有序列化缺陷,可按列族扫描并结合 QualifierFilter。
  • 组合过滤器使用 FilterList(operator=FilterList.Operator.MUST_PASS_ALL, filters=[...])。
  • SingleColumnValueFilter 的 filter_if_missing 和 latest_version_only 是构造参数。
  • 分页不是并发写入下的一致性快照;反向、多 Region 以及分裂/迁移恢复需要额外验证。

完整过滤和分页循环见场景示例。

6. 批量操作与缓冲写入

BatchGet 必须先构造,再增加列,不能链式赋值:

from hbasedriver.operations.batch import BatchGet

reads = BatchGet([b"user:000001", b"user:000002"])
reads.add_column(b"cf", b"name")
by_key = table.batch_get(reads)
for key, row in by_key.items():
    print(key, None if row is None else row.get(b"cf", b"name"))

返回值是以行键为索引的字典。需要保持请求顺序或重复行键时,保留原始输入列表。BatchPut、BatchGet、Batch 和 BufferedMutator 当前底层仍逐条请求,不等同于批量 RPC、Bulk Load 或跨行事务。

显式管理 Table 所有权的缓冲写入:

from hbasedriver.client.buffered_mutator import BufferedMutator, BufferedMutatorParams
from hbasedriver.operations.put import Put

params = BufferedMutatorParams()
params.write_buffer_size = 1024 * 1024
params.write_buffer_periodic_flush = 0
with BufferedMutator(table, params) as mutator:
    mutator.mutate(Put(b"import:001").add_column(b"cf", b"value", b"saved"))
    mutator.flush()

Params 构造器不接收关键字参数;通过属性设置。周期 flush 单位为毫秒,0 表示关闭后台定时线程。关闭 mutator 不会关闭调用方的 Table。

mutate() 返回不等于数据已写入。flush 失败可能留下部分成功,待发送缓冲也不保证保留,必须在上游保存可恢复的输入,不能把缓冲器当持久化队列。

7. 原子操作的边界

  • Increment:服务端递增;计数器存储为有符号 8 字节大端整数,不要用 b"0" 初始化。
  • CheckAndPut:同一行满足条件才写入;None 检查不存在,b"" 检查已有空值。
  • Append:追加字节;重复执行会重复追加。
  • RowMutations:同一行的操作组合;不是跨行事务。
  • 超时可能发生在服务端已经执行之后,不能盲目重试计数/追加。
  • table.increment() 只返回一个解码后的整数;如果依赖返回值,建议一次只操作一个计数器。

场景示例包含成功与条件不成立两条路径的断言。示例中的 claim 仅展示条件写入,不是带租约和 fencing token 的完整分布式锁。

8. 建表、删除与管理

建表的关键类型如下;此片段只构造对象,不操作集群:

from hbasedriver.common.table_name import TableName
from hbasedriver.operations.column_family_builder import ColumnFamilyDescriptorBuilder

name = TableName.value_of(b"default", b"users")
family = ColumnFamilyDescriptorBuilder(b"cf").build()

然后由已打开的 Admin 调用 admin.create_table(name, [family])。TableName 需要两个参数,builder 返回 protobuf 列族 schema,不存在可直接导入的 ColumnFamilyDescriptor。

删除需要先禁用表,且必须确认表归当前操作所有。不要在“表已存在则跳过创建”的示例末尾无条件删除那个表。admin.table_exists() 还会把异常转换成 False,False 不足以证明集群正常或表可安全重建。

truncate 当前是删除再重建,不保留完整表元数据和分区边界;快照恢复或克隆返回过程 ID,不代表已经完成。不要在普通文档验证中执行生产表删除、快照恢复或全局 balancer 修改。

9. 验证与故障定位

先将完整示例教程中的代码保存为本地 docs_quickstart.py,不要提交这个临时文件,再使用本仓库的 Docker 环境:

docker compose up -d
docker compose exec -T dev python docs_quickstart.py
docker compose exec -T dev python -m pytest test/test_batch_operations.py -v
docker compose stop

dev 对应 hbase_dev,不是其他项目的容器。完整示例创建唯一的 docs_demo_* 表并清理。Cookbook 的 8 个场景在准备阶段已直接运行验证;本次只发布文档和配置,不提交本地 Python 文档测试脚本,也不更新根目录的旧版示例。普通上下文片段不代表每段都独立执行,详细范围见验证说明。

排查顺序:确认 Python 导入路径 → ZooKeeper 地址 → 广播主机名可达性 → 表是否启用/列族存在 → API 参数及返回值 → 当前实现限制。错误报告保留必要栈信息,删除密码、令牌和客户数据,不要上传完整环境变量或 exports 文件。

10. 文档和发布版本

正式文档网站随 main 分支的文档更新自动构建和发布。英文 README 顶部有中文入口,PyPI 1.1.1 的项目说明和 Documentation 链接已纳入新的文档入口;旧版本的 PyPI 页面不会自动变化。

网站使用 MkDocs 和 GitHub Pages,提供导航、全文搜索、代码复制及深浅色切换。顶部有中文手册入口,但不是所有英文专题都已翻译。网站目前跟随 main,不是每个 PyPI 版本的独立文档快照。1.1.1 仅更新文档与包元数据,Python 源码与 1.1.0 一致;客户仍可直接 pip 安装,无需安装文档构建工具。

开始生产接入前,请读完当前限制:接口“有这个方法”与“所有参数都有端到端实现”是两回事。