唯品会 Dragonfly 日志系统的 Elasticsearch 实践

栏目: 后端 · 发布时间: 6年前

内容简介:唯品会日志系统,承接了公司上千个应用的日志,提供了日志快速查询、统计、告警等基础服务,是保障公司技术体系正常运行必不可缺的重要系统之一。日均接入应用日志600亿条,压缩后大小约40TB,大促时日志峰值流量达到每分钟3亿条。唯品会日志系统,取名Dragonfly,寓意像蜻蜓复眼一样,可以依据应用日志既准确又快速的观察到系统的运行细节、并发现系统的任何异动。最初,Dragonfly是围绕开源的ELK(Elasticsearch/Logstash/Kibana)技术栈打造的,后来架构不断演进,增加新的功能组件。

开篇-唯品会日志系统初探

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

唯品会日志系统,承接了公司上千个应用的日志,提供了日志快速查询、统计、告警等基础服务,是保障公司技术体系正常运行必不可缺的重要系统之一。日均接入应用日志600亿条,压缩后大小约40TB,大促时日志峰值流量达到每分钟3亿条。

唯品会日志系统,取名Dragonfly,寓意像蜻蜓复眼一样,可以依据应用日志既准确又快速的观察到系统的运行细节、并发现系统的任何异动。最初,Dragonfly是围绕开源的ELK(Elasticsearch/Logstash/Kibana)技术栈打造的,后来架构不断演进,增加新的功能组件。目前的系统架构如下图所示。

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

但无论怎么演进,快速、稳定的日志查询始终是日志系统的核心服务所在,因此Elasticsearch可谓是Dragonfly系统中的核心组件。本文将重点介绍唯品会日志系统有效使用Elasticsearch的各种实践经验。

Elasticsearch简介

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

朋友圈里这个月最为热议的技术新闻之一,就是Elastic公司2018.10.6在纳斯达克上市,当天开盘后股价就上涨了一倍。将一项技术通过开源不断做大做强,成为无可争议的垂直领域领导者,最终实现上市获得更大发展——Elastic公司实现了无数软件创业公司的梦想,并提供了一个完美的创业成功典范。而Elasticsearch正是这家公司的招牌产品。

Elasticsearch(下面简称ES)是基于Apache Lucene打造的分布式文档存储+文本查询引擎。它通过倒排索引(inverted-index)技术提供极快速的文本查询和聚合统计功能,通过合理的索引和分片设计,又可以支持海量的文本信息。因此非常适合用于搭建日志平台。

尽管如此,将这样一个开源软件,既要能贴合公司内部的实际使用场景,又要做到高吞吐、高容量、高可靠,还是需要做不少细致的工作,下面会一一道来。

Dragonfly系统从2015年开始搭建,最初使用Elasticsearch 1.x,后来升级到5.6版本。

硬件配置

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

Dragonfly系统在不同机房搭建了多个ES集群(配置了跨集群查询),共上百台机器,最大的2个集群均有接近50台服务器。这些服务器包含了两种硬件配置类型:

●一种使用多个SSD磁盘,并拥有性能强劲的CPU。 SSD服务器作为集群中的热数据服务器使用,负责新日志的写入,并提供使用频率最高的最近几天的日志查询服务。

●另一种使用多个大容量的HDD/SATA磁盘,搭配较弱的CPU。 HDD服务器作为集群中的冷数据服务器使用,负责保存较早前的日志。由于早前的日志访问频率较低,因此不需要很好的性能,而看重磁盘容量。

两种类型服务器的磁盘均使用RAID0阵列,内存大小为64GB或128GB。

通过冷热分离,可以保证ES集群的写入和实时查询性能,又能在成本较低的情况下提供较长的日志保存时间,下面还会详细介绍ES集群的冷热分离是怎么实现的。

日志索引管理

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

ES中的文档数据是保存在索引(index)之中的。索引可以划分多个分片(shard)分布在不同的节点上,并通过配置一定的备份数实现高可用。

对于日志数据,通常把每个应用、每天的日志保存到不同的索引中(这是以下很多讨论的前提)。 要承接公司上千个应用的海量日志,又要应对每个应用每天不同的数据量,如何有效管理这些日志索引,成为Dragonfly能否提供稳定和快速服务的关键。 下面将分多个方面为你介绍。你不会在官方文档中直接找到这些知识,它们来源于我们多年的实战经验。

1. 索引预创建

当有一个写入请求,而请求中指定的索引不存在时,ES会自动创建一个5分片的新索引。因为要完成寻找合适的节点、创建主分片、创建备份分片、广播新的集群信息、更新字段mapping等一系列的操作,创建一个新索引是耗时的。根据集群规模、新索引的分片数量而不同,在我们的集群中创建一个新索引需要几秒到几十秒的时间。如果要在新的一天开始的时刻,大量新一天的日志同时到来时触发创建上千个索引,必然会造成集群的长时间服务中断。因此,每天的索引必须提前创建。

