springboot1.5.x与自建的应用层APM系统落地实践

简书 慢黑八
转载请注明原创出处,谢谢!
如果读完觉得有收获的话,欢迎点赞加关注

APM

【概念篇】应用程序微服务化之后,我们想看到整个微服务的集群,上下游系统,服务依赖关系、流量分布、外部边界等内容。所以,监控(可观察性)是应用系统微服务化之后提出的一项基础性需求。今天,我们就来聊聊微服务监控(APM)的那些事。

采用系统分层的思想可视化监控分析可以分为3个层次

  • 1、基建层:云主机、操作系统、云服务等基础指标,由云厂商负责提供。
  • 2、工具层:k8s、docker、mesos、devops,由生态提供。
  • 3、应用层:中间件、数据库、消息队列、缓存等中间件由微服务或云原生应用的开发者提供。
    对于业务系统开发的人员来说,如何对应用层进行监控分析成为了他们需要急需解决的问题。

接下来我们就来说说如何对 "应用层进行监控分析" ,先看下下面三个概念

  • 1、日志(Logging):包含业务日志、系统日志、错误日志、警告日志等,分布式日志我们通常使用ELK进行收集,同时这也是比较简单的解决方案。
  • 2、指标(Metrics):指标是可累加的,它具有原子性。每个指标都是一个逻辑计量单元,体现了一段时间之内相关指标的状态。例如:队列深度、请求执行时间、http请求数及自定义的一些业务指标等。通过定义和收集需要具备某时间范围的查询能力。Prometheus是基于指标的系统,它通过定义和收集不同的指标数据,提供基于时间维度的查询能力。结合Grafana(开源)进行展示。
  • 3、追踪(Tracing):分布式追踪能力是最近几年技术人员最为关注的需求,由Twitter开源的ZipKin是目前运用最为刚广泛的分布式追踪系统,spring-cloud-sleuth是spring-cloud为zipkin开发的一组套件,使zipkin更好的结合在spring-cloud生态中。还有一些其他的开源分布式追踪系统也比较火,例如skywalking以及pinpoint、cat等。

所以,我们自建的APM系统,采用如下解决方案收集日志、指标、追踪3个维度的数据:

  • 1、日志:使用log4j2+filebeat+kafka+logstash+elasticSearch作为日志的收集,使用Kibana进行展示
  • 2、指标:使用Metrics/Prometheus-client+Prometheus+Tsdb进行指标的收集,使用Grafana进行展示
  • 3、追踪:使用spring-cloud-sleuth+kafka+zipkinServer+elasticSearch作为链路数据的收集,使用zipkin-ui进行链路追踪数据的展示。
    如下图,上面三个概念并不是相互独立的,往往会有一定的重叠,复杂和完善的监控系统一般是跨越多个维度的,下面我们具体来说一下重叠的部分:
  • 4、追踪+日志:通过简单的上下文传递,可以将请求的上下文ID输出到日志,让日志具备上下文关联的能力。可以根据traceid、spanid快速找到一次“请求范围内的日志”。
  • 5、日志+指标:可以通过解析系统现有的业务日志获取相关的指标数据,也可称为“可聚合的事件汇总”。
  • 6、追踪+指标:指明基于分布式追踪的数据分析(慢事务,错误,中间件调用等)应用间的关系(系统拓扑)以及数据流向(系统调用关系)
图1

【实践篇】 针对现有springboot1.5.x应用环境,与我们自建的apm系统进行整合。

一、现有环境

1、应用系统

springboot1.5 + JDK1.8等

2、APM系统

参见图1中的APM系统,包含elk6.7.1、grafana、Prometheus、tsdb、kafka、zipkinserver等
kibana   http://test.tech.**bank.com/kibana/ 用户名:onec***_dev 密码:**bank
zipkinui  http://test.tech.**bank.com/zipkin/

二、基于现有spring1.5.x 环境改造

1、追踪:使用spring-cloud-sleuth通过kafka传输zipkin链路数据到zipkinServer:

  • pom.xml文件增加依赖
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
 <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
</dependency>
  • application.properties应用配置中增加如下内容
    your_application为你的应用程序名称
