zoukankan      html  css  js  c++  java
  • 1002-谈谈ELK日志分析平台的性能优化理念

    在生产环境中,我们为了更好的服务于业务,通常会通过优化的手段来实现服务对外的性能最大化,节省系统性能开支;关注我的朋友们都知道,前段时间一直在搞ELK,同时也记录在了个人的博客篇章中,从部署到各个服务应用的采集都做了详细的介绍,但是并没有关于ELK方面的优化,那么,我们对于这些日志分析平台,我们如何去优化呢?优化的手段又有哪些呢?下面请听我娓娓道来~

    【ES优化】

    ES在前面的部署环节(https://www.cnblogs.com/bixiaoyu/p/9460554.html)已经简单了提到调优,但是不全;Elasticsearch作为数据持久化存储环节,主要就是接受采集端发送过来的数据,执行写磁盘,建立索引库,最后将结构化的数据存储到ES集群上,这是ES所需要完成的工作

    1.1:JVM内存的优化

    首先我们需要了解什么是jvm内存?作用是什么?

    jvm内存其实就是java内存堆,也是jvm需要管理的最大的一块内存空间,主要就是存放各种类型的实例对象;在java中,堆的概念被划分为,新生代和老年代,这样更有利于jvm管理内存堆中的对象,分配和回收

    我们设置堆内存主要就是创建实例对象,让所有对象实例和数据都在堆上进程分配,可以动态的分配内存大小;

    -Xms1g     #设置堆最小的内存
    -Xmx1g    #设置堆最大的内存

    如何设置最合理呢?

    首先我们要知道堆内存设置的越大,ES可用的堆就越大,同时呢,可用的缓存空间就越大,但是不能无限大,因为这样会浪费大量的内存,太多的堆内存可能会系统垃圾回收机制异常;

    优化准则:

    将最小堆(xms)和最大堆(xmx)设置为相同值即可,这样可以防止内存堆运行的有所变动;

    内存堆的值不要超过系统物理内存的50%(可以等于实际物理内存的一半),以确保有足够的物理内存给内核文件系统使用

    ES堆内存大小为什么不能超过物理 内存的50%?

    除了堆内存设置过大会造成资源浪费之后,还有一个原因,

    堆内存对于ES来说是个不可缺少的部分,能够对提高数据的执行效率,还有一个内存使用者,那就是是-lucene

    Lucene是一个开源的全文检索引擎工具 ,而我们的ES底层是基于Lucene来实现的丰富的检索功能;Lucene的性能依赖于操作系统之间的交互,如何说我们把可用的内存都给了ES的话,那么Lucene还有剩余的内存空间吗?这将会严重的影响性能;因此,我们最多只能将50%的可用内存资源分配给ES堆内存,剩下的50%留给Lucene了

    ps:这里注意一下,我们的Luceen使用的是物理内存剩余的50%,它并不使用堆内存;切记不要与ES堆内存混淆

    1.2:ES所在操作系统的内存优化

    可通过禁用swap·分区,如果是混合服务器的话可通过减低swap分区的使用积极性;

    /dev/mapper/centos-swap swap swap defaults 0 0    #进入/etc/fstab/.将其注释,永久生效;临时生效直接swapoff -a即可

    降低swao分区使用积极性,这句话是什么意思呢?首先我们要知道,系统的内存使用空间到达一定的阀值时候,便会占用swap空间,这个时候我们是可以控制这个阀值的;swappiness=0表示最大限度使用物理内存,也就是说,当物理内存使用100%之后,才去使用swap交换分区;

    如何设置呢?

    比如说,我们现在需要设置系统内存大小阀值,当物理内存使用90%的时候,只剩10%的物理内存,再去使用swap空间

    100-10=90%

    # vim /etc/sysctl.conf

    vm.swappiness = 10

    #修改之后执行sysctl -p生效

    #cat /proc/sys/vm/swappiness
    10

    1.3:·硬件优化(硬盘类型/raid类型)

    服务器硬盘选用SSD硬盘,配置成raid 0阵列以获得更佳的IO性能;

    【Logstash优化】

    logstash.yml配置优化:

    1)pipline.workers:控制output或filter插件的工作线程数(只能设置为正整数),因为logstash中的grok正则及其消耗系统计算字眼,同时filte也会存在瓶颈,此时增加工作线程,以提高性能

    2)pipeline.batch.size:批量执行event的最大值,该值用于input批量处理事件值,再打包发送给filter和output.可以提高性能,但是会增加额外的内存开销

    3)pipeline.batch.delay:批量处理事件的最大等待值(input需要按照batch处理的最大发送到消息队列,需要设置一个超时事件)

    Logstash同样运行在JVM内存中,关于jvm内存的配置原则不在述说和,和上述ES一样;

    堆内存一般要求初始值和最大值设置一致,防止动态调整堆内存大小的消耗;jvm内存的分配设置太大会拖慢系统,浪费资源,设置太小的话Logstash无法启动

    【Kafka的性能优化】

    既然我们在ELK中用到了Kafka,那么优化也是必须的,先来回顾一下,kafka是一个高吞吐分布式消息系统,并且提供了持久化,高性能主要表现在以下两点:

    第一,磁盘的连续读写性能远远高于随机读写

    第二:拆分一个topic主题分配多个partition分区,这样可以提供并发和吞吐量;

    另外,我们的kafka消息读写为什么这么高效?原因何在?

    我们要知道linux系统内核为文件设置一个缓存机制,所有对文件读写的数据内容都会存在着缓存中,称之为:page cache(页缓存)

    缓存 机制:

    当一个文件发生读操作时,系统会先去page cache页缓存中读取,如果找到,便会直接返回,没有缓存中没有需要读取的数据内容,那么会去磁盘中读取,此时系统写入一份到缓存中。,最终返回数据;

    当有写操作时,亦是如此,数据会首先写入缓存并进行标识,等待批量保存到文件系统,减少了磁盘的操作次数和系统额外开销

    我们的kafka就是依赖于这种机制,数据的读写交互便是在缓存中完成接力,不会因为kafka写入磁盘数据影响吞吐量,这就是为什么kafka非常高效的根本原因

    降低文件系统页面缓存

    主要针对于下面两个参数

    vm.dirty_background_ratio:  #指定了当文件系统缓存页数量达到系统内存的百分比阀值的时候,便会触发pdflush/flush/kdmflush后台运行写进程,将一定的缓存数据写入磁盘中

    vm.dirty_ratio:             #指定了当文件系统缓存页熟练达到系统设定的百分比阀值时候,为了保证避免数据丢失,系统不得不开始处理缓存页面,在这个过程中,可能很多应用会因为系统刷新内存数据,导致应用IO进程阻塞;这个时候呢,系统就会转入同时处理页缓存和堵塞应用

    ps:建议将vm.dirty_background_ratio设置为5%,vm.diry_ratio设置为10%;根据不同环境,需要进行测试而定

    topic的拆分:

    kafka读写单位是partition,将一个topic分配到多个partition可以提高系统的吞吐量,但前提是将不同的partition分配到不同的磁盘上,如果多个partition位于一个磁盘上就会出现多个进程同时对磁盘上多个文件进行读写,这样造成了磁盘的频繁调度,破坏了磁盘读写的连续性

    如何实现将不同的partition分配到不同的磁盘上呢?

    我们可以将磁盘上的多个目录配置到broker的log.dirs上

    # vim /usr/local/kafka/config/server.properties 

    log.dirs=/disk1/logs,/disk2/logs/,/disk3/logs    #kafaka在新建partition时,会将partition分布在paritition最少的目录上面,因此,不能将同一个磁盘上的多个目录设置到logs.dirs上

    kafka配置参数优化:

    num.network.threads=3    #broker处理消息的最大线程数

    num.io.threads=8      #broker处理磁盘IO的线程数

    一般num.network.threads主要就是处理网络IO,读写缓冲区数据,基本没有IO等待,配置线程数量为CPU核数n+1

    num.io.threads主要进行磁盘IO操作,高峰期可以能有些等待,因此配置较大一点,配置线程数量为CPU核数的2~3倍即可

    日志保留策略优化:

    kafka被打量的写入日志消息后,会生成打量的数据文件,也就是日志消息,这样会占用大量的磁盘空间。

    减少日志保留时间,通过log.retention.hours设置,单位是小时

    log.retention.hours=72    #保留日志数据的时间范围,过后便会删除

    段文件大小优化

    段文件配置大小为1GB,这样有利于快速的回收磁盘空间,重启kafka加载也会更快,如果说文件过小,那么文件数量就会较多,kafka启动的时候回单线扫描(log.dir)下的所有文件,文件较多启动较慢,会影响性能,

    log.segment.bytes=1073741824    #段文件最大大小,超过该阀值,会自动创建新的日志段

    Logs数据文件写盘策略优化

    为了大幅度提高producer写入吞吐量,需要制定定期批量写入文件磁盘的计划

    每当producer写入10000条消息事,便会将数据写入磁盘,

    #log.flush.interval.messages=10000   #强行将数据刷新到磁盘之前所能接受的消息数

    #log.flush.interval.ms=1000       #在强制刷新之前,消息可以停留在日志中最长的时间(单位毫秒,每间隔1秒时间,刷数据到磁盘中)

    【Filebeat优化】

    还记得我们为什么要使用filebeat采集日志数据吗?那是因为Logstash功能虽然强大,但是它依赖于java,在海量日志环境中,logstash进程会消耗更多的系统资源,这将严重的影响业务系统的性能,而我们说的filebeat是基于go语言,没有任何依赖,配置简单,占用系统资源少,比logstash更加的轻量级;但是有点还是需要注意。在日志量比较大的情况下或者日志异常突发时,filebeat也会占用大量的系统内存开销,所以说这方面的优化,也是至关重要的

    内存优化,Filebeat内存收到两种模式的限制,一种是内存模式,第二种是文件缓存模式,任选其一即可

    queue.mem:
        events: 4096           #表示队列可以存储的事件数量。默认值是4096个事件。
        flush.min_events: 512   #发布所需的最小事件数量。 默认值是0,表示可以直接输出发布事件,而无需额外的等待时间。 如果设置为非0,必须等待,在满足指定的事件数量后才能输出发布事件。
        flush.timeout: 5s   #表示最早的可用事件在队列中等待的最长时间,超过这个时间,立即输出发布事件,默认值是0s,表示立即可以输出发布事件

    配置含义:该队列能够存储4096个事件数量,如果超过512个可用的事件则在队列中等待5秒之后,将事件转发至output输出

    文件缓存模式调优

    此模式可以限制最大的使用内存

    ueue.spool:
      file:
        path: "${path.data}/spool.dat"      #Spool file的路径
        size: 512MiB        #Spool file的大小,也就是缓冲区的大小。
        page_size: 16KiB    #文件的页面大小。默认值为4096(4KiB)。
      write:
        buffer_size: 10MiB  #写缓冲区大小。一旦超过缓冲区大小,就刷新写缓冲区。
        flush.timeout: 5s   #写缓冲区中最旧事件的最长等待时间。如果设置为0,则在write.flush.events或write.buffer_size满足时写入缓冲区仅刷新一次。
        flush.events: 1024  #缓冲事件的数量。一旦达到上限,就刷新写缓冲区。

    文件系统资源的优化:

    fliebeat对日志的采集有一个弊端,那就是只要发现日志就会坚持把日志收集完,否则的话就会永久锁住文件句柄不放手,就算日志文件被删除,也不会放手,这就导致了文件系统大量的文件句柄被filebeat占用,导致收集日志异常,故此对其进行优化

    1)close_inactive:1m   #表示没有新日志采集后,多长时间关闭文件句柄;(也就是说无数据采集时候,等待多长时间便会自动关闭文件句柄),这里设置1分钟

    2)close_timeout:3h    #限定的数据传输时间,这里是指传输了三小时就强行关闭文件句柄,该配置解决了文件句柄耗尽的问题,但也存在着数据丢失的风险,需要综合考虑

    3)clean_inactive:72h   #表示多久会清理一次文件描述符在registry文件,默认值0表示不清理,如果不清理,registry会变大,带来性能问题

    4)ignore_older:70h    #设置了clean_inactive,就需要设置ignore_older,并且保证该值小于clean_inactive

    [小结]

    关于ELK综合方面的优化,也就介绍这么多了,其实ELK的优化方面很少,我个人觉得已经足够了,主要就是针对不同的环境和业务需求进行调参,调整适合自己的才是最好的,当然前提是你要知参数的各个含义;优化也是一个综合的技术,

    无论什么服务,我们能做到的优化点无非就是硬件,系统以及服务配置的调参;逐步测试,一步步达到最优的状态;这是进行优化的基本策略和思路(ps:本章可能还有很多优化策略没有写到,欢迎大佬填坑补充~)

  • 相关阅读:
    使用SpringAOP获取一次请求流经方法的调用次数和调用耗时
    疫苗之殇与理性应对之道
    【做更好的职场人】理性、弹性、开放的沟通
    使用IntelljIDEA生成接口的类继承图及装饰器模式
    订单导出应对大流量订单导出时的设计问题
    预发和线上的自动化对比工具微框架
    从实战角度看如何构建高质量的软件:一线工程师的一份质量手记
    代码问题及对策
    若干设计经验教训小记
    输入输出无依赖型函数的GroovySpock单测模板的自动生成工具(上)
  • 原文地址:https://www.cnblogs.com/bixiaoyu/p/9737576.html
Copyright © 2011-2022 走看看