Elasticsearch 集群的监控与报警

声明:
本文转自我的个人博客,有兴趣的可以查看原文。
转发请注明来源。

前段时间和运维小伙伴一起完善了公司 Elasticsearch 集群的监控和报警,整理成此文,涉及到公司架构和系统信息的不便透露的,都隐去了。

系统架构

谈监控之前,先看看我们的系统架构,下图是个简化的搜索架构:

搜索系统架构
搜索系统架构

系统分两部分:

  1. 蓝色部分,表示用户查询部分,客户端请求到达Tengine,Tengine将请求转发到AS(Advanced Search),AS将请求转发到Elasticsearch,Elasticsearch查询,然后将结果原路返回。其中,AS是我们自主研发的,用于Query验证、改写、记日志、相关性计算等等。在这里,AS和ES都是一个集群。
  2. 绿色部分,表示实时同步部分,系统日志、DB数据等通过消息队列到到我们的Sync程序,Sync将数据实时写入到ES集群。

上图覆盖了最重要的两个部分——实时索引与查询,全量索引仅需周期性进行一次,并未体现在此图中。对搜索集群添加监控,主要是针对图中各组件添加监控。

具体监控

基础监控

基础监控主要是一些常用的运维监控,主要包括:

  • CPU 使用率
  • IO
  • 内存
  • load
  • 磁盘空间、INode
  • 重传率
  • fd
  • ntp
  • coredump
  • JVM
  • ...

这部分,运维都有很丰富的经验,不用操心。

网关监控

网关监控,主要关注两个指标,RT和状态码,当RT > 1s 或者出现5XX的时候,进行报警。

AS监控

  1. 进程监控,当进程数发生变化时,报警;
  2. 日志监控,当日志出现ERROR时,报警。

Elasticsearch 进程监控

  1. 进程监控,进程数发生变化时,报警。
  2. ES 产生ERROR日志时,报警。

Elasticsearch指标监控

Elasticsearch 提供了丰富的API接口以便于采集集群、node、index等状态指标,可以根据这些指标做监控和报警。我们主要在集群级别、node 级别、index 级别三个层次进行采集和监控报警。

下面是一些主要关注的指标。

一、集群级别监控,采用GET _cluster/health,返回数据如下:

{
   "cluster_name": "cluster_name_1",
   "status": "green",
   "timed_out": false,
   "number_of_nodes": 6,
   "number_of_data_nodes": 4,
   "active_primary_shards": 38,
   "active_shards": 68,
   "relocating_shards": 0,
   "initializing_shards": 0,
   "unassigned_shards": 0
}

对于我们来说,一般重点关注集群状态 status以及其中的node数量。当集群状态变为yellow或red时报警。

另外,Elasticsearch 提供API对集群进行修改,而且,Elasticsearch 没有提供有效的权限控制,从而,也给我们带来了风险,所以,我们还加了一层监控,当集群配置发生变化时,报警。

二、node级别的监控,采用GET _nodes/stats接口取回node相关监控数据。

node_stats
node_stats

大部分数据在基础监控里已经做了,所以,这里主要关注红框部分——indices、thread_pool和fielddata_breaker三部分。

