编者按:大数据的应用热潮袭来,如何更好地利用大数据为企业创造价值也是大家的关注点。Druid 是一个用于大数据实时查询和分析的高容错、高性能开源分布式系统,旨在快速处理大规模的数据,并能够实现快速查询和分析。蚂蜂窝作为国内最早一批使用 Druid 的公司,汪木铃给大家带来一场在应用 Druid 实战过程中遇到的问题和优化经验。以下是此次演讲内容整理。
汪木铃
2014 年至今负责蚂蜂窝数据采集、对接、数据产品的开发及整个大数据平台的架构设计、技术选型, 专注于大数据工具链的定制开发及应用。
|蚂蜂窝大数据平台
自我介绍一下。我是2014年加入到蚂蜂窝,目前是负责整个蚂蜂窝的大数据平台。在2014年,其实蚂蜂窝整个数据团队刚成立,那个时候数据分析是用各种简单的脚本去做各种统计。当时在建设大数据平台,我们也面临很多问题。比如说怎么去规范数据的接入、怎么统一数据的整个处理机制、怎么统一对外的 API 服务等。
图 1
如图 1 看一下当前蚂蜂窝整个数据流,在这张图里边最左边,包括移动端都埋了打点。APP 内放了 IOS-SDK,所有的 API 都是在用 PHP,封装三个 PHP SDK,作为统一的数据采集入口。这三个 SDK 采集完数据,统一地把所有数据都导入到 Kafka。三个 SDK 在前端机产生一分钟文件,这个一分钟文件再通过 Kafkacat一分钟引入。另外一个也是通过 Tail-Kafka实时把这一分钟文件所有的数据统一录到 Kafka 里面。在 Kafka 下游,有实时系统,我们叫蚂蜂窝事件系统,叫 MES。MES 里面通过 SparkSteaming 写入。
另外一个引入实时报表系统理念,作为多维的数据分析。在离线这一块,Hive作为存储层,Presto作为查询层。最终这些所有的数据都有各自的 API,比如实时的报表 Mes Api,Druid API 后台,通过自研的可视化做图表分析。再接着就是一些个性化推荐的数据,数据存储在hbase。包括用户的行为分析,我们叫 MVT 后台,可以追踪用户到蚂蜂窝,无论是 APP,还是整个网站,都能跟踪。这是当前蚂蜂窝的整个数据情况。
图 2
图 2 是当前整个蚂蜂窝大数据平台的一个技术体系。在接入层,我去接业务库的,叫 binlog,采用canal去接入。另外一个就是通过sqoop 去同步mysql业务表。在前端录数据,录到 Kafka,包括实时的,就是 TAIL-Kafka。存储的话在 HDFS。在 REDIS上,当前我们采用spark+redis作为整个实施报表系统的运算。在调度我们是采用 YARN,以及整个 MESOS。MESOS 我们现在用来统一管理spark streaming,presto 。在计算层面很简单,用的是Hive,Spark,presto,包括后面的 Druid。
在应用平台,我们自研了实时数据报表mes,离线数据仓库mdw,以及mql。mql是基于 Presto 造了一个可视化的 sql 执行 ui。现在在 Presto 社区,其实基本上是没有,有的话,像airbnb做可视化很丑陋,而且相对使用上特别不好。所以我们自研了叫MQL及MQL-T。上面通过一分钟就能够去搭建各种的 sql 报表。MES 就是我们现在的实时报表,MHA 是我们自研的可以分析每个网页,每个区块的各种点击,UPS/UDS 就是我们一些个性化的服务。在应用就是一些流量统计,用户画像,包括一些个性化推荐。最左边对于整个技术平台一些监控,当前采用Graphite/Grafana ,包括基于硬件监控的zabbix,监控我们整个平台各个集群。现在这些集群总共将近有 150 台左右机器,分散到各个集群上面。这是当前蚂蜂窝整个平台的技术体系。
|K-V 型事件模型
图 3
在前面提到,怎么去统一地让我们的工程师去上报数据,我们引入了 PHP SDK,通过传入定义一个叫 basic 的技术属性,以及 attr 的自定义属性。basic 我们在对外提供的 PHP API 是放了三个参数,第一个叫 app code,第二个叫 event code,第三个是自定义属性,传的是 attr ,就可以去自定义自己的各自的业务里面的关键收集点。后面整个数据的一个处理,作为 K-V 事件模型是特别重要的。
|实时数据探索
图 4
在数据实时探索,在过去每一次按天或者按小时。但是现在蚂蜂窝在发展,按小时,按天的话肯定就不符合当前的情况。所以我们需要有实时的数据探索。这个在蚂蜂窝的事件系统,叫 MES。通过自研,在上面的红框当中(图 4),每一层级叫 app code,event code,包括自定义的 attr。最终在 MES 里边,假如说他上报一个数据只需要在整个 MES 里面去配调规则,这个数据就实时能够在这个报表上看到。
图 5
这是在最开始我们引入 Druid 之前,我们通过自研第一代的 MES,就是用spark+redis+hbase。这是现在当前整个 MES 实时报表系统,我们两个,采用两代。第一代就是,跟大家说叫 spark+redis+hbase。后面引入 Druid 就叫 Spark+Druid,通过 Thrift-Service 去给 MES 报表系统,给用户做一些实时的数据探索。
图 6
但是这两个引擎,第一代MES,计算UV是精确的,因为需要去精确计算每一个用户。实现的功能的就是虚拟 key,第一代自研的就是支持虚拟 key,就是我们一个产品需要衍生出产品名称。另外一个有一个一对多的关系,比如我们的一个目的地,需要映射到*的或者是省级的,这是第一代。
第一代MES,作为精确的UV计算,在 redis 里面去实时的数据分析,但是在精确计算带来价格的同时,消耗需要再用大量的资源,包括各种计算的资源。第一代的 MES,比如说我们在每次大促,这个时候在流量上来的时候,在第一代 MES 这个引擎里面会造成大量延迟。比如说一分钟有几百万的数据进来,第一代是满足不了,有些可能延迟十几分钟,二十几分钟。
在另外一个,整个第一代 MES 只支持你配好规则之后,我们才按这条规则给你算出这个结果。但是假如我们工程师之前在自定义属性attr上报了一个字段key。想在下个礼拜我想要再去算这个key,这个时候只能是重新把这一天的数据导入。所以这个时候算一天,第一代算一天十几个小时,各种 UV,各种复杂的特别多的运算,包括 UV 的计算规则,KV 的计算压力,很多很多,达到几千万,上百万。
所以在同时,我们当时考虑到,在数据量大的情况下,是不是我们可以去牺牲 UV 的计算。所以就引入在 Druid 里面。把 Druid 引入到 MES,误差基本上保持在 2% 左右。后面我们又通过雅虎提供的data sketch,可以精确调控 UV 的计算,它的默认值是 16384,16384 以下可以是精确的。当然这个值是可以控制的,就是 2 的 N 次幂,当前我们是调到特别大,800 多万。但 Druid 里面不支持MES第一代的虚拟 key。
|MES 第一代:Spark+Redis+Hbase 实时数据探索
因此,第一代存在下述问题。
-
流量高峰期处理延迟
-
纬度交叉分析,不灵活
-
消耗资源大
- 系统故障,重算慢
这是第一代、消耗大、系统故障,在大内存情况下很容易导致崩溃。马蜂窝之前就遇到突发,一组三台,每一台 512 个 G,这个时候内存太大了,哪天一个内存条坏的话,这一天的数据可能就要重新算,而且对于现在当前整个实时数据量来看,完全就不符合当前的现状,算一天需要十几个小时。
|MES第二代:Druid实时数据探索
图 7
第二代 MES 我们就引入了 Druid 实时数据探索。图 7 是 Druid 的一个基本架构图,在 Clint 端发起请求,由 BROKER 发配,发配到实时节点上,取得当前实时数据,包括在HISTORICAL,这个节点就是存储历史的,请求完之后,在 BROKER 之后,再返回的一个结果。这是比较简单的。
图 8
图 8 是当前整个 Druid 在蚂蜂的一个配置,有三台机器上面挂 overlord 及 coordinator。另外三台就叫 middleManager。另外还有八台作为数据存储的(historical)。我们在这 8 台当中又拆分了两个小的集群,就相当于有两个作为热备。另外 6 台,叫冷数据。我们在这两台热数据的只能允许查询最近 15 天的。在 15 天之前的数据发配到 Cold-historical 6 台机器去查询。在 broker 区分出 hot 跟 cold,最终通过一排 broker router 去发路由。这样的话,在查询高峰互不影响。
图 9
图 9 是蚂蜂窝三个重要的业务日志,在维度方面,比如说像 server-event 有 700 多个维度。 700 多个维度,当然维度越多,查询性能就会受影响,包括导入数据,通过批量录数据到 Druid 里面,这个时候也是非常缓慢的。我们保留的周期当前每天基本上数据量很大,进来整个数据,包括集群存储都不够,所以说我们在最重要的三个日志源里面保留最近 15 天的。在维度越多的情况下查起来,比如发一个请求,code 去查询当天的 PV 或者 UV,PV 还可以,但是最影响性能就是查询 UV 的时候。一分钟都查不出来,基本上都是三四分钟。所以说在这三个大的数据源情况下,假如说要去查询之前历史数据一段时间,可能查好几十分钟,或者基本上是没有办法达到秒级情况下查询出来。
所以在基于三个大的业务模块情况下,拆分出对于蚂蜂窝比较重要的几块业务,就是图中下图。logdata、mobile、以及 Page,以及另外一个就是我们给用户发的 push。各自的维度基本上都是在 20、30 个,指标就 5 个。在维度小的情况下,基本上查询,比如我查询一年的 PV,就这五个指标,我同时发起请求去查询,基本上是在秒级响应。假如说我把请求放置到上面那三个模块里边,查询整个前端都会超时。
图 10
在 Druid 里面对于datasource 有一个按时间密度去分的,我们历史数据在查询力度这个层面,只能让他查到按每小时去查,其他按天去分配。最新的数据就在最近 15 天,我们可以让他精确到一分钟的查询,对于历史数据,力度越精确,数据量到 Druid 里面越大。
图 11
现在在整个蚂蜂窝里面做了一个是从实时的数据,然后有一个用 spark,这个组件实时地导入到 Druid 里面。在这个里面,我们做事情之前,对外提供数据采集的时候,有一个 attr 自定义属性,那里面所有的 attr key 我们是未知的。所以我们需要把 attr 里面所有的数据在录 Druid 之前都打平之后,每一天达到 700 多个维度。
在离线批量导入,现在 Druid 支持,T+1 的数据校正。如果在 PSPARK+TRANQUILITY 这一阶段,因为 SPARK 的 task 失败的话,可能会导致这个数据到 Druid 里面 PV 会上升。所以说需要每天凌晨通过批量导入的方法把上一天的数据做一个数据校准。同样的是需要打平在 attr 里打平所有工程师上报的数据制定的值。
在 Druid 方面,通过 thrift-service 提供给 MES 展现。
图 12
图 12 是grafana,grafana现在有一个插件,可以去查询 Druid 里面的数据。当前我们几个比较重要的日志源,就会每天去监控。
|Druid 集群注意事项
在 Druid 里面配置,
1、维度不要太多,像蚂蜂窝最开始 700 多个维度。每天导进去将近 100 个 G,导进去十分耗时。
2、维度大小,不要太大。比如你来一个维度值几兆的,这个不行。
3、要去合理配置比例。在最开始,我们就拿了跟我们之前节点挂上了 10 个 T 的磁盘,作为整个 Druid 节点的数据存储,但是发现在你去查,无论你是去查任务,或者查历史数据。10 个 T 的磁盘跟不上来,查询各种超时,各种响应。
4、磁盘选用。其实采用的固态盘,基本上像我们现在的配置,就是 256 个 G 内存,1.2T 的固态盘。这个配置起来,你去查询整个历史数据,或者无论你查询其他的数据都是很快的。5、在segment大小,我们最开始是按天的,100个G,后面拆分成每小时去分。这个时候到几个G,几个G也不行,我们就是要在去拆分几个G,到最终查询相当于是在在300-700兆左右。
6、在Druid里面,不支持逗号,因为 Druid 里在底层逗号是用来分隔。
7、优先去升级 Druid 的版本。我们在最早从 0.6 慢慢升级到 0.8,我们现在用的是 0.9。每一次 Druid 的发版,优化了很多东西。你觉得每一个查询有问题,或者说你想要去更快查询这些数据,可以优先考虑一下去 github 上面去看看 Druid 的最新近况。
这个就是今天给大家分享的一些东西。当然我们在使用 Druid 的过程当中,其实还遇到其他很多问题。也希望 Druid 能越来越好。