集中式日志分析平台 - ELK Stack - 关于logstash的监控

运行 Logstash 时,它会自动捕获可用于监视Logstash部署的运行状况和性能的运行时指标。

Logstash 收集的指标包括:

  • Logstash 节点信息,如配置信息,OS 信息和 JVM 信息;
  • 插件信息,包括已安装插件的列表;
  • 节点统计信息,如 JVM 统计信息,进程统计信息,事件相关(event-related)统计信息和流水线运行时(pipeline runtime)统计信息;
  • 热线程;

我们可以使用 X-Pack 中的monitoring UI 来查看这些指标,深入了解 Logstash 如何运行,或者可以使用 Logstash 提供的基本监视 API 来检索这些指标。对于我湾,调研确定采用 searchguard 作为核心安全插件,所以不会为了一个无法整合到监控平台的 X-Pack monitoring 功能而去引入,我决定直接走 API 的方式提供指标数据。

监控 API 介绍

Logstash提供以下监视API来检索有关Logstash的运行时指标:

  • 节点信息API
  • 插件信息API
  • 节点统计API
  • 热线程API

您可以使用根资源来检索有关Logstash实例的一般信息,包括主机和版本。

curl -XGET 'localhost:9600/?pretty'

响应示例:

{
   "host": "skywalker",
   "version": "5.5.0",
   "http_address": "127.0.0.1:9600"
}

默认情况下,监视 API 尝试绑定到 tcp:9600。如果此端口已被另一个 Logstash 实例使用,则需要使用指定的—http.port 标志启动 Logstash 以绑定到其他端口。有关详细信息,请参阅命令行标志。

通用选项

以下选项可以应用于所有 Logstash 监控 API。

  • Pretty 式返回

当对任何请求进行追加 ?pretty=true 时,返回的 JSON 将被格式化展示(仅用于调试);

  • Human-Readable 式输出

对于Logstash 5.5.0,只有 Hot Threads API 支持该选项。当指定 human=true 时,结果将以纯文本而不是 JSON 格式返回。默认值为false。

统计信息会以适合人类阅读的格式(例如 "exists_time": "1h" or "size": "1kb")和计算机适合解释处理的格式(例如 "exists_time_in_millis": 3600000 or "size_in_bytes": 1024)返回。可以通过向查询字符串添加 ?human=false 来关闭。当统计数据的结果被监视工具消费时,而不是为人类消费而言,这是有道理的。human 标识位默认为 false。

节点信息 API

该 API 用于获取关于 logstash 节点的信息:

curl -XGET 'localhost:9600/_node/<types>'

<types> 是可选项,用来指定返回哪个类型的数据。

我们可以通过以下几种类型的组合来限制返回的信息(类型之间用逗号间隔):

类型 描述
pipeline 获取 pipeline 相关的信息和配置;
os 获取节点级别的 OS 信息;
jvm 获取节点级别的 JVM 信息,包括线程信息;

Pipeline 信息

以下的请求返回 pipeline 相关信息,包括 workers 的数量,批处理大小,以及批处理延迟:

curl -XGET 'localhost:9600/_node/pipeline?pretty'

如果想获得更多的 pipeline 信息,比如各个 input/filter/output 的信息,可以参阅 Pipeline Stats 部分。

返回示例:

