记一次线上日志堆栈不打印问题排查(附:高并发系统日志打印方案可收藏)

目录

  • 一.线上的日志堆栈不打印了
  • 二.一步一步仔细排查
  • 三.最后搞定
  • 四.聊一聊线上日志到底应该怎么打印
    • 4.1 日志打印的诉求
    • 4.2 常见的系统日志上报方案
      • 4.2.1 ELK 方案
      • 4.2.2 自定义log appender 完成应用日志采集.
    • 4.3 日志常见框架傻傻分不清
    • 4.4 日志在高并发系统中需要注意的 tips
      • 4.4.1 配置合理的日志级别
      • 4.4.2 记录合理的链路

一.线上的日志堆栈不打印了

线上的报错 error 日志不打印详细的堆栈信息了.本着追根到底的精神.仔细排查了下.目前的日志打印过程.系统和代码虽然是公司的,解决问题都是自己的呀.

正常打印.拥有详细的堆栈信息.

在这里插入图片描述

不正常打印.仅打印Exception className

二.一步一步仔细排查

第一反应是哪个神仙写法导致的.一般场景下不打印线上错误日志有这么几种场景.

  • logger.error(“关键字{}”,e)
    这种场景下 e 只会被 toString() 后打印一些简单的 toString() 方法,如果你的异常是自定义异常.那么相当于需要重写 toString() 方法,最后打印可以按照你的 toString() 方法进行打印.
    一般场景下,只会打印简短的日志信息.
  • logger.error(“关键字”+e.toString())

这种写法其实和上面第一种写法是一样的逻辑.仅仅只是通过手动拼接的逻辑来处理的.

一步两步跟踪代码.

第二步下面的日志打印.

如上第二步真实的日志打印如上.可以发现第二步其实没有什么问题.真实就是直接调用的 logger 的打印方法.

那其实可以发现具体就是在这个方法循环过程中出了问题,没有进入到的循环体中导致无法正确进行拼接,程序员的思维.通过配置发现整体的堆栈深度配置为 1 .先不论 1 是否合适.那么这里有一个判断.

int stackTraceLineNum = stackTraceLineNum > stackTraceElements.length ? 
stackTraceElements.length : stackTraceLineNum;

配置的值大于堆栈的深度 length 则使用stack具体的深度.否则则使用配置的stackTraceLineNum.那么这种情况下就是stackTraceElements.length=0.

那么问题来了什么情况会导致这个length为空呢?.点进去.

巴拉巴拉说了很长.发现有这么一段话.In the extreme case. a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.平时喜欢学外语的朋友都知道.这段话:在极端场景下.虚拟机考虑到堆栈信息可能被允许返回一个空数组从这个方法.我草,这是什么鬼.一时间发现这还是我写的那个 Java???

线索到这里基本断了.

理了理思路重新梳理了下发现问题的过程,重新将代码部署在预发环境.整体跑了一个遍,并通过 debug 也没哟复现.都是可以正常获取到 stack length.就这样上午一天过去了.并没有什么进展.第二天,脑子稍微清醒了点,确实想的不一样了.再来回想一下线上环境和预发环境的特点,特征.回归原点思考问题.

线上环境:

  • 流量特征:流量场景丰富.流量压力并发高.
  • 机器环境:线上机器一般配置较高.

预发开发等环境:
-流量特征:场景贫乏.流量压力小.
-机器环境:线上机器可能配置较差[可以通过配置升级来抹平]

那么其实还是要磨平线上环境之间的差异.并尝试了批量的压测,最终他出现了.老小子你还是来了.

通过发现每每执行到一段时间堆栈就不打印了,这个是不是就是注释里说的极端情况.联系注释提到的 virtual machine. 次数+vm. 这块你想到了什么. 不知道你想到了什么 .在老早之前总结过 jit 的一些特性.一时间马上检索一下(关键字: jit 堆栈不打印优化).确实有了.

oracle官网: https://www.oracle.com/java/technologies/javase/release-notes-introduction.html

三.最后搞定

马上开搞.

-XX:+OmitStackTraceInFastThrow 

配置上预发压测走起来,搞定.

幸福之余也再次查阅了一些资料.

