欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

分布式服务架构-第四章大数据日志系统的构建

时间:2023-05-01
1.开源日志框架的原理分析与应用实践 1.1 JDK Logger

不需要集成任何类库,只要有jvm运行环境,直接使用。

级别:all、finest、finer、fine、config、info、warning、servere、off

public static Logger logger = Logger.getLogger(JDKLoggerDemo.class.toString());

1.2 Apache Commons Logging

JCL提供了操作日志的接口,而具体的日志实现交给Log4j这样的开源日志框架完成。

1.2.1.实现结构

Commons Logging:org.apache.commons.logging 和org.apache.commons.logging.impl

实现类具体职责

Log:日志对象接口,封装了操作日志的方法,级别trace Commons Logging

①maven配置依赖

Commonss-loggingCommobss-logging1.1.3

②测试代码

private Log log = LogFactory.getLog(CommonsLoggingDemo.class);

③配置文件

#指定日志对象org.apache.commons.logging.Log = org.apache.commons.logging.impl.Jdk14Logger#指定日志工厂org.apache.commons.logging.LogFactory = org.apache.commons.logging.impl.LogFactoryImpl

1.2.3类加载方式

顺序:

寻找JVM内的org.apache.commons.logging.LogFactory属性配置,如果找到,使用配置的日志工厂使用jdk从1.3版本开始提供服务的发现机制,扫描类路径下的meta-INF/services/org.apache.commons.logging.LogFactory文件,如果找到,装载配置,使用其中配置加载日志工厂从类路径中查找配置文件commons-logging。properties,如果找到,则根据其中配置加载具体日志实现框架如果前面的配置文件不存在使用默认配置,通过反射api判断log4j是否存在于类路径中,不存在,判断jdk14Logger是否存在于类路径中,如果都不存在,则使用内部简单的SimpleLog来实现。

通过配置动态地找到具体的实现类,如果实现类不在类路径中或者被限制使用,则无法加载。

1.3 Apache Log4j(简称Log4j) 1.3.1实现结构

org.apache.log4 包含Log4j主要的实现类:Logger、Layout、Appender和LogManager

Logger :日志对象,负责捕捉日志记录信息

Level类定义级别:all ConsoleAppender:把日志输出到控制台中FileAppender:把日志输出到磁盘文件DailyRollingFileAppender:每天产生一个日志磁盘文件,日志文件按天滚动生成RollingFileAppender:日志磁盘文件的大小达到指定尺寸时会产生一个新的文件,日志文件按照日志大小滚动生成 Layout:对日志进行格式化,负责生成不同格式的日志信息

HTMLLayout:以HTML表格形式布局展示PatternLayout:自定义指定的格式展示SimpleLayout:只包含日志信息的级别和信息字符串TTCCLayout:包含日志产生的时间,线程,类别等信息 1.3.2使用方式

①maven配置依赖

log4j log4j 1.2.17

②测试代码

Logger log = Logger.getLogger(Log4jDemo.class);

③配置文件

# 声明 log4j.prgpertieslog4j.rootLogger = INFO,FILE,ConSOLElog4j.appender.FILE=org.apache.log4j.FileAppenderlog4j.appender.FILE.File = /home/robert/Log4jDemo.loglog4j.appender.FILE.ImmediateFlush=truelog4j.appender.FILE.Threshold=DEBUGlog4j.appender.FILE.Append=truelog4j.appender.FILE.layout=org.apache.log4j.PatternLayoutlog4j.appender.FILE.layout.conversionPattern=%d(ABSOLUTE) %5P %C(1):%L - %m%nlog4j.appender.ConSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.Target=System.outlog4j.appender.CONSOLE.ImmediateFlush=truelog4j.appender.CONSOLE.Threshold=DEBUGlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.encoding=UTF-8log4j.appender.CONSOLE.layout.conversionPattern=%d(ABSOLUTE) %5p %c(1):%L - %m%n# 声明log4j.xml<?xml version="1.0" encoding="UTF-8" ?>...

1.3.3Log4j 的锁和性能优化

Log4j默认的Appenders使用同步锁来实现

eg:Netty作为HTTP服务器实现的一个类似回显的服务,使用Log4j记录业务日志,压测时发现每秒最多可处理9000个请求,关闭日志时发现每秒最多可处理28000个请求。

为找性能瓶颈,在预测过程中,使用Jstack命令发现并发时线程都在等待一个写日志事件的锁。

多个线程同时使用一个Logger时,在Category层次上加了同步锁

