микросервисы go-kit: простой шлюз API

Микросервисы
микросервисы go-kit: простой шлюз API

Обзор

в предыдущей статье«Микросервисы go-kit: регистрация и обнаружение сервисов»В , арифметическая служба зарегистрирована в консуле, а служба обнаружения использует набор инструментов go-kit для реализации функции обнаружения арифметической службы. Посмотрев исходный код, можно обнаружить, что реализован только один интерфейс./calculate, а если интерфейсов для арифметических сервисов много?

Эта проблема беспокоит меня последние несколько дней, я думаю, что go-kit даст разумное решение, но я его не нашел.sd.FactoryЯ до сих пор не понимаю конструкции .

Чтобы решить эту проблему, я решил найти другой способ: динамически запрашивать экземпляр службы реестра по клиентскому HTTP-запросу, а вызов фоновой службы реализовать через реверс-прокси.

Это эквивалентно реализации простого шлюза, и все запросы, соответствующие правилам, могут вызывать серверные службы через этот шлюз. Правило здесь относится к пути к ресурсу HTTP-запроса./{serviceName}/#. То есть: первая часть пути — это имя экземпляра службы реестра, а остальная часть — путь REST экземпляра службы. как:

/arithmetic/calculate/Add/10/2
  • arithmeticдля имени службы;
  • /calculate/Add/10/2Интерфейс для арифметических сервисов.

внедрить шлюз

Шаг 1: Идеи реализации

Клиент инициирует запрос к шлюзу, шлюз анализирует информацию в пути к ресурсу запроса, запрашивает экземпляр службы реестра в соответствии с именем службы, а затем использует технологию обратного прокси-сервера для пересылки запроса клиента в реальный экземпляр службы. на серверной части, а затем верните ответную информацию клиенту.

网关实现思路

  • Правила для HTTP-запросов следующие:/{serviceName}/#, иначе он не будет одобрен.
  • Используйте обратный прокси-пакет, предоставленный golanghttputil.ReverseProxyРеализуйте простой обратный прокси-сервер, который может распределять нагрузку по запросам и случайным образом отправлять запросы экземплярам службы.
  • Используйте API-интерфейс клиента консула для динамического запроса экземпляров службы.

Шаг 2: Напишите метод обратного прокси

существуетarithmetic_consul_demoСоздайте каталог подgateway, а затем создайте новый файл gomain.go. Метод NewReverseProxy принимает два параметра: клиентский объект консула и средство ведения журнала, которое возвращает объект обратного прокси. Реализация этого метода заключается в следующем:

  • Получить путь запроса, проверить, соответствует ли он правилам, и вернуться напрямую, если он не соответствует правилам;
  • Разобрать путь запроса и получить имя службы (первая часть — это имя службы);
  • Используйте клиент консула для запроса экземпляра службы, и если результат запроса найден, он случайным образом выбирается в качестве целевого экземпляра;
  • В зависимости от выбранного целевого экземпляра задайте параметры обратного прокси:Schema,Host,Path.

Полный код выглядит следующим образом:

// NewReverseProxy 创建反向代理处理方法
func NewReverseProxy(client *api.Client, logger log.Logger) *httputil.ReverseProxy {

	//创建Director
	director := func(req *http.Request) {

		//查询原始请求路径,如:/arithmetic/calculate/10/5
		reqPath := req.URL.Path
		if reqPath == "" {
			return
		}
		//按照分隔符'/'对路径进行分解,获取服务名称serviceName
		pathArray := strings.Split(reqPath, "/")
		serviceName := pathArray[1]

		//调用consul api查询serviceName的服务实例列表
		result, _, err := client.Catalog().Service(serviceName, "", nil)
		if err != nil {
			logger.Log("ReverseProxy failed", "query service instace error", err.Error())
			return
		}

		if len(result) == 0 {
			logger.Log("ReverseProxy failed", "no such service instance", serviceName)
			return
		}

		//重新组织请求路径,去掉服务名称部分
		destPath := strings.Join(pathArray[2:], "/")

		//随机选择一个服务实例
		tgt := result[rand.Int()%len(result)]
		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
	}
	return &httputil.ReverseProxy{Director: director}

}

Шаг 3: Напишите основной метод

