HBase

1.Apache HBase的现状和发展 2.HBase RowKey与索引设计 3.HBase 应用与高可用实践 4.网易HBase实践 5.云上HBase冷热分离实践 6.Procedure V2 介绍 7.HBase in Practice 性能、监控及问题解决
展开查看详情

1. Apache HBase 的现状和发展 作者:杨文龙 一.HBase 是什么 HBase(Hadoop Database),是一个基于 Google BigTable 论文设计的高可靠性、高性能、 可伸缩的分布式存储系统。 它有以下特征: 1.HBase 仍然是采用行存储的,采用松散表的结构来获得动态列的功能; 2.原生海量数据分布式存储。在单个数据库中可以存档 GB 甚至上 pb。在一行中也可以存 储上百万列。任何大小的数据量都适合采用 HBase; 3.不仅支持随机查询,还支持范围查询; 4.高吞吐,低延迟。一个集群可以有上千万个 dps,平均的延迟可以做到一毫秒之内; 5.在线 NOSQL 数据库; 6.多版本,增量导入,多维删除。 1.1 HBase 的四大基因

2.1.1.1 自动分区 最开始的时候,我们的数据库是单机的数据库。慢慢的我们发现单机的数据库无法承受数据 和访问的爆发式增长。因此就出现了分库分表的方案。将数据库和表拆分到多个服务器上, 然后利用中间件作为一个路由。这里就会遇到一个问题,随着数据的增加,中间件就会成为 一个瓶颈。如果请求量爆发式增长的时候,要加载新的进去,整个物理的变化需要进行搬迁 之后才能够进行使用。 而在 HBase 中,使用的是自动分区功能。当访问量和请求量增加的时候它可以自动的进行 数据分片,以应对数据和请求的爆发式增长。 1.1.2 LSM-Tree LSM(Log Structured Merge)Tree,它的一个重要的功能就是随机写变成顺序写。 现在 LSM 模型是大数据库的标配。它主要包括如下几个特点: 1)写吞吐量高; 2)不受 hdd 随机写瓶颈和 ssd 随机写入放大干扰;

3.3)超强数据导入能力。 1.1.3 存储计算分离 HBase 本身不会存任何数据。数据都是存储在底层的 HDFS 中。存储计算分离有以下好处: 负载均衡更高效、资源扩容更节省、存储优化更便捷。

4.1.1.4 HBase 生态 HBase 有一个非常强大的朋友圈。具体见下: 1.2 场景 HBase 是几乎可以满足所有的大数据场景需求。比如说对象存储,比如说推荐系统。比如 说用来存储订单,用来存储聊天记录。高性能推送的朋友圈应用的场景。针对一些其他的场 景,我们可以利用 HBase 加上组件能力来实现这些场景的应用。比如说 HBase 加 Phoenix, 来实现 NEWSQL 的数据库。比如说 HBase 加上 geomesa 来实现时空数据的存储,滴滴 就是采用这种方案来存储他们的轨迹数据。在物联网场景,可以采用 HBase 加 OpenTSDB 来存储海量的时序数据。

5.1.3 使用 HBase 的商业公司 基本上每一个大型的公司都在使用 HBase。 1.4 HBase 特性总结

6.HBase,为大数据而生,有 LSM 树:离线导入效率巨高 、实时写入吞吐大、增量导入隔离 性强;伸缩性强;TTL:数据时效性,系统自动处理、时效性的个性化设置;多版本:数据 的第三维度、高效删除方式;动态列:数据发散的利器;协处理器:数据校正、高效适应个 性化;异构介质多副本存储:海量与实时的性价比满足;Erasure Code:因大而生。 二.HBase 社区的发展 2.1 HBase 的起源 HBase 于 2006 年诞生于 Powerset,一家从事自然语言处理和搜索的创业公司(后被微软收 购) HBase 的实现基于 Google 发布的 BigTable 论文,用来解决 Hadoop 中随机读写效率低 下的问题。HBase 最初的开发人员是 MichaelStack 和 JimKellerman。2007 年 4 月,HBase 做为一个模块提交到 Hadoop 的代码库中,代码量~8000 行,2010 年 5 月 HBase 成为 Apache 的顶级项目,同年,Facebook 把 HBase 使用在其消息平台中。

