做了几周的测试,踩了无数的坑,总结一下,全是干货,给大家分享~

一、elk 实用知识点总结

1、编码转换问题(主要就是中文乱码)

(1)input 中的codec => plain 转码

codec => plain {
charset => "GB2312"
}

将GB2312 的文本编码,转为UTF-8 的编码

(2)也可以在filebeat中实现编码的转换(推荐)

filebeat.prospectors:
- input_type: log
paths:
- c:\Users\Administrator\Desktop\performanceTrace.txt
encoding: GB2312

2、删除多余日志中的多余行

(1)logstash filter 中drop 删除

    if ([message] =~ "^20.*-\ task\ request,.*,start\ time.*") {   #用正则需删除的多余行
drop {}

(2)日志示例

2018-03-20 10:44:01,523 [33]DEBUG Debug - task request,task Id:1cbb72f1-a5ea-4e73-957c-6d20e9e12a7a,start time:2018-03-20 10:43:59   #需删除的行
-- Request String : {"UserName":"15046699923","Pwd":"ZYjyh727","DeviceType":2,"DeviceId":"PC-20170525SADY","EquipmentNo":null,"SSID":"pc","RegisterPhones":null,"AppKey":"ab09d78e3b2c40b789ddfc81674bc24deac","Version":"2.0.5.3"} -- End
-- Response String : {"ErrorCode":0,"Success":true,"ErrorMsg":null,"Result":null,"WaitInterval":30} -- End

3、grok 处理多种日志不同的行

(1)日志示例:

2018-03-20 10:44:01,523 [33]DEBUG Debug - task request,task Id:1cbb72f1-a5ea-4e73-957c-6d20e9e12a7a,start time:2018-03-20 10:43:59
-- Request String : {"UserName":"15046699923","Pwd":"ZYjyh727","DeviceType":2,"DeviceId":"PC-20170525SADY","EquipmentNo":null,"SSID":"pc","RegisterPhones":null,"AppKey":"ab09d78e3b2c40b789ddfc81674bc24deac","Version":"2.0.5.3"} -- End
-- Response String : {"ErrorCode":0,"Success":true,"ErrorMsg":null,"Result":null,"WaitInterval":30} -- End

(2)在logstash filter中grok 分别处理3行

match => {
"message" => "^20.*-\ task\ request,.*,start\ time\:%{TIMESTAMP_ISO8601:RequestTime}"
match => {
"message" => "^--\ Request\ String\ :\ \{\"UserName\":\"%{NUMBER:UserName:int}\",\"Pwd\":\"(?<Pwd>.*)\",\"DeviceType\":%{NUMBER:DeviceType:int},\"DeviceId\":\"(?<DeviceId>.*)\",\"EquipmentNo\":(?<EquipmentNo>.*),\"SSID\":(?<SSID>.*),\"RegisterPhones\":(?<RegisterPhones>.*),\"AppKey\":\"(?<AppKey>.*)\",\"Version\":\"(?<Version>.*)\"\}\ --\ \End.*"
}
match => {
"message" => "^--\ Response\ String\ :\ \{\"ErrorCode\":%{NUMBER:ErrorCode:int},\"Success\":(?<Success>[a-z]*),\"ErrorMsg\":(?<ErrorMsg>.*),\"Result\":(?<Result>.*),\"WaitInterval\":%{NUMBER:WaitInterval:int}\}\ --\ \End.*"
}
... 等多行

4、日志多行合并处理—multiline插件(重点)

(1)示例:

① 日志

2018-03-20 10:44:01,523 [33]DEBUG Debug - task request,task Id:1cbb72f1-a5ea-4e73-957c-6d20e9e12a7a,start time:2018-03-20 10:43:59
-- Request String : {"UserName":"15046699923","Pwd":"ZYjyh727","DeviceType":2,"DeviceId":"PC-20170525SADY","EquipmentNo":null,"SSID":"pc","RegisterPhones":null,"AppKey":"ab09d78e3b2c40b789ddfc81674bc24deac","Version":"2.0.5.3"} -- End
-- Response String : {"ErrorCode":0,"Success":true,"ErrorMsg":null,"Result":null,"WaitInterval":30} -- End

② logstash grok 对合并后多行的处理(合并多行后续都一样,如下)

filter {
  grok {
    match => {
      "message" => "^%{TIMESTAMP_ISO8601:InsertTime}\ .*-\ task\ request,.*,start\ time:%{TIMESTAMP_ISO8601:RequestTime}\n--\ Request\ String\ :\ \{\"UserName\":\"%{NUMBER:UserName:int}\",\"Pwd\":\"(?<Pwd>.*)\",\"DeviceType\":%{NUMBER:DeviceType:int},\"DeviceId\":\"(?<DeviceId>.*)\",\"EquipmentNo\":(?<EquipmentNo>.*),\"SSID\":(?<SSID>.*),\"RegisterPhones\":(?<RegisterPhones>.*),\"AppKey\":\"(?<AppKey>.*)\",\"Version\":\"(?<Version>.*)\"\}\ --\ \End\n--\ Response\ String\ :\ \{\"ErrorCode\":%{NUMBER:ErrorCode:int},\"Success\":(?<Success>[a-z]*),\"ErrorMsg\":(?<ErrorMsg>.*),\"Result\":(?<Result>.*),\"WaitInterval\":%{NUMBER:WaitInterval:int}\}\ --\ \End"
    }
  }
}

(2)在filebeat中使用multiline 插件(推荐)

① 介绍multiline

pattern:正则匹配从哪行合并

negate:true/false,匹配到pattern 部分开始合并,还是不配到的合并

match:after/before(需自己理解)

  after:匹配到pattern 部分后合并,注意:这种情况最后一行日志不会被匹配处理

  before:匹配到pattern 部分前合并(推荐)

② 5.5版本之后(before为例)

filebeat.prospectors:
- input_type: log
paths:
- /root/performanceTrace*
fields:
type: zidonghualog
multiline.pattern: '.*\"WaitInterval\":.*--\ End'
multiline.negate: true
multiline.match: before

③ 5.5版本之前(after为例)

filebeat.prospectors:
- input_type: log
paths:
- /root/performanceTrace*
input_type: log
multiline:
pattern: '^20.*'
negate: true
match: after

(3)在logstash input中使用multiline 插件(没有filebeat 时推荐)

① 介绍multiline

pattern:正则匹配从哪行合并

negate:true/false,匹配到pattern 部分开始合并,还是不配到的合并

what:previous/next(需自己理解)

  previous:相当于filebeat 的after

  next:相当于filebeat 的before

② 用法

input {
file {
path => ["/root/logs/log2"]
start_position => "beginning"
codec => multiline {
pattern => "^20.*"
negate => true
what => "previous"
}
}
}

(4)在logstash filter中使用multiline 插件(不推荐)

(a)不推荐的原因:

  ① filter设置multiline后,pipline worker会自动将为1

  ② 5.5 版本官方把multiline 去除了,要使用的话需下载,下载命令如下:

  /usr/share/logstash/bin/logstash-plugin install logstash-filter-multiline

(b)示例:

filter {
multiline {
pattern => "^20.*"
negate => true
what => "previous"
}

5、logstash filter 中的date使用

(1) 日志示例

2018-03-20 10:44:01 [33]DEBUG Debug - task request,task Id:1cbb72f1-a5ea-4e73-957c-6d20e9e12a7a,start time:2018-03-20 10:43:59

(2) date 使用

        date {
match => ["InsertTime","YYYY-MM-dd HH:mm:ss "]
remove_field => "InsertTime"
}

注:

match => ["timestamp" ,"dd/MMM/YYYY H:m:s Z"]

  匹配这个字段,字段的格式为:日日/月月月/年年年年 时/分/秒 时区

也可以写为:match => ["timestamp","ISO8601"](推荐)

(3)date 介绍

  就是将匹配日志中时间的key 替换为@timestamp 的时间,因为@timestamp 的时间是日志送到logstash 的时间,并不是日志中真正的时间。

6、对多类日志分类处理(重点)

① 在filebeat 的配置中添加type 分类

filebeat:
prospectors:
-
paths:
#- /mnt/data/WebApiDebugLog.txt*
- /mnt/data_total/WebApiDebugLog.txt*
fields:
type: WebApiDebugLog_total
-
paths:
- /mnt/data_request/WebApiDebugLog.txt*
#- /mnt/data/WebApiDebugLog.txt*
fields:
type: WebApiDebugLog_request
-
paths:
- /mnt/data_report/WebApiDebugLog.txt*
#- /mnt/data/WebApiDebugLog.txt*
fields:
type: WebApiDebugLog_report

② 在logstash filter中使用if,可进行对不同类进行不同处理

filter {
if [fields][type] == "WebApiDebugLog_request" { #对request 类日志
if ([message] =~ "^20.*-\ task\ report,.*,start\ time.*") { #删除report 行
drop {}
}
grok {
match => {"... ..."}
}
}

③ 在logstash output中使用if

if [fields][type] == "WebApiDebugLog_total" {
elasticsearch {
hosts => ["6.6.6.6:9200"]
index => "logstashl-WebApiDebugLog_total-%{+YYYY.MM.dd}"
document_type => "WebApiDebugLog_total_logs"
} 

二、对elk 整体性能的优化

1、性能分析

(1)服务器硬件Linux:1cpu 4GRAM

假设每条日志250 Byte

(2)分析

① logstash-Linux:1cpu 4GRAM

每秒500条日志

去掉ruby每秒660条日志

去掉grok后每秒1000条数据

 filebeat-Linux:1cpu 4GRAM

每秒2500-3500条数据

每天每台机器可处理:24h*60min*60sec*3000*250Byte=64,800,000,000Bytes,约64G

③ 瓶颈在logstash 从redis中取数据存入ES,开启一个logstash,每秒约处理6000条数据;开启两个logstash,每秒约处理10000条数据(cpu已基本跑满);

④ logstash的启动过程占用大量系统资源,因为脚本中要检查java、ruby以及其他环境变量,启动后资源占用会恢复到正常状态。

2、关于收集日志的选择:logstash/filter

(1)没有原则要求使用filebeat或logstash,两者作为shipper的功能是一样的,区别在于:

① logstash由于集成了众多插件,如grok,ruby,所以相比beat是重量级的;

② logstash启动后占用资源更多,如果硬件资源足够则无需考虑二者差异;

③ logstash基于JVM,支持跨平台;而beat使用golang编写,AIX不支持;

④ AIX 64bit平台上需要安装jdk(jre) 1.7 32bit,64bit的不支持;

⑤ filebeat可以直接输入到ES,但是系统中存在logstash直接输入到ES的情况,这将造成不同的索引类型造成检索复杂,最好统一输入到els 的源。

(2)总结

  logstash/filter 总之各有千秋,但是,我推荐选择:在每个需要收集的日志服务器上配置filebeat,因为轻量级,用于收集日志;再统一输出给logstash,做对日志的处理;最后统一由logstash 输出给els。

3、logstash的优化相关配置

(1)可以优化的参数,可根据自己的硬件进行优化配置

① pipeline 线程数,官方建议是等于CPU内核数

默认配置 ---> pipeline.workers: 2

可优化为 ---> pipeline.workers: CPU内核数(或几倍cpu内核数)

② 实际output 时的线程数

默认配置 ---> pipeline.output.workers: 1

可优化为 ---> pipeline.output.workers: 不超过pipeline 线程数

③ 每次发送的事件数

默认配置 ---> pipeline.batch.size: 125

可优化为 ---> pipeline.batch.size: 1000

④ 发送延时

默认配置 ---> pipeline.batch.delay: 5

可优化为 ---> pipeline.batch.size: 10

(2)总结

  通过设置-w参数指定pipeline worker数量,也可直接修改配置文件logstash.yml。这会提高filter和output的线程数,如果需要的话,将其设置为cpu核心数的几倍是安全的,线程在I/O上是空闲的。

  默认每个输出在一个pipeline worker线程上活动,可以在输出output 中设置workers设置,不要将该值设置大于pipeline worker数。

  还可以设置输出的batch_size数,例如ES输出与batch size一致。

  filter设置multiline后,pipline worker会自动将为1,如果使用filebeat,建议在beat中就使用multiline,如果使用logstash作为shipper,建议在input 中设置multiline,不要在filter中设置multiline。

(3)Logstash中的JVM配置文件

  Logstash是一个基于Java开发的程序,需要运行在JVM中,可以通过配置jvm.options来针对JVM进行设定。比如内存的最大最小、垃圾清理机制等等。JVM的内存分配不能太大不能太小,太大会拖慢操作系统。太小导致无法启动。默认如下:

-Xms256m #最小使用内存

-Xmx1g #最大使用内存

4、引入Redis 的相关问题

(1)filebeat可以直接输入到logstash(indexer),但logstash没有存储功能,如果需要重启需要先停所有连入的beat,再停logstash,造成运维麻烦;另外如果logstash发生异常则会丢失数据;引入Redis作为数据缓冲池,当logstash异常停止后可以从Redis的客户端看到数据缓存在Redis中;

(2)Redis可以使用list(最长支持4,294,967,295条)或发布订阅存储模式;

(3)redis 做elk 缓冲队列的优化:

① bind 0.0.0.0 #不要监听本地端口

② requirepass ilinux.io #加密码,为了安全运行

③ 只做队列,没必要持久存储,把所有持久化功能关掉:快照(RDB文件)和追加式文件(AOF文件),性能更好

  save "" 禁用快照

  appendonly no 关闭RDB

④ 把内存的淘汰策略关掉,把内存空间最大

  maxmemory 0 #maxmemory为0的时候表示我们对Redis的内存使用没有限制

5、elasticsearch 节点优化配置

(1)服务器硬件配置,OS 参数

(a) /etc/sysctl.conf 配置

vim /etc/sysctl.conf

① vm.swappiness = 1                     #ES 推荐将此参数设置为 1,大幅降低 swap 分区的大小,强制最大程度的使用内存,注意,这里不要设置为 0, 这会很可能会造成 OOM
② net.core.somaxconn = 65535 #定义了每个端口最大的监听队列的长度
③ vm.max_map_count= 262144 #限制一个进程可以拥有的VMA(虚拟内存区域)的数量。虚拟内存区域是一个连续的虚拟地址空间区域。当VMA 的数量超过这个值,OOM
④ fs.file-max = 518144 #设置 Linux 内核分配的文件句柄的最大数量

[root@elasticsearch]# sysctl -p 生效一下

(b)limits.conf 配置

vim /etc/security/limits.conf

elasticsearch    soft    nofile          65535
elasticsearch hard nofile 65535
elasticsearch soft memlock unlimited
elasticsearch hard memlock unlimited

(c)为了使以上参数永久生效,还要设置两个地方

vim /etc/pam.d/common-session-noninteractive

vim /etc/pam.d/common-session

添加如下属性:

session required pam_limits.so

可能需重启后生效

(2)elasticsearch 中的JVM配置文件

-Xms2g

-Xmx2g

① 将最小堆大小(Xms)和最大堆大小(Xmx)设置为彼此相等。

② Elasticsearch可用的堆越多,可用于缓存的内存就越多。但请注意,太多的堆可能会使您长时间垃圾收集暂停。

③ 设置Xmx为不超过物理RAM的50%,以确保有足够的物理内存留给内核文件系统缓存。

④ 不要设置Xmx为JVM用于压缩对象指针的临界值以上;确切的截止值有所不同,但接近32 GB。不要超过32G,如果空间大,多跑几个实例,不要让一个实例太大内存

(3)elasticsearch 配置文件优化参数

① vim elasticsearch.yml

bootstrap.memory_lock: true  #锁住内存,不使用swap
#缓存、线程等优化如下
bootstrap.mlockall: true
transport.tcp.compress: true
indices.fielddata.cache.size: 40%
indices.cache.filter.size: 30%
indices.cache.filter.terms.size: 1024mb
threadpool:
search:
type: cached
size: 100
queue_size: 2000

② 设置环境变量

vim /etc/profile.d/elasticsearch.sh export ES_HEAP_SIZE=2g    #Heap Size不超过物理内存的一半,且小于32G

(4)集群的优化(我未使用集群)

① ES是分布式存储,当设置同样的cluster.name后会自动发现并加入集群;

② 集群会自动选举一个master,当master宕机后重新选举;

③ 为防止"脑裂",集群中个数最好为奇数个

④ 为有效管理节点,可关闭广播 discovery.zen.ping.multicast.enabled: false,并设置单播节点组discovery.zen.ping.unicast.hosts: ["ip1", "ip2", "ip3"]

6、性能的检查

(1)检查输入和输出的性能

Logstash和其连接的服务运行速度一致,它可以和输入、输出的速度一样快。

(2)检查系统参数

① CPU

注意CPU是否过载。在Linux/Unix系统中可以使用top -H查看进程参数以及总计。

如果CPU使用过高,直接跳到检查JVM堆的章节并检查Logstash worker设置。

② Memory

注意Logstash是运行在Java虚拟机中的,所以它只会用到你分配给它的最大内存。

检查其他应用使用大量内存的情况,这将造成Logstash使用硬盘swap,这种情况会在应用占用内存超出物理内存范围时。

③ I/O 监控磁盘I/O检查磁盘饱和度

使用Logstash plugin(例如使用文件输出)磁盘会发生饱和。

当发生大量错误,Logstash生成大量错误日志时磁盘也会发生饱和。

在Linux中,可使用iostat,dstat或者其他命令监控磁盘I/O

④ 监控网络I/O

当使用大量网络操作的input、output时,会导致网络饱和。

在Linux中可使用dstat或iftop监控网络情况。

(3)检查JVM heap

  heap设置太小会导致CPU使用率过高,这是因为JVM的垃圾回收机制导致的。

  一个快速检查该设置的方法是将heap设置为两倍大小然后检测性能改进。不要将heap设置超过物理内存大小,保留至少1G内存给操作系统和其他进程。

  你可以使用类似jmap命令行或VisualVM更加精确的计算JVM heap

ELK填坑总结和优化过程的更多相关文章

  1. 【填坑往事】Android手机锁屏人脸解锁优化过程实录

    背景 写这篇文章,主要是为了以后面试方便.因为我简历上写了,上一份工作的最大亮点是将人脸解锁的速度由1200ms优化到了600ms,所以这些内容已经回答无数遍了.但每次总觉得回答的不完整,或者说总感觉 ...

  2. 【结果很简单,过程很艰辛】记阿里云Ons消息队列服务.NET接口填坑过程

    Maybe 这个问题很简单,因为解决方法是非常简单,但填坑过程会把人逼疯,在阿里云ONS工作人员.同事和朋友的协助下,经过一天的调试和瞎捣鼓,终于解决了这个坑,把问题记下来,也许更多人在碰到类似问题的 ...

  3. 【过程改进】 windows下jenkins常见问题填坑

    没有什么高深的东西,1 2天的时间大多数人都能自己摸索出来,这里将自己遇到过的问题分享出来避免其他同学再一次挖坑. 目录 1. 主从节点 2. Nuget自动包还原 3. powershell部署 4 ...

  4. Android Tips – 填坑手册

    出于: androidChina   http://www.androidchina.net/3595.html 学习 Android 至今,大大小小的坑没少踩,庆幸的是,在强大的搜索引擎与无私奉献的 ...

  5. Cython的用法以及填坑姿势

    因为项目需要,需要优化已有的Python代码.目前Python代码的执行过程是将Python代码转变成一行行指令,然后解释器解释指令的执行,调用到C代码层.如果去掉指令解释这个阶段,直接进入C代码层, ...

  6. [Xamarin]我的Xamarin填坑之旅(二)

    上一篇交代了我Xamarin填坑的背景,大概聊了聊第一步环境配置,第二步创建项目和开发框架选择.如果有一个可用的梯子,这部分基本不会出错. 接下来就具体聊一聊写代码的过程中遇到的一些事儿. 第三步是码 ...

  7. iOS端IM开发从入门到填坑

      让App聊起来 IM开发从入门到填坑Demo IM的实现方式 拿来主义,使用第三方IM服务 IM的第三方服务商国内有很多,底层协议基本上都是基于TCP的,类似有网易云信.环信.融云.极光IM.Le ...

  8. 写个续集,填坑来了!关于“Thread.sleep(0)这一行‘看似无用’的代码”里面留下的坑。

    "我报名参加金石计划1期挑战--瓜分10万奖池,这是我的第2篇文章,点击查看活动详情" 你好呀,我是居家十三天只出了一次小区门的歪歪. 这篇文章是来填坑的,我以前写文章的时候也会去 ...

  9. css 填坑常用代码分享

    以下是常用的代码收集,没有任何技术含量,只是填坑的积累.转载请注明出处,谢谢. 因为提交比较麻烦,后来转置github:https://github.com/jsfront/src/blob/mast ...

随机推荐

  1. SQL-记录创建篇-006

    创建记录: 自己添加记录: insert into table_name values(12,'张三',22) , values(1,'王五',32) insert into table_name(n ...

  2. Java类加载过程及static详解

    类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段. 其中类加载过程包括加载.验证.准备.解析和初始化五个阶段. 类加载器的任务就是根据一个类的 ...

  3. Dynamics CRM Plug-in

    Plug-in 就是我们俗称的dll file 或者是assembly file. 里面有自定义的代码可以运行在服务器端 Plug-in Pipeline: 只有3个阶段可以做改动: Pre-Vali ...

  4. cliipblard.js 实现点击复制

    <script src="js/clipboard.min.js"></script> <script type="text/javascr ...

  5. pxe+Kickstart自动装机补充知识点

    1.vmlinuzvmlinuz是可引导的.压缩的内核.“vm”代表“Virtual Memory”.Linux 支持虚拟内存,不像老的操作系统比如DOS有640KB内存的限制.Linux能够使用硬盘 ...

  6. 2.5 Visio2007不规则图形填充

    1.确保线和线接口的地方正好相交,没有多出来的线: 2.将图形选中>组合: 3.选中图形>形状>操作>连接>填充颜色. 因为图形式几条线段拼合的,不是封闭图形,所以需要将 ...

  7. C# Windows Service 基础

    Windows Service这一块并不复杂,但是注意事项太多了,网上资料也很凌乱,偶尔自己写也会丢三落四的.所以本文也就产生了,本文不会写复杂的东西,完全以基础应用的需求来写,所以不会对Window ...

  8. MySQL Point in Time Recovery the Right Way

    In this blog, I’ll look at how to do MySQL point in time recovery (PITR) correctly. Sometimes we nee ...

  9. 将string转为同名类名,方法名。(c#反射)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace stri ...

  10. .net updatePannel 局部刷新效果实现后,但是仍是全部刷新的修改方法

    最近做了一个小例子,就是晚上都有的那种小的updatepannel的局部刷新的小例子,但是发现按照那个例子虽然能够实现label2的局部刷新,但是看上去效果确实整个页面都在刷新,这让人很头疼,所以我在 ...