Сцена
Операция публикации MicroServices, как правило, для ввода нового кодового пакета, Kill It ОТКЛЮЧИВАЕТ РАЗВОДСТВИЕМУ приложение, замените новый пакет и запустите его.
Eureka используется в качестве центра реестра в Spring Cloud, который позволяет задержать данные списка обслуживания, то есть даже если приложение больше не в списке услуг, клиент все равно будет запрашивать этот адрес в течение определенного периода времени. Затем появится запрос, что приведет к неудаче.
Мы оптимизируем время обновления списка услуг, чтобы улучшить своевременность информации о списке услуг. Но независимо от того, что невозможно избежать периода времени, когда данные непоследовательны.
Таким образом, один из способов, которым мы думали, - повторить механизм. Когда машина А перезагружается, В в том же кластере может обычно предоставлять услуги. Если есть механизм повторения, вы можете повторить B в вышеупомянутом сценарии, не влияя на правильный ответ.
работать
Требуются следующие операции:
лента: readtimeout: 10000 ConnectTimeout: 10000 MaxAutoretries: 0 MaxAutoreTriesNextServer: 1 OttoretryonAlloperations: False
Представление пакета пружины
<depervice> <groupid> org.springframework.retry </GroupId> <ArtifactId> Spring-retry </artifactid> </depervice>
Принимая Zuul в качестве примера, вам также необходимо настроить и включить повторение:
zuul.retryable = true
Столкнулись с проблемой
Однако все было не таким гладким. Механизм повторного испытания вступил в силу, но он не запросил другую здоровую машину, как я представлял. Поэтому я был вынужден перейти в код с открытым исходным кодом и, наконец, обнаружил, что это была ошибка исходного кода, но она была исправлена, и версия была обновлена.
Анализ кода
Используемая версия
Spring-Cloud-Netflix-Core: 1.3.6.Srelease
пружина: 1.2.1.
Версия с зависимостью весеннего облака:
<dependencymanagement> <depertiencies> <dependency> <groupid> org.springframework.cloud </groupid> <artifactid> spring-cloud-зависимости </artifactid> <sersion> $ {Spring-cloud.version} </version> <pom> pom </type> <cerpope> import </scope> </vehyse> </verse> </type> </typope> Import </scope> </vehyboy> </vehysendency> </jeperiation> </depertionlindencymerieryПоскольку retry включена, метод retryableribbonlaininghttpclient.execute выполняется при запросе приложения:
public ribbonapachehttpresponse execute (final RibbonapachehttpRequest запрос, окончательный iClientConfig configuverRide), выбросы исключения {final requestConfig.Builder Builder = requestConfig.custom (); IClientConfig config = configOverride! = NULL? configoverride: this.config; builder.setConnecttimeout (config.get (commonclientConfigkey.connecttimeout, this.connecttimeout)); builder.setsockettimeout (config.get (commonclientconfigkey.readtimeout, this.readtimeout)); builder.setredirectsenabled (config.get (commonclientconfigkey.followredirects, this.followredirects)); final RequestConfig requestConfig = builder.build (); final LoadbalancedRypolicy Retrypolicy = LoadBalancedRitedRypolicyFactory.create (this.getClientName (), это); Retrycallback retrycallback = new retrycallback () {@override public ribbonapachehttpresponse dowithretry (context retrycontext) выбрасывает исключение {// на поиск политики выберет сервер и устанавливает его в контексте // Извлечение сервера и обновляет запрос, который будет сделан ribbonapachehtprequest newrequest = request; if (context ancementof loadbalancedrycontext) {serviceInstance service = (((LoadBalancedRyContext) контекст) .getServiceInstance (); if (service! = null) {// Реконструируйте URI запроса, используя хост и порт, установленные в контексте повторного повторного рита newRequest = newRequest.withnewuri (new uri (service.geturi (). getscheme (), newrequest.geturi (). getuserinfo (), service.gethost () service.getepport () geteRquept (). newRequest.geturi (). getQuery (), newRequest.geturi (). getFragment ())); }} newRequest = getSecureRequest (request, configoverride); Httpurirequest httpurirequest = newRequest.torequest (requestConfig); Окончательный httpresponse httpresponse = retryableribbonloadlanceshttpclient.this.delegate.execute (httpurirequest); if (retrypolicy.retryablestatuscode (httpresponse.getStatusline (). getStatuscode ())) {if (stockableHttpresponse.class.isinStance (httpresponse)) {((stockablehttpresponse) httpresponse) .close (); } бросить новый retryablestatuseexception (retryableribbonlancebalancehttpclient.this.clientName, httpresponse.getStatusline (). getStatuscode ()); } вернуть новую ленточную ленту (httpresponse, httpurirequest.geturi ()); }}; вернуть это. }Мы обнаружили, что мы сначала новичны с помощью повторного высказывания, а затем выполняем это.
Мы четко видим, что код retrycallback.dowithretry является фактическим запрошенным кодом, что означает, что этот метод.
Защищенный <T, E Extends Throwable> t DoExecute (retrycallback <t, e> retrycallback, recelebilyCallback <t> recordyCallback, StateState State) Throws E, FroundretReexception {retrypolicy retrypolicy = this.retrypolicy; Backoffpolicy BackoffPolicy = this.backoffpolicy; // разрешить политику повторной попытки инициализировать сам ... retrycontext context = open (retrypolicy, state); if (this.logger.istraceenabled ()) {this.logger.trace ("retrycontext Получено:" + context); } // Убедитесь, что контекст доступен по всему миру для клиентов, которым нуждается // IT ... retrySynchronization manage.register (context); Бросаемое LastException = null; логический источник = false; попробуйте {// дайте клиентам возможность улучшить контекст ... логический running = doopeninterceptors (retrycallback, context); if (! running) {бросить новое DerminatedretryException («Повторяет прекращение ненормально перехватчиком перед первой попыткой»); } // Получить или запустить контекст отступления ... backoffcontext backoffcontext = null; Object resource = context.getAttribute ("backoffContext"); if (ресурс экземпляр Backoffcontext) {backoffcontext = (backoffcontext) ресурс; } if (backoffcontext == null) {backoffcontext = backoffpolicy.start (context); if (backoffcontext! = null) {context.setattribute ("backoffcontext", backoffcontext); }} / * * Мы разрешаем пропустить весь цикл, если уже политика или контекст * запрещают первую попытку. Это используется в случае внешней попытки, чтобы позволить * восстановление в Handleretryexhaust, без обработки обратного вызова (что * выставит исключение). */ while (canretry (retrypolicy, context) &&! context.isexhaustedonly ()) {try {if (this.logger.isdebugenabled ()) {this.logger.debug ("retry: count =" + context.getretrycount ()); } // Сбросить последнее исключение, поэтому, если мы успешны // близкие перехватчики не будут думать, что мы потерпели неудачу ... LastException = null; return retrycallback.dowithretry (контекст); } catch (throwable e) {aStexception = e; try {registerThrowable (retrypolicy, состояние, контекст, E); } catch (Exception ex) {бросить новое DerminatedRetryException («Не может зарегистрировать бросание», Ex); } наконец {doonerrorInterceptors (retrycallback, context, e); } if (canretry (retrypolicy, context) &&! context.isexhaustedonly ()) {try {backoffpolicy.backoff (backoffcontext); } catch (backOffUntrupruptException ex) {aStexception = e; // отступаемое отключение было предотвращено другим потоком - сбой в повторном случае if (this.logger.isdebugenabled ()) {this.logger .debug ("abort retry, потому что прерывание: count =" + context.getRetryCount ()); } бросить ex; }} if (this.logger.isdebugenabled ()) {this.logger.debug ("Проверка на rethrow: count =" + context.getRetryCount ()); } if (woodRethrow (retrypolicy, context, state)) {if (this.logger.isdebugenabled ()) {this.logger.debug ("rethrow in restry для политики: count =" + context.getRetryCount ()); } бросить retrytemplate. <e> rupifnecessary (e); }} / * * Попытка состояния, которая может повторно повторно, может пересмотреть исключение до сих пор, * но если мы заберем это далеко в состоянии повторного состояния, есть причина для него, как выключатель схемы или классификатор отката. */ if (state! = null && context.hasattribute (global_state)) {break; }} if (state == null && this.logger.isdebugenabled ()) {this.logger.debug ("Retry не удалась } истощенная = true; return handleretryexhausted (recordyCallback, контекст, состояние); } catch (throwable e) {throw retrytemplate. <e> warifnecessary (e); } наконец {close (retrypolicy, context, state, lastexception == null || DocloseInterceptors (Retrycallback, контекст, стойкость); Retrysynchronization manage.clear (); }}Реализуйте механизм повторения за какое -то время. Когда исключение происходит, когда выполняется повторный размер. Затем используйте повторную политику, чтобы определить, нужно ли повторно повторно. Обратите особое внимание на регистр метод Мало того, что он определяет, будет ли повторно повторно, но в случае повторной попытки будет выбрана новая машина и вставлена в контекст, и тогда она будет внесена при повторном повторном обращении.
Но почему моя конфигурация не изменила телефон? Код отладки обнаружил, что RegisterThable (Retrypolicy, состояние, контекст, E); Выбранная машина в порядке, это новая и здоровая машина, но при выполнении кода Retrycallback.dowithretry (контекст) он все еще запрашивается.
Итак, давайте внимательно рассмотрим код retrycallback.dowithretry (контекст):
Мы нашли эту строку кода:
newRequest = getseCureRequest (запрос, configoverride); Защищенная ленточная лентажахттпрекест GetseCureRequest (ribbonapachehtprequest запрос, iclientConfig configupride) {if (issecure (configoverride)) {final uri secureuri = uricomponentsbuilder.fromuri (request.geturi () .scheme ("htttps") return request.withnewuri (secureuri); } return запрос; }NewRequest был построен с использованием контекста в предыдущем примере. Запрос - это данные, запрошенные в прошлый раз. Пока вы выполняете этот код, вы обнаружите, что NewRequest всегда будет перезаписан запросом. Когда мы увидели это, мы узнали, что это была ошибка исходного кода.
Адрес выпуска: https://github.com/spring-cloud/spring-cloud-netflix/issues/2667
Суммировать
Это очень обычный процесс проверки проблем. Во время этого процесса, когда я обнаружил, что конфигурация не соответствовала моим ожиданиям, я сначала проверил значение конфигурации и пробовал ее много раз без успеха. Поэтому после отладки точки останова я обнаружил, что точка останова была ненормальной. Поскольку сцена требует, чтобы одна машина была здоровой, а одна машина была в автономном режиме, я смоделировал ее сотни раз, прежде чем наконец я обнаружил эту линию кода. Даже проект с открытым исходным кодом является отличным проектом, и он неизбежно будет иметь ошибки, а не суеверные или слепые. С другой стороны, возможность чтения исходного кода также является важной способностью решать проблемы. Например, я ищу входы исходного кода, и для поиска кода требуется много времени.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.