Недавно в одном из моих проектов я получил требование выполнить резервный вызов для сбойного вызова веб-сервиса. Чтобы реализовать то же самое, я искал некоторую реализацию шаблона автоматического выключателя и, наконец, наткнулся на библиотеку 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@RestControllerpublic 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=8090spring.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 {@Autowiredprivate 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;@Servicepublic 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=8080employee.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@EnableHystrixDashboardpublic 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 |


