Logger性能优化
最近排查线上问题,无意中发现了Logger堵塞的情况,排查的同时也做下总结,做个笔记,以防备用。
先上图,看下实际堵塞的情况
从图中可以清楚的看到标黄的都在 waiting to lock <0x000000054011c380> 这个锁,这个锁被标红线程持有,如果标红的线程处理业务逻辑不够快,哪其它线程就会一直处在 BLOCKED 中。
关于org.apache.logging.log4j.core.appender.OutputStreamManager的说明,可以查看官方文档 点击查看,关于Write重载的几个方法如下
都有排它锁,这样在一个线程持有的时候,如果因为业务逻辑复杂、或者网络延迟 等等 都有机会造成线上发生的堵塞情况。
下面说下自己整理的主要优化方案
- 升级版本
a) Logback
Logback与Log4j的对比可以看官方文档 点击查看,如果升级到Logback记得要开启异步功能,进一步提高性能,异步配置如下
1 2 3 4 5 | < appender name ="async" class= "ch.qos.logback.classic.AsyncAppender"> < discardingThreshold >0</ discardingThreshold > < queueSize >512</ queueSize > < appender-ref ref ="file"/> </ appender > |
l discardingThreshold
默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。
l queueSize
BlockingQueue的最大容量,默认情况下,大小为256。
l appender-ref
关联的appender
b) Log4f2
是log4j的升级版,详细资料可以查看官方文档,点击查看,我比较喜欢功能就是支持lambda,延迟加载就是利用这个功能实现的
2. 延迟加载
延迟加载说直白点就是按需加载,只有在用到的时候触发。你是否在项目中经常这样写日志
logger.info("消息提示:"+e.getMessage()+",业务数据:"+e.getData()+",级别别:"+e.getLevel().getName());
或者这样
logger.info("消息提示:{},业务数据:{},级别别:{}", e.getMessage(), e.getData(), e.getLevel().getName());
不管你用上面两个示例中的哪种写法,运行的时候,不管设置的级别是多少,都会执行e的方法,如果有序列化的情况会更糟糕。理想情况是根据设置的日志级别,只在真正调用的时候再执行,这时可以用如下写法,做到按需索取日志
logger.info("消息提示:{},业务数据:{},级别别:{}", () -> e.getMessage(), () -> e.getData(), () -> e.getLevel().getName());
3. 根据环境设置不同的级别
根据程序运行的环境设置不同的日志级别,一般分为开发、测试、预上线、生产 环境,日志级别应该逐步提高,避免日志的IO频繁读写提高性能,建议设置为debug、info、warn、warn
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
2010-07-31 C#使用Jmail实现邮件的接收与发送详细示例
2010-07-31 Jmail:C# 利用Jmail属性,接收邮件
2010-07-31 C#中如何使用Jmail库