案例篇-HBase 在滴滴出行的应用场景和最佳实践

2019-01-09 11:55:22 641

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 在滴滴主要存放了以下四种数据类型:

  1. 统计结果、报表类数据:主要是运营、运力情况、收入等结果,通常需要配合 Phoenix 进行 SQL 查询。数据量较小,对查询的灵活性要求高,延迟要求一般。
  2. 原始事实类数据:如订单、司机乘客的 GPS 轨迹、日志等,主要用作在线和离线的数据供给。数据量大,对一致性和可用性要求高,延迟敏感,实时写入,单点或批量查询。
  3. 中间结果数据:指模型训练所需要的数据等。数据量大,可用性和一致性要求一般,对批量查询时的吞吐量要求高。
  4. 线上系统的备份数据:用户把原始数据存在了其他关系数据库或文件服务, 把 HBase 作为一个异地容灾的方案。

2. 使用场景介绍

2.1 场景一:订单事件

这份数据使用过滴滴产品的用户应该都接触过,就是 App 上的历史订单。近期 订单的查询会落在 Redis,超过一定时间范围或者当 Redis 不可用时,查询会落在 HBase 上。业务方的需求如下:

  1. 在线查询订单生命周期的各个状态,包括 status、event_type、order_detail 等信息。主要的查询来自于客服系统。
  2. 在线历史订单详情查询。上层会有 Redis 来存储近期的订单,当 Redis 不可用或者查询范围超出 Redis,查询会直接落到 HBase。
  3. 离线对订单的状态进行分析。
  4. 写入满足每秒 10K 的事件,读取满足每秒 1K 的事件,数据要求在 5s 内可用。

_2019_01_09_11_36_09

按照这些要求,我们对 Rowkey 做出了下面的设计,都是很典型的 scan 场景。

订单状态表
Rowkey:reverse(order_id) + (MAX_LONG - TS) Columns:该订单各种状态

订单历史表
Rowkey:reverse(passenger_id | driver_id) + (MAX_LONG - TS) Columns:用户在时间范围内的订单及其他信息

2.2 场景二:司机乘客轨迹

这也是一份滴滴用户关系密切的数据,线上用户、滴滴的各个业务线和分析人员都会使用。举几个使用场景上的例子:用户查看历史订单时,地图上显示所经过的路线;发生司乘纠纷,客服调用订单轨迹复现场景;地图部门用户分析道路拥堵情况。

_2019_01_09_11_37_25

用户们提出的需求:

  1. 满足 App 用户或者后端分析人员的实时或准实时轨迹坐标查询;
  2. 满足离线大规模的轨迹分析;
  3. 满足给出一个指定的地理范围,取出范围内所有用户的轨迹或范围内出现过的用户。

其中,关于第三个需求,地理位置查询,我们知道 MongoDB 对于这种地理索引有源生的支持,但是在滴滴这种量级的情况下可能会发生存储瓶颈,HBase 存储 和扩展性上没有压力但是没有内置类MongoDB 地理位置索引的功能,没有就需要我们自己实现。通过调研,了解到关于地理索引有一套比较通用的 GeohHash 算法 。

GeoHash 是将二维的经纬度转换成字符串,每一个字符串代表了某一矩形区域。 也就是说,这个矩形区域内所有的点(经纬度坐标)都共享相同的 GeoHash 字符串,比如说我在悠唐酒店,我的一个朋友在旁边的悠唐购物广场,我们的经纬 度点会得到相同的 GeoHash 串。这样既可以保护隐私(只表示大概区域位置而 不是具体的点),又比较容易做缓存。

_2019_01_09_11_38_47

但是我们要查询的范围和 GeohHash 块可能不会完全重合。以圆形为例,查询时会出现如图 4 所示的一半在 GeoHash 块内,一半在外面的情况(如 A、B、C、 D、E、F、G 等点)。这种情况就需要对 GeoHash 块内每个真实的 GPS 点进行第 二次的过滤,通过原始的 GPS 点和圆心之间的距离,过滤掉不符合查询条件的数据。

_2019_01_09_11_39_29

最后依据这个原理,把 GeoHash 和其他一些需要被索引的维度拼装成 Rowkey, 真实的 GPS 点为 Value,在这个基础上封装成客户端,并且在客户端内部对查询 逻辑和查询策略做出速度上的大幅优化,这样就把 HBase 变成了一个 MongoDB 一样支持地理位置索引的数据库。如果查询范围非常大(比如进行省级别的分析), 还额外提供了 MR 的获取数据的入口。

两种查询场景的 Rowkey 设计如下:

  1. 单个用户按订单或时间段查询: reverse(user_id) + (Integer.MAX_LONG- TS/1000)
  2. 给定范围内的轨迹查询:reverse(geohash) + ts/1000 + user_id

2.3 场景三:ETA

ETA 是指每次选好起始和目的地后,提示出的预估时间和价格。提示的预估到达 时间和价格,最初版本是离线方式运行,后来改版通过 HBase 实现实时效果,把 HBase 当成一个 KeyValue 缓存,带来了减少训练时间、可多城市并行、减少人工干预的好处。

整个 ETA 的过程如下:

  1. 模型训练通过 Spark Job,每 30 分钟对各个城市训练一次;
  2. 模型训练第一阶段,在 5 分钟内,按照设定条件从 HBase 读取所有城市数据;
  3. 模型训练第二阶段在 25 分钟内完成 ETA 的计算;
  4. HBase 中的数据每隔一段时间会持久化至 HDFS 中,供新模型测试和新的特征提取。

