Микросервис на Golang

imageСреди беспорядка найдите простоту; среди раздора найдите гармонию; в трудности найдите возможность…
© Альберт Эйнштейн

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

В последнее время мне довелось поработать над созданием микросервисов на языке Golang. Это был интересный опыт. Однако во многом получается (по крайней мере у меня), что каждый раз новый микросервис создаётся заново и с нуля. Конечно, можно использовать предыдущие наработки, но в таком подходе нет некоей системности, и мне захотелось сделать инструмент, который бы несколько упорядочил такую работу (искренне на это надеюсь). Не сомневаюсь, это не единственная идея в разработке микросервисов, но если вы ими интересуетесь, возможно, вам будет интересно прочитать данную статью.

Что такое микросервис, я думаю, во избежание холивара, тут не стоит говорить. Также и о достоинствах и недостатках промолчим. Отмечу лишь, что они есть, и именно благодаря наличию оных микросервисная архитектура востребована.

Архитектура микросервиса в моей библиотеке включает в себя хэндлер, тюнер (конфигуратор), очередь, пару демонстрационных middleware и хранилище для них. Работает всё очень просто: в приложении загружается конфигурация с учётом файла конфигурации, окружения и командной строки. Создаётся хранилище с middleware и под нужные роуты формируются соответствующие очереди. Далее запускается сервер и по запросу приложение отрабатывает нужные очереди.

Тюнер


Важным моментом для микросервиса является загрузка конфигурации. Я постарался сделать этот функционал максимально гибким. По умолчанию конфигурация загружается из указанного файла (`config.toml`). Адрес файла конфигурации можно изменить из командной строки, например так: вашсервис -confile config.toml Таким образом можно создать несколько разных конфигурационных файла и запускать микросервис с одной из конфигураций по выбору.

Поскольку в конфигурировании микросервиса задействован не только файл, но и переменные окружения и параметры командной строки, то уточню порядок и приоритетность конфигурирования. Самым низким приоритетом обладает конфигурация из файла. Если в операционной системе настроены переменные окружения, то они имеют более высокий приоритет, чем переменные из конфигурационного файла. Параметры командной строки имеют самый важный приоритет. Для изменения параметра в командной строке нужно указывать его название в виде названии раздела и названия параметра (с прописной буквы!). Вот пример изменения порта — вашсервис -Main/Port 85

5dc753b79800f1b1df184ee5cab36b26.jpgЕщё немного о конфигурировании: помимо варианта с закидыванием конфигурации в заранее заготовленную структуру, вполне можно было бы использовать вариант импорта данных в обычный map, и потом спокойно использовать значения по ключу. У этого способа есть несомненное достоинство — не нужно добавляя данные в конфигурационный файл дублировать это в конфигурационной структуре. Т.е. всё проще и быстрее. Минусом же будет то, что ошибки неправильного указания ключа переносятся с этапа компиляции на этап выполнения, и кроме того, тут IDE уже не станет нам делать подсказки, что кстати, само по себе очень хорошо в плане защиты от опечаток и как следствие — ошибок.

Storage


На самом деле, хранилище middleware объектов Storage никак не обязательно для использования в микросервисе, и я не пытался реализовать что-нибудь из того, что часто связывают с DI. Тут скорее субъективное удобство создания и инициализации структур в одном месте. Кроме того, благодаря хранилищу IDE любезно подсказывает названия структур и их экспортируемых методов.

Middleware


Чтобы не засорять пространство хэндлеров, в микросервисе предусмотрено использование сервисного функционала в стиле middleware. К каждому такому сервису предъявляются минимальные требования: он должен принимать в качестве аргументов http.ResponseWriter, *http.Request и возвращать их. В дистрибутиве продемонстрирован пример с подключением метрики перед и после хэндлера для фиксации времени обработки запроса (duration).