锁一个在Category层次,一个在Appender层次,在高并发的情况下对系统的性能影响很大一个时段只能有一个线程在打印日志会阻塞其他大部分业务线程,而对日志收集不是核心链路上的功能,应作为一个辅助操作,不能影响核心业务功能。

。。。

1.4 Slf4j

可以只依赖于Slf4j来实现日志打印,具体日志实现由配置来决定使用Log4j还是Logback等。

1.4.1实现结构

门面模式,在编译时确定底层日志实现框架,只要底层的日志实现Jar包和Slf4j的静态编译转接包在类路径下即可。

Slf4j对于每种日志实现框架都提供了一个转接的jar包,jar包里面包含LoggerFactoryBinder接口的实现。

Slf4j实现的静态编译绑定架构,应用层程序会用Slf4j api打印日志,api使用不同的日志实现转接Jar包里面的StaticLoggerBinder类到不同的日志实现框架中。

增加了参数化日志,打印复杂日志内容时不再需要判断相应的级别是否已经打开

1.4.2使用方式

①pom.xml中单独引入底层日志实现的转接Jar包

eg

org.slf4j slf4j-api 1.7.20org.slf4j slf4j-log4j12 1.7.12log4j log4j 1.2.17

②代码

Logger logger = LoggerFactory.getLogger(Slf4jLog4jDemo.class);

③配置文件

<?xml version="1.0" encoding="UTF-8" ?>

Slf4j只提供了一个核心模块slf4j-api.jar,这个模块下只有日志接口,没有具体的实现,需要单独添加底层日志实现的转接包和实现Jar包。但是这个底层日志类实际和Slf4j并没有任何关系,Slf4j通过增加日志的中间转接层来转换相应的实现。

1.5 Logback 1.5.1实现结构

Logback三个模块:logback-core、logback-classic 和 logback-access

logback-core:后面两个模块的基础模块,包含日志框架实现的所有基础类logback-classic:完整地实现了Slf4j APIlogback-access 与 Servlet 容器集成,提供了丰富的HTTP访问日志功能 1.5.2使用方式

①依赖

org.slf4j slf4j-api 1.7.20ch.qos.logback logback-classic 1.1.7ch.qos.logback logback-core 1.1.7ch.qos.logback logback-access 1.1.7

②代码

Logger logger = LoggerFactory.getLogger(Slf4jLogbackDemo.class);

③配置文件

${pattern} /home/robert/log/log.out testLog-%d{yyyy-MM-dd}.log 30 ${pattern}

1.5.3性能提升

Logback对Log4j的内核进行了重写和优化,在一些关键执行路径上性能提升了至少10倍,初始化内存加载也变得更小了。

1、6 Apache Log4j 2(Log4j 2,Log4j升级版本)

通过log4j-to-slf4j兼容模式,使用Log4j 2 api的应用完全可以转接到Slf4j支持的任何日志框架上。

可以动态地加载修改过的配置,在动态加载的过程中不会丢失日志

1.6.1实现结构

Log4j 2 实现了API模块和实现模块分离,包含2个jar包,一个log4j-api.jar(对外提供api,主要包含Logger 类和LogManager类),另一个log4j-core.jar(实现日志记录功能的核心基础类)

1.6.2使用方式

①添加依赖

org.apache.logging.log4j log4j-core 2.5org.apache.logging.log4j log4j-api 2.5

②代码

Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

③配置文件

<?xml version="1.0" encoding="UTF-8">

1.6.3 性能提升

通过在一个单独的线程里执行I/O操作来提高性能,实现方式:异步Appender 和异步Logger

异步Appender:内部通过ArrayBlockingQueue来实现,异步的线程从队列里取走日志事件并写入磁盘,每当队列为空时,会对缓冲的批量日志事件进行一次罗盘错字异步Logger:目标是尽可能快的使打印日志的方法调用返回,Logger分为所有Logger全异步 和 同步与异步混合。异步Logger使用无所的Disruptor RingBuffer来实现。

异步配置:jvm启动参数:-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsycLoggerContextSelector异步同步混合:在配置文件中显示指定的 或 2.日志系统的优化和最佳实践 2.1 开发人员的日志意识

开发时有意识的设想代码出现问题时的场景,记录关键程序运行信息打印日志时必须包含环境信息,eg,用户id,角色参数返回值逻辑判断结果,循环次数等对异常等错误信息必须打印错误级别及以上级别的日志,对线上日志要定期检查,没有异常日志产生的服务才是健康的服务。生产环境将关闭的日志必须在打印日志前进行判断,以此来提高执行效率必须使用占位符的方式代替字符串连接,这样程序更加简洁,并且性能有所提高对关键业务步骤必须大点并记录耗时和结果等信息 2.2 日志级别的设置

