В настоящее время я экспериментирую с небольшим веб-сервером Haskell, написанным на Snap, который загружает и предоставляет клиенту много данных.И мне очень, очень трудно получить контроль над процессом сервера.В случайные моменты процесс использует много ресурсов ЦП от секунд до минут и перестает отвечать на запросы клиентов.Иногда использование памяти резко возрастает (а иногда и падает) на сотни мегабайт в течение нескольких секунд.
Надеюсь, у кого-то больше опыта работы с долго выполняющимися процессами на Haskell, которые используют много памяти и могут дать мне несколько указателей, чтобы сделать его более стабильным.Я отлаживаю эту штуку уже несколько дней и начинаю немного отчаяться.
Небольшой обзор моей настройки:
При запуске сервераЯ прочитал около 5 гигабайт данных в большую (вложенную) структуру типа Data.Map в памяти.Вложенная карта имеет строгое значение, и все значения внутри карты имеют типы данных, причем все их поля также сделаны строгими.Я потратил много времени на то, чтобы не осталось недооцененных громов.Импорт (в зависимости от загрузки моей системы) занимает около 5-30 минут.Странно то, что колебания в последовательных прогонах намного больше, чем я ожидал, но это другая проблема.
Большая структура данных живет внутри «TVar», который используется всемиклиентские потоки, порожденные сервером Snap.Клиенты могут запрашивать произвольные части данных, используя небольшой язык запросов.Объем запроса данных обычно невелик (до 300 КБ или около того) и затрагивает лишь небольшую часть структуры данных.Все запросы только для чтения выполняются с использованием readTVarIO, поэтому они не требуют никаких транзакций STM.
Сервер запускается со следующими флагами: + RTS -N -I0-qg -qb.Это запускает сервер в многопоточном режиме, отключает простой и параллельный сборщик мусора.Похоже, это значительно ускоряет процесс.
Сервер в основном работает без проблем.Тем не менее, время от времени клиентский запрос истекает, и процессор нагружается до 100% (или даже более 100%) и продолжает делать это долгое время.Между тем сервер больше не отвечает на запрос.
Существует несколько причин, по которым я могу думать, что может вызвать использование процессора:
Запрос просто занимает много времени.время, потому что впереди много работы.Это несколько маловероятно, потому что иногда это происходит для запросов, которые оказались очень быстрыми в предыдущих запусках (с быстрым я имею в виду 20-80 мс или около того).
Есть еще некоторые неоцененные громкие словакоторые должны быть рассчитаны до того, как данные могут быть обработаны и отправлены клиенту.Это также маловероятно, по той же причине, что и в предыдущем пункте.
Каким-то образом происходит сборка мусора и начинается сканирование всей моей кучи объемом 5 ГБ.Я могу себе представить, что это может занять много времени.
Проблема в том, что я понятия не имею, как точно определить, что происходит и что с этим делать.Поскольку процесс импорта занимает так много времени, результаты профилирования не показывают мне ничего полезного.Кажется, нет никакого способа условно включить и выключить профилировщик изнутри кода.
Лично я подозреваю, что проблема здесь в GC.Я использую GHC7, который, кажется, имеет много возможностей для настройки работы GC.
Какие настройки GC вы рекомендуете при использовании больших куч с обычно очень стабильными данными?