斗鱼是一个面向广大用户的在线直播平台,每天都有大量的用户通过斗鱼的客户端参与线上互动。随着业务的迅速发展,斗鱼需要对客户端收集到的功能数据进行统计和分析,以开发出具备多维度分析图表和数据监控的APM(应用性能监控)平台。
为了实现这一目标,我们需要对从不同客户端收集的不同数据进行多维度的组合和聚合,从而生成可以在图表中展示的数据。例如,我们可以通过时间、地理位置、网络环境、客户端类型以及CDN供应商等多个维度,对各项指标进行多维度分析,包括客户端网络性能(如完整请求耗时、请求耗时、响应耗时、DNS耗时、TCP耗时、TLS耗时等)、错误时间段内的占比及具体数量、状态码分布等。以下是两个示例图表:
我们最初使用的APM平台基于Elasticsearch(简称ES)实时聚合。然而,在运行一段时间后,我们发现基于ES的方案存在一些问题:在处理复杂的多维度组合查询时,ES的性能压力很大,查询时间过长,用户难以等待,甚至可能出现数据精度丢失的问题。因此,为了更好地支持业务发展,我们决定尝试Apache Kylin。
作为首次使用Kylin,我们面临着搭建Kylin集群的挑战。考虑到业务稳定性,我们选择独立搭建一套专门用于Kylin的环境。Kylin支持多种Hadoop版本,我们选择了Cloudera CDH 5.14.4和Kylin 2.4.1。我们采用了CM(Cloudera Manager)的形式搭建集群,共17台机器,其中包括3台CM节点,以及HDFS、YARN、Zookeeper、Hive、HBase、Kafka和Spark 2等角色。我们部署了4台Kylin服务机器,采用了1个“all”节点、1个“job”节点和2个“query”节点,确保查询节点和作业节点都有备份,满足高可用需求。
斗鱼客户端收集的APM数据会先暂存在Kafka消息队列中,Kylin支持直接从Kafka主题中摄入数据,而无需先落Hive。我们选择了这种直连Kafka的方式构建实时Cube。在构建过程中,我们遇到了一些挑战:
Kafka数据格式要求:Kylin需要配置基于Kafka主题的Streaming Table。由于我们对这些要求不够了解,最初的Cube构建常常失败。经过排查和改进,我们发现需要对原始数据进行清洗和规整。我们使用流处理(如Storm/Flink)对Kafka中的数据进行处理,再写入新的Kafka主题供Kylin消费。
任务定时调度:我们需要定时从Kafka消费数据进行构建。一开始,由于对Kylin的理解不足,构建的Cube性能较差。我们发现每隔10~20分钟进行一次构建是最优方案。
Kylin的剪枝与优化:由于业务复杂,Cube的维度可能非常多。为了避免Cuboid数量爆炸式增长,我们需要结合业务进行优化和剪枝。例如,通过挑选、分组、设置层级维度、联合维度和必要维度等手段,减少计算成本。
在Kylin集群运行过程中,我们遇到了磁盘空间不足和服务不稳定的问题。我们采取了以下措施:
Kylin在后期维护中经常出现由于HBase连接超时导致的任务失败。我们通过调整HBase的相关参数(如hbase.rpc.timeout和hbase.client.operation.timeout)解决了这个问题。
由于业务迭代,我们需要在已有的Cube上添加新的维度和指标,或者修正原有的设计缺陷。目前我们采用重新设计整个流程的方式来解决这些问题。
通过引入Kylin,我们显著提升了查询速度,极大地改善了斗鱼APM系统的用户体验。原本需要90秒的查询现在只需2~3秒,仪表盘的加载时间也从几分钟缩短到几秒钟。在开发效率方面,虽然初期遇到了一些挑战,但在熟悉Kylin原理后,开发效率已经不逊于ES。
目前Kylin仍有一些不足,例如数据的实时性略逊于ES,但Kylin在处理海量历史数据时表现更佳。我们期待Kylin在未来的发展中不断完善,特别是在实时统计方面能够达到秒级延迟。