数据查询的玄铁剑:云HBase原生二级索引发布
HBase原生提供了主键索引,用户可以根据rowkey进行高效的单行读、前缀匹配、范围查询操作。但若需要使用属性列进行查询时,则只能使用filter在查询范围内进行逐行过滤。在扫描范围较大时,会浪费大量的IO,请求RT也无法保证。为此,HBase增强版推出了原生二级索引来解决非rowkey查询的性能问题。
云HBase增强版是基于阿里内部的HBase分支(亦称Lindorm)构建的,二级索引是其核心能力之一,历经多年双11大考,在性能、吞吐、稳定性等方面都具备核心竞争力。
下面,我们从一组示例出发来了解索引的使用及其能力。
功能简介
从表设计和查询设计的角度看,HBase增强版二级索引的使用与RDBMS的二级索引基本一致。下面我们看一个简单的示例:大学生信息表(Students
),该表的主键(即rowkey)是学号,非主键是学生姓名和所属的学院名称。学生与学院是多对一的关系。
通过HBase shell建表,建索引:
# 创建主表student,列族名为f create 'student', 'f' # 创建索引表department,为department列建索引 # COVERED_ALL_COLUMNS是HBase增强版引入的新属性关键字, # 意味冗余主表student中的所有列,以此来避免回查主表 create_index 'department', 'student', {INDEXED_COLUMNS => ['f:departement']}, {COVERED_COLUMNS => ['COVERED_ALL_COLUMNS']}
通过Java API进行数据访问
// 定义一些常量 String id = "11"; // 一个随机的学号 String studentName = "Harry"; String department = "CS"; byte[] f = Bytes.toBytes("f"); byte[] qStudent = Bytes.toBytes("name"); byte[] qDepartment = Bytes.toBytes("department"); // 写入一个学生的数据 Put put = new Put(Bytes.toBytes(id)); put.addColumn(f, qStudent, Bytes.toBytes(studentName)); put.addColumn(f, qDepartment, Bytes.toBytes(department)); Table t = conn.getTable("student"); t.put(put); // put成功返回意味着主表和索引表都成功更新,变更立即可见 // 按department进行查询 Scan scan = new Scan(); SingleColumnValueFilter where = new SingleColumnValueFilter( f, qDepartment, EQUAL, Bytes.toBytes(department)); scan.setFilter(where); ResultScanner rs = t.getScanner(scan); // 处理查询结果...
从上例可见,用HBase API直接描述查询请求即可使用索引。HBase增强版会自动根据filter以及索引schema来匹配到最合适的索引进行查询,必要时,在查完索引后也会回查主表(上例中,如果不是全冗余索引,则会回查主表来补全列)。更多使用上的说明请参考二级索引开发手册。
HBase增强版二级索引的主要特性有:
- 支持为单个主表建多个索引
- 支持单列和多列索引(组合索引)
- 支持冗余索引:可显式指定冗余列,或冗余所有列,避免回查主表的性能损耗
- 查询优化:根据scan和filter自动选择合适的索引表进行查询,必要时会自动回查主表
- online schema change:支持给已经在使用的表建索引,对主表读写无影响
- 支持TTL:索引表会自动继承主表的TTL,主表和索引表数据一起过期
- 支持自定义数据版本:用户自定义数据时间戳写入(暂未开放)
产品优势
高性能
HBase增强版二级索引直接内置于内核中,并做了深度优化,提供了强大的吞吐与性能。下图是HBase增强版二级索引与Apache Phoenix的全局索引的性能对比:
从上图可见,无论RT还是吞吐,HBase增强版二级索引均远超Apache Phoenix。
写后可读
数据写入返回成功后,则索引数据可立即被读到,消除传统异步建索引方案中的数据延迟,提供具有一定程度的强一致性语义(主表和索引表的数据一致性),具体语义如下:
- 返回客户端写入成功,之后可立即读到刚写入的数据(包括主表和索引数据);写入过程中不保证同时可见
- 返回超时或IO出错,则在一段时间内,该数据在主表和索引表中的可见性无法确定,但保证最终一致,即要么全成功,要么全不成功
HBase增强版提供的”写成功后更新立即可见的语义“,可用于一些分布式协同的任务,比如spark,在某些节点更新数据,另外一些节点读取上一轮计算写入的数据。此时,一定可以读到刚写入的数据。
全冗余索引
全冗余索引可彻底避免回查主表,提升性能;同时也是语法糖,避免手工维护复杂的DDL。下面分别介绍。
如果查询中需要的列在索引表中没有,则查完索引后,还需回查主表。在分布式场景下,回表查询会使得查询RT大幅度升高,最差情况下可能会回查主表的全部region,访问集群中的所有机器。此时,索引带来的性能收益已经可有可无。通过精良的查询设计和索引设计,我们可以在设计阶段避免回查,但随着业务发展变化,这个约束很难维持。因此,仍然需要冗余索引(Covered Index)来解决。
HBase增强版创造性的引入了全冗余索引的概念,即冗余主表中的所有列,以此来彻底避免回查主表。配合HBase的schema-free特性,主表中新增的任何列都会自动冗余到索引表中。无论业务模式如何变化,都不需要回查主表。
同时,全冗余也是可大幅度提升效率的语法糖,我们可以对比如下两个SQL语句:
CREATE INDEX idx ON dt (c1, c2) include(c3, c4, c5, c6, ....); CREATE INDEX idx ON dt (c1, c2) include(ALL);
对于大部分业务来说,表里有数十列是常态,个别表可能会有数百列。如果为了建冗余索引,而把这数百列的列名再写一遍,无疑是巨大的负担(只能写工具自动化做,人来做太容易出错)。全冗余索引的新语法给人工维护DDL提供了可能。
为了获得上述两点收益,全冗余索引的代价是会占用更多存储空间。配合HBase增强版深度优化的ZStandard压缩算法,可有效降低冗余带来存储开销。冷热分离特性亦可应用于索引表,进一步控制成本。
基于原生API的查询优化
对大部分场景来说,业务一行代码不改就能用上索引。
从本文开头的示例代码中可见:
- 写:写主表即可,会自动同步到索引,强一致。用户无需担心索引更新的问题
- 读:基于主表进行查询,直接按业务逻辑进行查询表达,系统自动选择合适的索引表进行查询
这样,用户只需为那些性能不好的查询设计并添加索引,即可从索引特性中受益,实际的数据读写代码一般不需要修改。同时,既有的HBase生态相关的产品,都可以无缝使用上索引。一些如Spring的框架软件也可帮助用户获得业务上的灵活性。
大表建索引
从一开始就设计好主表和全部索引几乎是不可能的。因此,在后续业务发展过程中,索引表可能需要不断的删除和新增。为此,对一个已经有大量数据表添加、删除索引,将是一个关键的运维操作。HBase增强版二级索引针对此场景做了特别的优化:
- schema在线修改:索引的变更不影响主表的正常读写(就像一次普通的alter表操作),不影响其他索引表
- 服务端rebuild:在服务端为主表的历史数据构建索引
- 支持对超大主表添加索引:支持TB级别的主表添加新索引
- 流控:大主表的索引rebuild会消耗大量的系统资源,因此,精准的流控即可在兼顾索引构建速度的前提下,保障系统整体性能不会被影响
在有上述特性的加持下,索引变更的运维成本和风险大大降低,从容的适应业务发展。
原理简介
HBase增强版二级索引是一种全局二级索引,每个索引表都是一张独立的HBase表。每张表的主键(rowkey)设计决定了其能支持的查询模式。当同一份数据有多种rowkey组织时,就能支持多种查询模式。这里,主表和它的索引表,可以看做是同一份数据的不同组织形式,各自能够高效的支持一定的查询模式。
考虑本文开始时给出的学生信息表的示例:
主表Student:以学号(id)为主键(rowkey),每行有两列,学生姓名(name)和所属的学院(department)。该设计仅支持按id进行查询。如果用户要按department或者name来查询,需要全表扫描 + filter。在学生数较少时,这种暴力扫描完全可行。但在数据量大时(数十万乃至上亿时),这种操作是无法执行的。
为了高效的支持按department查询,可为其建立一个全冗余索引(使用HBase shell):
create_index 'department', 'student', {INDEXED_COLUMNS => ['f:departement']}, {COVERED_COLUMNS => ['COVERED_ALL_COLUMNS']}
在建索引时,系统会自动为主表中的存量数据构建索引,写入索引表中。主表行和索引行是一一对应的。之后主表上发生的数据更新,也会自动同步给索引表。
考虑如下查询:
-- 查找所有计算机学院(cs)的学生的姓名(name) select name from student where department = 'cs';
这个查询会直接命中索引表,按department列进行前缀匹配。从每一个索引行中提取name字段,返回给客户端。
如果我们没有建立冗余索引,则索引表中不会存在name列。此时,在从索引表中读取到学号(id)后,必须回查主表(三次按id的单行读)来读取name列。在分布式场景下,10/12/13这三个id的数据可能分布在三台机器上。因此,回查主表最差情况下需要3次RPC,加上查索引表的一次RPC,共需4次RPC。而如果是冗余索引,则只需查索引表的一次RPC即可。
因此,在分布式场景,尤其是节点很多的大集群,回查主表带来的性能损耗是巨大的(RT可能会增长数倍)。这也是我们设计全冗余索引的初衷:避免回查,提高性能。
总结
数据只有被查询才能创造价值,HBase原生高性能二级索引为多维度查询提供了一种有效的解决方案。在表设计上,用户可以参考MySQL等关系型数据库的索引设计思路来进行HBase的索引设计。业务无需更改代码,查询优化可自动进行索引表的选择。强一致、全冗余索引等特性也有效降低了业务的使用门槛。
未来,我们将对索引做进一步的优化和扩展,提供优质的用户体验。欢迎大家体验HBase增强版。如您有对HBase相关的任何问题,欢迎通过钉钉与我们联系(钉钉搜索“云HBase值班”)。
相关链接
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
多个阿里云ecs实例挂载同一个共享存储块
共享块存储是阿里云块存储下的一个产品。用户可以像使用本地硬盘一样对挂载到ECS服务器上的块存储做分区、创建文件系统等操作。共享块存储是专为企业级客户的核心业务高可用架构设计的,除了拥有块存储的功能,还能同时挂载到多个ecs实例上。 什么是共享块存储 在政府、企业、金融客户的核心业务中,经常会用到Oracle RAC架构,这个架构有一个最基本的要求,就是多个计算节点能够同时访问同一份数据。那么,传统的硬盘由于不支持并发的挂载和读写访问,不满足要求,所以阿里云ECS提供了共享块存储这个产品,能够支持多个ECS实例进行并发读写访问,是一个提供高随机IOPS的一个数据块级的存储设备。 共享块存储的主要用于传统关系型数据库高可用架构、服务器高可用HA架构、基于ECS实例搭建的Docker集群、其他需要Share-Disk的业务等业务场景。 ECS挂载共享块存储步骤 今天介绍如何将一块共享块存储,同时发给多个ECS实例进行并发的读写访问。 点我登录阿里云,进入ECS控制台,在控制台在存储下面有云盘和共享块存储两个管理界面。点击进入共享块存储管理界面里面。 点击创建共享块存储在某一个地域和可用区下,...
- 下一篇
Delta Lake 0.5.0 正式发布,支持包括 Hive/Presto 等多种查询引擎
Delta Lake 0.5.0 于2019年12月13日正式发布,正式版本可以到 这里 下载使用。这个版本支持多种查询引擎查询 Delta Lake 的数据,比如常见的 Hive、Presto 查询引擎。并发操作得到改进。当然,这个版本还是不支持直接使用 SQL 去增删改查 Delta Lake 的数据,这个可能得等到明年1月的 Apache Spark 3.0.0 的发布。好了,下面我们来详细介绍这个版本的关键特性。 通过使用 manifest 文件来支持多种查询引擎 在之前版本的 Delta Lake,只支持使用 Spark 去查询 Delta Lake 的数据,使得它的使用场景有点限制。但是通过引入了 manifest 文件(参见 #76),我们可以使用 Presto/Amazon Athena 等查询引擎去查询 Delta
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,CentOS7官方镜像安装Oracle11G
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker安装Oracle12C,快速搭建Oracle学习环境