В микросервисной архитектуре одна служба делится на несколько микрослужб. Службе обычно необходимо вызывать (в сетевом режиме) несколько служб для выполнения ожидаемой функции. Стабильность службы ограничивается общей стабильностью других служб. В случае сбоя службы потребитель службы не сможет нормально работать, а воздействие будет постепенно усиливаться и даже приводить к краху всего кластера службы, что является лавинным эффектом службы.
Чтобы предотвратить лавинное обслуживание, персонал отдела исследований и разработок внедрил такие методы, как управление потоком, улучшенный кэш, автоматическое расширение службы, снижение качества обслуживания и автоматический выключатель. В этой статье будет представлен сервисный предохранитель и использование go-kit+Hystrix для реализации решения для предохранителей для микросервисов.
Сервисный предохранитель
Автоматический выключатель службы означает, что когда вызывающий абонент обнаруживает, что поставщик услуг медленно отвечает или недоступен, вызывающий абонент напрямую не может защитить себя и больше не вызывает целевую службу. С учетом возможного восстановления поставщика услуг попытки доступа будут предприняты через некоторое время. По сути, это применение «шаблона автоматического выключателя», который объясняется в специальной статье Мартина Фаулера. Это показано на следующей диаграмме состояний выключателя автоматического выключателя:
- Закрытое начальное состояние, если запрос был успешным, остается Закрытое состояние; количество отказов не истекает, если установлен порог, останется Закрытое состояние; если количество отказов достигает заданного порога, состояние переключается на Открыто.
- В состоянии Open вызывающий объект больше не вызывает целевую службу и возвращается непосредственно в случае сбоя. Если достигнуто заданное время повтора, состояние переключается на Half Open, что позволяет попробовать некоторые запросы. Если попытка успешна, он переходит в состояние «Закрыто», а в случае неудачи — в состояние «Открыто».
Для прерывания обслуживания наиболее часто используемым Hystrix в отрасли является выход Netflix, который обеспечивает удобство для микросервисов, созданных Spring Cloud. Следующее цитируется из официального введения в Hystrix:
Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.
Hystrix — это отказоустойчивая и отказоустойчивая библиотека, предназначенная для изоляции точек доступа к удаленным системам, службам и сторонним библиотекам, предотвращения каскадных сбоев и обеспечения отказоустойчивости в сложных распределенных системах, где сбои неизбежны.
В этом примере будет использоваться версия Hystrix для языка go.afex/hystrix-go
Осуществить обслуживание предохранителей управления.
Практическая тренировка
Этот пример основан на изменениях arithmetic_trace_demo, вgateway
Добавьте стратегию управления сервисным автоматическим выключателем вregister
Помимо временного добавления некоторого кода имитации неисправности, никаких других изменений не производится.
Шаг 0: Подготовка кода
Скопируйте каталог arithmetic_trace_demo и переименуйте его в arithmetic_circuitbreaker_demo.
Загрузите зависимости go, необходимые для этого примера:
go get github.com/afex/hystrix-go
Измените docker/docker-compose.yml и добавьте экземпляр hystrix-dashboard следующим образом:
version: '2'
consul:
image: progrium/consul:latest
ports:
- 8400:8400
- 8500:8500
- 8600:53/udp
hostname: consulserver
command: -server -bootstrap -ui-dir /ui
zipkin:
image: openzipkin/zipkin
ports:
- 9411:9411
hystrix:
image: mlabouardy/hystrix-dashboard:latest
ports:
- 8181:9002
Шаг 2: Добавьте gateway/router.go
Прежде чем мы начнем, кратко расскажем о командном режиме hystrix-go, который обеспечиваетDo
Метод выполняет бизнес-логику пользователя в асинхронном режиме и будет заблокирован до тех пор, пока выполнение не завершится успешно или не произойдет ошибка, и определяется следующим образом:
func Do(name string, run runFunc, fallback fallbackFunc) error
- name: имя выполняемой команды, обычно устанавливаемое на имя запроса или имя службы.
- run: метод бизнес-логики, который инкапсулирует логику вызова поставщика услуг в этом методе.
- резервный вариант: метод обратного вызова при возникновении ошибки во время процесса выполнения, обычно инкапсулирующий информацию об ошибке.
Чтобы завершить вызов hystrix-go, я инкапсулировал логику исходного обратного прокси в метод Do и реализовал ServeHTTP через тип HystrixRouter, который инкапсулирует логику отслеживания ссылок и обнаружения сервисов (Это просто для демонстрации).
HystrixRouter
Ниже приведены методы определения и создания, в основном инкапсулирующие отслеживание ссылок и обнаружение служб.
// HystrixRouter hystrix路由
type HystrixRouter struct {
svcMap *sync.Map //服务实例,存储已经通过hystrix监控服务列表
logger log.Logger //日志工具
fallbackMsg string //回调消息
consulClient *api.Client //consul客户端对象
tracer *zipkin.Tracer //服务追踪对象
}
func Routes(client *api.Client, zikkinTracer *zipkin.Tracer, fbMsg string, logger log.Logger) http.Handler {
return HystrixRouter{
svcMap: &sync.Map{},
logger: logger,
fallbackMsg: fbMsg,
consulClient: client,
tracer: zikkinTracer,
}
}
Следующая основная логика будет реализована в ServeHTTP, основные идеи таковы:
- Разберите имя сервиса в пути запроса и проверьте, не добавлен ли он в мониторинг Hystrix: если нет, настройте информацию и кэшируйте ее в списке сервисов, если да, то пропустите.
- Инкапсулируйте логику обнаружения служб, обратного управления и отслеживания ссылок в методе Do. В случае сбоя обнаружения службы возвращается сообщение об ошибке, в случае сбоя обратного прокси возвращается сообщение об ошибке (здесь добавлен метод обратного вызова для ошибок обратного прокси);
Подробный код выглядит следующим образом, что можно понять по комментариям:
func (router HystrixRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//查询原始请求路径,如:/arithmetic/calculate/10/5
reqPath := r.URL.Path
if reqPath == "" {
return
}
//按照分隔符'/'对路径进行分解,获取服务名称serviceName
pathArray := strings.Split(reqPath, "/")
serviceName := pathArray[1]
//检查是否已经加入监控
if _, ok := router.svcMap.Load(serviceName); !ok {
//把serviceName作为命令对象,设置参数
hystrix.ConfigureCommand(serviceName, hystrix.CommandConfig{Timeout: 1000})
router.svcMap.Store(serviceName, serviceName)
}
//执行命令
err := hystrix.Do(serviceName, func() (err error) {
//调用consul api查询serviceNam
result, _, err := router.consulClient.Catalog().Service(serviceName, "", nil)
if err != nil {
router.logger.Log("ReverseProxy failed", "query service instace error", err.Error())
return
}
if len(result) == 0 {
router.logger.Log("ReverseProxy failed", "no such service instance", serviceName)
return errors.New("no such service instance")
}
director := func(req *http.Request) {
//重新组织请求路径,去掉服务名称部分
destPath := strings.Join(pathArray[2:], "/")
//随机选择一个服务实例
tgt := result[rand.Int()%len(result)]
router.logger.Log("service id", tgt.ServiceID)
//设置代理服务地址信息
req.URL.Scheme = "http"
req.URL.Host = fmt.Sprintf("%s:%d", tgt.ServiceAddress, tgt.ServicePort)
req.URL.Path = "/" + destPath
}
var proxyError error = nil
// 为反向代理增加追踪逻辑,使用如下RoundTrip代替默认Transport
roundTrip, _ := zipkinhttpsvr.NewTransport(router.tracer, zipkinhttpsvr.TransportTrace(true))
//反向代理失败时错误处理
errorHandler := func(ew http.ResponseWriter, er *http.Request, err error) {
proxyError = err
}
proxy := &httputil.ReverseProxy{
Director: director,
Transport: roundTrip,
ErrorHandler: errorHandler,
}
proxy.ServeHTTP(w, r)
return proxyError
}, func(err error) error {
//run执行失败,返回fallback信息
router.logger.Log("fallback error description", err.Error())
return errors.New(router.fallbackMsg)
})
// Do方法执行失败,响应错误信息
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
}
}
Шаг 3: Изменить шлюз/main.go
Сначала создайте объект hystrixRouter и передайте параметры в соответствии со списком параметров метода, а затем оберните возвращаемое значение промежуточным программным обеспечением службы zipkin.
hystrixRouter := Routes(consulClient, zipkinTracer, "Circuit Breaker:Service unavailable", logger)
handler := zipkinhttpsvr.NewServerMiddleware(
zipkinTracer,
zipkinhttpsvr.SpanName("gateway"),
zipkinhttpsvr.TagResponseSize(true),
zipkinhttpsvr.ServerTags(tags),
)(hystrixRouter)
чтобы пройтиhystrix-dashboard
Для мониторинга службы необходимо включить службу мониторинга hystrix в режиме реального времени.Код выглядит следующим образом:
//启用hystrix实时监控,监听端口为9010
hystrixStreamHandler := hystrix.NewStreamHandler()
hystrixStreamHandler.Start()
go func() {
errc <- http.ListenAndServe(net.JoinHostPort("", "9010"), hystrixStreamHandler)
}()
Ну, код шлюза изменен.
Шаг 4: Запустите и протестируйте
бегать
Запустите докер, зарегистрируйтесь, шлюз по очереди, а затем используйте инструмент почтальона Runner для тестирования.
#启动consul、zipkin、hystrix-dashboard
sudo docker-compose -f docker/docker-compose.yml up
./register/register -consul.host localhost -consul.port 8500 -service.host 192.168.192.146 -service.port 9000
./gateway/gateway -consul.host localhost -consul.port 8500
В Postman добавляется новая коллекция с именем Circuitbreaker и создается новый почтовый запрос. Откройте Runner (верхний левый угол), выберите только что созданную коллекцию, установите временной интервал на 100 миллисекунд и количество итераций на 1000 (временно не выполняется). Как показано ниже:
Откройте браузер и введитеhttp://localhost:8181/hystrix
, введите адрес мониторинга hystrix в поле вводаhttp://192.168.192.146:9010
(Здесь необходимо настроить адрес хоста), а затем начать мониторинг, как показано ниже:
Подготовка завершена, приступаем к испытаниям.
контрольная работа
Нажмите кнопку «Запустить прерывание цепи» в интерфейсе Runner Postman, а затем просмотрите панель мониторинга Hysytrix, вы увидите следующий интерфейс, состояние автоматического выключателяClosed
:
Затем закройте сервис регистрации (остановка прямо в терминале, что удобно для быстрого старта ниже). Вы обнаружите, что состояние автоматического выключателя вскоре изменится наOpen
:
Перезапустите службу регистрации, и состояние автоматического выключателя будет восстановлено доClosed
:
анализировать
Параметры, установленные Hystrix по умолчанию:
- DefaultErrorPercentThreshold = 50: когда частота отказов запросов достигает 50 %, прерыватель цепи переключается в открытое состояние.
- DefaultTimeout = 1000: запросы, превышающие это время, считаются исключениями службы. То, что я установил в коде, также равно 1 секунде.
- DefaultSleepWindow = 5000: В состоянии Open повторная попытка выполняется каждые 5 секунд.
Изначально служба реестра нормальная, все запросы выполняются плавно, поэтому находится в состоянии Closed, при закрытии реестра (симуляция сбоя), когда количество невыполненных запросов достигает установленного порога, он переходит в состояние Open ; после восстановления службы, когда Hystrix достигает времени повторной попытки, служба восстановлена.
Суммировать
В этой статье hystrix-go используется для обслуживания шлюза в комплекте.gateway
Добавлена схема управления автоматическим выключателем службы, имитирующая службу регистрации из «нормального восстановления после сбоя» вhystrix-dashboard
Наблюдается изменение состояния выключателя.
В фактическом процессе разработки, из-за сложных зависимостей между службами, очень необходимо добавить к нашим службам меры управления предохранителями служб, чтобы обеспечить своевременную остановку убытков и предотвратить сбой одной зависимой службы, который повлияет на все бизнес-линии. Эта статья является лишь введением в сервисный предохранитель, и необходимы дальнейшие исследования предохранителя Hystrix и механизма перехода на более раннюю версию.
Ссылка в этой статье
- Код для этой статьи @github
- Hystrix
- hystrix-go
- CircuitBreaker
- Перевод официальных документов Hystrix
Эта статья была впервые опубликована в моей публичной учетной записи WeChat [Xi Yiang Bar], пожалуйста, отсканируйте код, чтобы следовать!