作者:程序诗人来源:https://www.cnblogs.com/scy251147/p/9193075.html

在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环。为什么说是高并发环节中不可缺少的呢? 原因在于,如果直接用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类,实现方式如下:

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

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

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如下:

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

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

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

businessLogger.error(JsonUtils.toJSONString(myMessage))

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

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

注意,为每个日志文件都单独创建了一个位点文件,里面存储了对应的文件的位点读取信息。当worker扫描开始的时候,会首先读取位点文件里面的位点信息,然后找到相应的日志文件,从位点信息位置开始进行消费。这就是整个增量消费worker的核心。

具体代码实现如下(代码太长):

此种方式由于worker扫描是每隔一段时间启动一次进行消费,所以导致数据从产生到入库,可能经历时间超过一分钟以上,但是在一些对数据延迟要求比较高的业务场景,比如库存扣减,是不能容忍的,所以这里我们就引申出第三种做法,基于内存文件队列的异步日志消费。

方案三:基于内存文件队列的异步日志消费

由于方案一和方案二都严重依赖log4j,且方案本身都存在着要么丢数据,要么入库时间长的缺点,所以都并不是那么尽如人意。但是本方案的做法,既解决了数据丢失的问题,又解决了数据入库时间被拉长的尴尬,所以是终极解决之道。而且在大促销过程中,此种方式经历了实战检验,可以大面积的推广使用。

此方案中提到的内存文件队列,是我司自研的一款基于RandomAccessFile和MappedByteBuffer实现的内存文件队列。队列核心使用了ArrayBlockingQueue,并提供了produce方法,进行数据入管道操作,提供了consume方法,进行数据出管道操作。而且后台有一个worker一直启动着,每隔5ms或者遍历了100条数据之后,就将数据落盘一次,以防数据丢失。具体的设计,就这么多,感兴趣的可以根据我提供的信息,自己实践一下。

由于有此中间件的加持,数据生产的时候,只需要入压入管道,然后消费端进行消费即可。未被消费的数据,会进行落盘操作,谨防数据丢失。当大促的时候,大量数据涌来的时候,管道满了的情况下会阻塞接口,数据不会被抛弃。虽然可能会导致接口在那一瞬间无响应,但是由于有落盘操作和消费操作(此操作操控的是JVM堆外内存数据,不受GC的影响,所以不会出现操作暂停的情况,为什么呢?因为用了MappedByteBuffer),此种阻塞并未影响到接口整体的ops。

在实际使用的时候,ArrayBlockingQueue作为核心队列,显然是全局加锁的,后续我们考虑升级为无锁队列,所以将会参考Netty中的有界无锁队列:MpscArrayQueue。预计性能将会再好一些。

上面就是在进行异步日志消费的时候,我所经历的三个阶段,并且一步一步的优化到目前的方式。虽然过程曲折,但是结果令人欢欣鼓舞。