a631b4844e64adcfec36adb94d4b5d5d.pngВ зависимости от того, какие задачи решаются микросервисом и в каком окружении он это делает, почти наверняка вам потребуются и другие сервисы, например валидация. Рассмотрите для них возможность подключения к хэндлеру в качестве middleware. И обратите внимание, что демонстрационные метрики и сессия вынесены в отдельный подкаталог, чтобы подчеркнуть дистанцию между микросервисом и используемыми в нём middleware.

Очередь


Эта сущность такая же простая, как и всё остальное. Она просто хранит список функций (хэндлера и мидлвар), и когда надо, запускает их на исполнение методом Run. При этом, если какой-то из методов возвратит nil вместо *http.Request, очередь прекращает выполнение (например это мог бы сделать валидатор, ну или контролёр доступа).

Handler


В дистрибутиве handler содержит в себе совсем мало кода и занимается в общем тем, что создаёт и возвращает очередь выполнения queue. Однако именно методы handler и являются теми хэндлерами, которые обработают поступивший запрос, всё остальное по сути обвес микросервиса. Если это так, то почему бы не сделать просто кучу автономных функций, которые и будет вызывать роутер? На это есть причина: благодаря объединению посредством структуры хэндлеры-методы теперь смогут иметь доступ (если потребуется) к полям структуры (общему контексту приложения). На самом деле очень удобно для каждого публичного метода (читай — обработчика) создать отдельный файл, например handle_hello_word.go, что впрочем не мешает организовать всё каким угодно другим образом.

Алгоритм работы с микросервисом


Создание нового Middleware


К примеру вы хотите добавить валидатор в качестве middleware. В этом случае сначала в файле конфигурации config.toml добавляете раздел и в нём нужные параметры. Например так:
[Validation]
Number	= "integer"

Теперь создаёте соответствующую структуру (например ConfValidation) в файле config.go и добавляете её там же в структуру Config. Далее в storage добавляете создание валидатора, и после этого его можно использовать при формировании очереди в main.go

Создание нового хэндлера


Для этого нужно просто создать новый публичный метод в handler, который на вход принимает http.ResponseWriter, *http.Request и возвращает их. Посмотрите созданный для демонстрации метод HelloWorld.

Perfomance


16a312c9964285aec2b465a322a428a8.png Для общего понимания того, что скорость работы микросервиса при использовании предложенной архитектуры будет достаточно высокой, приведу результаты бенчмарка, полученные мной на моём компьютере IntelCore i3–2120:
  • BenchmarkMain-4 5000000 261 ns/op
  • BenchmarkMainParallel-4 10000000 137 ns/op

Зависимости


  • Логер github.com/Sirupsen/logrus
  • Сессии github.com/gorilla/sessions
  • Роутер github.com/claygod/Bxog
  • Конфиг github.com/BurntSushi/toml

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

Заключение


Библиотека Microservice не претендует на лавры единственно верного решения, но при случае, надеюсь, сможет помочь вам сформировать архитектуру собственного микросервиса, став прототипом будущего приложения.

Ссылки


  • Библиотека github.com/claygod/microservice
  • Документация godoc.org/github.com/claygod/temp/microservice-doc
  • Report goreportcard.com/report/github.com/claygod/microservice

Комментарии (5)

  • 29 декабря 2016 в 17:00

    0

    Look at my horse, my horse is amazing! : D

  • 29 декабря 2016 в 17:19

    0

    , а как же авторизация?
    • 29 декабря 2016 в 19:04

      0

      Для авторизации как раз-таки стоит сделать отдельный микросервис
  • 29 декабря 2016 в 17:29 (комментарий был изменён)

    –4

    Но черно-белой картинке глаза на вульгарные сиси похожи, особенно в профиль.
  • 29 декабря 2016 в 19:28 (комментарий был изменён)

    +1

    Это клево. Наверное. Если б хоть чего-нибудь понял — обязательно был бы более уверен!

    Автор! Нет бы хоть в общих чертах объяснить, для проходящих мимо. И примерчиков бы приложил пару штук! Не тут, так хоть в доках или на гитхабе.

    Иначе в массы не пойдет!
    ЗЫ. А вот роутер интересный, попробую на досуге, thanks.

© Habrahabr.ru