Для микросервисов необходим изящный онлайн и офлайн сервисов.
С точки зрения выхода в сеть, если компонент или контейнер не запущен успешно, служба не должна подвергаться воздействию внешнего мира.В автономном режиме, если машина была выключена, служба должна быть гарантированно отключена, чтобы предотвратить попадание исходящего трафика на неработоспособные машины.
Оффлайн изящно
Базовый автономный режим (Spring/SpringBoot/встроенный контейнер)
Во-первых, сама JVM поддерживает корректное завершение работы через shutdownHook.
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
close();
}
});
Этот метод поддерживает корректное завершение работы в следующих сценариях:
1. Программа выходит нормально 2. Используйте System.exit () 3. Терминал Используйте Ctrl + C 4. Используйте Убить PID, чтобы убить процесс
Так что если вы хотите убить -9 программа должна быть перегружена.
Фактически, в Springboot для вас был реализован shutdownHook, который поддерживает реакцию на сигналы Ctrl+c или kill -15 TERM.
Просто запустите приложение, а затем нажмите Ctrl+c, чтобы просмотреть журнал, и вы увидите, что оно распечатывает журнал предполагаемого закрытия... в классе AnnotationConfigEmbeddedWebApplicationContext, а реальная логика реализации находится в его родительском классе AbstractApplicationContext (это на самом деле находится в весеннем классе, что это значит, расширение для изящного завершения работы поддерживается весной).
public void registerShutdownHook() {
if (this.shutdownHook == null) {
this.shutdownHook = new Thread() {
public void run() {
synchronized(AbstractApplicationContext.this.startupShutdownMonitor) {
AbstractApplicationContext.this.doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
public void destroy() {
this.close();
}
public void close() {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.doClose();
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
} catch (IllegalStateException var4) {
;
}
}
}
}
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Closing " + this);
}
LiveBeansView.unregisterApplicationContext(this);
try {
this.publishEvent((ApplicationEvent)(new ContextClosedEvent(this)));
} catch (Throwable var3) {
this.logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", var3);
}
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
} catch (Throwable var2) {
this.logger.warn("Exception thrown from LifecycleProcessor on context close", var2);
}
}
this.destroyBeans();
this.closeBeanFactory();
this.onClose();
this.active.set(false);
}
}
Что с ним можно сделать, на самом деле очевидно, что он публикует метод ContextClosedEvent в методе doClose, не только ли нам его расширять.
Таким образом, мы можем написать прослушиватель для прослушивания ContextClosedEvent и выполнять автономную логику при возникновении события.Для микросервисов это выход службы из реестра.
@Component
public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent){
//注销逻辑
zookeeperRegistry.unregister(mCurrentServiceURL);
...
}
}
Могут возникнуть сомнения, что вообще в микросервисах выход из сервисов часто является первым шагом к изящному офлайну, а потом будет выполняться операция выключения.Ну и что, если в это время придет трафик?
Лично я бы предложил, чтобы после выхода из службы можно было включить блокировку запросов для отклонения трафика, а отклоненный трафик можно было обрабатывать через функцию аварийного переключения самого микросервисного фреймворка.
Офлайн в Докере
Хорошо, кто-то сказал, я использую докер для развертывания сервисов, поддерживает ли он изящный автономный режим.
Давайте посмотрим, что делают некоторые команды остановки docker:
Вообще говоря, обычные люди могут использовать команду docker stop или docker kill для закрытия контейнера (конечно, если пользовательская информация USR2 зарегистрирована на предыдущем шаге, она может быть закрыта командой docker exec kill -12).
Для остановки докера он отправит SIGTERM (сообщение о термине kill -15) процессу PID1 контейнера, и по умолчанию он будет ждать 10 секунд, а затем отправит SIGKILL (сообщение kill -9) в PID1.
Таким образом, очевидно, что остановка докера позволяет программе иметь время отклика по умолчанию, равное 10 с, для корректного завершения работы, пока программа может реагировать на сигнал kill -15, как описано в предыдущем шаге. Тогда это лучший способ.
Конечно, если метод shutdownHook выполняется 50 с, это определенно не элегантно. Время ожидания можно добавить с помощью docker stop -t.
Скрипт выключения внешнего контейнера (Jetty)
Если вам нужно развернуть его во внешнем контейнере (лично считаю, что это тратит ресурсы и увеличивает сложность). Так ты можешь изящно остановиться?
Да, конечно, есть два пути:
Прежде всего, сама структура RPC предоставляет элегантный онлайн- и офлайн-интерфейс для вызова завершения жизненного цикла всего приложения, а также предоставляет разработчикам точки расширения для настройки логики отключения самой службы в автономном режиме. В то же время операция вызова этого интерфейса будет инкапсулирована в операцию preStop и закреплена в сценарии завершения работы причала или других контейнеров, гарантируя, что автономный интерфейс вызывается до того, как контейнер остановится, чтобы завершить жизненный цикл всего приложения. . Класс выполнения в сценарии завершения работы инициирует автономную службу -> закрывает порт -> проверяет автономную службу до завершения -> завершает работу контейнерного процесса.
Простой способ включить команду kill -15 непосредственно в сценарии. Элегантный на линии
Изящно подключиться к сети может быть сложнее, потому что нет реализации по умолчанию, но, короче говоря, принцип заключается в том, чтобы убедиться, что порт существует, прежде чем подключаться к сети.
Встроенный контейнер springboot элегантно запускается
Это очень просто, а элегантный запуск отрасли на уровне приложений достигается за счет встроенных контейнеров, и его также можно использовать с серией проверок работоспособности, чтобы поднять шумиху.
Обратитесь к исходному коду проверки работоспособности диван-загрузки, Сначала он выполнит некоторые проверки работоспособности компонентов Springboot при запуске программы, а затем выполнит проверки работоспособности некоторых промежуточных программ дивана, которые он сделал сам. весь процесс проверки работоспособности завершен (в настоящее время sofaboot не может выполнять проверки работоспособности на своем собственном уровне приложения. У него есть написанные связанные интерфейсы, но порт готов, если он написан мертвым ...) Только когда служба открыта или изящно работает онлайн, когда пора проверить его здоровье?
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
healthCheckerProcessor.init();
healthIndicatorProcessor.init();
afterHealthCheckCallbackProcessor.init();
publishBeforeHealthCheckEvent();
readinessHealthCheck();
}
Вы можете видеть, что он прослушивает событие ContextRefreshedEvent. В режиме встроенного контейнера метод запуска режима встроенного контейнера находится в методе refreshContext.После выполнения метода публикуется событие ContextRefreshedEvent, то есть при отслеживании этого события встроенный в контейнере должен быть успешно запущен.
Однако событие ContextRefreshedEvent в некоторых конкретных сценариях, по разным причинам, ContextRefreshedEvent будет отслеживаться несколько раз, и нет возможности гарантировать, что текущее событие является последним событием, чтобы корректная онлайн-логика могла выполняться правильно. .
В Springboot также есть еще более заднее событие, называемое ApplicationReadyEvent, он скрыт в высвобождении, что слушатели. Кроме того, позади refrefresh (контекст, null), гарантия может быть полностью построена контейнерным портом, поэтому мы можем слушать Это событие для выполнения элегантной линии логики, даже промежуточное программное обеспечение интеграции, связанное со здоровьем здесь.
@Component
public class GracefulStartupListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent){
//注册逻辑 优雅上线
apiRegister.register(urls);
...
}
}
Элегантный запуск внешнего контейнера (Jetty)
В настоящее время режим развертывания большинства приложений, будь то режим развертывания причала или режим развертывания докера (также с использованием образа причала), в основном использует внешние контейнеры. Тогда эта ситуация сложнее, по крайней мере, на уровне приложения нельзя наблюдать за рабочим состоянием внешнего контейнера, а сам контейнер не предоставляет никаких хуков для реализации.
Затем, как и в случае с элегантным онлайн, инфраструктура RPC должна предоставить элегантный онлайн-интерфейс для инициализации всего жизненного цикла приложения и предоставить разработчикам точки расширения для выполнения пользовательской онлайн-логики (информация об обнаружении версии отчета и т. д.). Вызов этого интерфейса также инкапсулирован в операцию postStart, которая закрепляется в сценарии запуска внешнего контейнера, такого как причал, чтобы гарантировать, что приложение переходит в оперативный режим после запуска контейнера. Контейнер выполняет процесс, аналогичный запуску контейнера -> проверка работоспособности -> логика онлайн-сервиса -> исправность онлайн-сервиса до завершения.Добавить Автора адрес:Лихорадка большая.Новый/изящный-так…