indices部分如下:

        "indices": {
            "docs": {
               "count": 3344,
               "deleted": 983
            },
            "store": {
               "size_in_bytes": 6529920,
               "throttle_time_in_millis": 2263
            },
            "indexing": {
               "index_total": 114516,
               "index_time_in_millis": 66226,
               "index_current": 969,
               "delete_total": 802,
               "delete_time_in_millis": 93,
               "delete_current": 0
            },
            "get": {
               "total": 449,
               "time_in_millis": 13,
               "exists_total": 571,
               "exists_time_in_millis": 1847,
               "missing_total": 878,
               "missing_time_in_millis": 56,
               "current": 0
            },
            "search": {
               "open_contexts": 0,
               "query_total": 3419,
               "query_time_in_millis": 262,
               "query_current": 0,
               "fetch_total": 319,
               "fetch_time_in_millis": 189,
               "fetch_current": 0
            },
            "merges": {
               "current": 1,
               "current_docs": 175,
               "current_size_in_bytes": 374,
               "total": 557,
               "total_time_in_millis": 77614,
               "total_docs": 3878,
               "total_size_in_bytes": 9545
            },
            "refresh": {
               "total": 4036,
               "total_time_in_millis": 3788
            },
            "flush": {
               "total": 07,
               "total_time_in_millis": 03
            },
            "warmer": {
               "current": 0,
               "total": 45,
               "total_time_in_millis": 233
            },
            "filter_cache": {
               "memory_size_in_bytes": 124,
               "evictions": 778
            },
            "id_cache": {
               "memory_size_in_bytes": 0
            },
            "fielddata": {
               "memory_size_in_bytes": 1348,
               "evictions": 0
            },
            "percolate": {
               "total": 0,
               "time_in_millis": 0,
               "current": 0,
               "memory_size_in_bytes": -1,
               "memory_size": "-1b",
               "queries": 0
            },
            "completion": {
               "size_in_bytes": 0
            },
            "segments": {
               "count": 350,
               "memory_in_bytes": 392,
               "index_writer_memory_in_bytes": 961,
               "version_map_memory_in_bytes": 8
            },
            "translog": {
               "operations": 12025,
               "size_in_bytes": 0
            },
            "suggest": {
               "total": 0,
               "time_in_millis": 0,
               "current": 0
            }
         }
  • doc 部分显示node中的所有documents数量,以及已经被标记删除的。当每分钟被标记删除的数量突然增大时,需要关注下。
  • store显示物理存储信息。
  • indexing 显示了被索引的docs数量,是一个累计递增值,只要内部进行index操作就会增加,所以,index、create、update都会增加。可以利用这个累计值,监控每分钟的变化,从而做出预警。
  • get 显示的是调用 GET | HEAD 方法的次数,也是累计值。
  • search 描述search 相关监控数据,query_time_in_millis/query_total可以用来粗略估计搜索引擎的查询效率。fetch 相关统计描述搜索过程(query-then-fetch)中fetch 操作的统计数据。
  • merge 包含Lucene 段合并的一些信息,对于实时写数据量大的ES集群,merge相关指标十分重要,因为merge操作会消耗大量的CPU和IO。
  • fielddata 描述fielddata占的内存以及被淘汰的情况,需要关注fielddata.eviction,这个值应该很小。另外,fielddata很耗内存,如果fielddata统计占内存很多,也要考虑下这样使用的业务场景是否合理。
  • segment 统计Lucene 的segments相关信息,这个值应该不会太大。

Elasticsearch 自身维护它的线程池,一般来讲,我们不需要配置,默认的即可。在API返回的结果中,有很多种线程池,格式都是统一的,如下:

            "index": {
               "threads": 24,
               "queue": 0,
               "active": 0,
               "rejected": 0,
               "largest": 24,
               "completed": 676231817
            }

上面的信息展示了线程池里现场的数量,有多少现成正在work,有多少在队列里。如果队列满了,新的请求将被rejected掉,显示在rejected,这时候,通常说明我们的系统到了瓶颈了,因为,我们的系统以最大的速度处理都处理不过来了,所以,这个指标要注意。

除了上面显示的index 线程池,还有很多线程池,不过很多都可以忽略,但有些重要的还是需要关注:

  • index: 处理一般index请求的线程池。
  • bulk:处理bulk indexing请求的线程池。
  • get:处理get-by-ID请求的线程池。
  • search:处理所有search和query请求的线程池。
  • merge:管理 Lucene merge的线程池。

最后,需要关注Circuit Breaker的相关指标:

         "fielddata_breaker": {
            "maximum_size_in_bytes": 11699,
            "maximum_size": "0.7gb",
            "estimated_size_in_bytes": 568,
            "estimated_size": "1.2gb",
            "overhead": 1.03,
            "tripped": 0
         }

简单来说,fielddata的大小只有在加载完了之后才会知道,如果fielddata的大小比分配内存还大,那就会导致OOM,于是,Elasticsearch 引入了断路器,用于预先估算内存够不够,如果不够,断路器就会被触发(tripped)并返回异常,而不至于导致OOM。

所以,这个指标里,最重要的就是 tripped了,如果这个值很大或者说一直在增长,那么,就说明你的查询需要优化或者说需要更多内存了。

三、index 级别监控

index 级别的监控可以以index为单位进行统计,如某个index有多少search请求、search时耗费了多少时间等,可以用于发现热点索引或比较慢的索引。

然而,在实际应用中,index级别的监控并不是很有用,一般来说,瓶颈都出现在node级别,不会到index级别;而且,index级别的数据采集自不同机器,不同环境也会受影响。

查看index 级别的监控命令是 GET index_name/_stats,如果index_name改成 _all,则统计所有index的数据。

同步程序监控

同步程序监控主要包括三个方面:

  1. 基础监控。同步数据量大,同步程序单独部署了一个集群,也需要相应的基础监控。
  2. 同步程序进程数监控。
  3. 同步程序日志监控,如版本冲突等ERROR都能采集到。

业务监控

我们还做了业务层面的监控,针对不同index进行基础埋点,同时,新上业务时,也会添加使用的Query语句进行埋点,系统定时跑这些埋点,当出现异常时报警。

总结

Elasticsearch 集群的监控是在运维同事的帮助下搭建的,到目前为止,基本能满足需求,但因为自身以前没有这方面经验,所以,这方面也许做得还不够,还望批评指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容