мы запускаем нашу java-систему более 2 лет, и ни разу не зависла. У нас есть 2 физических сервера, на которых запущено аналогичное программное обеспечение Java (по 2 JVM на каждом сервере) для формирования кластера. Насколько я могу судить, сбой начался только тогда, когда мы ввели закрепление ядра и mappedbus.io для доступа к общей памяти между двумя 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
p.s. это произошло 16.04 и ядром 4.15 тоже. Обновление до 18.04 и 5.0 было попыткой решить проблему зависания системы, но не помогло.
Еще я подумал о том, что, возможно, этот след - всего лишь симптом, а не проблема. То есть мое приложение связало сервер и заставило другие процессы заблокироваться на io и получить эти ошибки. Но поскольку сервер полностью зависает, у меня нет возможности узнать состояние моего приложения в то время.
Во-первых, просто повторюсь, у меня нет убедительных доказательств того, что основная память + разделяемая память - это соломинка, которая ломает пресловутую спину верблюда, но это мое лучшее предположение, основанное на истории изменений и сбоях.
Модель процессора - Intel (R) Xeon (R) CPU E5-2620 v4 @ 2,10 ГГц с турбонаддувом. Их 2 на сервере. Я закрепляю номера ЦП 2,4,6, которые, как мне кажется, находятся на одном физическом ЦП. Гиперпоточность включена.
Настройка такая. JVM-A имеет закрепленный поток занятого вращения, записывающий в отображаемый в память файл X и чтение из отображенного в память файла Y. JVM-B имеет закрепленный занятый спин-поток, считывающий из отображенного в память файла X и записывающий обратно в отображенный в память файл Y. В JVM- Затем закрепленный поток чтения публикует сообщение в кольцевом буфере дезинтегратора с закрепленным занятым рабочим потоком. Сообщение представляет собой распоряжение о заказе, которое, наконец, отправляется на рынок этому работнику. Это торговая платформа с малой задержкой.
Этот пост дает лучшее исследование LockSupport.parkNanos, чем я могу здесь https://hazelcast.com/blog/locksupport-parknanos-under-the-hood-and-the-curious-case-of-parking/
У меня есть 2 жестких диска 10000 об / мин в RAID 1 со встроенным RAID-контроллером.
Что касается целевой задержки, да, теоретически мы могли бы объединить две JVM в одну и полностью избавиться от этого отображаемого в память файлового канала. Однако прежде чем это сделать, нужно учесть другие соображения, поэтому я хотел бы сначала сосредоточиться на понимании этой технической проблемы.
Наконец, postgres на этом сервере работает только в режиме восстановления, он не является основным. Кроме того, наша система вообще не выполняет много операций ввода-вывода базы данных. На самом деле он используется только для начальной загрузки и начала дня и сохранения дневной торговой активности в течение ночи. Один из сбоев произошел в то время, когда операции ввода-вывода базы данных были бы почти нулевыми.
Итак, в конце концов проблема оказалась довольно простой. Мое изолированное тестирование никогда не приводило к сбою машины, потому что мне не хватало этого элемента в моем тестовом коде. Проблема не в общей памяти или закреплении ядра сама по себе. Просто изоляция ядер немного уменьшила доступный общий ресурс до точки, когда планировщик мог бы не хватить, потому что ...
Обе JVM были установлены с приоритетом в реальном времени с использованием
sudo renice -n -20 $!
sudo chrt -r -a -p 99 $!
Вся JVM была перебита, поэтому в общей сложности почти 300 потоков с максимальным приоритетом. Переключение контекста более 150 000 / с даже при относительно низкой загрузке ЦП.
Мы оставили приятность и убрали изменение в реальном времени. Кажется, это исправило. Первоначальная цель устаревшей настройки RT может быть достигнута путем изменения того, как мы занимаемся вращением / закреплением / c-состояниями / p-состояниями и т. Д.
«Заблокировано» в случае hung_task_timeout_secs
означает, что задача долгое время находилась в непрерывном состоянии D. 120 секунд - это невероятное количество времени для выполнения операций ввода-вывода.
Начните мониторинг, который может получить метрики с этого хоста. netdata хорош для этого, он каждую секунду собирает много информации в памяти, поэтому не нужно много дискового ввода-вывода. И имеет красивые графики.
Проверьте задержку диска, например, с iostat -xz 1
. Ожидания, превышающие однозначные миллисекунды, не подходят. Расскажите, что это за хранилище: шпиндели, твердотельные накопители, SAN LUN.
Что касается вращения и закрепления, я подозреваю, что вы заставляете планировщик голодать. Расскажите о конкретной модели процессора, о которой идет речь, и о том, какие ядра вы закрепляете, для чего. Как LockSupport.parkNanos()
реализовано?
Обзор vmstat 1
. Постоянно выполняя много задач r
или бесперебойный b
состояния не годится.
Рассмотрите возможность установки BPF и использования сценариев для сбора диагностических данных о задачах. runqslower
покажет ожидающие задачи выше определенного порога. Идеально очень быстро, обратите внимание, что пороговые единицы - микросекунды.
Вернувшись на минутку, рассмотрим дизайн этой штуки.
Какова именно цель задержки, что делать и как быстро?
Есть ли причина, по которой postgres работает на одном хосте? Если бы он был удаленным и доступ к нему осуществлялся через TCP, его ввод-вывод не был бы проблемой для приложения JVM.