QA环境可以使用debug及以下级别刚上线的应用还没有到稳定期,使用debug级别上线后稳定应用,使用info常年不出现问题的应用使用error

对于不同情况应该使用的日志级别:

使用trace级别的日志输出最细粒度的信息事件,通过这些信息可以跟踪程序执行的任一步骤使用debug级别日志输出细粒度的信息事件,这些信息对调试应用程序非常有用info级别:输出粗粒度信息时间,突出强调应用程序运行的关键逻辑和过程warn级别:输出可能出现的错误,或输出潜在发生错误的环境信息,或打印用户输入的非法信息error级别:输出错误事件,但仍不影响系统的继续运行,发生异常一定要记录error日志并打印异常堆栈,异常在封装后抛出时一定要保留根源异常和错误信息,构成异常树。fatal级别:严重的错误时间,将会导致应用程序的退出 2.3 日志的数量和大小

控制日志输出量,避免由于业务上量而导致服务器磁盘沾满并大量地输出无用的日志,不利于系统性能提升,也不利于快速定位错误点

不要随便把对象JSON序列化后打印出来,如果要打印,使用JSON格式打印会占用很大空间

单条日志不超过1KB

构建大数据日志系统时要有容错能力,遇到连续的大日志时可以采取抛弃的策略,避免出现内存占用过多的问题。

2.4 切割方式

使用脚本切割

cat app.log > app.'date'+%Y-%m-%d''.logcat /dev/null > app.log

脚本首先通过cat文件把当前日志文件内容滚动存储到另外一个带日期后缀的日志文件中,然后清空当前的日志文件。

问题:

丢失一部分日志打印到另一个文件中,会导致磁盘I/O瞬间迅速增加,在严重情况下会影响应用程序打印日志或进行磁盘I/O操作

推荐使用:日志框架原生的按照日期滚动的Appender来记录日志,在滚动周期结束后,会对当前日志文件重命名,然后生成新的日志文件。

2.5 日志格式的配置

Log4j通过配置可以显示不同的环境信息,常用内置环境信息

%p:输出日志信息的优先级:debug、info、warn、error、fatal%d:输出日志时间点日期或时间:默认格式JSO8601,也可以指定格式%r:输入自应用启动到输出该log信息所用的毫秒数%c:输出日志信息所属的类目,通常就是所在类全名%t:输出产生该日志事件线程名%M:输出产生该日志的方法名%l:输出日志事件的发生位置 2.6 一行日志导致的线上事故

线上运行良好的服务,在一次上线的过程中增加一行日志,导致这个服务的数据库连接池的连接出现用光的情况。

private void doSomething(......, Map param){ log.debug("......" + param);}

观察日志,线上服务开始偶发地报NullPointerException

查看线程的调用堆栈,是在一个领域模型的toString()方法报出来的

分析:增加日志导致NullPointerException,日志打印了Map内容,map包含这个对象,打印时需要将这个对象转为字符串,会调用对象的toString()方法

只有字段domainObject1为空是会产生NullPointerException

问什么字段domainObject1会为空? —数据来源分析为什么会引起数据库连接池里面的连接用光?

上层处理业务逻辑中,手工拿到了数据库连接,遇到空指针并没有释放数据库连接,因此多个数据库连接被占用,最后数据库连接逐渐被用光,无法提供正常服务。 3.大数据日志系统的原理与设计 3.1 通用架构和设计

日志框架引用在应用服务上,产生的日志通常存储在本地文件里,按天或小时滚动产生日志文件。

采集器部署在每个应用服务器上,监控本地日志文件,获取新产生的内容,发送到对应缓冲队列节点解析器集群监听缓冲队列集群,获取进入的日志处理,通常会把基于行的文本日志转换成JSON格式的数据,便于后续存储解析器集群的节点将日志转成JSON格式,把日志存储在有序的存储系统中并建立索引,为后续客户端提供搜索服务。 3.2日志采集器

持续的收集和解析服务日志,收集服务器性能数据,并传输处理后的数据到后端系统。

3.2.1常见的日志采集器

(1)Logstash

开源的服务端数据处理管道,可以并发地从多个数据源获取数据,转换数据发送数据到一个数据存储或缓冲区。