发现这是 javafast throw 优化,感叹确实 jit 牛哈.通过次数来检测是否进行详细的堆栈打印.返回来也能理解,虚拟机默认在一些次数打印之后就不再打印详细的堆栈.默认开发者已经关注到相关的堆栈信息了.以此来减少性能损耗.主要应对常见的一些 Exception .

NullPointerException
ArithmeticException
ArrayIndexOutOfBoundsException
ArrayStoreException
ClassCastException

fast throw 本身从 jvmjit 层面来说是一个正向的优化措施,在线上整体的流量还是比较高的场景下,如果一旦将屏蔽优化内容.将徒增很多日志的打印,导致磁盘的 IO 升高以及磁盘利用率升高.所以本次的屏蔽也仅仅是开启了部分分组的配置,即能够保证在指定机器排查问题的场景下完成日志的追踪,也能够包装 fast throw 自带优化能够大部分被利用到.如果你的应用也是这种场景我也是建议使用这种方案.

四.聊一聊线上日志到底应该怎么打印

不止于此通过这次我们正好来聊一聊日志打印的这样一个流程.以及分享目前在搞的一个高并发系统是怎样去打印日志的.

4.1 日志打印的诉求

一般场景下打印日志主要基于以下几种诉求.

目标

  • 技术诉求:排查问题;基于关键字主动告警监测系统异常情况.
  • 业务运营诉求:基于关键字做流量统计,数据分析获取用户的具体产品功能反馈.以期进一步改进产品方案

关键路径

  • 正常业务处理的日志告警关键字打印,需要能将堆栈打印;
  • 支持一些巨量的存储以及结构化复杂查询能力
  • 具备大促高峰流量的降级可配置

4.2 常见的系统日志上报方案

第一步:应用系统所在机器.一般是 Linux 完成系统日志采集.当发生所关心的日志文件变化时.由监听的进程将日志发送这里有很多种选择.常见的如下:

rsyslog:相对性能比较好,久经考验的老战士.配置较为复杂.
filebeat:性能相比没有rsyslog好.但使用相对简单.使用也比较广泛.

第二步:完成服务端日志接收.这里一般是 Logstash.也就是我们常说的ELK里的L.

第三步:完成日志入库.这里的库可以是 message.es.redis.mysql 集成的三方还是比较多的.

第四步:选择合适的工具来完成日志的展示.比如说:kibana

4.2.1 ELK 方案

在这里插入图片描述

一般比较常见的大厂方案基本如此.

  • step1:通过 slf4j 门面完成应用日志文件输出.
  • step2:通过 rsyslog 监听文件变更完成日志文件发送.
  • step3:通过 logstash 完成日志服务端解析发送.支持的插件也比较多.
    具体可参考: https://www.elastic.co/guide/en/logstash/current/output-plugins.html
    -step4:完成 es 数据存储.

一键开箱即用的es存储满足巨量的存储且支持水平扩展.并提供比较友好的查询 kibana 能力.

适用场景:业务系统的日志打印抽取.
优点:完全独立在系统应用之外不影响任何系统性能;日志侧可以做到资源的友好伸缩.
缺点:巨量的日志打印后容易出现资源的浪费

4.2.2 自定义log appender 完成应用日志采集.

在这里插入图片描述

这种自定义appender方案比较适用于一些常见的后台操作.如ERP内部的用户日志记录.如:用户在2024年04月26日17:42:29 完成对租户 101 ,库存 201 的商品
库存调整。

4.3 日志常见框架傻傻分不清

一套日志编写标准.

SLF4J:是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)

以下为一些具体的实现.

  1. Jul (Java Util Logging):JDK中的日志记录工具,也常称为JDKLog、jdk-logging,自Java1.4以来的官方日志实现。
  2. Log4j:Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。
  3. Log4j2:一个具体的日志实现框架,是Log4j 1的下一个版本,与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1。
  4. Logback:一个具体的日志实现框架,和Slf4j是同一个作者,但其性能更好。

4.4 日志在高并发系统中需要注意的 tips

4.4.1 配置合理的日志级别

常见的日志级别.
分别是 all, errorwarninginfodebugtrace