Rowkey:salting+cited+type0+type1+type2+TS

Column:order, feature

_2019_01_09_11_41_26
**
2.4 场景四:监控工具 DCM**

用于监控 Hadoop 集群的资源使用(Namenode,Yarn container 使用等),关系 数据库在时间维度过程以后会产生各种性能问题,同时我们又希望可以通过 SQL 做一些分析查询,所以使用 Phoenix,使用采集程序定时录入数据,生产成报表, 存入 HBase,可以在秒级别返回查询结果,最后在前端做展示。

_2019_01_09_11_42_57

图 7、图 8、图 9 是几张监控工具的用户 UI,数字相关的部分做了模糊处理。

_2019_01_09_11_43_59

_2019_01_09_11_44_50

_2019_01_09_11_45_38

3. 滴滴在 HBase 对多租户的管理

我们认为单集群多租户是最高效和节省精力的方案,但是由于 HBase 对多租户基本没有管理,使用上会遇到很多问题:在用户方面比如对资源使用情况不做分 析、存储总量发生变化后不做调整和通知、项目上线下线没有计划、想要最多的 资源和权限等;我们平台管理者也会遇到比如线上沟通难以理解用户的业务、对 每个接入 HBase 的项目状态不清楚、不能判断出用户的需求是否合理、多租户在 集群上发生资源竞争、问题定位和排查时间长等。

针对这些问题,我们开发了 DHS 系统(Didi HBase Service)进行项目管理,并且在 HBase 上通过 Namespace、RS Group 等技术来分割用户的资源、数据和权 限。通过计算开销并计费的方法来管控资源分配。

_2019_01_09_11_46_45

DHS 主要有下面几个模块和功能:

  1. 项目生命周期管理:包括立项、资源预估和申请、项目需求调整、需求讨论; 2. 用户管理:权限管理,项目审批;
  2. 集群资源管理;
  3. 表级别的使用情况监控:主要是读写监控、memstore、blockcache、locality。

当用户有使用 HBase 存储的需求,我们会让用户在 DHS 上注册项目。介绍业务 的场景和产品相关的细节,以及是否有高 SLA 要求。
之后是新建表以及对表性能需求预估,我们要求用户对自己要使用的资源有一个准确的预估。如果用户难以估计,我们会以线上或者线下讨论的方式与用户讨论 帮助确定这些信息。然后会生成项目概览页面,方便管理员和用户进行项目进展的跟踪。

HBase 自带的 jxm 信息会汇总到 Region 和 RegionServer 级别的数据,管理员会 经常用到,但是用户却很少关注这个级别。根据这种情况我们开发了 HBase 表级别的监控,并且会有权限控制,让业务 RD 只能看到和自己相关的表,清楚自己项目表的吞吐及存储占用情况。

通过 DHS 让用户明确自己使用资源情况的基础之上,我们使用了 RS Group 技术,把一个集群分成多个逻辑子集群,可以让用户选择独占或者共享资源。共享和独占各有自己的优缺点,如表 1。

_2019_01_09_11_48_36

根据以上的情况,我们在资源分配上会根据业务的特性来选择不同方案:

  1. 对于访问延迟要求低、访问量小、可用性要求低、备份或者测试阶段的数据: 使用共享资源池;
  2. 对于延迟敏感、吞吐要求高、高峰时段访问量大、可用性要求高、在线业务: 让其独占一定机器数量构成的 RegionServer Group 资源,并且按用户预估 的资源量,额外给出 20%~30%的余量。
    最后我们会根据用户对资源的使用,定期计算开销并向用户发出账单。

4. RS Group

RegionServer Group,实现细节可以参照 HBase HBASE-6721 这个 Patch。滴滴在这个基础上作了一些分配策略上的优化,以便适合滴滴业务场景的修改。RS Group 简单概括是指通过分配一批指定的 RegionServer 列表,成为一个 RS Group, 每个 Group 可以按需挂载不同的表,并且当 Group 内的表发生异常后,Region 不会迁移到其他的 Group。这样,每个 Group 就相当于一个逻辑上的子集群,通 过这种方式达到资源隔离的效果,降低管理成本,不必为每个高 SLA 的业务线单独搭集群。

_2019_01_09_11_50_12

5. 总结

在滴滴推广和实践 HBase 的工作中,我们认为至关重要的两点是帮助用户做出 良好的表结构设计和资源的控制。有了这两个前提之后,后续出现问题的概率会大大降低。良好的表结构设计需要用户对 HBase 的实现有一个清晰的认识,大多 数业务用户把更多精力放在了业务逻辑上,对架构实现知之甚少,这就需要平台管理者去不断帮助和引导,有了好的开端和成功案例后,通过这些用户再去向其他的业务方推广。资源隔离控制则帮助我们有效减少集群的数量,降低运维成本, 让平台管理者从多集群无止尽的管理工作中解放出来,将更多精力投入到组件社区跟进和平台管理系统的研发工作中,使业务和平台都进入一个良性循环,提升用户的使用体验,更好地支持公司业务的发展。

hbase 集群 Group 存储 客服

作者

hbase小能手
TA的文章

相关文章