从各个数据源收集数据后,Logstash可以快速的解析和转换日志数据,从原始数据中提取出字段的明值对形成结构化JSON。

Logstash通常会把处理后的结构化日志数据存储到搜索引擎中,可以为Logstash配置安全的传输通道,也可以使用安全的Elasticsearch集群,保证数据不泄露。

Logstash有200多个插件,可以组合匹配编排不同数据源,具有良好的扩展性。

Logstash具有容错性,任意节点出问题,会通过持久化处理的数据保存在内部的缓冲区中保证数据不会丢失,但可能会重复发送,内部有消息的缓冲区,big存储在硬盘中,本身有削峰能力。

(2)Fluentd

开源数据采集器,C和Ruby语言开发的轻量级系统,占用系统资源比较少,一般只占用30-40MB内存,单线程每秒可处理1.3万日志,可以统一收集日志数据,然后进行转换和存储,为使用者提供基础数据支持,帮助使用者做相应的决策。具有统一的JSON格式处理,可插拔的架构,轻量级等特点。

(3)Flume

高可用的,高可靠的,分布式的海量日志采集,聚合,转换和传输的系统,通过定制化支持从各类日志源采集日志。同时支持TCP和UDP两种传输模式,然后对日志进行简单加工,再写到日志的存储系统中,并支持对输出目标进行扩展和定制。

(4)Scribe

能够从各种日志源收集日志,并存储到一个中央存储系统上,以便于集中统计,分析和处理,为它的使用者提供查询和搜索等功能,它提供了一套可扩展,可容错的方案,可在众多的应用服务器上分布式地收集日志,然后归集日志到统一的存储系统中。

当中央存储系统的网络或者机器出现故障时,Scribe会将日志暂存到本地磁盘,当中央存储系统恢复后,Scribe会将转存的日志重新传输给中央存储系统。----【容错性】

通常与Hadoop组合使用,用户向HDFS中存储日志,通过Hadoop的MapReduce任务对数据进行定时处理,然后将处理加工的数据指标存储到其他数据存储系统中,用于监控,报警或者通过日志展示系统来对外提供查询和搜索功能。

(5)Rsyslog

提供了高性能,安全和模块化等特性

3.2.2Logstash和Fluentd对比

支持平台:L-任何支持JVM的平台,F-Linux和Windows传输方式:L-需配合Redis来提供稳定性,F-本身带有缓冲系统,有容错性,可用性,稳定性,只是需要使用者多花时间和心思在配置上即可实现高效的日志采集器性能:L-会用更多内存,对于大量的服务节点可以使用Filebeat来代Logstash,F-会用更少的内存,可以用Fluent Bit 和Fluented Forwarder实现更轻量器架构。插件系统:最大的不同是管理插件的方式。L-Gitub库管理插件。F-没有一个中心管理插件,事件路由方式:L-使用可编程的方式进行事件路由,F-标记配置的方式路由。 3.2.3日志采集的最佳实践

断点续采,采集器存储文件指纹及行位置到本地的一个文件中,文件指纹通常指文件的inode,即使文件重命名,文件的inode也不会发生变化,因此采集器通常追踪的是文件的inode信息和行号,文件名修改并不影响inode信息,只是影响了它所在的文件目录的信息,但是如果文件被压缩后,inode实际发生了改变,则文件已经成为另外一个文件了,需手工处理。

3.3 日志缓冲队列

如果没有日志缓冲队列,直接让日志采集器推送日志给日志解析器,则在日志解析器负载较高时,会拖住日志采集器,导致日志采集器变慢。如果采集器的内部缓冲或者内存被吃光,则会导致日志丢失,由于日志采集器与应用服务部署在一起,也可能会影响应用服务正常运行。

日志缓冲队列连接日志的收集器和日志解析器。

3.4日志解析器

从日志缓冲队列读取日志,解析日志,转换日志,然后以JSON的格式存储到后续的日志存储系统中。日志解析器必须连续稳定的执行,而且要有可伸缩性。

Logstash是解析日志的一个好工具,可以把基于行的文本格式的日志转换成结构化的JSON格式,提供了不同的插件来解析不同的日志,对于Tomcat、Nginx日志都有对应的解析插件。

3.5 日志存储和搜索

日志解析器从解析后的日志中提取指标等存入日志存储系统中,在日志存储系统中进行索引,并支持后续的搜索。使用全文检索的搜索引擎技术egElasticsearch,Solr等。

