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

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

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

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

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

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

    Тюнер


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

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

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

    Middleware


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

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

    Handler


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

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


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

    Perfomance


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

    • BenchmarkMain-2 10000000 195 ns/op
    • BenchmarkMainParallel-2 10000000 107 ns/op


    Зависимости



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

    Заключение


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

    Ссылки




    UPD


    С учётом комментариев немного изменил библиотечку, удалив хранилище и подправив метод организации мидлваре (без очередей), что кстати, даже немного ускорило работу приложения в бенче.

    Only registered users can participate in poll. Log in, please.

    Используете ли вы микросервисную архитектуру?

    • 44.5%Да, использую121
    • 43.8%Нет, но собираюсь119
    • 11.8%Нет, и не буду32
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 27

      +6

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

        0
        а как же авторизация?
          0
          Для авторизации как раз-таки стоит сделать отдельный микросервис
          –10
          Но черно-белой картинке глаза на вульгарные сиси похожи, особенно в профиль.
            +2
            Это клево. Наверное. Если б хоть чего-нибудь понял — обязательно был бы более уверен!

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

            Иначе в массы не пойдет!
            ЗЫ. А вот роутер интересный, попробую на досуге, thanks.
              –1
              mgremlin, дело в том, что описанная библиотека, она сразу же и пример. Т.е. если вы запустите её, то по адресу localhost увидите классический hello world.

              За хороший отзыв о роутере спасибо!
              +1
              Статья слишком сумбурна, чтобы применять ее в продакшене
                +1
                да и вообще «микросервис» здесь только в названии статьи. В самом коде нет ничего, что бы отличало его от простой заготовки веб-приложения.
                  –1
                  Микросервис и должен быть прост, или Вы считаете иначе?

                  Сам микросервис можно организовать как угодно, лишь бы давал правильные ответы, а я всего лишь предлагаю вариант. И если у Вас есть большой опыт создания микросервисов, то думаю, Вам не составит труда привести примеры и своё видение внутреннего строения микросервиса?
                    +1
                    Микросервис и должен быть прост, или Вы считаете иначе?
                    изначально он должен обладать единичной зоной ответственности

                    Вам не составит труда привести примеры и своё видение внутреннего строения микросервиса

                    я говорю, что в вашем «микросервисе» нет ничего, чтобы отличало его от любой заготовки любого веб-приложения. И я против, чтобы все, что создается на go и смотрящим в веб автоматически называлось микросервисом. Строго говоря, микросервис может быть веб-приложением, но может и не быть. Так же справедливо и обратное: не каждое веб-приложение — микросервис. Соответственно и создали вы болванку того, что может быть микросервисом, а может и не быть — каких-то отличительных особенностей в коде нет.
                    Добавьте сервис дискавери, сервисы по работе с апи/апи-шлюзом, балансировку, (g)rpc-клиент/сервер.
                    Фреймворки для создания микросервиса на го уже существуют — можете ознакомиться с фичами.
                      –1
                      Добавьте сервис дискавери, сервисы по работе с апи/апи-шлюзом, балансировку, (g)rpc-клиент/сервер.

                      Вы описываете микросервисную архитектуру, а не микросервис.
                        0
                        нет, я описываю фичи, которыми может и часто обладает единичный микросервис.
                          0
                          zelenin, если у вас всё это содержится в микросервисе, то он сам фактически содержит микросервисы. Обратите внимание, Вы сами пишете слово `сервисы` во множественном числе.
                            0
                            я использую слово «сервисы» в другом контексте. Апи-клиент или клиент для сервис-дискавери являются сервисами приложения.
                              0
                              Если сравнивать Ваше и моё видение микросервиса, то похоже, что Вы делаете микросервисы более «жирными». В принципе, если их ответственность при этом мала и неделима, это тоже вполне рабочий вариант. Мне кажется, я понимаю Вашу точку зрения. Если не затруднит, поглядите сделанный мной для фана ММОА.
                                +1
                                все не так. я лишь сказал, что вы сделали не заготовку под микросервис, а заготовку под веб-приложение. Оно может быть как приложением, отдающим данные по api, так и блогом. Но вы почему-то назвали это модным словом «микросервис», хотя для такой более узкой специализации у болванки нет никаких специализированных фич (не факт что они все и нужны в конкретном микросервисе).
                                Обсуждение исчерпало себя.
                +3
                Удивительно непонятное описание продукта, просто исключительно странное. Даже мое понимание области в которой автор копает, не вносит ясности. Термины используется так, как я нигде не видел. Видимо очередь это не очередь а конвейер? И что за storage, для чего, куда и почему его основное достоинство это авто–дополнение в IDE? Хотя, похоже и storage это не то, что все под этим понимают, т.к. в нем автор предлагает хранить (?) middleware про которое я тоже уже не уверен, что это такое у автора и зачем его там хранить.

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

                Я не для придирок или прочих издевательств, но в попытке понять о чем это было вообще и как оно относится к микросервисам в частности.

                  0
                  Видимо очередь это не очередь а конвейер?

                  Наверно для меня эти термины близки. Какую Вы принципиальную разницу вкладываете в эти два термина?

                  middleware про которое я тоже уже не уверен, что это такое у автора и зачем его там хранить

                  В моём понимании это промежуточное программное обеспечение. В библиотеке для примера это метрики, которые находятся «снаружи» микросервиса.

                  И что за storage, для чего...

                  Это простое хранилище объектов, оно только для удобства, чтобы инициализировать миддлваре объекты в одном месте.

                  авто–дополнение в IDE

                  Ну… это просто удобно, по крайней мере мне.

                  но на иностранном языке, который немного похож на английский, но точно не он.

                  Тут не в бровь, а в глаз, ибо учил я немецкий вперемежку с французским, так что транслятор, это наше всё… :(

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

                    Для термина middleware в го мире есть довольно четкое соглашение, что это такое, и что люди под этим подразумевают, особенно в контексте http обработок. Например вот это https://github.com/pressly/chi/tree/master/middleware

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

                  Спасибо, я подумаю над этим, может быть изменю названия, и тогда естественно, поправлю и в статье.

                  Для термина middleware в го мире есть довольно четкое соглашение

                  Если Вам не трудно, сформулируйте здесь (не только для меня), и тогда уж… то, что я называю миддлваре, как в принципе это назвали бы Вы?

                  То, что там читать трудно, а понять — невозможно

                  Скорей всего сокращу до простых предложений, которые и транслятор сможет осилить (надеюсь).
                    +2
                    насколько я вижу, у тебя это тоже типа middlware, но с нестандартной сигнатурой func(http.ResponseWriter, *http.Request) (http.ResponseWriter, *http.Request). Если поменять на func(h http.Handler) http.Handler то станет как у всех, и самое главное — ты сможешь использовать все подобные, готовые middlware без всяких модификаций.

                    Общее замечание: в принципе, идея создания фреймоврка такого рода мнe кажется делом сомнительным. Во первых, есть неплохие и проверенные боем библиотеки, которые это уже делают основнию часть, например chi. Во вторых — идея добавления туда и конфигурации и еще чего мне не кажется полезной. Да, я понимаю, что при создании сервиса хочется упростить начальные телодвижения, однако лично я пошел по другому пути и написал простой кодо-генератор, который делает рабочий скелет приложения с chi, набором middlware для него (у меня в каждом сервисе надо определенный набор, например JWT), логгером, main с флагами и env (github.com/jessevdk/go-flag) перехватчик сигналов и еще по мелочи. Кроме того, оно генерит не только исходный текст, но и все, что надо для сборки и деплоя (Dockerfile, CI yml, ansible yml)
                      0

                      А планируете ли вы выкладывать этот инструмент на гитхаб?

                        0
                        назвать это гордо «интрументом» я бы не решиился. Там весь код это 50-60 строк определяющие структуру параметров, заворачивающие «templates» со всем, что человек туда положил в bindata и делающее по всем файлам в нем filepath.Walk с ExecuteTemplate. Могу, конечно, выложить, просто мне казалось это тривиальным.
                          0

                          Выкладывайте, пожалуйста. Мне бы очень подошло, поскольку я только начал читать литературу по Golang :)

                            0
                            Присоединяюсь, очень интересно для новичков.
                          0
                          С учётом критики в комментах подправил библиотечку, в результате чего очереди и хранилище отвалились за ненадобностью, хотя сами мидлваре я всё же прикручиваю немного по другому.

                          написал простой кодо-генератор, который делает рабочий скелет приложения

                          Как-то не приходилось сталкиваться с кодогенерацией, насколько удобным Вам показался этот инструмент?

                      Only users with full accounts can post comments. Log in, please.