• 分布式日志和链路追踪


    分布式日志

    实现思路

    分布式日志框架服务的实现思路基本是一致的,如下:

    • 日志收集器:微服务中引入日志客户端,将记录的日志发送到日志服务端的收集器,然后以某种方式存储
    • 数据存储:一般使用ElasticSearch分布式存储,把收集器收集到的日志格式化,然后存储到分布式存储中
    • web服务:利用ElasticSearch的统计搜索功能,实现日志查询和报表输出

    比较知名的分布式日志服务包括:

    • ELK:elasticsearch、Logstash、Kibana
    • GrayLog

    ELK存在的问题

    1. 不能处理多行日志,比如Mysql慢查询,Tomcat/Jetty应用的Java异常打印
    2. 不能保留原始日志,只能把原始日志分字段保存,这样搜索日志结果是一堆Json格式文本,无法阅读。
    3. 不符合正则表达式匹配的日志行,被全部丢弃。

     Graylog的优点

    1. 一体化方案,安装方便,不像ELK有3个独立系统间的集成问题。
    2. 采集原始日志,并可以事后再添加字段,比如http_status_code,response_time等等。
    3. 自己开发采集日志的脚本,并用curl/nc发送到Graylog Server,发送格式是自定义的GELF,Flunted和Logstash都有相应的输出GELF消息的插件。自己开发带来很大的自由度。实际上只需要用inotifywait监控日志的modify事件,并把日志的新增行用curl/netcat发送到Graylog Server就可。
    4. 搜索结果高亮显示,就像google一样。
    5. 搜索语法简单,比如: source:mongo AND reponse_time_ms:>5000,避免直接输入elasticsearch搜索json语法
    6. 搜索条件可以导出为elasticsearch的搜索json文本,方便直接开发调用elasticsearch rest api的搜索脚本。

    GrayLog的使用

    GrayLog的流程框架图

    流程如下:

    • 微服务中的GrayLog客户端发送日志到GrayLog服务端
    • GrayLog把日志信息格式化,存储到Elasticsearch
    • 客户端通过浏览器访问GrayLog,GrayLog访问Elasticsearch

    这里MongoDB是用来存储GrayLog的配置信息的,这样搭建集群时,GrayLog的各节点可以共享配置。

    GrayLog的安装

    此时我们需要在docker中安装Mongodb, elasticSearch,GrayLog。

    1. #部署Elasticsearch
    2. docker run -d \
    3. --name elasticsearch \
    4. -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    5. -e "discovery.type=single-node" \
    6. -v es-data:/usr/share/elasticsearch/data \
    7. -v es-plugins:/usr/share/elasticsearch/plugins \
    8. --privileged \
    9. -p 9200:9200 \
    10. -p 9300:9300 \
    11. elasticsearch:7.17.5
    12. #部署MongoDB(
    13. docker run -d \
    14. --name mongodb \
    15. -p 27017:27017 \
    16. --restart=always \
    17. -v mongodb:/data/db \
    18. -e MONGO_INITDB_ROOT_USERNAME=sl \
    19. -e MONGO_INITDB_ROOT_PASSWORD=123321 \
    20. mongo:4.4
    21. #部署 ,分别设置es和mongo的地址
    22. docker run \
    23. --name graylog \
    24. -p 9000:9000 \
    25. -p 12201:12201/udp \
    26. -e GRAYLOG_HTTP_EXTERNAL_URI=http://192.168.150.101:9000/ \
    27. -e GRAYLOG_ELASTICSEARCH_HOSTS=http://192.168.150.101:9200/ \
    28. -e GRAYLOG_ROOT_TIMEZONE="Asia/Shanghai" \
    29. -e GRAYLOG_WEB_ENDPOINT_URI="http://192.168.150.101:9000/:9000/api" \
    30. -e GRAYLOG_PASSWORD_SECRET="somepasswordpepper" \
    31. -e GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 \
    32. -e GRAYLOG_MONGODB_URI=mongodb://sl:123321@192.168.150.101:27017/admin \
    33. -d \
    34. graylog/graylog:4.3

    命令解读:

    • 端口信息:
      • -p 9000:9000:GrayLog的http服务端口,9000
      • -p 12201:12201/udp:GrayLog的GELF UDP协议端口,用于接收从微服务发来的日志信息
    • 环境变量
      • -e GRAYLOG_HTTP_EXTERNAL_URI:对外开放的ip和端口信息,这里用9000端口
      • -e GRAYLOG_ELASTICSEARCH_HOSTS:GrayLog依赖于ES,这里指定ES的地址
      • -e GRAYLOG_WEB_ENDPOINT_URI:对外开放的API地址
      • -e GRAYLOG_PASSWORD_SECRET:密码加密的秘钥
      • -e GRAYLOG_ROOT_PASSWORD_SHA2:密码加密后的密文。明文是admin,账户也是admin
      • -e GRAYLOG_ROOT_TIMEZONE="Asia/Shanghai":GrayLog容器内时区
      • -e GRAYLOG_MONGODB_URI:指定MongoDB的链接信息
    • graylog/graylog:4.3:使用的镜像名称,版本为4.3

    进行测试

    访问对应的9000端口。

     集成微服务进行测试

    导入依赖

    1. <dependency>
    2. <groupId>biz.paluch.logging</groupId>
    3. <artifactId>logstash-gelf</artifactId>
    4. <version>1.15.0</version>
    5. </dependency>

    修改Logback.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!--scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。-->
    3. <!--scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。-->
    4. <!--debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
    5. <configuration debug="false" scan="false" scanPeriod="60 seconds">
    6. <springProperty scope="context" name="appName" source="spring.application.name"/>
    7. <!--文件名-->
    8. <property name="logback.appname" value="${appName}"/>
    9. <!--文件位置-->
    10. <property name="logback.logdir" value="/data/logs"/>
    11. <!-- 定义控制台输出 -->
    12. <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    13. <layout class="ch.qos.logback.classic.PatternLayout">
    14. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level - %logger{50} - %msg%n</pattern>
    15. </layout>
    16. </appender>
    17. <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    18. <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    19. <level>DEBUG</level>
    20. </filter>
    21. <File>${logback.logdir}/${logback.appname}/${logback.appname}.log</File>
    22. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    23. <FileNamePattern>${logback.logdir}/${logback.appname}/${logback.appname}.%d{yyyy-MM-dd}.log.zip</FileNamePattern>
    24. <maxHistory>90</maxHistory>
    25. </rollingPolicy>
    26. <encoder>
    27. <charset>UTF-8</charset>
    28. <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
    29. </encoder>
    30. </appender>
    31. <appender name="GELF" class="biz.paluch.logging.gelf.logback.GelfLogbackAppender">
    32. <!--GrayLog服务地址-->
    33. <host>udp:192.168.150.101</host>
    34. <!--GrayLog服务端口-->
    35. <port>12201</port>
    36. <version>1.1</version>
    37. <!--当前服务名称-->
    38. <facility>${appName}</facility>
    39. <extractStackTrace>true</extractStackTrace>
    40. <filterStackTrace>true</filterStackTrace>
    41. <mdcProfiling>true</mdcProfiling>
    42. <timestampPattern>yyyy-MM-dd HH:mm:ss,SSS</timestampPattern>
    43. <maximumMessageSize>8192</maximumMessageSize>
    44. </appender>
    45. <!--evel:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALLOFF,-->
    46. <!--不能设置为INHERITED或者同义词NULL。默认是DEBUG。-->
    47. <root level="INFO">
    48. <appender-ref ref="stdout"/>
    49. <appender-ref ref="GELF"/>
    50. </root>
    51. </configuration>

    这样就实现了微服务的分布式日志。

    调用work服务的查询方法,日志就会出现在控制面板上。

    日志回收策略

    点击Default index set的Edit进行设置日志的回收策略。

    日志的回策略有三种。

    分别是:

    • Index Message Count:按照日志数量统计,默认超过20000000条日志开始清理
    • Index Size:按照日志大小统计,默认超过1GB开始清理
    • Index Time:按照日志日期清理,默认日志存储1天

    搜索语法
    搜索语法的格式

    1. #不指定字段,默认从message字段查询
    2. 输入:undo
    3. #输入两个关键字,关系为or
    4. undo 统计
    5. #加引号是需要完整匹配
    6. "undo 统计"
    7. #指定字段查询,level表示日志级别,ERROR3)、WARNING(4)、NOTICE(5)、INFO(6)、DEBUG(7
    8. level: 6
    9. #或条件
    10. level:(6 OR 7)

    自定义展示字段

    可以在allMessage中显示字段。

     这里添加了level字段。

    日志统计仪表

    创建仪表

    点击Create new dashboard,创建一个新的仪表。

     在该仪表中我们可以进行DIY。

    可以DIY成这种效果。

    分布式日志面试题

    问: 在服务中你们通常会记录哪些信息呢?
    答: 会记录: 服务的名称,日志的级别,日志的详细信息,时间,对应的类,调用的方法。

    问: 那会在什么时候进行记录日志?

    答: 在有异常信息调用重要方法时的参数传入时会记录日志。

    链路追踪

    APM  

    什么是APM?

    随着微服务架构的流行,一次请求往往需要涉及到多个服务,因此服务性能监控和排查就变得更复杂

    • 不同的服务可能由不同的团队开发、甚至可能使用不同的编程语言来实现
    • 服务有可能布在了几千台服务器,横跨多个不同的数据中心

    因此,就需要一些可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题,这就是APM系统,全称是(Application Performance Monitor,当然也有叫 Application Performance Management tools)

    APM最早是谷歌公开的论文提到的 Google Dapper。Dapper是Google生产环境下的分布式跟踪系统,自从Dapper发展成为一流的监控系统之后,给google的开发者和运维团队帮了大忙,所以谷歌公开论文分享了Dapper。

    原理

    1. 包括:前端(A),两个中间层(B和C),以及两个后端(D和E)
    2. 当用户发起一个请求时,首先到达前端A服务,然后分别对B服务和C服务进行RPC调用;
    3. B服务处理完给A做出响应,但是C服务还需要和后端的D服务和E服务交互之后再返还给A服务,最后由A服务来响应用户的请求;

    如何才能实现跟踪呢?需要明白下面几个概念:

    • 探针:负责在客户端程序运行时收集服务调用链路信息,发送给收集器
    • 收集器:负责将数据格式化,保存到存储器
    • 存储器:保存数据
    • UI界面:统计并展示

    探针会在链路追踪时记录每次调用的信息,Span是基本单元,一次链路调用(可以是RPC,DB等没有特定的限制)创建一个span,通过一个64位ID标识它;同时附加(Annotation)作为payload负载信息,用于记录性能等数据。

    span的基本结构

    1. type Span struct {
    2. TraceID int64 // 用于标示一次完整的请求id
    3. Name string //名称
    4. ID int64 // 当前这次调用span_id
    5. ParentID int64 // 上层服务的调用span_id 最上层服务parent_id为null,代表根服务root
    6. Annotation []Annotation // 记录性能等数据
    7. Debug bool
    8. }

    Skywalking的使用 

    主要的特征:

    • 多语言探针或类库
      • Java自动探针,追踪和监控程序时,不需要修改源码。
      • 社区提供的其他多语言探针
    • 多种后端存储: ElasticSearch, H2
    • 支持OpenTracing
      • Java自动探针支持和OpenTracing API协同工作
    • 轻量级、完善功能的后端聚合和分析
    • 现代化Web UI
    • 日志集成
    • 应用、实例和服务的告警

    部署安装

    1. #在此之前需要部署es
    2. #oap服务,需要指定Elasticsearch以及链接信息
    3. docker run -d \
    4. -e TZ=Asia/Shanghai \
    5. --name oap \
    6. -p 12800:12800 \
    7. -p 11800:11800 \
    8. -e SW_STORAGE=elasticsearch \
    9. -e SW_STORAGE_ES_CLUSTER_NODES=192.168.150.101:9200 \
    10. apache/skywalking-oap-server:9.1.0
    11. #部署ui,需要指定oap服务
    12. docker run -d \
    13. --name oap-ui \
    14. -p 48080:8080 \
    15. -e TZ=Asia/Shanghai \
    16. -e SW_OAP_ADDRESS=http://192.168.150.101:12800 \
    17. apache/skywalking-ui:9.1.0

    访问对应的端口48080。

    微服务探针

    我们需要在对应的微服务中添加探针。

    需要准备Keywalking-gent文件(在资源中获取)

    打开Idea在对应的微服务上添加VM的配置

    1. #在探针处添加skywalking-agent.jar在电脑的对应位置
    2. #设置服务的名称
    3. #设置skywalking的面板地址
    4. -javaagent:D:\skywalking-agent\skywalking-agent.jar
    5. -Dskywalking.agent.service_name=ms::sl-express-ms-work
    6. -Dskywalking.collector.backend_service=192.168.150.101:11800

    进行配置,效果为下:

    访问接口进行测试

  • 相关阅读:
    CAA的VS Studio安装
    thymeleaf的日常使用
    毫米波雷达模块技术革新:在自动驾驶汽车中的前沿应用
    浅谈ArrayList和LinkedList
    Allergo导出Gerber文件
    解决导入maven工程时cannot resolve依赖问题
    实体机 安装 centos
    大厂秋招真题【DFS/BFS】美团20230812秋招T5-小美的字符串变换
    新手使用gin 创建第一个接口
    arm-linux 应用层调用驱动函数
  • 原文地址:https://blog.csdn.net/Ostkakah/article/details/134045030