如果存在较长时间的日志仍然需要被经常查询,则我们需要定期整理这些日志的索引,让他们与时俱进,提供更高的查询效率如果较长时间存在的日志偶尔需要被查询,则建议对这些数据进行归档,eg:对一年以外的数据可以把他们存储到搜索集群的外部,当有需要时再进行挂载如果对较长时间以前的日志没有查询需求,则我们需要实现定期清理不用的日志数据的功能 3.6 日志展示系统

通常使用Kibana做这件事

3.7 监控和报警

日志被结构化后存储到日志存储和搜索系统中,可以基于这些数据构建监控和报警系统,定时地在日志存储和搜索系统中查找服务和某一标准数据指标,然后与预定义的阈值进行对比,超出阈值,则通过短信、邮件或自动语音电话报警

3.8 日志系统的容量和性能评估

在设计一套大数据日志处理系统时,要充分地评估日志系统的容量和性能,设计好系统的各个集群内节点的数量,给每个节点配置最合理的资源。

假设:每天处理来自200台机器的2TB日志,每条日志1KB,监控报警延时不超过5min,单台服务器产生日志峰值吞吐量10000/s,所有应用服务器瞬时的日志峰值之和1 000 000/s

每台机器每秒处理日志量:

2TB/1KB/200台/24x60x60=115/s

单台机器10000/s,Logstash和Fluentd采集都可以

日志峰值 1000 000 /s吞吐量,kafka吞吐量为100000/s,需要10个kafka节点集群处理,计算kafka网络I/O是否满足

100万/10台 x 1KB = 100MB

网络需承受100MB/s 负载量,假设kafka节点都是千兆网卡,刚好满足。

日志解析处理成功到存储需20ms,每秒峰值处理100万条。需时间100万 x 20ms = 2万秒

延迟不超过5min 并发数为

2万秒/5min = 66.67并发

即需要有333个核心处理器处理峰值时的1 000 000/s的吞吐量,假设使用4核 8GB 共需要处理机

66/4 = 16台

需要16台日志解析器来处理峰值吞吐量1000 000/s

考虑系统将来的业务增长量,对系统设计的资源要求冗余,根据经验对系统的容量设计5~10倍冗余为合理值,

4 ELK系统的构建和使用

ELK开源项目Elasticsearch Logstash Kibana集合,

职责

Elasticsearch:基于Lucene搜索引擎的NoSQL数据库Logstash:基于管道的处理工具,从不同数据源接收数据,执行不同的转换,发送数据到不同的目标系统Kibana:工作在Elasticsearch上,是数据的展示层系统 4.1 Elasticsearch

用来提供专业的搜索服务的产品。

一个NoSQL数据库,把数据存储在一个无模式数据存储中,聚焦于搜索功能,通常是通过一个REST API从Elasticsearch中完成搜索和查询的。

安装包,启动服务

对外提供RESTful风格的API 可以使用HTTP PUT 或POST协议来执行索引数据的功能。

4.2 Logstash

采集日志,存储到Elasticsearch中,不仅可以从不同日志源采集日志,还可以过滤、处理和转换数据。

下载安装启动

1.Logstash输入源

可以处理不同输入源的日志和时间。通过这些输入源,从不同的数据源导入数据并管理数据,最终把处理后的数据发送到大数据存储和搜索系统。

首先需要配置数据源,在过滤器中不定义任何输入源,则默认输入源就是命令行的标准输入,既然一次可以配置多个输入源,最好对输入源进行分类和标记,在过滤器和输出中才能引用他们。

2.Logstash输出目标

Logstash有许多输入目标,通过这些输入目标,把日志和时间通过不同的技术发送到不同的位置和服务,也可以把事件输出到文本文件等分布式存储中,也能转化称消息发送到消息系统中等

Logstash能够处理来自多个输入源的事件,可以使用多个过滤器,应定义事件处理的输出目标,如果没有定义则标准控制台输出是默认的输出目标。

3.Logstash过滤器

Logstash有丰富的过滤器,可以接收,处理,计算,测量事件等。

Logstash的配置包含输入,输出和过滤器三个段,一个配置文件中可以有多个输入、输出和过滤器的实例,也可以把他们分组并放到不同配置文件中。

4.3 Kibana

基于浏览器页面显示Elasticsearch数据的前端展示系统,使用HTML和Javascript实现,是Elasticsearch提供日志分析的网页界面工具,可用它对日志进行高效汇总,搜索,可视化等操作。

最大的亮点是图标和可视化展示能力。

安装配置启动

ip:http://localhost:5601

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。