application.name: your_application
spring.kafka.producer.bootstrap-servers=ip:port
spring.kafka.producer.compression-type=gzip
spring.kafka.producer.acks=all
spring.kafka.producer.retries=3
spring.kafka.producer.batch-size=1048576
spring.kafka.producer.buffer-memory=6291456
spring.sleuth.sampler.percentage=1.0
spring.zipkin.sender.type=kafka
spring.zipkin.compression.enabled=true
spring.zipkin.service.name=your_application
spring.zipkin.message-timeout=1

2、日志:使用filebeat,收集json格式的log4j日志,通过kafka,logstash处理后存储至elastic search存储中,另外在日志中输出tracid、spanid、parentid等信息。

  • 待filebeat收割的日志输出配置,修改应用程序log4j2.xml配置文件,添加以下appender块
    注:filebeat以行位单位读取日志,下配置中,compact、eventEol需要全部配置位true,保证json格式日志按行输出
<!--以下是Properties中的改造-->
<Property name="PROJECT_NAME">your_application</Property>
<property name="LOG_PATH" value="/path/to" />
<property name="MAX_FILE_SIZE" value="1000MB" />

<!--以下是appenders中的改造-->
<RollingRandomAccessFile name="ALLJSON_LOG"
    fileName="${LOG_PATH}/alljson.log"
    filePattern="${LOG_PATH}/alljson-%d{yyyyMMdd-HHmmss.SSS}.log">
    <JSONLayout charset="UTF-8" locationInfo="true"
            properties="true" complete="false" compact="true" eventEol="true"
            propertiesAsList="false" includeStacktrace="true">
    <KeyValuePair key="serviceName" value="${PROJECT_NAME}" />
    </JSONLayout>
    <Policies>
        <!--当日志大小达到1000MB时,以上述filePattern定义的格式进行打包压缩 -->
        <SizeBasedTriggeringPolicy
            size="${MAX_FILE_SIZE}" />
    </Policies>
    <DefaultRolloverStrategy max="10" /><!--压缩包数量不超过10 -->
</RollingRandomAccessFile>

<Async name="ASYNC_ALLJSON_LOG" bufferSize="262144">
    <AppenderRef ref="ALLJSON_LOG" />
</Async>

<!--以下是Loggers中的改造-->
<root level="${LOG_ROOT_LEVEL}">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="ASYNC_ALLJSON_LOG"/>
</root>
  • 因为log4j.xml中的<KeyValuePair>需要使用高版本log4j2,这里我使用2.11.2这个版本,并且排出logback
    pom.xml引入高版本的log4j2依赖,如下:
<!--  引入log4j2依赖   -->
<dependency>
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-log4j2</artifactId>  
</dependency> 
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.11.2</version>
</dependency> 
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.11.2</version>
</dependency> 
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.11.2</version>
</dependency>
  • filebeat安装配置:
1、下载filebeat  wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.7.1-linux-x86_64.tar.gz
2、解压tar -xvf  filebeat-6.7.1-linux-x86_64.tar.gz
3、进入 filebeat-6.7.1-linux-x86_64目录配置filebeat.yml文件
- type: log
  # Change to true to enable this input configuration.
  enabled: true
  # Paths that should be crawled and fetched. Glob based paths.
  paths:
    #- /app/onecard-canary-service/logs/info.log
    - /path/to/alljson.log

output.kafka:
  enabled: true
  hosts: ["IP:PORT"]
  topic: 'topic.name'
  partition.hash:
    reachable_only: true
  compression: gzip
  max_message_bytes: 1000000
  required_acks: 1

4、执行命令,运行filebeat:  nohup ./filebeat -e -c filebeat.yml &
  • 如果想在控制台或者其他的log appender中也看到traceid的相关信息,需要配置LOG_PATTERN.
<property name="LOG_PATTERN"
            value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%X{X-B3-TraceId},%X{X-B3-SpanId},%X{X-B3-ParentSpanId},%X{X-Span-Export}]
            %c{36} [%line] - %msg%n" />

%X{X-B3-TraceId},%X{X-B3-SpanId},%X{X-B3-ParentSpanId},%X{X-Span-Export}就是traceid、spanid、parentid的相关信息

3、指标:

未完、待续....