作者简介
许鹏,携程高级研发经理,负责机票大数据基础平台的构建和运维。
机票业务看起来简单,实际上整个流程的处理链条很长,调用关系也非常复杂,上下游涉及的各类日志种类约60个,每种日志都有独立格式和请求/响应报文,日生产的日志数据量约50-100亿,如果时间范围再扩大到15天,数据量轻松的达到千亿级以上。
如何在海量的数据中提取想要的数据,这不是一件容易的事情。在大多数情况下,我们需要一种稳定而快速的架构,帮助我们在资源和性能之间获得平衡,于是我们开始了探索之旅。
一、初始架构
1.1 ElasticSearch
首先需要解决存储和查询的问题,海量的数据需要存储起来,供查询使用。如何有效的存储和查询这些日志数据,是系统设计时要回答的首要问题。
日志数据存储的特点和要求:
- 支持海量写入,TPS要能够支撑>50K/s
- 支持灵活的schema
- 支持灵活的数据查询,响应时间要尽可能短,时延<5s
- 对于过期的数据,支持海量删除
按照以上指标,我们对市面上的产品进行摸底和预研,选定了三种存储方式来进行对比:Cassandra、HBase、ElasticSearch。
1.1.1 Cassandra
Cassandra支持海量的数据写入,但是查询字段单一,同时对于数据删除不够友好,不支持行级别的TTL。当有大量的cell过期后,很容易出现TombStone的问题,并且在数据定期清理的过程中,很容易出现数据写入超时等现象。
1.1.2 HBase
1)HBase支持海量数据写入,在过期数据处理层面,不容易产生Cassandra才有的TombStone现象。但在查询接口层面,需要调用api才行,使用难度较高,尽管引入apache phoenix可以通过SQL来进行查询,但这增强了系统解决方案的复杂度。
2)HBase对于Row Key的查询能够快速返回,如果变更查询条件,响应会下降非常明显。
1.1.3 Elasticsearch
在排除了Cassandra和HBase之后,开始尝试Elasticsearch,通过研究发现,Elasticsearch可以很好的满足我们的需求:
- 支持灵活的数据结构,支持schemaless
- 可以通过水平扩展来支持海量的数据写入
- 查询方式灵活,响应时间短,平均查询响应低于<1s
- 结合别名和每天创建新索引,可以很好的移除过期数据,同时操作过程对用户透明
1.2 Kafka
Kafka作为消息队列,在存储日志数据的同时,隔离开数据产生的应用和数据处理流程。
1.3 ETL
为了把海量日志从Kafka近实时的导入到Elasticsearch,我们采用spark来进行处理,当前数据导入延迟不超过5s。
1.4 全局ID
每一次用户会话请求会被赋予一个单独的全局ID(TransactionID),这个全局ID会在各个模块之间的消息传递中出现。通过这样一个全局ID,开发人员可以追踪请求在整个链路中的处理情况。
各开发模块将含有全局ID的日志信息存储到Kafka集群中。
二、架构演进
第一代架构采用Elasticsearch解决了日志存储的问题,单日志查询的表现令人满意。
在实际系统使用过程中发现,由于机票日志种类繁多, 同时对50个以上日志并行查询会导致ElasticSearch集群整体状态变黄甚至变红,集群变的不稳定,整体反应速度变得非常缓慢。
硬件扩容Or提升性能,在架构层次需要进行决策,扩容能够解决一些问题,但是对于携程机票而言,后续还会有更多的日志接入,架构层面必须均衡资源和性能的平衡,而不是单纯的硬件扩容,我们决定在架构层面进一步演进来提升性能。
2.1 增加二级索引
通过分析,发现由于Elasticsearch会保存最近15天的日志,如果针对每一个TransactionID,都去查询15天的所有日志,那么查询响应时间会变得缓慢。
实际上每一个TransactionID不可能都存在于60多种日志中,做了很多多余的查询,如果能够精确的查询就好了。
为了增强查询的精确性,我们采用只对存有TransactionID的索引进行查询,我们建立了二级索引,通过二级索引,可以将TransactionID映射到一到多个具体的Elasticseaerch索引,然后对这些索引发起查询请求,获取详情信息。
也就是说,我们建立了索引,在查询前能准确的知道一个TransactionID在哪些日志、哪些日期中存在。
这样可以准确的查询这些日志,去掉不需要查询的日志。
通过二级索引的设置,查询速度获得很大的提升,由原来的20-30秒提升到5秒以内。
2.2 冷热数据分离
二级索引的建立解决了很大一部分问题,随着而来又产生了新的问题。
每天的二级索引数据量高达5亿条,随着时间推移二级索引数据量迅速增长,查询速度出现了抖动甚至大幅度下降,二级索引本身变成了瓶颈。
对二级索引我们再次做出了优化,对冷热数据进行切割,当天的二级索引会存储到redis中,因为系统使用中发现,用户一般对于当天的请求处理情况关注的比较多。Redis可以在5ms以内返回二级索引结果。
对于历史的二级索引,会将信息从Redis导入到Elasticsearch中。
三、小结
目前,机票日志追踪系统仍然在不断的、持续的演进中,比如最新的二级索引中冷数据不再存储到ElasticSearch,而是存储在codis集群中,ETL我们采用更快更好的批量灌入方式等等。
随着大数据技术的不断发展和进步,相信我们的架构也会不断的升级换代,架构的升级必然带来效能的提升,这就是技术的魅力所在。
我们始终相信,架构没有最好,只有更好。