当前位置:首页 > 文章 > 正文内容

你所不知道的日志异步落库

廖万里3年前 (2022-10-27)文章86816

在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环。为什么说是高并发环节中不可缺少的呢? 原因在于,如果直接用mq进行日志落库的时候,低并发下,生产端生产数据,然后由消费端异步落库,是没有什么问题的,而且性能也都是异常的好,估计tp99应该都在1ms以内。但是一旦并发增长起来,慢慢的你就发现生产端的tp99一直在增长,从1ms,变为2ms,4ms,直至send timeout。尤其在大促的时候,我司的系统就经历过这个情况,当时mq的发送耗时超过200ms,甚至一度有不少timeout产生。

考虑到这种情况在高并发的情况下才出现,所以今天我们就来探索更加可靠的方法来进行异步日志落库,保证所使用的方式不会因为过高的并发而出现接口ops持续下降甚至到不可用的情况。

 

方案一: 基于log4j的异步appender实现

此种方案,依赖于log4j。在log4j的异步appender中,通过mq进行生产消费入库。相当于在接口和mq之间建立了一个缓冲区,使得接口和mq的依赖分离,从而不让mq的操作影响接口的ops。

此种方案由于使用了异步方式,且由于异步的discard policy策略,当大量数据过来,缓冲区满了之后,会抛弃部分数据。此种方案适用于能够容忍数据丢失的业务场景,不适用于对数据完整有严格要求的业务场景。

来看看具体的实现方式:

首先,我们需要自定义一个Appender,继承自log4j的AppenderSkeleton类,实现方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class AsyncJmqAppender extends AppenderSkeleton {
 
    @Resource(name = "messageProducer")
    private MessageProducer messageProducer;
 
    @Override
    protected void append(LoggingEvent loggingEvent) {
        asyncPushMessage(loggingEvent.getMessage());
    }
 
    /**
     * 异步调用jmq输出日志
     * @param message
     */
    private void asyncPushMessage(Object message) {
 
        CompletableFuture.runAsync(() -> {
 
            Message messageConverted = (Message) message;
 
            try {
                messageProducer.send(messageConverted);
            catch (JMQException e) {
                e.printStackTrace();
            }
 
        });
    }
 
 
    @Override
    public boolean requiresLayout() {
        return false;
    }
 
    @Override
    public void close() {
 
    }
}

然后在log4j.xml中,为此类进行配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--异步JMQ appender-->
<appender name="async_mq_appender" class="com.jd.limitbuy.common.util.AsyncJmqAppender">
    <!-- 设置File参数:日志输出文件名 -->
    <param name="File" value="D:/export/Instances/order/server1/logs/order.async.jmq" />
    <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
    <param name="Append" value="true" />
    <!-- 设置文件大小 -->
    <param name="MaxFileSize" value="10KB" />
    <!-- 设置文件备份 -->
    <param name="MaxBackupIndex" value="10000" />
    <!-- 设置输出文件项目和格式 -->
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%m%n" />
    </layout>
</appender>
<logger name="async_mq_appender_logger">
    <appender-ref ref="async_mq_appender"/>
</logger>

最后就可以按照如下的方式进行正常使用了:

1
private static Logger logger = LoggerFactory.getLogger("filelog_appender_logger");

注意: 此处需要注意log4j的一个性能问题。在log4j的conversionPattern中,匹配符最好不要出现 C% L%通配符,压测实践表明,这两个通配符会导致log4j打日志的效率降低10倍。

方案一很简便,且剥离了接口直接依赖mq导致的性能问题。但是无法解决数据丢失的问题(但是我们其实可以在本地搞个策略落盘来不及处理的数据,可以大大的减少数据丢失的几率)。但是很多的业务场景,是需要数据不丢失的,所以这就衍生出我们的另一套方案来。

 

方案二:增量消费log4j日志

此种方式,是开启worker在后台增量消费log4j的日志信息,和接口完全脱离。此种方式相比方案一,可以保证数据的不丢失,且可以做到完全不影响接口的ops。但是此种方式,由于是后台worker在后台启动进行扫描,会导致落库的数据慢一些,比如一分钟之后才落库完毕。所以适用于对落库数据实时性不高的场景。

具体的实现步骤如下:

首先,将需要进行增量消费的日志统一打到一个文件夹,以天为单位,每天生成一个带时间戳日志文件。由于log4j不支持直接带时间戳的日志文件生成,所以这里需要引入log4j.extras组件,然后配置log4j.xml如下:

你所不知道的日志异步落库

之后在代码中的申明方式如下:

1
private static Logger businessLogger = LoggerFactory.getLogger("file_rolling_logger");

最后在需要记录日志的地方使用方式如下:

1
businessLogger.error(JsonUtils.toJSONString(myMessage))

这样就可以将日志打印到一个单独的文件中,且按照日期,每天生成一个。

然后,当日志文件生成完毕后,我们就可以开启我们的worker进行增量消费了,这里的增量消费方式,我们选择RandomAccessFile这个类来进行,由于其独特的位点读取方式,可以使得我们非常方便的根据位点的位置来消费增量文件,从而避免了逐行读取这种低效率的实现方式。

注意,为每个日志文件都单独创建了一个位点文件,里面存储了对应的文件的位点读取信息。当worker扫描开始的时候,会首先读取位点文件里面的位点信息,然后找到相应的日志文件,从位点信息位置开始进行消费。这就是整个增量消费worker的核心。具体代码实现如下(代码太长,做了折叠):


本文链接:https://www.kkkliao.cn/?id=137 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


“你所不知道的日志异步落库” 的相关文章

马斯克倡议设台湾特别行政区,台地区专家:不希望台海冲突,反映商人普遍心声

马斯克倡议设台湾特别行政区,台地区专家:不希望台海冲突,反映商人普遍心声

 美国电动车大厂特斯拉公司创办人马斯克针对台海紧张局势,提出中国将台湾地区设为“特别行政区”方案。彰化师范大学创意创新创业研究中心主任王信文接受香港中评社访问表示,特斯拉电动车有75%的供应链来自台湾,马斯克当然不希望台海冲突,波及商业发展,这某方面也反映商人普遍心声,商人会作此呼吁,代表已嗅到战争...

美媒:ASML开始被中企无情地“打脸”了

美媒:ASML开始被中企无情地“打脸”了

点击关注,每天精彩不断!导读:美媒:ASML开始被中企无情的“打脸”了!自从我国华为公司被打压以后,很多科技企业都意识到了自主研发和生产半导体芯片的重要性;而想要生产芯片并不是一件容易的事情;作为21世纪最伟大的发明之一,半导体芯片如今在整个科技领域都起着至关重要的作用,虽然说一个小小的芯片看上去只...

一个时代终于结束了,电商行业被改写

一个时代终于结束了,电商行业被改写

如果你仔细观察近两年电商行业的新变化,你会明显地感觉到,时代一次又一次被改写。淘宝为什么被拼多多赶超了?抖音是娱乐平台,却为什么突然改做电商了?因为一个时代结束了。众所周知,传统的电商是货架电商。货架店上的本质就是把产品上到店里,然后通过搜索引擎优化或者付费推广的模式,带来流量,然后通过促销的方法,...

嫦娥五号样品揭秘:月球如何“延寿”8亿年?

嫦娥五号样品揭秘:月球如何“延寿”8亿年?

文 | 《中国科学报》记者 冯丽妃嫦娥五号玄武岩与阿波罗玄武岩形成示意图。受访者供图月球一直“活到”了什么时候?这是月球演化历史研究中科学家一直想了解的一个重大科学问题。一年前,中科院地质与地球物理研究所(以下简称地质地球所)的科学家们利用嫦娥五号带回的月球样品,证明月球在距今20亿年前仍喷发过滚烫...

iframe如何实现全屏,高度自适应浏览器实现

iframe编写<iframe id="iframe"         name="iframe"      ...

特斯拉再降价,为何受伤最大的不是比亚迪?

特斯拉再降价,为何受伤最大的不是比亚迪?

特斯拉降价算新闻吗?素有“韭菜收割机”之称的特斯拉,不论涨价或者降价都是再普通不过的常规操作,但是这一次,轻轻松松就闯上了热搜。降一次价,上一次热搜?当然这一方面,是因为本次降价幅度不小,Model 3官降1.3万到1.8万元不等,主销车型Model Y最高降幅甚至达到3.7万元。就算结合客观情况,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。