Основная задача метода main — создать объект подключения к консулу, создать объект логирования и запустить HTTP-сервис обратного прокси. Весь процесс аналогичен предыдущим примерам, вставляем код напрямую (для удобства тестирования прямо указываю адресную информацию консул-сервиса):

func main() {

	// 创建环境变量
	var (
		consulHost = flag.String("consul.host", "192.168.192.146", "consul server ip address")
		consulPort = flag.String("consul.port", "8500", "consul server port")
	)
	flag.Parse()

	//创建日志组件
	var logger log.Logger
	{
		logger = log.NewLogfmtLogger(os.Stderr)
		logger = log.With(logger, "ts", log.DefaultTimestampUTC)
		logger = log.With(logger, "caller", log.DefaultCaller)
	}

	// 创建consul api客户端
	consulConfig := api.DefaultConfig()
	consulConfig.Address = "http://" + *consulHost + ":" + *consulPort
	consulClient, err := api.NewClient(consulConfig)
	if err != nil {
		logger.Log("err", err)
		os.Exit(1)
	}

	//创建反向代理
	proxy := NewReverseProxy(consulClient, logger)

	errc := make(chan error)
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		errc <- fmt.Errorf("%s", <-c)
	}()

	//开始监听
	go func() {
		logger.Log("transport", "HTTP", "addr", "9090")
		errc <- http.ListenAndServe(":9090", proxy)
	}()

	// 开始运行,等待结束
	logger.Log("exit", <-errc)
}

Шаг 4: Запустите

  1. Запустите консул с докером. Терминал переключается наarithmetic_consul_demoдиректории выполните следующую команду:
sudo docker-compose -f docker/docker-compose.yml up
  1. Запустите службу арифметических операций. Чтобы проверить эффект балансировки нагрузки, я запустил два экземпляра.Обратите внимание на необходимость использования другого порта
./register/register -consul.host localhost -consul.port 8500 -service.host 192.168.192.146 -service.port 9000

./register/register -consul.host localhost -consul.port 8500 -service.host 192.168.192.146 -service.port 9002
  1. Введите в браузереhttp://localhost:8500видимыйarithmeticЕсть два примера, как показано ниже:

服务实例

  1. cd в каталог в терминалеgateway,воплощать в жизньgo buildЗавершите компиляцию, затем запустите службу шлюза.
> ./gateway -consul.host localhost -consul.port 8500

> ts=2019-02-26T07:49:39.0468058Z caller=main.go:54 transport=HTTP addr=9090

Шаг 5: Тест

Используйте postman для выполнения теста запроса, как показано ниже, и вы обнаружите, что вызов службы прошел успешно.

Postman测试

В то же время вы можете увидеть следующий вывод на терминале, указывающий на то, что несколько запросов обращались к разным экземплярам службы:

ts=2019-02-26T07:49:39.0468058Z caller=main.go:54 transport=HTTP addr=9090
ts=2019-02-26T07:49:46.8559985Z caller=main.go:94 serviceid=arithmetic82460623-ccdc-4192-a042-c0603ef18888
ts=2019-02-26T07:50:00.1249302Z caller=main.go:94 serviceid=arithmetic65153818-27b3-4f19-8fd1-d7d698168f20
ts=2019-02-26T09:04:09.0470362Z caller=main.go:94 serviceid=arithmetic65153818-27b3-4f19-8fd1-d7d698168f20
ts=2019-02-26T09:04:10.176327Z caller=main.go:94 serviceid=arithmetic65153818-27b3-4f19-8fd1-d7d698168f20

Суммировать

В этой статье используется технология обратного прокси-сервера в сочетании с консулом реестра для реализации простого шлюза API. Поскольку golang предоставляет набор инструментов обратного прокси, весь процесс реализации относительно прост. Продукты, используемые в реальных проектах, такие как Zuul, Nginx и т. д., также включают в себя такие функции, как ограничение тока, фильтрация запросов и аутентификация личности. Шлюз реализует только прокси запроса, и основное внимание уделяется пониманию его внутреннего процесса и углублению понимания.

Ссылка в этой статье

Эта статья была впервые опубликована в моей публичной учетной записи WeChat [Xi Yiang Bar], пожалуйста, отсканируйте код, чтобы следовать!