异步日志记录

16

目前在我的应用程序中,在某些点上,我们正在将一些重要的内容记录到日志文件中。

基本上只是为了记录,我们正在创建可用数据的JSON,然后记录到日志文件中。这是记录数据以JSON格式的业务需求。

现在从可用数据创建JSON,然后记录到文件中需要很长时间,并影响原始请求返回时间。现在的想法是改善这种情况。

我们讨论过的其中一件事是使用线程池来创建。

Executors.newSingleThreadExecutor() 

在我们的代码中,我们将任务提交给它,然后进行数据转换为JSON并进行日志记录。

这是一个好的方法吗?由于我们正在管理线程池本身,这会创建一些问题吗?

如果有人能分享更好的解决方案,我将不胜感激。可以尝试使用Log4j来解决这个问题。我尝试使用AsyncAppender,但没有达到任何预期的结果。

我们正在使用EJB 3、JBoss 5.0、Log4j和Java6。

6个回答

11

我相信你在使用单独的线程池进行日志记录方面走在了正确的轨道上。在许多产品中,您会看到异步日志记录功能。日志是通过与请求线程不同的线程累积并推送到日志文件中的。特别是在生产环境中,有数百万个传入请求,而您的响应时间需要少于几秒钟。您不能承受任何使系统变慢的事情,例如日志记录。因此,所采用的方法是将日志添加到内存缓冲区中,并以合理大小的块异步推送它们。

在使用线程池进行日志记录时需要注意一些问题 由于多个线程将在日志文件和内存日志缓冲区上工作,您需要注意日志记录。您需要将日志添加到FIFO类型的缓冲区中,以确保日志按时间戳排序后打印到日志文件中。还要确保文件访问得到同步,避免出现日志文件倒置或混乱的情况。


感谢给我信心朝着正确的方向前进。但我的唯一担忧是,我正在使用应用程序创建的线程池...这会造成任何问题吗?或者有没有办法利用jboss线程池来解决这个问题。 - Rips

7
请查看Logback,其中的AsyncAppender已经提供了独立的线程池、队列等,并且易于配置。它几乎与你正在做的事情相同,但可以避免重复造轮子。

这个和log4j.AsyncAppender有什么区别吗?此外,作为其中的一部分,我不仅想异步记录日志,还想将数据转换为JSON。 - Rips
@Rips 如果你还有其他任务(如数据转换),那么你的解决方案也可以。关于log4j和logback,log4j的开发已经停止,而logback是活跃的。有关log4j与logback的更多详细信息,请查看此[链接](https://dev59.com/VXVC5IYBdhLWcg3wz0l9)。 - Alankar Srivastava

3

是否考虑使用 MongoDB 作为日志记录工具

  1. MongoDB 插入操作可以异步完成。如果记录速度慢、停滞或中断,用户体验会受到影响。MongoDB 提供了向日志集合发送插入请求的能力,而无需等待响应码(如果需要响应码,需要调用 getLastError() 方法,但在此处不需要)。
  2. 旧日志数据将自动进行 LRU(最近最少使用)处理。通过使用固定集合(capped collections),我们可以为日志预分配空间。一旦已经满了,日志会绕回并重复使用指定的空间。这样就不会出现过多的日志信息导致磁盘快满,也不需要编写日志归档/删除脚本。
  3. 在此类问题上,执行速度足够快。首先,MongoDB 在一般情况下非常快,对于这种问题来说速度足够快。其次,在使用固定集合时,插入顺序会自动保留,因此我们不需要在时间戳上创建索引。这使得速度更快,而且在日志记录用例中非常重要,因为写入次数远高于读取次数(与大多数数据库问题相反)。
  4. 基于文档/JSON 的格式非常适合日志信息。这种格式非常灵活,“无架构”意味着我们可以随时添加额外的字段。

2
谢谢你分享这个,但我认为我们现在不会走那条路。 - Rips


0

您也可以尝试使用CoralLog来异步记录数据,使用 disruptor 模式。这样,您可以在记录器线程中花费最少的时间,并将所有艰苦的工作传递给执行实际文件 I/O 的线程。它还提供了内存映射文件以加速消费者线程并减少队列争用。

免责声明:我是 CoralLog 的开发人员之一。


0

免责声明:我是elf4j-engine/elf4j-provider的开发者。

请查看elf4j-engine。异步是唯一的日志记录模式。还支持“开箱即用”的JSON模式格式。希望它能满足大多数“注意事项”和常见用例。

Juned Ahsan已经提出了很好的警告。再加上一些......

  1. 如果您正在使用 Executors.newSingleThreadExecutor(),那么FIFO部分已经由该单线程池(带有内置的FIFO任务队列)处理。只需确保在线程池接管工作后不再进行多线程“扇出”(或者如果您继续进行多线程操作,则所有注意事项都适用)。

  2. 通过使用异步线程池,日志记录的真正昂贵部分是在将日志条目数据交给线程池之前必须执行的操作(例如输出文件写入)。例如,如果您需要调用方线程信息或调用方帧详细信息(例如调用方法、行号和调用文件名),则这些操作很难由来自池的异步线程完成,而调用方/应用程序线程需要在将日志数据交给线程池之前完成大部分收集工作。数据收集可能需要包括遍历调用堆栈跟踪帧以提取详细信息,因此它有点昂贵但难以避免。异步性可以帮助一旦收集到所有数据就可以提高输出性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接