作者:Anton Hägerstrand

翻译:杨振涛

Meltwater每天要处理数百万量级的帖子数据,因此需要一种能处理该量级数据的存储和检索技术。

从0.11.X 版本开始我们就已经是Elasticsearch的忠实用户了。在经历了一些波折之后,最终我们认为做出了正确的技术选型。

Elasticsearch用于支持我们的主要媒体监控应用,客户通过该应用可以检索和分析媒体数据,比如新闻文章、(公开的)Facebook帖子、Instagram帖子、博客和微博。我们通过使用一个混合API来收集这些内容,并爬取和稍作加工,使得它们可被Elasticsearch检索到。

本文将分享我们所学到的经验、如何调优Elasticsearch,以及要绕过的一些陷阱。

如果想了解更多关于我们在Elasticsearch方面的点滴,可参考之前博文中的numad issues(http://suo.im/5bDszP)和 batch percolator(http://suo.im/5qFQb9)。

数据量

每天都有数量相当庞大的新闻和微博产生;在高峰期需要索引大约300多万社论文章,和近1亿条社交帖子数据。其中社论数据长期保存以供检索(可回溯到2009年),社交帖子数据保存近15个月的。当前的主分片数据使用了大约200 TB的磁盘空间,副本数据大约600 TB。

我们的业务每分钟有3千次请求。所有的请求通过一个叫做“search-service”的服务,该服务会依次完成所有与Elasticsearch集群的交互。大部分检索规则比较复杂,包括在面板和新闻流中。比如,一个客户可能对Tesla和Elon Musk感兴趣,但希望排除所有关于SpaceX或PayPal的信息。用户可以使用一种与Lucene查询语法类似的灵活语法,如下:

Tesla AND "Elon Musk" NOT (SpaceX OR PayPal)

我们最长的此类查询有60多页。重点是:除了每分钟3千次请求以外,没有一个查询是像在Google里查询“Barack Obama”这么简单的;这简直就是可怕的野兽,但ES节点必须努力找出一个匹配的文档集。

版本

我们运行的是一个基于Elasticsearch 1.7.6的定制版本。该版本与1.7.6 主干版本的唯一区别是,我们向后移植(backport)了roaring bitsets/bitmaps(http://suo.im/5bE6od) 作为缓存。该功能是从Lucene 5移植到Lucene 4的,对应移植到了ES 1.X版本。Elasticsearch 1.X中使用默认的bitset作为缓存,对于稀疏结果来说开销非常大,不过在Elasticsearch 2.X中已经做了优化。

为何不使用较新版本的Elasticsearch呢?主要原因是升级困难。在主版本间滚动升级只适用于从ES 5到6(从ES 2到5应该也支持滚动升级,但没有试过)。因此,我们只能通过重启整个集群来升级。宕机对我们来说几乎不可接受,但或许可以应对一次重启所带来的大约30-60分钟宕机时间;而真正令人担心的,是一旦发生故障并没有真正的回滚过程。

截止目前我们选择了不升级集群。当然我们希望可以升级,但目前有更为紧迫的任务。实际上该如何实施升级尚未有定论,很可能选择创建另一个新的集群,而不是升级现有的。

节点配置

我们自2017年6月开始在AWS上运行主集群,使用i3.2xlarge实例作为数据节点。之前我们在COLO(Co-located Data Center)里运行集群,但后续迁移到了AWS云,以便在新机器宕机时能赢得时间,使得我们在扩容和缩容时更加弹性。

我们在不同的可用区运行3个候选master节点,并设置discovery.zen.minimum_master_nodes为2。这是避免脑裂问题

split-brain problem

(https://qbox.io/blog/split-brain-problem-elasticsearch)非常通用的策略。

我们的数据集在存储方面,要求80%容量和3个以上的副本,这使得我们运行了430个数据节点。起初打算使用不同层级的数据,在较慢的磁盘上存储较旧的数据,但是由于我们只有相关的较低量级旧于15个月的数据(只有编辑数据,因为我们丢弃了旧的社交数据),然而这并未奏效。每个月的硬件开销远大于运行在COLO中,但是云服务支持扩容集群到2倍,而几乎不用花费多少时间。

你可能会问,为何选择自己管理维护ES集群。其实我们考虑过托管方案,但最后还是选择自己安装,理由是: AWS Elasticsearch Service

(http://suo.im/4PLuXa)暴露给用户的可控性太差了,

Elastic Cloud(https://www.elastic.co/cn/cloud)的成本比直接在EC2上运行集群要高2-3倍。

为了在某个可用区宕机时保护我们自身,节点分散于eu-west-1的所有3个可用区。我们使用AWS plugin(http://suo.im/5qFQEP)来完成该项配置。它提供了一个叫做aws_availability_zone的节点属性,我们把

cluster.routing.allocation.awareness.attributes

设置为aws_availability_zone。这保证了ES的副本尽可能地存储在不同的可用区,而查询尽可能被路由到相同可用区的节点。

这些实例运行的是Amazon Linux,临时挂载为ext4,有约64GB的内存。我们分配了26GB用于ES节点的堆内存,剩下的用于磁盘缓存。为何是26GB?因为JVM是在一个黑魔法之上构建的(https://www.elastic.co/blog/a-heap-of-trouble)。

我们同时使用Terraform

(https://www.terraform.io/)自动扩容组来提供实例,并使用Puppet(https://puppet.com/)完成一切安装配置。

索引结构

因为我们的数据和查询都是基于时间序列的,所以使用了

time-based indexing(http://suo.im/547GbE),

类似于ELK (elasticsearch, logstash, kibana) stack(https://www.elastic.co/elk-stack)。同时也让不同类型的数据保存在不同的索引库中,以便诸如社论文档和社交文档类数据最终位于不同的每日索引库中。这样可以在需要的时候只丢弃社交索引,并增加一些查询优化。每个日索引运行在两个分片中的一个。

该项设置产生了大量的分片(接近40k)。有了这么多的分片和节点,集群操作有时变得更特殊。比如,删除索引似乎成为集群master的能力瓶颈,它需要把集群状态信息推送给所有节点。我们的集群状态数据约100 MB,但通过TCP压缩可减少到3 MB

(可以通过curl localhost:9200/_cluster/state/_all 查看你自己集群的状态数据)。Master节点仍然需要在每次变更时推送1.3 GB数据(430 节点 x 3 MB 状态大小)。除了这1.3 GB数据外,还有约860 MB必须在可用区(比如 最基本的通过公共互联网)之间传输。这会比较耗时,尤其是在删除数百个索引时。我们希望新版本的Elasticsearch能优化这一点,首先从ES 2.0支持仅发送集群状态的差分数据(http://suo.im/547UyM)这一特性开始。

Performance 性能

如前所述,我们的ES集群为了满足客户的检索需求,需要处理一些非常复杂的查询。

为应对查询负载,过去几年我们在性能方面做了大量的工作。我们必须尝试公平分享ES集群的性能测试,从下列引文就可以看出。

不幸的是,当集群宕机的时候,不到三分之一的查询能成功完成。我们相信测试本身导致了集群宕机。

—— 摘录自使用真实查询在新ES集群平台上的第一次性能测试

为了控制查询执行过程,我们开发了一个插件,实现了一系列自定义查询类型。通过使用这些查询类型来提供Elasticsearch官方版本不支持的功能和性能优化。比如,我们实现了phrases中的wildcard查询,支持在SpanNear查询中执行;另一个优化是支持“*”代替match-all-query;还有其他一系列特性。

Elasticsearch和Lucene的性能高度依赖于具体的查询和数据,没有银弹。即便如此,仍可给出一些从基础到进阶的参考:

  • 限制你的检索范围,仅涉及相关数据。比如,对于每日索引库,只按相关日期范围检索。对于检索范围中间的索引,避免使用范围查询/过滤器。

  • 使用wildcards时忽略前缀wildcards - 除非你能对term建立倒排索引。双端wildcards难以优化。

  • 关注资源消耗的相关迹象 数据节点的CPU占用持续飙高吗?IQ等待走高吗?看看GC统计。这些可以从profilers工具或者通过JMX代理获得。如果ParNewGC消耗了超过15%的时间,去检查下内存日志。如果有任何的SerialGC停顿,你可能真的遇到问题了。不太了解这些内容?

    没关系,这个系列博文很好地介绍了JVM性能(http://suo.im/4AJgps) 。

    记住,ES和G1垃圾回收器一起并非最佳(http://suo.im/4WBTA5)。

  • 如果遇到垃圾回收问题,请不要尝试调整GC设置。这一点经常发生,因为默认设置已经很合理了。相反,应该聚焦在减少内存分配上。具体怎么做?参考下文。

  • 如果遇到内存问题,但没有时间解决,可考虑查询Azul Zing。这是一个很贵的产品,但仅仅使用它们的JVM就可以提升2倍的吞吐量。不过最终我们并没有使用它,因为我们无法证明物有所值。

  • 考虑使用缓存,包括Elasticsearch外缓存和Lucene级别的缓存。在Elasticsearch 1.X中可以通过使用filter来控制缓存。之后的版本中看起来更难一些,但貌似可以实现自己用于缓存的查询类型。我们在未来升级到2.X的时候可能会做类似的工作。

  • 查看是否有热点数据(比如某个节点承担了所有的负载)。可以尝试均衡负载,使用分片分配过滤策略shard allocation filtering

    (http://suo.im/4IfruL),或者尝试通过集群重新路由

    cluster rerouting(http://suo.im/5ja7cU)

    来自行迁移分片。我们已经使用线性优化自动重新路由,但使用简单的自动化策略也大有帮助。

  • 搭建测试环境(我更喜欢笔记本)可从线上环境加载一部分代表性的数据(建议至少有一个分片)。使用线上的查询回放加压(较难)。使用本地设置来测试请求的资源消耗。

  • 综合以上各点,在Elasticsearch进程上启用一个profiler。这是本列表中最重要的一条。

    我们同时通过Java Mission Control (http://suo.im/4zYEsP)和 VisualVM (http://suo.im/4AJeIM)使用飞行记录器。在性能问题上尝试投机(包括付费顾问/技术支持)的人是在浪费他们(以及你自己)的时间。排查下JVM哪部分消耗了时间和内存,然后探索下Elasticsearch/Lucene源代码,检查是哪部分代码在执行或者分配内存。

  • 一旦搞清楚是请求的哪一部分导致了响应变慢,你就可以通过尝试修改请求来优化(比如,修改term聚合的执行提示(http://suo.im/4WBUJx),或者切换查询类型)。修改查询类型或者查询顺序,可以有较大影响。如果不凑效,还可以尝试优化ES/Lucene代码。这看起来太夸张,却可以为我们降低3到4倍的CPU消耗和4到8倍的内存使用。某些修改很细微(比如 indices query (http://suo.im/4WBUR7)),但其他人可能要求我们完全重写查询执行。最终的代码严重依赖于我们的查询模式,所以可能适合也可能不适合他人使用。因此目前为止我们并没有开源这部分代码。不过这可能是下一篇博文的好素材。

图表说明:响应时间。有/没有 重写Lucene查询执行。同时也表明不再有节点每天多次发生内存不足。

顺便说明下,因为我知道会面临一个问题:从上一次性能测试我们知道通过升级到ES 2.X能小幅提升性能,但是并不能改变什么。话虽如此,但如果你已经从ES 1.X集群迁移到了ES 2.X,我们很乐意听取关于你如何完成迁移的实践经验。

如果读到了这里,说明你对Elasticsearch是真爱啊(或者至少你是真的需要它)。我们很乐意学习你的经验,以及任何可以分享的内容。欢迎在评论区分享你的反馈和问题。

400+节点的 Elasticsearch 集群运维相关推荐

  1. 400+节点的Elasticsearch集群运维

    墨墨导读:本文将分享我们所学到的经验.如何调优Elasticsearch,以及要绕过的一些陷阱. Meltwater每天要处理数百万量级的帖子数据,因此需要一种能处理该量级数据的存储和检索技术. 从0 ...

  2. 升腾威讯怎么恢复集群_PB级大规模Elasticsearch集群运维与调优实践

    导语 | 腾讯云Elasticsearch 被广泛应用于日志实时分析.结构化数据分析.全文检索等场景中,本文将以情景植入的方式,向大家介绍与腾讯云客户合作过程中遇到的各种典型问题,以及相应的解决思路与 ...

  3. PB 级大规模 Elasticsearch 集群运维与调优实践

    作者:bellen,腾讯云大数据研发工程师. 腾讯云 Elasticsearch 被广泛应用于日志实时分析.结构化数据分析.全文检索等场景中,本文将以情景植入的方式,向大家介绍与腾讯云客户合作过程中遇 ...

  4. PB级大规模Elasticsearch集群运维与调优实践

    导语 | 腾讯云Elasticsearch 被广泛应用于日志实时分析.结构化数据分析.全文检索等场景中,本文将以情景植入的方式,向大家介绍与腾讯云客户合作过程中遇到的各种典型问题,以及相应的解决思路与 ...

  5. 优酷蓝鲸近千节点的Redis集群运维经验总结

    http://www.infoq.com/cn/news/2016/08/youku-Redis-nosql Redis是时下比较流行的Nosql技术.在优酷我们使用Redis Cluster构建了一 ...

  6. 【Elasticsearch】Elasticsearch 集群 运维 高性能 架构设计 高负载

    1.概述 转载:干货 |<深入理解Elasticsearch>读书笔记 5.集群扩展 如何扩展集群? 5.1 垂直扩展 向Elasticsearch集群添加更多的资源.制约因素--如:JV ...

  7. etcd 集群运维实践

    [编者的话]etcd 是 Kubernetes 集群的数据核心,最严重的情况是,当 etcd 出问题彻底无法恢复的时候,解决问题的办法可能只有重新搭建一个环境.因此围绕 etcd 相关的运维知识就比较 ...

  8. Kafka的灵魂伴侣Logi-KafkaManger(4)之运维管控–集群运维(数据迁移和集群在线升级)

    推荐一款非常好用的kafka管理平台,kafka的灵魂伴侣 滴滴开源Logi-KafkaManager 一站式Kafka监控与管控平台 技术交流 有想进滴滴LogI开源用户群的加我个人微信: jjdl ...

  9. 阿里巴巴大规模神龙裸金属 Kubernetes 集群运维实践

    戳蓝字"CSDN云计算"关注我们哦! 导读:值得阿里巴巴技术人骄傲的是 2019 年阿里巴巴 双11 核心系统 100% 以云原生的方式上云,完美支撑了 54.4w 峰值流量以及 ...

最新文章

  1. buuctf(misc) FLAG [LSB隐写]
  2. Pwn环境配置(三)——ubuntu环境搭建
  3. c语言 函数的参数传递示例_nexttoward()函数以及C ++中的示例
  4. mysql数据库服务器名_mysql数据库服务器名
  5. 工厂模式——三个工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)...
  6. Vue动态权限路由addRoutes执行初次白屏解决方法。
  7. indesign入门教程,如何创建文本列?
  8. python安装包打不开
  9. 三菱plc与西门子plc编程有什么不同?
  10. 基于MSP430f5529的红外循迹小车
  11. 总结oninput、onchange与onpropertychange事件的用法和区别
  12. 信息论——最大流最小割定理
  13. KumiaoQQ机器人框架源码(带成品)
  14. Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器
  15. 学会了这些!你就是天下间的美容高手
  16. 用少量箭射爆气球,leetcode习题
  17. 05、Python中转义字符与字符串
  18. 11 java 王少飞-Java语言的主要特性分析
  19. alta公司1553b板卡编程相关
  20. 二十四、 修正单纯形法(矩阵运算角度)

热门文章

  1. 牛客 - Yuki with emofunc and playf(同余最短路)
  2. 洛谷 - P3975 [TJOI2015]弦论(后缀自动机)
  3. 中石油训练赛 - Cafebazaar’s Chess Tournament(FFT)
  4. 牛客 - 树上子链(树的直径-处理负权)
  5. UVA1374 Power Calcilus快速幂计算
  6. 理解A*寻路算法具体过程
  7. C++静态成员和静态成员函数
  8. 剖析入侵技术 嗅探软件了解
  9. live555 源码分析:MediaSever
  10. DevOps工程师到底是做什么的?