7.2.2 HBase 项目现状 目前 HBase 的代码已经超过 100 万行,HBase 仍然是最活跃的 Apache 项目之一,拥有 76 个 Committer,42 位 PMC,共有 328 位 Contributor,其中 14 位 Committer/PMC 来自中国。 2.3 HBase 目前版本 HBase 目前版本众多。见下图:

8.三.HBase 2.0 3.1 HBase2.0 版本发布历史 HBase2.0 的发布是一部血泪史,因为在四年前已经有这个版本了,由于一些因素,造成了 没有人管理。最后花了一年多的时间才稳定他的版本发布出来,他的 Release Manager 多 次更换,才把他发布出来。由此,我们吸取了这次教训,我们以后会做好版本控制,把控好 发布的节奏。

9.3.2 新功能 3.2.1 Region Replica Region Replica 这个功能在 1.2 版本中已经存在,但是为什么叫做新功能呢?是因为之后 修改了很多 bug,在 1.4 版本才稳定下来,然后 1.4 和 2.0 是同时发布的。在 CAP 理论 中,HBase 一直是一个 CP 系统,遵循强一致的读写语义,所以 Server 宕机后需要一定的恢 复时间,如果宕机了,客户端可以从另外的副本中去读取数据,Region Replica 为数据分 片 Region 准备了多个副本,host 在不同的 RegionServer 上,同时,客户端也可以做到, 对多个副本同时发请求,然后做到选择最快速的那个副本,提供高可用读,宕机 0 影响, 规避抖动,毛刺,降低 P999 延迟;缺点是需要额外耗费 CPU/Memory 资源,但不会占用 额外空间。

10.3.2.2 读写链路 Off-heap 第二个新功能是全链路 Off-heap,意思就是读写链路数据端到端 Off-heap,减少 java GC 带来的停顿,进一步降低 P999 延迟,提高吞吐。这个功能我们从两方面来实现的:写链路 Off-heap,我们使用在 RPC 层使用 Netty 的 Off-heap ByteBuffer,使用支持 Off-heap 的 Protobuf。同时使用 Off-heap 的 Chunk 来存储 Memstore 中的 KeyValue。 在读链路 Off-heap 方面,使用 Off-heap 的 Bucket Cache,HBase 自己管理内存的,我 们从 Bucket Cache 读取数据的时候,先要从 Protobuf 做一次拷贝,因为可能读取的时候, 发生内存不够了,再次分配的情况。在读取对 Bucket Cache 进行引用计数,保证读取的时 候,内存不会被回收掉,读取时不再需要先拷贝到 heap,对 Bucket Cache 进行了一系列 性能优化。

11.后面这是 HBase 官方放着阿里巴巴在双十一对 HBase 优化之后的对比图,可以看到优化之 后他的请求的曲线更加平稳,吞吐量增长了 30%,这个案例大家可以去 HBase 的官方去看 一下。 3.2.3 In Memory Compaction 在 HBase2.0 中另外一个重磅的功能就是 In Memory Compaction,以前我们知道 HBase 中使用的数据结构是 java 中原生的跳表,但是跳表依然是一个松散的结构,这样的话,虽 然内存不断的在增大,但是刷到之后,会造成通过 In memory 的 flush 不会到 hdfs 上,

12.反而回转到更加紧凑的 CellArrayMap 这个结构,同时多个 CellArrayMap 会在内存中做 compaction,使内存的使用更加紧凑。然后通过 In memory 的 flush 和 compaction,在 内存中可以存储更多的数据,因此可以提高读性能,同时减少磁盘 IO,减轻 compaction 小文件造成的写放大。这个功能社区也有介绍。 3.2.4 小对象存储 MOB 之前我们建议在 HBase 上不要存很大的 KV 值,但是 MOB(Moderate Object Storage) 功 能使 HBase 能高效地存储那些 100k~10M 中等大小的对象。这使得用户可以把文档、图 片对象保存到 HBase 系统中,用户写入的小对象 flush 成一个独立文件,原有的 KV 中的 value 只存这个对象的引用路径,对于存储对象文件,更少地进行 compaction 来减少写入 放大效应。

