Это может быть немного эзотерически, но у меня есть странная проблема со stat ().
А именно - в системе Linux с установленным хранилищем Isilon NFS. У меня есть процесс, у которого разница во времени при запуске fstat
в том же файле.
Я могу воспроизвести это с помощью C, который не делает ничего сложнее, чем open-write-stat-close; открыть-статистика-закрыть
И эти два числа будут - иногда - отличаться на несколько миллисекунд - файл может показаться «старше», чем он есть на самом деле.
Я не понимаю, считывает ли «статистика» время с хоста или с сервера. И я также не понимаю, связана ли проблема с Isilon (хотя, похоже, этого не происходит с хранилищем NetApp).
Может ли кто-нибудь дать мне представление о том, что может происходить?
Например:
time mismatch: 1468936451.862865611 != 1468936451.860183107
Первый - это время чтения, когда дескриптор файла открыт. Второй - время чтения после закрытия (и fsync
).
Как видите, файл «на сервере» немного старше, чем на клиенте.
В C
чтобы проверить это:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main ()
{
while (1)
{
struct stat sb[2];
/*
* Open file
*/
int fd = open ("test.dat", O_CREAT | O_RDWR | O_APPEND, 0644);
if (fd < 0)
{
perror ("failed to open file (1)");
return EXIT_FAILURE;
}
/*
* Write to it
*/
write (fd, "", 1);
/*
* Ensure it's sync'd to disk
*/
if (fsync (fd) < 0)
{
perror ("failed to fsync file");
return EXIT_FAILURE;
}
/*
* Stat the file
*/
if (fstat (fd, &(sb[0])) < 0)
{
perror ("failed to fstat file (1)");
return EXIT_FAILURE;
}
/*
* Close it
*/
close (fd);
/*
* Open file
*/
fd = open ("test.dat", O_RDONLY);
if (fd < 0)
{
perror ("failed to open file (2)");
return EXIT_FAILURE;
}
/*
* Stat it again
*/
if (fstat (fd, &(sb[1])) < 0)
{
perror ("failed to fstat file (2)");
return EXIT_FAILURE;
}
/*
* Close it
*/
close (fd);
/*
* Check the times match
*/
if (sb[0].st_mtime != sb[1].st_mtime ||
sb[0].st_mtim.tv_nsec !=sb[1].st_mtim.tv_nsec)
{
printf ("time mismatch: %d.%09ld != %d.%09ld\n",
(int)(sb[0].st_mtime), sb[0].st_mtim.tv_nsec,
(int)(sb[1].st_mtime), sb[1].st_mtim.tv_nsec);
}
}
}
И вы можете запустить его, запустив это в монтировании NFS, а затем вызвав stat (команда оболочки в порядке) из другой системы. Например. на самом исилоне:
while true
do
stat test.dat
done
Это вызывает у меня такие ошибки, как:
time mismatch: 1468936613.313045037 != 1468936613.310174576
time mismatch: 1468936613.547768543 != 1468936613.544878047
time mismatch: 1468936615.228495345 != 1468936615.225862947
time mismatch: 1468936619.036053897 != 1468936619.033362349
time mismatch: 1468936619.988151772 != 1468936619.985529620
time mismatch: 1468936664.541226541 != 1468936664.538549678
time mismatch: 1468936666.165674866 != 1468936666.163171366
time mismatch: 1468936666.787528027 != 1468936666.784797051
time mismatch: 1468936711.334376729 != 1468936711.331868927
И ... я не думаю, что так должно быть.
Редактировать:
Сюжет становится более плотным - при запуске вышеуказанного и захвате пакетов ответ на вызов NFS GETATTR с сервера непоследователен. Я получаю две разные отметки времени.
Параметры монтирования, похоже, не имеют значения, но мы попробовали установить noac
и actimeo=0
, sync
lookupcache=none
и т.п.
Все наши узлы isilon синхронизируются по протоколу ntp с одними и теми же источниками. Как обычно, между ними есть небольшой дрейф.
Мы обнаружили, что можем применить обходной путь в виде isi export modify --zone <zoneid> <exportnumber> --time-delta 1
Это устанавливает разрешение метки времени на 1 с, а не на 1 нс. Однако, хотя это снижает частоту возникновения проблемы, она все равно будет происходить - только реже, потому что это происходит только на границе «1 с».