web操作日志丢失_日志异步落库,你了解不相关推荐

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

    https://www.cnblogs.com/scy251147/p/9193075.html 在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环.为什么说是高并发环节中不可 ...

  2. 你完全没了解过的日志异步落库

    前言 在互联网设计架构过程中,日志异步落库,俨然已经是高并发环节中不可缺少的一环.为什么说是高并发环节中不可缺少的呢? 原因在于,如果直接用mq进行日志落库的时候,低并发下,生产端生产数据,然后由消费 ...

  3. cx_oracle写日志信息_日志系统的设计

    笔者在写作本章节的时候,并不敢把此章节的标题叫做<高性能日志系统的设计>,之所以不敢加上"高性能"三个字的原因是: 第一,我对于日志系统设计知识和经验都来自于学习和工作 ...

  4. 取证 c语言实现日志导出_日志与日志不一样:五种不能忽略的日志源

    给日志源分出主次大有利于开展有效事件响应. 就像分诊护士一样,安全人员也必须给数据分出个优先主次,以帮助他们更好地识别问题,使公司企业及其数据和设备能够避免入侵者和网络攻击的伤害. 但是,记录和监视I ...

  5. [战略]对空间_日志风格_日志分类_日志标记_的整体说明

    1.写作目的 为方便 粉丝.好友和网友等友好人士阅读Fans的QQ空间的日志, 以及Fans对日志的创作和管理, 特写此文来说明下空间的日志风格.日志分类.日 志标记. 2.日志风格的说明 a.坚持原 ...

  6. java 操作日志设计_日志系统新贵 Loki,确实比笨重的ELK轻

    本文同步Java知音社区,专注于Java 作者:linkt1234http://blog.csdn.net/Linkthaha/article/details/100575278 最近,在对公司容器云 ...

  7. mysql 日志丢失_失而复得数据库日志文件丢失后的恢复

    前几天听英语用到虚拟光驱装resseta stone ,没想到各种不顺,把我的本本给整瘫痪了.后来重整旗鼓,装了云端,总算是把它搞定了,由于瘫痪来的很突然,所以我的一些数据不小心丢了一些.我新建的数据 ...

  8. 上网日志留存_日志留存系统

    日志留存系统 0 14 2020-04-14 15:44 使用大数据技术分析处理用户的上网记录,并将结果存入es或生成日志文件上报给工信部,公安部.也可以在系统内部进行查询用户上网记录 作品职责:1. ...

  9. java批量删除日志文件_日志清理与文件批量删除

    工具下载地址:小工具 作为一个开发人员,一个一线的码农,我们在写程序的时候往往会给自己的程序添加很多的日志输出,这是一个好习惯,但是很多程序员却没有在程序里面增加日志定期清除的好习惯,从事IT领域十多 ...

  10. golang日志服务器_日志系统 | log/syslog (log) – Go 中文开发手册 - Break易站

    Go 中文开发手册 日志系统 | log/syslog (log) - Go 中文开发手册 import "log/syslog"概述索引示例 概述 软件包系统日志为系统日志服务提 ...

最新文章

  1. DFS:深入优先搜索 POJ-2386 Lake Counting
  2. 计算机网络实验指导书实验报告,计算机网络实验一 熟悉常用的网络命令实验报告模板...
  3. c#属性的相关学习总结。
  4. tf.split()
  5. 梁迪:源于热爱乐于分享,MVP代表圆桌会议
  6. [SDOI2011]消耗战
  7. mysql count(*),count(1)与count(column)区别
  8. JS操作iframe元素
  9. 《剑指offer》面试题17——合并两个有序的链表(C++):
  10. 计算机开机切换用户界面,win7开机登录界面怎么设置?win7更换开机画面壁纸解决办法...
  11. Ubuntu下搭建android开发环境
  12. 数学建模overleaf模板_数学建模论文模板及套路
  13. 【英语:基础进阶_原著扩展阅读】J1.英文原著的选择和有效阅读方法
  14. 从零开始学习node.js
  15. JRUL数字交流三相电流继电器
  16. 华为服务器新机安装配置,安装驱动,制作raid,raid5
  17. uniapp 选择元素,操作元素属性
  18. redis命令之string类型incr/decr命令用法详情
  19. fedora 14下建立samba服务器
  20. (邱维声)高等代数课程笔记:行列式的性质

热门文章

  1. python相关参考地址收藏
  2. Eclipse Code Template 设置自动加注释
  3. 野村证券分析师称微软不会收购雅虎和RIM
  4. 题解【[BJOI2012]算不出的等式】
  5. 高级装饰器---验证用户登录
  6. getchar吸收回车
  7. 浅谈C++ Lambda 表达式(简称LB)
  8. java判断数组值类型,判断(1分) Java语言中的数组元素只能是基本数据类型而不能为对象类型。...
  9. java数组程序_java数组
  10. django mysql socket_django mysql 读写分离