{
  "pipeline": {
    "workers": 8,
    "batch_size": 125,
    "batch_delay": 5,
    "config_reload_automatic": true,
    "config_reload_interval": 3
    "id" : "main"
  }

OS 信息

以下请求返回关于 OS 相关信息,比如 OS 名称、架构、版本和可用的处理器个数:

curl -XGET 'localhost:9600/_node/os?pretty'

返回示例:

{
  "os": {
    "name": "Mac OS X",
    "arch": "x86_64",
    "version": "10.12.4",
    "available_processors": 8
  }

JVM 信息

以下请求返回节点级别 JVM 信息,比如节点级别 JVM 进程号、版本、VM 信息、内存使用率以及 GC 信息:

curl -XGET 'localhost:9600/_node/jvm?pretty'

返回示例:

{
  "jvm": {
    "pid": 59616,
    "version": "1.8.0_65",
    "vm_name": "Java HotSpot(TM) 64-Bit Server VM",
    "vm_version": "1.8.0_65",
    "vm_vendor": "Oracle Corporation",
    "start_time_in_millis": 1484251185878,
    "mem": {
      "heap_init_in_bytes": 268435456,
      "heap_max_in_bytes": 1037959168,
      "non_heap_init_in_bytes": 2555904,
      "non_heap_max_in_bytes": 0
    },
    "gc_collectors": [
      "ParNew",
      "ConcurrentMarkSweep"
    ]
  }
}

插件信息 API

插件信息 API 可以获取所有已安装的 logstash 的插件信息。该 API 是基于 bin/logstash-plugin list --verbose 命令返回的信息进行处理后得到的。

curl -XGET 'localhost:9600/_node/plugins?pretty'

返回示例:

{
  "total": 93,
  "plugins": [
    {
      "name": "logstash-codec-cef",
      "version": "4.1.2"
    },
    {
      "name": "logstash-codec-collectd",
      "version": "3.0.3"
    },
    {
      "name": "logstash-codec-dots",
      "version": "3.0.2"
    },
    {
      "name": "logstash-codec-edn",
      "version": "3.0.2"
    },
    .
    .
    .
  ]

节点状态 API

节点状态 API 用于获取 logstash 运行时的统计信息。

curl -XGET 'localhost:9600/_node/stats/<types>'

<types> 是可选项,用于指定具体返回类型。

默认情况下,所有状态都会返回。我们可以通过各种类型组合(以逗号分隔)来过滤出我们想要的信息:

类型 描述
jvm 获取 JVM 状态,包括线程信息、内存使用率、GC 和 uptime。
process 获取进程信息,包括文件描述符、内存占用以及 CPU 使用率。
pipeline 获取运行时 logstash pipeline 信息。
reloads 获取运行时配置 reload 的失败和成功信息。
os 获取运行时当 logstash 运行在容器中的 cgroups 信息。

JVM 信息

以下请求返回 JVM 信息:

curl -XGET 'localhost:9600/_node/stats/jvm?pretty'

返回示例:

{
  "jvm": {
    "threads": {
      "count": 35,
      "peak_count": 36
    },
    "mem": {
      "heap_used_in_bytes": 318691184,
      "heap_used_percent": 15,
      "heap_committed_in_bytes": 519045120,
      "heap_max_in_bytes": 2075918336,
      "non_heap_used_in_bytes": 189382304,
      "non_heap_committed_in_bytes": 200728576,
      "pools": {
        "survivor": {
          "peak_used_in_bytes": 8912896,
          "used_in_bytes": 9538656,
          "peak_max_in_bytes": 35782656,
          "max_in_bytes": 71565312,
          "committed_in_bytes": 17825792
        },
        "old": {
          "peak_used_in_bytes": 106946320,
          "used_in_bytes": 181913072,
          "peak_max_in_bytes": 715849728,
          "max_in_bytes": 1431699456,
          "committed_in_bytes": 357957632
        },
        "young": {
          "peak_used_in_bytes": 71630848,
          "used_in_bytes": 127239456,
          "peak_max_in_bytes": 286326784,
          "max_in_bytes": 572653568,
          "committed_in_bytes": 143261696
        }
      }
    },
    "gc": {
      "collectors": {
        "old": {
          "collection_time_in_millis": 58,
          "collection_count": 2
        },
        "young": {
          "collection_time_in_millis": 338,
          "collection_count": 26
        }
      }
    },
    "uptime_in_millis": 382701
  }

进程信息

以下请求返回进程信息:

curl -XGET 'localhost:9600/_node/stats/process?pretty'

返回示例

{
  "process": {
    "open_file_descriptors": 164,
    "peak_open_file_descriptors": 166,
    "max_file_descriptors": 10240,
    "mem": {
      "total_virtual_in_bytes": 5399474176
    },
    "cpu": {
      "total_in_millis": 72810537000,
      "percent": 0,
      "load_average": {
        "1m": 2.41943359375
      }
    }
  }
}

Pipeline 信息

以下请求返回 pipeline 信息,包括:

  • Input/filter/output 的事件数量;
  • 配置的各个 filter/output 信息;
  • Config reload 成功或失败的信息(当 config reload enable 情况下);
  • 持久化队列的信息(当 persistent queues enable 情况下);
curl -XGET 'localhost:9600/_node/stats/pipeline?pretty'

返回示例:

{
  "pipeline" : {
    "events" : {
      "duration_in_millis" : 1955,
      "in" : 100,
      "filtered" : 100,
      "out" : 100,
      "queue_push_duration_in_millis" : 71
    },
    "plugins" : {
      "inputs" : [ {
        "id" : "729b0efdc657715a4a59103ab2643c010fc46e77-1",
        "events" : {
          "out" : 100,
          "queue_push_duration_in_millis" : 71
        },
        "name" : "beats"
      } ],
      "filters" : [ {
        "id" : "729b0efdc657715a4a59103ab2643c010fc46e77-2",
        "events" : {
          "duration_in_millis" : 64,
          "in" : 100,
          "out" : 100
        },
        "matches" : 100,
        "patterns_per_field" : {
          "message" : 1
        },
        "name" : "grok"
      } ],
      "outputs" : [ {
        "id" : "729b0efdc657715a4a59103ab2643c010fc46e77-3",
        "events" : {
          "duration_in_millis" : 1724,
          "in" : 100,
          "out" : 100
        },
        "name" : "stdout"
      } ]
    },
    "reloads" : {
      "last_error" : null,
      "successes" : 2,
      "last_success_timestamp" : "2017-05-25T02:40:40.974Z",
      "last_failure_timestamp" : null,
      "failures" : 0
    },
    "queue" : {
      "events" : 0,
      "type" : "persisted",
      "capacity" : {
        "page_capacity_in_bytes" : 262144000,
        "max_queue_size_in_bytes" : 8589934592,
        "max_unread_events" : 0
      },
      "data" : {
        "path" : "/path/to/data/queue",
        "free_space_in_bytes" : 89280552960,
        "storage_type" : "hfs"
      }
    },
    "id" : "main"
  }
}

Reload 信息

以下请求返回配置 reload 成功和失败的信息:

curl -XGET 'localhost:9600/_node/stats/reloads?pretty'

返回示例:

{
  "reloads": {
    "successes": 0,
    "failures": 0
  }
}

OS 信息

当 logstash 运行在容器中时,以下请求返回 cgroups 相关信息,我们可以从中获取更精确的 CPU 负载,包括容器是否达到瓶颈:

curl -XGET 'localhost:9600/_node/stats/os?pretty'

返回示例:

{
  "os" : {
    "cgroup" : {
      "cpuacct" : {
        "control_group" : "/elastic1",
        "usage_nanos" : 378477588075
                },
      "cpu" : {
        "control_group" : "/elastic1",
        "cfs_period_micros" : 1000000,
        "cfs_quota_micros" : 800000,
        "stat" : {
          "number_of_elapsed_periods" : 4157,
          "number_of_times_throttled" : 460,
          "time_throttled_nanos" : 581617440755
        }
      }
    }
  }

热线程 API

热线程 API 用来获取当前 logstash 的热线程信息。热线程的定义是:该线程占用很高的 CPU并且执行指令持续很长时间。

curl -XGET 'localhost:9600/_node/hot_threads?pretty'

返回示例:

{
    "time": "2017-01-12T12:09:45-08:00",
    "busiest_threads": 3,
    "threads": [
      {
        "name": "LogStash::Runner",
        "percent_of_cpu_time": 1.07,
        "state": "timed_waiting",
        "traces": [
          "java.lang.Object.wait(Native Method)",
          "java.lang.Thread.join(Thread.java:1253)",
          "org.jruby.internal.runtime.NativeThread.join(NativeThread.java:75)",
          "org.jruby.RubyThread.join(RubyThread.java:697)",
          "org.jruby.RubyThread$INVOKER$i$0$1$join.call(RubyThread$INVOKER$i$0$1$join.gen)",
          "org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:663)",
          "org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:198)",
          "org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)",
          "org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)",
          "org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)"
        ]
      },
      {
        "name": "[main]>worker7",
        "percent_of_cpu_time": 0.71,
        "state": "waiting",
        "traces": [
          "sun.misc.Unsafe.park(Native Method)",
          "java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)",
          "java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)",
          "java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)",
          "java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)",
          "java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)",
          "org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1470)",
          "org.jruby.ext.thread.Mutex.lock(Mutex.java:91)",
          "org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)",
          "org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)"
        ]
      },
      {
        "name": "[main]>worker3",
        "percent_of_cpu_time": 0.71,
        "state": "waiting",
        "traces": [
          "sun.misc.Unsafe.park(Native Method)",
          "java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)",
          "java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)",
          "java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)",
          "java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)",
          "java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)",
          "org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1470)",
          "org.jruby.ext.thread.Mutex.lock(Mutex.java:91)",
          "org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)",
          "org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)"
        ]
      }
    ]
  }
}

被允许使用的参数包括:

参数 描述
threads 返回的热线程个数,默认为 3。
human 如为 true,返回 plain text,反之则是 json,默认是 false。
ignore_idle_threads 如为 true,不返回闲置线程,默认是 true。

可以使用 ?human 参数返回可读性较高的格式。

curl -XGET 'localhost:9600/_node/hot_threads?human=true'

human-readable 返回示例:

 ::: {}
 Hot threads at 2017-01-12T12:10:15-08:00, busiestThreads=3:
 ================================================================================
 1.02 % of cpu usage, state: timed_waiting, thread name: 'LogStash::Runner'
        java.lang.Object.wait(Native Method)
        java.lang.Thread.join(Thread.java:1253)
        org.jruby.internal.runtime.NativeThread.join(NativeThread.java:75)
        org.jruby.RubyThread.join(RubyThread.java:697)
        org.jruby.RubyThread$INVOKER$i$0$1$join.call(RubyThread$INVOKER$i$0$1$join.gen)
        org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:663)
        org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:198)
        org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
        org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
        org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
 --------------------------------------------------------------------------------
 0.71 % of cpu usage, state: waiting, thread name: '[main]>worker7'
        sun.misc.Unsafe.park(Native Method)
        java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
        java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
        java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
        org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1470)
        org.jruby.ext.thread.Mutex.lock(Mutex.java:91)
        org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)
        org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)
 --------------------------------------------------------------------------------
 0.71 % of cpu usage, state: timed_waiting, thread name: '[main]>worker3'
        sun.misc.Unsafe.park(Native Method)
        java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
        java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
        java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
        sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
        sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        java.lang.reflect.Method.invoke(Method.java:497)
        org.jruby.javasupport.JavaMethod.invokeDirectWithExceptionHandling(JavaMethod.java:466)
        org.jruby.javasupport.JavaMethod.invokeDirect(JavaMethod.java:324)

参考文献

https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html

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

推荐阅读更多精彩内容