现状:
我正在 WAGO PFC200 PLC(定制嵌入式 Linux 固件)上运行 docker 容器。
容器运行一个 python 脚本,该脚本收集系统信息,如 CPU 负载、内存使用情况等,并将其写入 .json 文件。此过程在无限 while 循环中重复 3 秒。
该文件被写入容器文件系统“/app/out”创建的子目录,该子目录被挂载到linux文件系统的“/tmp”。
目标 从控制器上的 codesys 运行时环境中运行的程序中循环打开并读取 json 文件。
问题 打开 .json 文件时,有时 json 文件在语法上不正确。在 Codesys IDE 中测试 PLC 程序以及从 mobaXterm(FTP 文件浏览器)的文件浏览器打开文件时,会发生这种情况。然而,当我使用 NANO 在 SSH 会话中打开文件时,问题从未出现。
3 个错误文件示例:
{
"Operating System": "Linux",
"CPU Load": 26.0,
"CPU Average Load (1, 5, 15 minutes)": [
1.48828125,
2.6689453125,
2.6484375
],
"Total RAM": 512839680,
"Used RAM": 99794944,
"Shared RAM": 3022848,
"Total Swap Size": 0,
"Available Swap Size": 0
}e": 0
}
{
"Operating System": "Linux",
"CPU Load": 14.9,
"CPU Average Load (1, 5, 15 minutes)": [
1.5234375,
1.2978515625,
1.8134765625
],
"Total RAM": 512839680,
"Used RAM": 96014336,
"Shared RAM": 3035136,
"Total Swap Size": 0,
"Available Swap Size": 0
} 0
}
{
"Operating System": "Linux",
"CPU Load": 32.0,
"CPU Average Load (1, 5, 15 minutes)": [
1.1513671875,
1.2685546875,
1.265625
],
"Total RAM": 512839680,
"Used RAM": 98611200,
"Shared RAM": 3125248,
"Total Swap Size": 0,
"Available Swap Size": 0
}": 0
}
*我的观察
不正确的文件总是会添加 json 本身末尾的一部分(例如“e”:0 }")
此错误总是伴随着较长的加载时间和加载屏幕: 在此输入图片描述
打开文件时大约每 5-10 次发生一次
我的猜测
这似乎与打开和读取文件的同时写入文件有关。
我已经尝试过的
def write_to_json(data, filename):
with open(filename, 'w') as file:
try:
# Acquire an exclusive lock on the file
print("Acquiring lock...")
fcntl.flock(file, fcntl.LOCK_EX)
print("Lock acquired.")
# Write the system information to the file
json.dump(data, file, indent=4)
# Ensure data is written to disk
file.flush()
os.fsync(file.fileno())
finally:
# Release the lock
print("Releasing lock...")
fcntl.flock(file, fcntl.LOCK_UN)
print("Lock released.")
尝试使用 strace 记录文件上的操作
尝试记录“flock”控制台命令的操作
结果
“调试”打印(“正在获取锁...”等)都循环出现在容器控制台中
问题依然存在
strace只显示打开、读、写等,但不显示锁定
我不能使用“auditd”代替,因为它没有安装,我无法安装新的软件包
我的问题
是否有其他方法可以跟踪文件锁定操作以检查脚本的 fcntl 是否有效?
它甚至可以工作吗,因为文件被写入到挂载的目录中并且Python脚本没有通过它的调用“到达”Linux文件系统?
是否有其他方法可以限制同时读取和写入文件(如果这甚至是问题)?
还有哪些其他原因可能导致所显示的行为?
提前感谢您的回答!
我希望我已经添加了所有必要的信息。如果您需要实际代码或其他任何内容,请告诉我。
不要就地更新文件。
写入临时文件,完成后重命名。重命名文件是一个原子操作,因此读取该文件的应用程序将始终看到一致的数据。