Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ScheduledExecutor服务单按1分钟的时间表运行10分钟(systemd-日记故障)_Java_Multithreading_Systemd_Scheduledexecutorservice_Journal - Fatal编程技术网

Java ScheduledExecutor服务单按1分钟的时间表运行10分钟(systemd-日记故障)

Java ScheduledExecutor服务单按1分钟的时间表运行10分钟(systemd-日记故障),java,multithreading,systemd,scheduledexecutorservice,journal,Java,Multithreading,Systemd,Scheduledexecutorservice,Journal,我有一个executor服务,应该每分钟向磁盘写入一些内容 日程安排如下: scheduledCacheDump = new ScheduledThreadPoolExecutor(1); scheduledCacheDump.scheduleAtFixedRate(this::saveCachedRecords, 60,

我有一个executor服务,应该每分钟向磁盘写入一些内容

日程安排如下:

    scheduledCacheDump = new ScheduledThreadPoolExecutor(1);
    scheduledCacheDump.scheduleAtFixedRate(this::saveCachedRecords,
                                           60,
                                           60,
                                           TimeUnit.SECONDS
    );
该任务使用由主线程填充的共享列表,因此它在该列表上同步:

   private void saveCachedRecords() {
        LOG.info(String.format("Scheduled record dump to disk. We have %d records to save.", recordCache.size()));
        synchronized (recordCache) {
            Iterator<Record> iterator = recordCache.iterator();
            while (iterator.hasNext()) {
               // save record to disk
               iterator.remove();
            }
        }
    }
private void saveCachedRecords(){
LOG.info(String.format(“计划将记录转储到磁盘。我们有%d条记录要保存。”,recordCache.size());
已同步(记录缓存){
迭代器迭代器=recordCache.Iterator();
while(iterator.hasNext()){
//将记录保存到磁盘
iterator.remove();
}
}
}
我的名单声明如下:

private final List<Record> recordCache = new ArrayList<>();
private final List recordCache=new ArrayList();
主线程以批处理方式接收数据,因此每隔一秒钟左右,它就会接收30条记录,并将其缓存在列表中。剩下的时间,它在等待一个套接字

我不明白的是,从日志中可以看出,我的计划任务通常会在一分钟后触发:


9月16日09:30:43定时记录转储到磁盘。我们有27条记录要保存。
9月16日09:31:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:32:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:33:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:34:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:35:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:42:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:43:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:44:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:45:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:46:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:55:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:56:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:57:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:58:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日09:59:43定时记录转储到磁盘。我们有27条记录要保存。
9月16日10:04:43定时记录转储到磁盘。我们有27条记录要保存。
9月16日10:05:43预定记录转储到磁盘。我们有27条记录要保存。
9月16日10:06:43定时记录转储到磁盘。我们有27条记录要保存。

看看这个:

  • 9月16日09:59:43定时记录转储到磁盘。我们有27条记录要保存
  • 9月16日10:04:43定时记录转储到磁盘。我们有27条记录要保存
=>5分钟

甚至:

  • 9月16日09:46:43预定记录转储到磁盘。我们有27条记录要保存
  • 9月16日09:55:43预定记录转储到磁盘。我们有27条记录要保存
=>9分钟

我的日志在
synchronized()
范围内,因此我不知道任务是否确实按时调度并在锁上等待10分钟,或者这是否只是一个真正的调度问题。我将把它移出,但一般来说,我无法理解一个线程如何在每秒释放一次的锁上保持阻塞10分钟

我该如何调查这件事

仅供参考:它运行的机器是KVM机器,这可能是一个因素吗?

哦,天哪

这根本不是Java的错。这是systemd的错

我的进程作为systemd服务运行,因此我提取的日志来自systemd journald。 猜猜看,systemd有一个利率限制。当调度程序被触发时,我的守护进程会命中它,所以我得到了很多这样的行:


抑制了来自/system.slice/xxx.service的570条消息
已抑制来自/system.slice/xxx.service的769条消息
抑制了来自/system.slice/xxx.service的745条消息
已抑制来自/system.slice/xxx.service的729条消息
已抑制来自/system.slice/xxx.service的717条消息
已抑制来自/system.slice/xxx.service的95条消息
已抑制来自/system.slice/xxx.service的543条消息

所以。。是的,我移除了journald上的节流装置,现在我每分钟都有我的痕迹

解决办法是:

  • 编辑
    /etc/systemd/journald.conf
  • 在末尾添加行:
    RateLimitInterval=0
  • 执行
    systemctl重新启动systemd journald
  • 执行
    systemctl重新启动myservice
现在我一切都很顺利


我将更新标题以备将来参考:)

您检查过GC活动了吗?我没有。有没有一个CLI工具来做这个(我不是java专家,我承认)与你的问题无关,但是考虑使用一个并发的链接队列代替一个数组,它是线程安全的,而且一个队列似乎比你需要的列表更合适,堆的大小是什么?我的列表中有相当数量的记录(27条),但每一条记录都会被每秒操纵以向其中添加数据。当我将其转储到磁盘时,我会完全清空列表并重新开始。所以ConcurrentLinkedQueue就没那么好了,因为我仍然需要在记录修改中进行sync(),这就意味着你应该修复你的其他代码,不要那么多垃圾邮件。达到速率限制意味着您的守护进程在默认情况下会在30秒内记录超过1K条消息。当其他事情变得疯狂时,完全取消费率限制将对您的日志有害。(例如,wpa_supplicant或NetworkManager)这是一台生产机器,我们每秒接收30条消息,每条消息2行,因此它每分钟输出3600条消息。它是非常可压缩的(我们的logrotate将2GB的日志压缩为17MB),但我们需要它们,所以我们不会对它们进行速率限制。。