
мы используем нашу систему Java уже более 2 лет, и ни разу не было зависаний системы. У нас есть 2 физических сервера, на которых запущено похожее программное обеспечение Java (2 JVM на каждом сервере), образуя кластер. Насколько я могу судить, сбои начались только тогда, когда мы ввели закрепление ядра и mappedbus.io для общего доступа к памяти между 2 JVM на одном из серверов. Зависание системы произошло всего 4 раза за 2 недели, и оно происходит только на машине, где мы настроили закрепление ядра и доступ к отображенным в память файлам между JVM. Мы отключили эту конфигурацию, поэтому мы не закрепляем ядра для вращения при чтении отображенных в память файлов и не закрепляем наш основной поток приложения. Обратите внимание, когда я говорю закрепить, мы также занимаемся закреплением потока, работающего на этом закрепленном ядре.
Хотя это совершенно анекдотично. Поскольку система не зависает каждый день, я не могу сказать наверняка, что это как-то связано с закреплением ядра или доступом к общей памяти. Однако, при отключенном закреплении (и активном вращении) и доступе к общей памяти в цикле с помощью LockSupport.parkNanos(5000) у нас, похоже, не было никаких зависаний системы.
Задержка имеет для нас решающее значение, поэтому такая «незанятая» настройка является лишь временным решением.
Также, пожалуйста, обратите внимание, что я перенес приложение на идентичный сервер и также смог испытать это полное зависание системы. Поэтому я не могу считать это аппаратным сбоем.
Итак, изучая логи до или после сбоя, вот что мне кажется важным. Таких стеков несколько. Я просто публикую здесь первый (т.е. я не верю, что это как-то связано с самим postgres)
kernel: [25738.874778] INFO: task postgres:2155 blocked for more than 120 seconds.
kernel: [25738.874833] Not tainted 5.4.0-050400-generic #201911242031
kernel: [25738.874878] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kernel: [25738.874928] postgres D 0 2155 2056 0x00004000
kernel: [25738.874931] Call Trace:
kernel: [25738.874942] __schedule+0x2e3/0x740
kernel: [25738.874948] ? __wake_up_common_lock+0x8a/0xc0
kernel: [25738.874951] schedule+0x42/0xb0
kernel: [25738.874957] jbd2_log_wait_commit+0xaf/0x120
kernel: [25738.874961] ? wait_woken+0x80/0x80
kernel: [25738.874965] jbd2_complete_transaction+0x5c/0x90
kernel: [25738.874969] ext4_sync_file+0x38c/0x3e0
kernel: [25738.874974] vfs_fsync_range+0x49/0x80
kernel: [25738.874977] do_fsync+0x3d/0x70
kernel: [25738.874980] __x64_sys_fsync+0x14/0x20
kernel: [25738.874985] do_syscall_64+0x57/0x190
kernel: [25738.874991] entry_SYSCALL_64_after_hwframe+0x44/0xa9
kernel: [25738.874993] RIP: 0033:0x7f96dc24b214
kernel: [25738.875002] Code: Bad RIP value.
kernel: [25738.875003] RSP: 002b:00007fffb2abd868 EFLAGS: 00000246 ORIG_RAX: 000000000000004a
kernel: [25738.875006] RAX: ffffffffffffffda RBX: 00007fffb2abd874 RCX: 00007f96dc24b214
kernel: [25738.875007] RDX: 00005635889ba238 RSI: 00005635889a1490 RDI: 0000000000000003
kernel: [25738.875009] RBP: 00007fffb2abd930 R08: 00005635889a1480 R09: 00007f96cc1e1200
kernel: [25738.875010] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
kernel: [25738.875011] R13: 0000000000000000 R14: 000056358899c5a0 R15: 0000000000000001
ps это произошло на 16.04 и ядре 4.15 тоже. Обновление до 18.04 и 5.0 было попыткой решить зависание системы, но не дало никаких результатов.
Другое, что я рассмотрел, это то, что, возможно, эта трассировка — всего лишь симптом, а не проблема. То есть, мое приложение связало сервер и заставило другие процессы заблокироваться на io и получить эти ошибки. Но поскольку сервер полностью завис, у меня нет возможности узнать состояние моего приложения в это время.
Дополнительная информация в ответ на комментарии
Во-первых, повторюсь, у меня нет веских доказательств того, что закрепление ядра и общая память — это та самая соломинка, которая сломает спину верблюда, но это мое лучшее предположение, основанное на истории изменений и сбоях.
Модель ЦП — Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz с турбонаддувом. На сервере их 2. Я закрепляю номера ЦП 2,4,6, которые, как я считаю, находятся на одном физическом ЦП. Гиперпоточность ВКЛЮЧЕНА.
Настройка выглядит следующим образом. JVM-A имеет закрепленный занятый спин-поток, пишущий в отображенный в память файл X и читающий из отображенного в память файла Y. JVM-B имеет закрепленный занятый спин-поток, читающий из отображенного в память файла X и пишущий обратно в отображенный в память файл Y. В JVM-B закрепленный читающий поток затем публикует сообщение в кольцевом буфере разрушителя с закрепленным занятым спин-воркером. Сообщение представляет собой инструкцию заказа, которая в конечном итоге отправляется на рынок этим воркером. Это торговая платформа с низкой задержкой.
В этом посте представлено лучшее исследование LockSupport.parkNanos, чем здесь.https://hazelcast.com/blog/locksupport-parknanos-under-the-hood-and-the-curious-case-of-parking/
У меня есть 2 жестких диска по 10 000 об/мин в RAID 1 со встроенным RAID-контроллером.
Что касается целевой задержки, да, теоретически мы могли бы объединить две JVM в одну и полностью избавиться от этого отображенного в памяти файлового канала. Однако есть и другие соображения, прежде чем это делать, поэтому я хотел бы сначала сосредоточиться на понимании этой технической проблемы.
Наконец, postgres на этом сервере работает только в режиме восстановления, он не является основным. Кроме того, наша система вообще не делает много ввода-вывода базы данных. Она используется только для начальной загрузки и начала дня, а также для сохранения торговой активности дня в течение ночи. Один из сбоев произошел в то время, когда ввод-вывод базы данных был бы почти нулевым.
решение1
«Заблокировано» в данном случае hung_task_timeout_secs
означает, что задача находилась в состоянии непрерывности D в течение указанного времени. 120 секунд — это довольно необычное количество времени для выполнения ввода-вывода.
Запустите мониторинг, который может получить метрики с этого хоста.нетдатахорош для этого, он собирает много информации каждую секунду в памяти, так что не так много дисковых операций ввода-вывода. И имеет хорошие графики.
Проверьте задержку диска, например, с помощью iostat -xz 1
. Ожидания выше однозначных мс нехороши. Поделитесь, что это за хранилище, шпиндели, твердотельные накопители, SAN LUN.
Что касается вращения и закрепления, у меня есть подозрение, что вы заставляете планировщик голодать. Поделитесь конкретной моделью ЦП, о которой идет речь, и какие ядра вы закрепляете, чтобы что делать. Как это LockSupport.parkNanos()
реализовано?
Обзор vmstat 1
. Постоянное наличие множества задач в запущенном r
или непрерываемом b
состоянии не является хорошим.
Рассмотрите возможность установки BPF и использования скриптов для сбора диагностических данных задач.runqslower
покажет ожидающие задачи выше определенного порога. Очень быстро — это идеально, обратите внимание, что пороговые единицы — микросекунды.
Возвращаясь на минутку, задумайтесь о конструкции этой вещи.
Какова именно целевая задержка, что и как быстро она выполняется?
Есть ли причина, по которой postgres работает на том же хосте? Если бы он был удаленным и имел доступ через TCP, его ввод-вывод не был бы проблемой для приложения JVM.
решение2
Итак, в конце концов, проблема оказалась довольно простой. Мое изолированное тестирование так и не смогло привести к сбою машины, потому что в моем тестовом коде отсутствовал этот элемент. Проблема не связана с общей памятью или закреплением ядер сама по себе. Просто изоляция ядер немного сократила доступный общий ресурс до точки, когда планировщик мог бы голодать, потому что ...
Обе JVM были настроены на приоритет реального времени с помощью
sudo renice -n -20 $!
sudo chrt -r -a -p 99 $!
Вся JVM была ускорена, так что в общей сложности почти 300 потоков с максимальным приоритетом. Переключение контекста более 150 000/с даже при относительно низкой загрузке ЦП.
Мы оставили приятность и убрали изменение реального времени. Кажется, это исправило ситуацию. Первоначальная цель устаревшей настройки RT может быть достигнута путем изменения того, как мы используем busyspin/pinning/c-states/p-states и т. д.