13.3.2.5 Assignment MangerV2 这是一个非常重要的模块,HBase 中的状态流转,建表删表,都需要在 Assignment MangerV2 上进行,之前旧 AM 系统参与角色多,状态更新混乱,效率低,无事务保证,容 易出现 RIT 问题。所以 AM V2 使用 ProcedureV2 来保证 Table/Region 状态转换在 master 重启后仍然能恢复执行,然后去除了 Zookeeper 做为中间角色,Master/RegionServer 直接交互,Region assign/unassgin 速度大大提升。

14.3.2.6 其他 在 HBase2.0 中,还有非常多的新功能,具体如下: 3.3 兼容性和升级建议 建议如下:

15.四.HBase 未来规划 4.1 HBaseConAsia & 开发者圆桌会议 HBase 众多开发者也会参加这个会议,参与讨论它的未来发展方向。 4.2 更加易用 HBase 已经提供 Java 的 API,但是这个案例不太友好,我们目前打算提供 Native 的 SQL 接口,能够做到轻量级的 SQL 支持、内置的二级索引方案、与 Spark SQL 更好地结合等功 能。 4.3 更高性能 在以后的版本中,不用在对 HBase 的性能担心了, 我们在以后的版本中准备从 Use CCSMap to improve HBase YGC tim、全链路异步化、基于非易失存储的 WALLess 方案等方面努 力成为 LSM 模型下性能最好的 Java 存储引擎。

16.4.4 更强扩展性和稳定性 这个方面我们以下几个方面来解决: 五.如何成为 Committer

17.

18.

19. HBase RowKey 与索引设计 作者:毕杰山 今天分享的内容主要是 HBase RowKey 与索引设计相关的一些技巧、原则和相关案例。将 分以下四部分分析,第一部分简单介绍 HBase 基础知识,第二部分探讨合理的需求调研方 法 , 第 三 部 分 是 关 于 RowKey 与 索 引 设 计 的 一 些 技 巧 、 原 则 , 第 四 部 分 是 关 于 OpenTSDB/JanusGraph/GeoMesa 典型案例的设计分享。 一.HBase 基础 第一部分包括基础概念与数据模型介绍、快速浏览读写流程、介绍 RowKey 在读写流程中 发挥的作用。 首先是基本概念介绍。 Table:同传统数据库中的表是类似的,但他的不同之处在于它是基于 SchemaLess 的设计, 比传统数据库表更加灵活。 Region:将表横向切割成一个个子表,从而实现分布式的存储,子表在 HBase 中称作

20.Region,它关联了数据的一个区间。 Column Family:HBase 可以将一行数据分成不同列的集合,这些列的集合称为 Column Family,不同的 Column Family 文件被存储在不同的路径中。 RegionServer:指 HBase 里面数据服务的进程,每个 Region 必须要分到 RegionServer 上才能提供正常的读写服务。 MemStore:用来在内存中缓存一定大小的数据,达到一定大小后批量写入到底层文件系统 中。 HFile:HBase 数据在底层分布式文件系统中的文件组织格式。 关于进程角色如下图,主要有 ZooKeeper、Master、RegionServer 等角色。Meta 表的 路由信息在 ZooKeeper 中;Master 负责表管理操作,Region 到各个 RegionServer 的分 配以及 RegionServer Failover 的处理等;RegionServer 提供数据读写服务。HBase 的所 有数据文件都存放在 HDFS 中。

21.我们先来理解一下 KeyValue 的概念。在 HBase 中所存储的数据,是以 KeyValue 形式存 在的。KeyValue 拥有特定的组织结构,如下图所示。一个 KeyValue 可以理解成 HBase 表 中的一个列,当一行存在多个列时,将包含多个 KeyValue。同一行的 KeyValue 有可能存 在于不同的文件中,但在读取的时候,将会按需合并在一起返回给客户端。用户写数据时, 需要定义用户数据的 RowKey,指定每一列所存放的 Column Family,并且为其定义相应 的 Qualifier(列名),Value 部分存放用户数据。HBase 中每一行可拥有不同的 KeyValues, 这就是 HBase Schema-Less 的特点。 下面介绍 KeyValue 多版本。HBase 中支持数据的多版本,通过带有不同时间戳的多个 KeyValue 版本来实现的。HBase 所保存的版本数目是可配置的,默认存放 3 个版本。在普