日常开发中,我们需要选择恰当的日志级别

  • all: 所有日志级别打印.
  • fatal :无法修复的程序异常
  • error :错误日志,指比较严重的错误,对正常业务有影响,需要运维配置监控的;通常我们会在throw异常时进行打印。
  • warn :警告日志,一般的错误,对业务影响不大,但是需要开发关注。
  • info :信息日志,记录排查问题的关键信息,通常我们会在方法入口和出口打印出入参信息等。
  • debug :用于开发DEBUG的,关键逻辑里面的运行时数据。通常我们用来调试关键程序,例如我们可以将SQL的日志级别调为debug,在本地或者测试环境调试时,可以看到具体SQL。
  • trace :最详细的信息,一般这些信息只记录到日志文件中。

对于一些流量比较高的场景线上尽量不打印非error级别日志.无差别打印所有级别日志将会对磁盘的造成性能损耗,很可能就会将磁盘打爆,进而影响正常的系统的业务IO

4.4.2 记录合理的链路

基于上一点我们总会有排查一些线上问题的时候,这无可避免。这时候如果要打印 用以排查问题的日志(非error级别),对于这种场景还是秉着尽可能少打印的原则。
比如说:保证能够做到随机抽量打印或者业务id过滤后打印,这个就视具体的业务类型而定。
如:库存,商品支持商品id来进行过滤;订单,售后支持订单id来进行过滤;

具备日志白名单(用户 id or pin )后查阅用户链路

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/4245.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题:最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,-5,4] 输出:6…

Docker 的数据管理 端口映射 容器互联 镜像创建

一 Docker 的数据管理 1 管理 Docker 容器中数据主要有两种方式: 数据卷(Data Volumes) 数据卷容器(DataVolumes Containers)。 1.1 数据卷 数据卷是一个供容器使用的特殊目录,位于容器中。可将宿主机…

江开2024年春《计算机组成原理 060214》第4次计分作业参考答案

答案:更多答案,请关注【电大搜题】微信公众号 答案:更多答案,请关注【电大搜题】微信公众号 答案:更多答案,请关注【电大搜题】微信公众号 单选题 1某计算机字长32位,其存储容量为4GB&am…

STM32F103 USB 端口的电阻配置

参考ST 官方的STLINK V2 电路图,如下: STLINK V2 的主控是STM32F103CBT6,USB 端口电路在左下角。DP,DM 上串的是0 Ω 电阻,所以103 系列芯片应该是内置了匹配电阻,外置的22Ω 可以去掉了。DP 外接了1.5K 上…

VirtualBox7.0.16的蓝屏大坑与ssh登陆ubuntu虚拟机的办法

背景: 安装了最新版的VirtualBox,装了ubuntu系统,在win10下通过ssh死活无法与ubuntu进行正常登陆控制。 然后开始了踩坑。 问题1:ssh登陆失败,但是主机能ping通ubuntu,反过来也能ping通,网络…

数组和指针经典笔试题讲解

目录 创作不易,如对您有帮助,还望一键三连,谢谢!!! 1.sizeof和strlen的对比 1.1sizeof 1.2strlen 1.3sizeof和strlen对比 2.数组笔试题讲解 数组名的理解 2.1一维数组 2.2字符数组 题目一&#x…

如何在自己的网站页面中嵌入一个【悬浮音乐播放器】

如何嵌入【悬浮音乐播放器】 前言正文1.打开网易云网页版2.设置自己想要的高度和宽度看注意事项 3.选择是否为自动播放4.在header.php文件中</head>标签前插入下面代码5.在heard.php 中<body>标签后边增加一个 div层6.复制播放器代码到\<div>标签的里边7.保存…

sheng的学习笔记-AI-支持向量机(SVM)

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录 什么是向量机 SVM算法原理 SVM基本模型 SVM对偶问题 什么是对偶问题&#xff1a; 为什么使用对偶问题 拉格朗日定理 拉格朗日乘子法 对偶问题算法 非线性SVM算法原理 核函数 常用核函数 软间隔与正则化 软…

链栈的基本操作(链表实现)

目录 定义 我们这篇文章讲的是链栈的实现 链栈的基本操作 定义链栈 初始化栈 判断栈是否为空 入栈 出栈 获取栈顶元素 销毁栈 测试完整代码 定义 栈&#xff08;Stack&#xff09;是一种遵循后进先出&#xff08;LIFO&#xff0c;Last In First Out&#xff09;原则…