此外,还有一个必须提前创建索引的关键原因,就是ES索引的分片数在创建时就必须给定,不能再动态增加(早期版本还不能减少,ES 5.x开始提供了shrink操作)。在两种情况下会造成问题:

●如果某个应用的日志量特别大,如果我们使用过少的分片数(如默认的5个分片),就会造成严重的热点问题,也就是分配到这个大索引分片的节点,将要处理更多的写入和查询数据量,成为集群的瓶颈。

●大部分的应用日志量非常小,如果分配了过多的分片数,就会造成集群需要维护的活跃分片数目很大,在节点间定时同步的集群信息数据也会很大,在集群繁忙的时候更容易出现请求超时,在集群出现故障的时候恢复时间也更长。

出于以上考虑, 必须提前创建索引,并为不同应用的索引指定合适的分片数量。 分片的数量可以由以下公式计算:

n_shards=avg_index_size/ size_per_shard * magnified_factor

其中:

●avg_index_size为前N天这个应用索引大小的指数移动平均值(日期越靠近、权重越大)

●size_per_shard为期望每个分片的大小。分片过大容易造成上述热点问题,同时segment merge操作的开销更大(下面详细介绍),在需要移动分片时耗时也会较久;而过小又会造成集群分片总数过多。因此要选取一个均衡的大小,我们使用的是20GB。

●magnified_factor为扩大系数,是我们根据公司特有的促销场景引入的。在促销日,业务请求数会数倍甚至数十倍于平时,日志量也会相应增长,因此我们需要在促销日为索引增加更多分片数。

索引预创建的操作我们放在前一天的清早(后面会看到,开销很大的操作我们都放在夜间和凌晨)进行。即今天凌晨会根据之前索引大小的EMA及上述公式计算出分片数,创建明天的索引。

2. 替补索引

这是很有意思的一个概念,你不会在任何其他ES相关的文章找到它(如果有,请注意百分百是抄袭:)

它解决的是这样的问题:即使我们已经提前估算出一个应用的日志索引的分片数,但是仍然会有异常情况。有时你会发现某个应用某一天的日志忽然增加了很多,可能是开发打开了DEBUG级别开关查问题,也可能在做压测,或者可能是bug死循环的打印了无数stacktrace。有时是一个新接入的应用,由于没有历史索引,所以并不能估算出需要的分片数。以上情况都有可能引起分片数不足的问题。

记得上面提到过索引在创建后就不能再动态调整分片数了,怎么破?

让我们来新创建一个替补索引(substitude index)吧,这一天接下来的所有日志都会写到这里。替补索引的命名,我们会在原索引名的基础上加上-subst后缀,因此用户在查询今天的日志时,查询接口仍可以通过一定的规则指定同时使用今天的“正选”索引和替补索引。

我们定时扫描当天索引的平均分片大小,一旦发现某个索引的分片大小过大,就及时创建替补索引。注意,创建替补索引时仍需指定分片数,这是根据当天已过去的小时数比上还剩下的小时数,以及当时已经写入的数据量估算得出的。

替补索引还有一种使用场景。有时促销是在晚上进行的,一到促销开始,请求量和日志量会出现一个非常大的尖峰。而由于已经写入了大半天的日志,分片已经比较大,这时任何的写入都可能引起更大规模的segment merge(熟悉ES的同学会知道,每次refresh会生成新的segment,小的segment会不断merge变成更大的segment,越大的segment merge时对磁盘IO和CPU的开销占用越大。这相当于HBase的compaction行为,也同样会有写放大问题),会使写入速率受到限制。而如果这时切换到新的索引写入(场上球员请全部给我下来~),就可以减轻merge的影响,对保障流量尖峰时ES集群的写入速率非常有帮助。

这种促销日的替补索引是提前创建的。分片数的计算、以及还有可能使用到“替补的替补”,就不再赘述了。

3. Force Merge

当数据写入ES时先产生小的segment。segment会占用堆内存,数量过多对查询时间也有影响。因此ES会按一定的策略进行自动合并segment的动作,这前文已经提过。此外,ES还提供force merge的方法(在早期版本称为optimize),通过调用此方法可以进一步强化merge的效果。

具体的,我们在凌晨执行定时任务,对前一天的索引,按照分片大小以及每个segment 500MB的期望值,计算出需要合并到的segment数量,然后执行force merge。

通过这个操作,我们可以节省很多堆内存。具体每个节点segment的内存占用,可以在_nodes//stats api中查看到。当segment memory一项占用heap大小2/3以上,很容易造成各种gc问题。

另外由于force merge操作会大量读写磁盘,要保证只在SSD服务器上执行。

4. 冷热分离

最初搭建ES集群时,为了保证读写速率,我们使用的都是SSD类型的服务器。但由于SSD磁盘成本高,容量小,随着接入应用越来越多,不得不缩短日志保存天数,一度只能提供7天的日志,用户开始产生抱怨。

我们自然而然产生了冷热分离的想法。当时在网上并不能找到ES冷热分离部署的案例,但出于曾经翻阅过官方文档多遍后对ES各种api的熟悉,我们认为是可行的。

