赞
踩
如今2023了,大多数javaweb架构都是springboot微服务,一个前端功能请求后台可能是多个不同的服务共同协做完成的。例如用户下单功能,js转发到后台网关gateway服务,然后到鉴权spring-sercurity服务,然后到业务订单服务,然后到支付服务,后续还有发货、客户标签等等服务。
其中每个服务会启动多个实例做负载均衡,这样一来我们想看这个功能的完成流程日志,需要找到对应的服务器ip,日志文件在哪,其中又要确定具体负载转发到哪些台服务器上了。 如果是生产问题想要快速定位原因,需要一套解决方案!
spring cloud
(springBoot+服务发现+网关+负载熔断等netflex)。本人目前使用的是springboot+eureka+gateway+springSercurity+openfeign+springConfig 配合业务功能涉及中间件redis、quartz、kafka、mysql、elasticsearchjs发起ajax请求后台网关服务
网关服务集成了maven<artifactId>spring-cloud-starter-zipkin</artifactId>
依赖,会自动给当前的请求header中添加tranceId字段和spanId字段。这两个字段值随机生成。其中tranceId等于spanId在header中没有这两个字段的时候:例如tranceId=123a,spanId=123a 并添加到header中。并且打印日志的时候会把这个信息打印出来
之后网关根据请求路径转发到业务服务A,A服务的zipkin发现header中有tranceId信息,就只生成spanId,例如tranceId=123a,spanId=231b 并添加到header中。并且打印日志的时候会把这个信息打印出来。
A服务又rpc调用了B服务。B服务的zipkin发现header中有tranceId信息,就只生成spanId,例如tranceId=123a,spanId=342h 并添加到header中。并且打印日志的时候会把这个信息打印出来。
调用完结返回前端响应。
到此服务器的日志文件就会新增上述的日志。然后filebeat
工具监听到了各个服务的新日志,读取并推送到kafka
消息队列的topic下生产新数据,logstash
工具提前配置并启动消费kafka, 处理并保存数据到elasticsearch
。这里好奇为什么不直接通过filebeat
直接推送es,或者springboot的log框架直接通过appender直接推送es呢?
持久化es之后,通过kibana
查询日志,查询条件是tranceId=123a
即可查询出完整的日志。
我分了两部分,有些是部署在服务器上的jar,我就通过filebeat采集;有些是部署到本地笔记本上的服务,直接在logback.xml配置一个appender输出到kafka,不经过filebeat。
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>6.6</version>
</dependency>
<appender name="fileUserLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 配置我们自己写的包的日志信息,目的是为了方便查看自己的类日志,此日志文件只有我们自己的的log --> <File>${logdir}/user.${appname}.${serverport}.${KPHOSTNAME}.log</File> <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间--> <FileNamePattern>${logdir}/history/user.${appname}.${serverport}.%d{yyyy-MM-dd}.${KPHOSTNAME}.log</FileNamePattern> <!--只保留最近90天的日志--> <maxHistory>90</maxHistory> <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志--> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> <!--日志输出编码格式化--> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <pattern> <pattern> { "dateTime": "%d{yyyy-MM-dd HH:mm:ss.SSS}", "message": "%message", "stackTrace": "%exception", "level": "%level", "traceId": "%X{X-B3-TraceId:-}", "spanId": "%X{X-B3-SpanId:-}", "service": "${appname}", "thread": "%thread", "class": "%logger.%method[%line]" } </pattern> </pattern> <timestamp> <timeZone>GMT+8</timeZone> </timestamp> </providers> </encoder> </appender>
input { kafka{ bootstrap_servers => "ssx-kafka-dmsv.ssx:9092" client_id => "logstash_kafka_consumer_id" group_id => "logstash_kafka_consumer_group" auto_offset_reset => "latest" consumer_threads => 1 decorate_events => true topics => ["logstash"] } } filter { json { source => "message" } } output{ elasticsearch{ hosts => ["ssx-elk-dmsv.ssx:9200"] index => "logstash-%{+YYYY.MM.dd}" } }
$ cat kibana.yml
server.host: "0.0.0.0"
server.shutdownTimeout: "5s"
elasticsearch.hosts: [ "http://localhost:9200" ]
monitoring.ui.container.elasticsearch.enabled: true
i18n.locale: "zh-CN"
$ cat node.options
--unhandled-rejections=warn
--dns-result-order=ipv4first
## enable OpenSSL 3 legacy provider
#--openssl-legacy-provider
filebeat.modules: filebeat.inputs: - type: log enabled: true paths: - /spring-boot-logs/*/user.*.log #include_lines: ["^ERR", "^WARN"] # 适用于日志中每一条日志占据多行的情况,比如各种语言的报错信息调用栈 multiline: pattern: '^[[:space:]]' negate: false match: after processors: - drop_fields: fields: ["metadata", "prospector", "offset", "beat", "source","type"] output.kafka: hosts: ["ssx-kafka-dmsv.ssx:9092"] topic: logstash codec.format: string: '%{[message]}'
日志文件内容,我想看这个请求完整的流程
apiVersion: apps/v1 kind: Deployment metadata: name: ssx-elk-dmsv namespace: ssx spec: replicas: 1 selector: matchLabels: app: ssx-elk-dmsv template: metadata: labels: app: ssx-elk-dmsv spec: hostAliases: - ip: "192.168.0.101" hostnames: - "node101" - ip: "192.168.0.102" hostnames: - "node102" - ip: "192.168.0.103" hostnames: - "node103" - ip: "127.0.0.1" hostnames: - "elasticsearch" containers: - name: ssx-elasticsearch8-c image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2 imagePullPolicy: IfNotPresent ports: - containerPort: 9200 env: #容器运行前需设置的环境变量列表 - name: discovery.type #环境变量名称 value: "single-node" #环境变量的值 这是mysqlroot的密码 因为是纯数字,需要添加双引号 不然编译报错 - name: xpack.security.enabled #禁用登录验证 value: "false" #环境变量的值 这是mysqlroot的密码 因为是纯数字,需要添加双引号 不然编译报错 - name: ES_JAVA_OPTS value: -Xms512m -Xmx512m volumeMounts: - mountPath: /usr/share/elasticsearch/data #这是mysql容器内保存数据的默认路径 name: c-v-path-elasticsearch8-data - mountPath: /usr/share/elasticsearch/logs #这是mysql容器内保存数据的默认路径 name: c-v-path-elasticsearch8-logs - mountPath: /usr/share/elasticsearch/.cache #这是mysql容器内保存数据的默认路径 name: c-v-path-elasticsearch8-cache - mountPath: /etc/localtime #时间同步 name: c-v-path-lt - name: ssx-kibana-c image: docker.elastic.co/kibana/kibana:8.10.2 imagePullPolicy: IfNotPresent ports: - containerPort: 5601 # 开启本容器的80端口可访问 volumeMounts: - mountPath: /usr/share/kibana/data #无用,我先看看那些挂载需要 name: c-v-path-kibana8-data - mountPath: /usr/share/kibana/config name: c-v-path-kibana8-config - mountPath: /etc/localtime #时间同步 name: c-v-path-lt - name: ssx-logstash-c image: docker.elastic.co/logstash/logstash:8.10.2 imagePullPolicy: IfNotPresent env: #容器运行前需设置的环境变量列表 - name: xpack.security.enabled #禁用登录验证 value: "false" #环境变量的值 这是mysqlroot的密码 因为是纯数字,需要添加双引号 不然编译报错 - name: LOG_LEVEL #禁用登录验证 value: "info" #环境变量的值 这是mysqlroot的密码 因为是纯数字,需要添加双引号 不然编译报错 - name: MONITORING_ENABLED #禁用登录验证 value: "false" #环境变量的值 这是mysqlroot的密码 因为是纯数字,需要添加双引号 不然编译报错 args: ["-f","/myconf/logstash.conf"] volumeMounts: - mountPath: /myconf #配置 name: c-v-path-logstash8-conf - mountPath: /usr/share/logstash/data #data name: c-v-path-logstash8-data - mountPath: /etc/localtime #时间同步 name: c-v-path-lt - name: ssx-filebeat-c image: docker.elastic.co/beats/filebeat:8.10.2 imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /usr/share/filebeat/filebeat.yml #配置 name: c-v-path-filebeat8-conf - mountPath: /usr/share/filebeat/data #配置 name: c-v-path-filebeat8-data - mountPath: /spring-boot-logs #data name: c-v-path-filebeat8-spring-logs - mountPath: /etc/localtime #时间同步 name: c-v-path-lt volumes: - name: c-v-path-elasticsearch8-data #和上面保持一致 这是本地的文件路径,上面是容器内部的路径 hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/elasticsearch8/data #此路径需要实现创建 注意要给此路径授权777权限 不然pod访问不到 - name: c-v-path-elasticsearch8-logs #和上面保持一致 这是本地的文件路径,上面是容器内部的路径 hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/elasticsearch8/logs #此路径需要实现创建 注意要给此路径授权777权限 不然pod访问不到 - name: c-v-path-elasticsearch8-cache #和上面保持一致 这是本地的文件路径,上面是容器内部的路径 hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/elasticsearch8/.cache #此路径需要实现创建 注意要给此路径授权777权限 不然pod访问不到 - name: c-v-path-kibana8-data #和上面保持一致 这是本地的文件路径,上面是容器内部的路径 hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/kibana8/data #此路径需要实现创建 注意要给此路径授权777权限 不然pod访问不到 - name: c-v-path-kibana8-config #和上面保持一致 这是本地的文件路径,上面是容器内部的路径 hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/kibana8/config #此路径需要实现创建 注意要给此路径授权777权限 不然pod访问不到 - name: c-v-path-logstash8-conf hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/logstash8/myconf - name: c-v-path-logstash8-data hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/logstash8/data - name: c-v-path-lt hostPath: path: /etc/localtime #时间同步 - name: c-v-path-filebeat8-conf hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/filebeat8/myconf/filebeat.yml - name: c-v-path-filebeat8-data hostPath: path: /home/app/apps/k8s/for_docker_volume/elk/filebeat8/data - name: c-v-path-filebeat8-spring-logs hostPath: path: /home/ssx/appdata/ssx-log/docker-log nodeSelector: #把此pod部署到指定的node标签上 kubernetes.io/hostname: node101 --- apiVersion: v1 kind: Service metadata: name: ssx-elk-dmsv namespace: ssx spec: ports: - port: 9200 name: ssx-elk8-9200 protocol: TCP targetPort: 9200 - port: 5601 #我暂时不理解,这个设置 明明没用到? name: ssx-kibana8 protocol: TCP targetPort: 5601 # 容器nginx对外开放的端口 上面的dm已经指定了 selector: app: ssx-elk-dmsv type: ClusterIP
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。