Как я могу гарантировать отправку сердцебиения "остаться в живых"?

У нас есть клиентское приложение RMI, написанное на Java, которое должно отправлять периодические сообщения "оставайся в живых" в серверное приложение. Мы реализовали это как отдельный поток пульса, который отправляет сообщение о том, что осталось в живых, на сервер, а затем спит в течение 15 секунд, используя Thread.sleep().

Поток имеет высокий приоритет:

Thread heartbeatThread = new Thread(new HeartbeatRunnable(server));
heartbeatThread.setPriority(Thread.MAX_PRIORITY);
heartbeatThread.start();

Однако, когда ящик, на котором работает клиент, использует много ЦП, мы обнаруживаем, что пропускаются тактовые импульсы, что заставляет сервер предполагать, что наше клиентское приложение умерло.

Мы добавили вызовы Thread.yield() в мой основной поток, хотя это не помогло устранить проблему.

Есть ли способ гарантировать, что пульс отправляется вовремя, пока мое приложение еще работает?

6 ответов

Решение

Вы можете реализовать многопоточность в пользовательском режиме в непоточной среде, свободно разбрасывая в своем коде самописную функцию "yield".

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

Это грубое решение, но, учитывая, что вы попробовали правильное решение, и оно не работает, возможно, вам стоит вернуться к этому.

Фактически, вы могли бы поместить макрос в начало каждого вызова функции, который быстро проверяет время и при необходимости вызывает функцию heartbeat.

(Ах, у вас есть макросы в Java? Думаю, нет - но вы поняли).

Вы не можете действительно гарантировать это. Вы можете отправить сердцебиение в другом потоке, чтобы предотвратить добавление пульса к вашей задержке. Также может быть целесообразно установить задержку между двумя контрольными импульсами равной половине времени, которое сервер использует для определения того, что клиент мёртв, то есть, если ваш сервер блокирует ваш клиент по истечении 15 секунд, (попытайтесь) отправлять контрольные сигналы каждые 7,5 секунд.

Это зависит от того, какой процесс использует процессор.

Если это не ваш процесс, и поэтому клиентский процесс действительно не отвечает, то он, по сути, не является живым, поэтому не целесообразно отправлять heartbeart. Наличие сердцебиения, которое говорит: "Я активен и могу обрабатывать сообщения", когда ящик слишком загружен, чтобы сделать это, может ввести в заблуждение.

Если цель сообщения "пульс" состоит в том, что "этот процесс запущен, но может пройти полчаса, пока я не вернусь к вам", отправьте это сообщение на сервер. Или установите тайм-аут на тот, который соответствует отзывчивости клиента.

Вы должны настроить количество "пропущенных тактовых импульсов", которое сервер ожидает, прежде чем решить, что клиент недоступен.

Так, например, если ваш интервал сердечных сокращений составляет 15 секунд, а количество пропущенных сердечных сокращений равно 4, то сервер будет ожидать максимум 60 секунд (1 минуту), прежде чем решить, что клиент недоступен.

Если вы хотите, чтобы сервер объявил, что он жив, вам лучше представить открытый сокет. На вашем клиенте просто читайте из этого сокета. Он заблокируется (так как ваш сервер ничего не пишет), и если сервер исчезнет / выключится, ваш клиент получит IOException, указывающее, что сокет / порт сервера исчез.

Это не будет зависеть от сервера, обеспечивающего своевременное сердцебиение. Он использует мало ресурсов (порт TCP на стороне сервера и почти без полосы пропускания) и своевременно сообщает, когда сервер (или серверный компьютер) становится недоступным.

Возможно, лучшим решением будет использование Timer scheduleAtFixedRate. При этом, если одно выполнение задерживается (чего нельзя избежать в Java), последующие вызовы не будут затронуты.

Другие вопросы по тегам