22.通的读取流程中,旧版本的数据是不可见的,但通过指定版本数或者版本号的读取,可以获 取旧版本数据。下图是普通读取流程与多版本读取流程的对比。 用户数据存入到 HBase 表中时,需要进行 Qualifier (KeyValue/Qualifier(KeyValue/列) 设 计。一个最简单的设计是保持 HBase 的列与用户数据一致,如下图 1 的设计。这种,基本 上与关系型数据库的设计是一致,但这种会带来较大冗余 (KeyValue 结构化开销)。但 HBase 基于 KeyValue 的接口,决定了这种设计可以是非常灵活的,例如我们也可以考虑 为 HBase 的每一行只设置两个列,其中 Name 为一个列,其它内容合并到一个列中,如下 图 2 所示。 尽管我们在使用 HBase 表存放数据的时候,需要预先做好列设计。但这个设计仅仅由应用 层感知,HBase 并没有存放任何的 Schema 信息来描述这个设计。也就是说,应用层需要 知道为每一表/每一行设计了什么样的列(KeyValue),然后在读取的时候做相应的解析。然 HBase 中并没有 Schema 信息,那么每一行中的列,也可以是任意添加的。如上图所示, 绿色背景的 KeyValue 为后续增加的。 关于 Column Family,前面提到它是列的集合。每个 Column Family 里面关联了一个

23.MemStore,关联了多个 HFile 文件。当我们在选择是否要应用多个 Column Family 的时 候,需要调研所读写应用的业务特点,有些数据可能会一起写入,有时候临时增加数据,此 时可以考虑用两个 Column Family。如下图所示,假设为表设置了两个列族,而且定义每 一个列族中要存放的列:{Name}->Column Family-A,{City,Phone,Gender}->Column Family-B 不同列族的数据会被存储在不同的路径中。即设置多个列族时一行数据可能存在 于两个路径中。整行读取的时候,需要将两个路径中的数据合并在一起才可以获取到完整的 一行记录。但如果仅仅读取 Name 一列的话,只需要读取 Column Family-A 即可。 下图所示,读写数据的简单路由机制。一开始会先去 ZooKeeper 中获取 Meta 表的路由信 息,然后在 Meta 中定位每条数据关联的用户 Region 路径。下面这部分是基于 RowKey 从 Meta 表定位关联 Region 方法,通过一个反向扫描的方式进行。

24.下面介绍一下写入流程。客户端通过发请求到 RegionServer 端,写入的时候会先写入 WAL 日志中,其次会将数据写入 memstore 内存,当数据达到一定大小后会 flush 成一个个的 HFile 文件,当文件达到一定数量后,通过 compaction 的操作合并成更大文件,这样数据 读取会更快。

25.Region Split。有人可能会有疑问,分裂的时候需不需搬迁数据?当一个 Region 变的过大 后,会触发 Split 操作,将一个 Region 分裂成两个子 Region。Region Split 过程并不会 真正将父 Region 中的 HFile 数据搬到子 Region 目录中。Split 过程仅是在子 Region 中创 建了到父 Region 的 HFile 引用文件,子 Region1 中的引用文件指向原 HFile 的上部,而 子 Region2 的引用文件指向原 HFile2 的下部。数据的真正搬迁工作是在 Compaction 过 程完成的。

26.下面是读取流程。当进行读取时,客户端会先发送 scan 请求到 RegionServer,打开 scanner,然后调 next 请求获取一行数据,也可以将一批数据先放入 Result 的 Cache 中 去,客户端不断迭代获取内容,scan 每次获取多少行数据通常需要结合自己业务特点去获取 合理的值。 关于 Scanner 的抽象。由于数据一开始会先写入 MemStore,当数据达到一定大小以后再 Flush 成底层文件,那么在读取的时候首先需要解决的问题是什么?因为数据可能存在于多 个列族中,然后每个列族里又有内存里面的数据,还有些数据可能存在于多个文件中,那么

27.应该如何读取呢?这里涉及到数据的抽象,这里将 Region 的读取会封装成 ResultScanner 对象,每个列族封装成 StoreScanner 对象,每个 StoreScanner 里面又有多个 HFile、 MemStore 等。StoreScanner 包含一个 SegmentScanner 和多个 StoreFileScanner,这 些 Scanner 会被组织在优先级队列里面,在 Scan 的时候一定会优先指定一个起始 Key 的 值,Scanner 在打开的时候会将指针定位到指定 Key 的位置,每个 Scanner 在打开的时候 会对 KeyValue 进行排序,然后放入一个优先级队列中。然后客户端每次通过 Next 请求驱 动 Scan 的调用,Scanner Next 请求调用如下图所示,用 ScannerA-D 表示上面提到的各 种 Scanner ,当依次 Next 请求调用 时,会判断哪 个 Scanner 的数据是 最小的。比如 ScannerA 先读,读取 KeyValue 数据,然后判断 Scanner 是否读取完毕,是否超出了 Scan 范围,假如没有读完会被再次丢回队列,重新排序,如此循环获取数据。 关于 HFile 的组织结构。HFile 中数据按 Block 组织,一个 Data Block 的默认大小为 64KB, Data Block 中直接存储了 KeyValue 信息,最底层的 Block 是 Leaf Index Block,Data Block 的索引信息存储在 Leaf Index Block 中。而 Leaf Index Block 的信息存储在 Root Index 中(不考虑 Intermediate Index Block 情形)。从 Root Index Block 到 Leaf Index Block Leaf

28.Index BlockLeaf Index Block Leaf Index Block Leaf Index BlockLeaf Index Block 再到 Data Block,以及从 Data Block 到用户数据 KeyValue 的 数据组织,正是一种典型的 B + Tree 结构。 下面我们回顾一下 RowKey 在读写流程中发挥的作用: 读写数据时通过 RowKey 路由到对应的 Region,MemStore 中的数据按 RowKey 排序, HFile 中的数据按 RowKey 排序。 RowKey 的设计直接关乎 Region 的划分,我们如何划分 Region? 首先通过分析业务读写吞吐量以及总的数据量信息,设定合理的 Region 数量目标,接下来 预先定义 RowKey 的结构以及数据分布特点划分 RowKey 区间,然后按照设定的 Split 信 息建表。 RowKey 查询的局限性。根据下表信息,基于 Name+Phone+ID 构建 RowKey。如果提供 的查询条件能够尽可能丰富的描述 RowKey 的前缀信息,则查询时延越能得到保障。如下 面几种组合条件场景:Name+Phone+ID、Name+Phone、Name。如果查询条件不能提 供 Name 信息,则 RowKey 的前缀条件是无法确定的,此时只能通过全表扫描的方式来查 找结果。一种业务模型的用户数据 RowKey,只能采用单一结构设计。但事实上,查询场景 可能是多维度的。例如在上面的场景基础上,还需要单独基于 Phone 列进行查询。这是 HBase 二级索引出现的背景。即二级索引是为了让 HBase 能够提供更多维度的查询能力。 注意:HBase 原生并不支持二级索引方案,但基于 HBase 的 KeyValue 数据模型与 API, 可以轻易地构建出二级索引数据。Phoneix 提供了两种索引方案,而一些大厂家也都提供 了自己的二级索引实现。

29.常见的两种二级索引。方案一全局索引(下右图)、方案二本地索引(下左图)。方案一优点: 数据按索引字段全部排序,基于索引字段的小批次查询性能高。能够支持更大的查询并发数。 方法的复杂度较低。缺点是:生成索引数据对实时写入的影响较大。方案二优点:每一个用 户 Region 都拥有独立的索引数据,目前最佳的实践是将这部分索引数据存放于一个独立的 列族中。方案缺点:按索引字段进行查询时,需要访问所有的索引 Region,随着数据量和 Region 数目的不断增多,查询时延无保障,查询所支持的并发数也会降低。

为了让众多HBase相关从业人员及爱好者有一个自由交流HBase相关技术的社区,阿里巴巴、小米、华为、网易、京东、滴滴、知乎等公司的HBase技术研究人员共同发起了组建中国HBase技术社区。
关注他