●首先,在节点的配置文件中通过node.tag属性使用不同的标签可以区分不同类型的服务器(如硬件类型,机柜等);

●通过index.routing.allocation.include/exclude的索引设置可以指定索引分片只能分配在某种tag的服务器上;

●利用以上方法,我们在创建的新的索引时,指定只分配在热数据服务器(SSD服务器)上。使拥有强劲磁盘IO和CPU性能的热数据服务器承接了新日志的写入和查询;

●设置夜间定时任务,将N天前的索引修改为只能分配在冷数据服务器(HDD服务器)上。使访问频率降低的索引relocate到大磁盘容量的服务器中保存。

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

通过以上冷热分离的部署方法,我们只增加了少量大磁盘容量的服务器(成本比SSD类型的服务器还低很多),就将日志保存时长增加到了30天,部分应用可以按需保存更长时间。

5. 日志归档

从上面可以看出,通过冷热分离,热数据服务器只存放最近3天的日志索引,其余27天的索引都存放在冷数据服务器上。这样的话,冷数据服务器的segment memory将非常大,远超过官方文档建议的不超过32GB的heap配置。如果要增加heap到32GB以上,会对性能有一定影响。

考虑到越久远的日志,查询的可能性越低,我们将7天以前的日志进行了归档——也就是close索引的操作。close的索引是不占用内存的,也就解决了冷数据服务器的heap使用问题。

Dragonfly前端放开放了归档日志管理的页面,用户如需查询7天前的日志,可以自助打开已经归档的日志——也就是重新open已经close掉的索引。

日志写入降级策略

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

前面已经提到过,我们公司促销高峰时的日志量会达到平日的数十倍。我们不可能配备足够支撑促销高峰期日志量的服务器规模,因为那样的话在全年大部分时间内很多服务器资源是浪费的。而在服务器规模有限的情况下,ES集群的写入能力是有限的,如果不采取任何措施,在促销高峰期、以及万一集群有故障发生时,接入的日志将发生堆积,从而造成大面积的写入延迟,用户将完全无法查询最新的日志。此时如果有业务故障发生但无法通过日志来分析的话,问题会非常致命。

因此就需要有合理的降级措施和预案,以保证当日志流入速率大于日志写入ES集群的速率时,Dragonfly仍能提供最大限度的服务。我们首先需要做出取舍,制订降级服务的目标,最终我们采用的是:保证各个应用都有部分服务器的日志可以实时查询。

唯品会的日志,是从应用服务器先采集到Kafka做缓存的,因此可以在读取Kafka数据写入ES的过程中做一些处理。严格来说如何实现这一目标并不属于Elasticsearch的范畴。

要达到降级服务目标,我们需要设计一套组合拳:

●日志上传到Kafka时,使用主机名作为partitioning hash key,即同一台应用服务器的日志会采集到同一个Kafka topic的partition中;

●在消费Kafka topic时,使用同一个consumer group的多个实例,每个consumer实例设置不同的处理优先级;

●对Kafka consumer按照优先级不同,配置不同的写ES的线程数。优先级越高,写入线程数越多,写入速率越快;优先级越低,写入线程数越少,甚至暂停写入;

●这样就能保证高优先级的consumer能够实时消费某些partition并写入到ES中,通过hashing采集到那些被实时消费的partition的主机日志,也将在ES中可以被实时查询;

●随着度过日志流量高峰,当ES集群支持高优先级consumer的日志写入没有压力时,可以逐步增加次高优先级consumer的写入线程数。直到对应partition的堆积日志被消费完,又可以对更低优先级的consumer进行同样的调整;

●最终所有堆积的日志都被消费完,降级结束。

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

结语

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

除了核心组件Elasticsearch,Dragonfly日志系统还在日志格式规范、日志采集客户端、查询前端、规则告警、错误日志异常检测等方面做了很多的工作,有机会再跟大家继续分享。

推荐阅读

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

唯品会Noah云平台实现内幕披露

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

基于Kafka1.0消息可靠性设计之消费重试策略

唯品会 Dragonfly 日志系统的 Elasticsearch 实践

唯品会高吞吐量Access Log存储的实现

“唯技术”一档专为唯品技术人发声的公众号

欢迎投稿!!

只要是 技术相关的文章 尽管砸过来!

唯品会 Dragonfly 日志系统的 Elasticsearch 实践


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法基础

算法基础

[美] 托马斯 H.科尔曼(Thomas H.Cormen) / 王宏志 / 机械工业出版社 / 2015-12 / 59.00

本书介绍了什么是计算机算法,如何描述它们,以及如何来评估它们。这些计算机算法将提供:利用计算机搜索信息的简单方式;解决各种排序问题的方法;利用有向无环图和最短路径法来解决基本问题的方法(可用于建模公路网络,任务间的依赖及金融关系);解决字符串(例如DNA结构)问题的方法;密码学背后的基本原理;数据压缩的基础知识;以及甚至一些没有人能够理解如何在计算机上用相当长的时间来解决的问题。 本书适合作......一起来看看 《算法基础》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换