开发日志(20240422):一次以为是跨域但并不是跨域的问题排查记录

1. 日志 在前后端联调的时候&#xff0c;遇到了报错&#xff0c;如下图所示&#xff08;现在再看感觉非常简单了&#xff09;&#xff0c;发现前一个请求通过了&#xff0c;但是第二个请求报错&#xff0c;然后看到 strict-origin-when-cross-origin 条件反射的认为是跨域配置…

Java web应用性能分析之【sysbench基准测试】

Java web应用性能分析之【CPU飙高分析之MySQL】-CSDN博客 Java web应用性能分析之【Linux服务器性能监控分析概叙】-CSDN博客 Java web应用性能分析概叙-CSDN博客 Java web应用性能分析之【基准测试】-CSDN博客 上面基本科普了一下基准测试&#xff0c;这里我们将从sysbench…

深入浅出 Transformer

Transformer 背后的核心概念&#xff1a;注意力机制、编码器-解码器架构、多头注意力等等。 一、理解注意力机制 注意力机制能够集中注意力在输入序列的某些部分&#xff0c;同时忽略其他部分&#xff0c;就像我们人类在理解句子时关注特定的单词或短语一样。 自注意力是种特…

眼图仪参数理解和一些测量指标

参考资料&#xff1a; https://www.eet-china.com/mp/a35960.html 一&#xff1a;关于眼图仪&#xff1a; :::warning ●如果追溯历史&#xff0c;大约47年前&#xff0c;眼图就已经开始广泛应用。在1962年-2002的40年间&#xff0c;眼图的测量方法是基于采样示波器的传统方法…

C++默认构造函数的合成

编译器只在编译期需要的时候合成默认构造函数&#xff0c;而不是在用户需要的时候 文章目录 引入编译器合成默认构造函数的四种情况情况一 类中包含带有默认构造函数的类的成员对象情况二 派生类的基类带有默认构造函数情况三 类带有一个虚函数情况四 派生自一个虚基类的类 参考…

Day53|动态规划part14: 1143.最长公共子序列、1035. 不相交的线、53. 最大子序和

1143. 最长公共子序列 这题有点像递增子序列和公共子数组的组合&#xff0c; 要求公共子序列不一定非要是连续的。 确定dp数组下标及其含义 dp[i][j]表示text1[i - 1]与text2[j - 1]结尾的最高公共子序列。 长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的…

Redis 服务等过期策略和内存淘汰策略解析

redis服务是基于内存运行的&#xff0c;所以很多数据都存放在内存中&#xff0c;但是内存又不是无限的&#xff0c;所以redis就引出了key的过期和淘汰策略。 一、Redis的过期策略&#xff1a; 我们在set key的时候&#xff0c;可以给它设置一个过期时间&#xff0c;比如expire …

【神经网络结构可视化】PlotNeuralNet的安装、测试及创建自己的神经网络结构可视化图形

文章目录 前提准备1、下载MikTeX2、下载Git bash3、下载PlotNeuralNet 进行测试1、解压PlotNeuralNet-master.zip2、打开Git bash3、 在my_project中查看生成的pdf文件 创建自己的神经网络结构可视化图形 前提准备 1、下载MikTeX 下载链接&#xff1a; MikTeX ( https://mikt…

【图解计算机网络】TCP协议三次握手与四次挥手

TCP协议三次握手与四次挥手 三次握手流程为什么是三次握手&#xff0c;而不是两次或四次四次挥手流程TIME_WAIT 为什么要等待 2MSL为什么握手是三次&#xff0c;挥手是四次&#xff1f; 三次握手流程 首先是客户端&#xff08;也就是我们的浏览器&#xff09;发送一个SYN标志位…

C++11 数据结构5 队列的概念,队列的顺序存储,实现,测试

一&#xff0c;队列的概念 队列是一种特殊的受限制的线性表。 队列&#xff08;queue&#xff09;是只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作的线性表。 队列是一种先进先出的t&#xff08;First In First Out&#xff09;的线性表&#xff0c;简称FIF…

请编写函数fun,其功能是:将所有大于1小于整数m的非素数存入xx所指数组中,非素数的个数通过k传回。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法完整代码和详细的解析。 题干 请编…