Недавно в одном из моих проектов я получил требование выполнить резервный вызов для сбойного вызова веб-сервиса. Чтобы реализовать то же самое, я искал некоторую реализацию шаблона автоматического выключателя и, наконец, наткнулся на библиотеку Netflix Hystrix, которая, по моему мнению, является наиболее подходящей библиотекой в соответствии с нашим приложением.
В этом посте я попытался продемонстрировать тонкий пример нашей проблемы и того, как Hystrix решила ту же проблему, используя один микросервис и клиент для доступа к ней вместе с Hystrix Dashboard. Прежде чем углубиться в кодирование, давайте вкратце разберемся, что такое Hystrix и как он работает внутри компании.
Что такое Hystrix?
Hystrix — это библиотека, которая помогает нам контролировать взаимодействие между распределенными сервисами, добавляя терпимость к задержкам и логику отказоустойчивости. Это достигается за счет изоляции точек доступа между службами, предотвращения каскадных сбоев между ними и предоставления альтернативных вариантов, которые улучшают общую отказоустойчивость нашей системы.
Он реализует схему автоматического выключателя, которая работает на переходах автоматического выключателя из положения ЗАКРЫТО в ОТКРЫТО, когда цепь соответствует указанному порогу, а процент ошибок превышает процент пороговой ошибки. Пока он разомкнут, он замыкает все запросы, сделанные на этот автоматический выключатель. Через некоторое время следующий единственный запрос пропускается (это состояние HALF-OPEN). Если запрос не выполняется, автоматический выключатель возвращается в состояние ОТКРЫТО на время ожидания. Если запрос выполняется успешно, автоматический выключатель переходит в состояние ЗАКРЫТО, и все запросы, сделанные к этому автоматическому выключателю, передаются службе. Больше вы можете изучить здесь .
Теперь давайте приступим к созданию микросервиса службы сотрудника, работающего на порте 8090 и клиенте для доступа к нему, а также панели мониторинга Hystrix, выполнив следующие шаги:
Шаг 1: Перейдите на start.spring.io и создайте новый проект employee-service, добавив веб-стартеры, на основе следующего изображения:
Шаг 2: Отредактируйте EmployeeServiceApplication.java, чтобы добавить метод, который возвращает список сотрудников, следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class EmployeeServiceApplication { public static void main(String[] args) { SpringApplication.run(EmployeeServiceApplication. class , args); } @RequestMapping (value = "/list" ) public String list() { return "Arpit, Sanjeev, Abhishek" ; } } |
Шаг 3: Измените application.properties, указав имя приложения и номер порта службы, следующим образом:
1
2
|
server.port= 8090 spring.application.name=employee-service |
Шаг 4: Перейдите в каталог employee-service и выполните команду: mvn spring-boot: run . После запуска откройте http: // localhost: 8090 / list .
Далее мы создадим hystrix-client, который получит доступ к нашему недавно созданному сервису employee и, если он не работает, вернет ответ от резервного метода.
Шаг 5: Перейдите на start.spring.io и создайте новый проект hystrix-client, добавив стартеры Web, Hystrix и Actuator, на основе следующего изображения:
Шаг 6: Отредактируйте HystrixClientApplication.java, чтобы добавить метод, который вызывает employee-service для получения ответа, и если служба недоступна или недоступна по какой-либо причине, возвращает ответ от резервного метода, как показано ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import com.test.service.IEmployeeService; @EnableHystrix @EnableCircuitBreaker @SpringBootApplication @RestController @ComponentScan (basePackages = { "com.test.service" }) public class HystrixClientApplication { @Autowired private IEmployeeService employeeService; public static void main(String[] args) { SpringApplication.run(HystrixClientApplication. class , args); } @RequestMapping ( "/list" ) public String list() { return employeeService.list(); } static class ApplicationConfig extends WebMvcConfigurerAdapter { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } } } |
Шаг 7. Создайте интерфейс IEmployeeService и его класс реализации EmployeeServiceImpl в пакете com.test.service и измените их следующим образом:
IEmployeeService.java
1
2
3
4
5
|
package com.test.service; public interface IEmployeeService { String list(); } |
EmployeeServiceImpl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package com.test.service.impl; import java.net.URI; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.test.service.IEmployeeService; @Service public class EmployeeServiceImpl implements IEmployeeService { @Value ( "#{'${employee.service.url}'}" ) private String employeeServiceUrl; @HystrixCommand (commandProperties = { @HystrixProperty (name = "execution.isolation.strategy" , value = "THREAD" ), @HystrixProperty (name = "execution.timeout.enabled" , value = "true" ), @HystrixProperty (name = "execution.isolation.thread.timeoutInMilliseconds" , value = "500" ), @HystrixProperty (name = "execution.isolation.thread.interruptOnTimeout" , value = "true" ), @HystrixProperty (name = "fallback.enabled" , value = "true" ), @HystrixProperty (name = "circuitBreaker.enabled" , value = "true" ), @HystrixProperty (name = "circuitBreaker.requestVolumeThreshold" , value = "10" ), @HystrixProperty (name = "circuitBreaker.sleepWindowInMilliseconds" , value = "1000" ), @HystrixProperty (name = "circuitBreaker.errorThresholdPercentage" , value = "10" ), @HystrixProperty (name = "circuitBreaker.forceOpen" , value = "false" ), @HystrixProperty (name = "circuitBreaker.forceClosed" , value = "false" ) }, fallbackMethod = "fallback" , commandKey = "list" , groupKey = "EmployeeServiceImpl" , threadPoolKey = "thread-pool-employee-service" , threadPoolProperties = { @HystrixProperty (name = "coreSize" , value = "5" ) }, ignoreExceptions = { IllegalAccessException. class }) public String list() { RestTemplate restTemplate = new RestTemplate(); URI uri = URI.create(employeeServiceUrl + "/list" ); return restTemplate.getForObject(uri, String. class ); } public String fallback() { return "Fallback call, seems employee service is down" ; } } |
@HystrixCommand, указанное выше, используется для переноса кода, который будет выполнять потенциально опасную функциональность с отказоустойчивостью и задержкой, захватом статистики и метрик производительности, прерывателем цепи и переборкой.
@HystrixProperty, указанное выше, используется для управления поведением HystrixCommand. Все доступные варианты перечислены здесь .
Шаг 8. Отредактируйте файл application.properties, чтобы указать порт приложения, на котором должен работать Hystrix-клиент , и URL-адрес, по которому доступен сервис-сотрудник , следующим образом:
1
2
|
server.port= 8080 employee.service.url=http: //localhost:8090 |
Шаг 9: Перейдите в каталог hystrix-client и выполните команду: mvn spring-boot: run . После запуска откройте http: // localhost: 8080 / list .
Hystrix работает?
Завершите приложение сотрудника службы . Должно быть замечено аварийное сообщение: аварийный вызов, кажется, служба работника не работает .
Затем мы создадим Hystrix Dashboard, который предоставит нам графическое представление запросов об успехе и сбоях, состояния канала, состояния хоста, кластера и пула потоков приложения.
Шаг 10: Перейдите на start.spring.io и создайте новый проект hystrix-dashboard, добавив стартеры Hystrix Dashboard. После создания отредактируйте HystrixDashboardApplication.java следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
|
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class HystrixDashboardApplication { public static void main(String[] args) { SpringApplication.run(HystrixDashboardApplication. class , args); } } |
Шаг 11: Измените application.properties, чтобы указать порт приложения, на котором должна работать Hystrix-Dashboard , следующим образом:
1
|
server.port= 8383 |
Шаг 12: Перейдите в каталог hystrix-dashboard и выполните команду: mvn spring-boot: run . После запуска откройте http: // localhost: 8383 / hystrix и введите http: // localhost: 8080 / hystrix.stream в текстовом поле потока и нажмите Monitor Stream . Как только панель инструментов будет загружена, мы увидим изображение, похожее на приведенное ниже:
Полный исходный код размещен на github .
Ссылка: | Устойчивость к сбоям и задержкам микросервисов с использованием Netflix Hystrix от нашего партнера JCG |