1.背景
**
1.1 对接业务类型**
HBase 是建立在 Hadoop 生态之上的 Database,源生对离线任务支持友好,又因为 LSM 树是一个优秀的高吞吐数据库结构,所以同时也对接了很多线上业务。 在线业务对访问延迟敏感,并且访问趋向于随机,如订单、客服轨迹查询。离线 业务通常是数仓的定时大批量处理任务,对一段时间内的数据进行处理并产出结果,对任务完成的时间要求不是非常敏感,并且处理逻辑复杂,如天级别报表、 安全和用户行为分析、模型训练等。
1.2 多语言支持
HBase 提供了多语言解决方案,并且由于滴滴各业务线 RD 所使用的开发语言各 有偏好,所以多语言支持对于 HBase 在滴滴内部的发展是至关重要的一部分。我 们对用户提供了多种语言的访问方式:HBase Java native API、Thrift Server(主 要应用于 C++、PHP、Python)、JAVA JDBC(Phoenix JDBC)、Phoenix QueryServer (Phoenix 对外提供的多语言解决方案)、MapReduce Job(Htable/Hfile Input)、 Spark Job、Streaming 等。
**
1.3 数据类型**
HBase 在滴滴主要存放了以下四种数据类型:
- 统计结果、报表类数据:主要是运营、运力情况、收入等结果,通常需要配合 Phoenix 进行 SQL 查询。数据量较小,对查询的灵活性要求高,延迟要求一般。
- 原始事实类数据:如订单、司机乘客的 GPS 轨迹、日志等,主要用作在线和离线的数据供给。数据量大,对一致性和可用性要求高,延迟敏感,实时写入,单点或批量查询。
- 中间结果数据:指模型训练所需要的数据等。数据量大,可用性和一致性要求一般,对批量查询时的吞吐量要求高。
- 线上系统的备份数据:用户把原始数据存在了其他关系数据库或文件服务, 把 HBase 作为一个异地容灾的方案。
2. 使用场景介绍
2.1 场景一:订单事件
这份数据使用过滴滴产品的用户应该都接触过,就是 App 上的历史订单。近期 订单的查询会落在 Redis,超过一定时间范围或者当 Redis 不可用时,查询会落在 HBase 上。业务方的需求如下:
- 在线查询订单生命周期的各个状态,包括 status、event_type、order_detail 等信息。主要的查询来自于客服系统。
- 在线历史订单详情查询。上层会有 Redis 来存储近期的订单,当 Redis 不可用或者查询范围超出 Redis,查询会直接落到 HBase。
- 离线对订单的状态进行分析。
- 写入满足每秒 10K 的事件,读取满足每秒 1K 的事件,数据要求在 5s 内可用。
按照这些要求,我们对 Rowkey 做出了下面的设计,都是很典型的 scan 场景。
订单状态表
Rowkey:reverse(order_id) + (MAX_LONG - TS) Columns:该订单各种状态
订单历史表
Rowkey:reverse(passenger_id | driver_id) + (MAX_LONG - TS) Columns:用户在时间范围内的订单及其他信息
2.2 场景二:司机乘客轨迹
这也是一份滴滴用户关系密切的数据,线上用户、滴滴的各个业务线和分析人员都会使用。举几个使用场景上的例子:用户查看历史订单时,地图上显示所经过的路线;发生司乘纠纷,客服调用订单轨迹复现场景;地图部门用户分析道路拥堵情况。
用户们提出的需求:
- 满足 App 用户或者后端分析人员的实时或准实时轨迹坐标查询;
- 满足离线大规模的轨迹分析;
- 满足给出一个指定的地理范围,取出范围内所有用户的轨迹或范围内出现过的用户。
其中,关于第三个需求,地理位置查询,我们知道 MongoDB 对于这种地理索引有源生的支持,但是在滴滴这种量级的情况下可能会发生存储瓶颈,HBase 存储 和扩展性上没有压力但是没有内置类MongoDB 地理位置索引的功能,没有就需要我们自己实现。通过调研,了解到关于地理索引有一套比较通用的 GeohHash 算法 。
GeoHash 是将二维的经纬度转换成字符串,每一个字符串代表了某一矩形区域。 也就是说,这个矩形区域内所有的点(经纬度坐标)都共享相同的 GeoHash 字符串,比如说我在悠唐酒店,我的一个朋友在旁边的悠唐购物广场,我们的经纬 度点会得到相同的 GeoHash 串。这样既可以保护隐私(只表示大概区域位置而 不是具体的点),又比较容易做缓存。
但是我们要查询的范围和 GeohHash 块可能不会完全重合。以圆形为例,查询时会出现如图 4 所示的一半在 GeoHash 块内,一半在外面的情况(如 A、B、C、 D、E、F、G 等点)。这种情况就需要对 GeoHash 块内每个真实的 GPS 点进行第 二次的过滤,通过原始的 GPS 点和圆心之间的距离,过滤掉不符合查询条件的数据。
最后依据这个原理,把 GeoHash 和其他一些需要被索引的维度拼装成 Rowkey, 真实的 GPS 点为 Value,在这个基础上封装成客户端,并且在客户端内部对查询 逻辑和查询策略做出速度上的大幅优化,这样就把 HBase 变成了一个 MongoDB 一样支持地理位置索引的数据库。如果查询范围非常大(比如进行省级别的分析), 还额外提供了 MR 的获取数据的入口。
两种查询场景的 Rowkey 设计如下:
- 单个用户按订单或时间段查询: reverse(user_id) + (Integer.MAX_LONG- TS/1000)
- 给定范围内的轨迹查询:reverse(geohash) + ts/1000 + user_id
2.3 场景三:ETA
ETA 是指每次选好起始和目的地后,提示出的预估时间和价格。提示的预估到达 时间和价格,最初版本是离线方式运行,后来改版通过 HBase 实现实时效果,把 HBase 当成一个 KeyValue 缓存,带来了减少训练时间、可多城市并行、减少人工干预的好处。
整个 ETA 的过程如下:
- 模型训练通过 Spark Job,每 30 分钟对各个城市训练一次;
- 模型训练第一阶段,在 5 分钟内,按照设定条件从 HBase 读取所有城市数据;
- 模型训练第二阶段在 25 分钟内完成 ETA 的计算;
- HBase 中的数据每隔一段时间会持久化至 HDFS 中,供新模型测试和新的特征提取。
Rowkey:salting+cited+type0+type1+type2+TS
Column:order, feature
**
2.4 场景四:监控工具 DCM**
用于监控 Hadoop 集群的资源使用(Namenode,Yarn container 使用等),关系 数据库在时间维度过程以后会产生各种性能问题,同时我们又希望可以通过 SQL 做一些分析查询,所以使用 Phoenix,使用采集程序定时录入数据,生产成报表, 存入 HBase,可以在秒级别返回查询结果,最后在前端做展示。
图 7、图 8、图 9 是几张监控工具的用户 UI,数字相关的部分做了模糊处理。
3. 滴滴在 HBase 对多租户的管理
我们认为单集群多租户是最高效和节省精力的方案,但是由于 HBase 对多租户基本没有管理,使用上会遇到很多问题:在用户方面比如对资源使用情况不做分 析、存储总量发生变化后不做调整和通知、项目上线下线没有计划、想要最多的 资源和权限等;我们平台管理者也会遇到比如线上沟通难以理解用户的业务、对 每个接入 HBase 的项目状态不清楚、不能判断出用户的需求是否合理、多租户在 集群上发生资源竞争、问题定位和排查时间长等。
针对这些问题,我们开发了 DHS 系统(Didi HBase Service)进行项目管理,并且在 HBase 上通过 Namespace、RS Group 等技术来分割用户的资源、数据和权 限。通过计算开销并计费的方法来管控资源分配。
DHS 主要有下面几个模块和功能:
- 项目生命周期管理:包括立项、资源预估和申请、项目需求调整、需求讨论; 2. 用户管理:权限管理,项目审批;
- 集群资源管理;
- 表级别的使用情况监控:主要是读写监控、memstore、blockcache、locality。
当用户有使用 HBase 存储的需求,我们会让用户在 DHS 上注册项目。介绍业务 的场景和产品相关的细节,以及是否有高 SLA 要求。
之后是新建表以及对表性能需求预估,我们要求用户对自己要使用的资源有一个准确的预估。如果用户难以估计,我们会以线上或者线下讨论的方式与用户讨论 帮助确定这些信息。然后会生成项目概览页面,方便管理员和用户进行项目进展的跟踪。
HBase 自带的 jxm 信息会汇总到 Region 和 RegionServer 级别的数据,管理员会 经常用到,但是用户却很少关注这个级别。根据这种情况我们开发了 HBase 表级别的监控,并且会有权限控制,让业务 RD 只能看到和自己相关的表,清楚自己项目表的吞吐及存储占用情况。
通过 DHS 让用户明确自己使用资源情况的基础之上,我们使用了 RS Group 技术,把一个集群分成多个逻辑子集群,可以让用户选择独占或者共享资源。共享和独占各有自己的优缺点,如表 1。
根据以上的情况,我们在资源分配上会根据业务的特性来选择不同方案:
- 对于访问延迟要求低、访问量小、可用性要求低、备份或者测试阶段的数据: 使用共享资源池;
- 对于延迟敏感、吞吐要求高、高峰时段访问量大、可用性要求高、在线业务: 让其独占一定机器数量构成的 RegionServer Group 资源,并且按用户预估 的资源量,额外给出 20%~30%的余量。
最后我们会根据用户对资源的使用,定期计算开销并向用户发出账单。
4. RS Group
RegionServer Group,实现细节可以参照 HBase HBASE-6721 这个 Patch。滴滴在这个基础上作了一些分配策略上的优化,以便适合滴滴业务场景的修改。RS Group 简单概括是指通过分配一批指定的 RegionServer 列表,成为一个 RS Group, 每个 Group 可以按需挂载不同的表,并且当 Group 内的表发生异常后,Region 不会迁移到其他的 Group。这样,每个 Group 就相当于一个逻辑上的子集群,通 过这种方式达到资源隔离的效果,降低管理成本,不必为每个高 SLA 的业务线单独搭集群。
5. 总结
在滴滴推广和实践 HBase 的工作中,我们认为至关重要的两点是帮助用户做出 良好的表结构设计和资源的控制。有了这两个前提之后,后续出现问题的概率会大大降低。良好的表结构设计需要用户对 HBase 的实现有一个清晰的认识,大多 数业务用户把更多精力放在了业务逻辑上,对架构实现知之甚少,这就需要平台管理者去不断帮助和引导,有了好的开端和成功案例后,通过这些用户再去向其他的业务方推广。资源隔离控制则帮助我们有效减少集群的数量,降低运维成本, 让平台管理者从多集群无止尽的管理工作中解放出来,将更多精力投入到组件社区跟进和平台管理系统的研发工作中,使业务和平台都进入一个良性循环,提升用户的使用体验,更好地支持公司业务的发展。