Программа C застряла в режиме непрерывного ожидания при выполнении дискового ввода-вывода в Mac OS X Snow Leopard - PullRequest
16 голосов
/ 07 января 2010

Одна строка фона: я разработчик Redis, базы данных NoSQL . Одна из новых функций, которые я реализую, - это виртуальная память, потому что Redis забирает все данные в памяти. Благодаря тому, что VM Redis может переносить редко используемые объекты из памяти на диск, есть ряд причин, по которым это работает гораздо лучше, чем позволить операционной системе выполнять за нас обмен (объекты redis состоят из множества небольших объектов, расположенных в несмежных местами, когда Redis сериализует их на диск, они занимают в 10 раз меньше места по сравнению со страницами памяти, где они живут и т. д.).

Теперь у меня есть альфа-реализация, которая отлично работает на Linux, но не очень хорошо на Mac OS X Snow Leopard. Время от времени, пока Redis пытается переместить страницу из памяти на диск, процесс redis переходит в состояние непрерывного ожидания на несколько минут. Я не смог отладить это, но это происходит либо при вызове fseeko(), либо fwrite(). Через несколько минут звонок, наконец, возвращается, и Redis продолжает работать без проблем: без сбоев.

Объем передаваемых данных очень маленький, что-то вроде 256 байтов. Так что это не должно быть связано с очень большим количеством операций ввода-вывода.

Но есть интересная деталь о файле подкачки, который является целью операции записи. Это большой файл (26 гигабайт), созданный с помощью fopen(), который открывается с расширением ftruncate(). Наконец, файл unlink() отредактирован так, что Redis продолжает ссылаться на него, но мы уверены, что после завершения процесса Redis ОС действительно освободит файл подкачки.

Хорошо, это все, но я здесь для дальнейших подробностей. И кстати, вы даже можете найти реальный код в Redis git, но это не так просто понять за пять минут, учитывая, что это довольно сложная система.

Большое спасибо за любую помощь.

Ответы [ 5 ]

11 голосов
/ 07 января 2010

Насколько я понимаю, в HFS + очень плохая поддержка разреженных файлов. Возможно, ваша запись запускает расширение файла, которое инициализирует / материализует большую часть файла.

Например, я знаю, что mmap создает новый большой пустой файл, а затем записывает в несколько случайных мест, получая очень большой файл на диске с HFS +. Это довольно раздражает, поскольку mmap и разреженные файлы - чрезвычайно удобный способ работы с данными, и практически любая другая платформа / файловая система справляется с этим изящно.

Файл подкачки записывается линейно? То есть мы либо заменяем существующий блок, либо пишем новый в конце и увеличиваем указатель свободного пространства? Если это так, то, возможно, более частые вызовы ftruncate меньшего размера для расширения файла приведут к более коротким паузам.

Кроме того, мне любопытно, почему Redis VM не использует mmap, а затем просто перемещает блоки в попытке сконцентрировать горячие блоки в горячие страницы.

1 голос
/ 07 января 2010

antirez, я не уверен, что мне сильно поможет, поскольку мой опыт Apple ограничен Apple ][, но я попробую.

Первым делом вопрос. Я бы подумал, что для виртуальной памяти скорость работы была бы более важной мерой, чем дисковое пространство (особенно для БД NoSQL, где скорость - это весь смысл, иначе вы бы использовали SQL, не так ли?). Но, если ваш файл подкачки имеет размер 26G, возможно, нет: -)

Некоторые вещи, которые можно попробовать (если это возможно).

  1. Попробуйте на самом деле изолировать проблему от поиска или записи. Мне трудно поверить, что поиск может занять так много времени, поскольку в худшем случае это должно быть изменение указателя буфера. Тем не менее, я не писал OSX, поэтому я не уверен.
  2. Попробуйте отрегулировать размер файла подкачки, чтобы узнать, не в этом ли причина проблемы.
  3. Вы когда-нибудь динамически расширяли файл подкачки (в отличие от предварительного выделения)? Если вы это сделаете, это может быть причиной проблемы.
  4. Ты всегда пишешь в файл как можно ниже? Может случиться так, что создание файла 26G на самом деле может не заполнить его данными, но, если вы создадите его, а затем запишете в последний байт, ОС, возможно, придется обнулять байты до этого (откладывая инициализацию, если есть). *
  5. Что произойдет, если вы просто предварительно выделите весь файл (записываете в каждый байт), а не отсоедините его? Другими словами, оставляйте файл там между запусками вашей программы (конечно, создавая его, если он еще не существует). Затем в коде запуска Redis просто инициализируйте файл (указатели и тому подобное). Это может избавить от любых проблем, подобных тем, которые приведены в пункте 4 выше.
  6. Спросите также на различных сайтах BSD. Я не уверен, насколько Apple изменилась под крышками, но OSX - это просто BSD на самом низком уровне (Pax ducks для обложки).
  7. Также подумайте над тем, чтобы спросить на сайтах Apple (если вы этого еще не сделали).

Ну, это мой маленький вклад, надеюсь, это поможет. Удачи в вашем проекте.

0 голосов
/ 07 января 2010

Как однажды Линус сказал в списке рассылки Git:

«Я понимаю, что людям OS X трудно принять это, но OS X файловые системы, как правило, полная и полная чушь - даже больше, чем Windows ".

0 голосов
/ 07 января 2010

Вы пробовали отладку с DTrace и или Instruments (экспериментальный интерфейс Apple dtrace)?

Изучение леопарда с DTrace

Отладка Chrome на OS X

0 голосов
/ 07 января 2010

Вы отключили кеширование файлов для своего файла? т.е. fcntl (fd, F_GLOBAL_NOCACHE, 1)

...