Облако для SOA приложений и не только

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Привет Хабр.

Сегодня я хочу рассказать про своё детище - платформу "qSOA.cloud", которая позволяет запускать приложения построенные по SOA в облаке по разумной цене. Например, стоимость размещения простого HTTP API сервиса, который обрабатывает ~400 000 запросов в сутки, может составлять от 3$/месяц. При этом всё устроено удобно и просто в "одном окне", так, что разработчикам сервисов не нужно думать об инфраструктурной обвязке, а нужно просто реализовывать бизнес логику. Логи, метрики, трейсинг, дискавери, рутинг, ... встроены в платформу, а сервис просто выполняет функцию, нужную бизнесу.

В SOA я очень глубоко погрузился 5 лет назад в одной E-Commerce компании из Юго-Восточной Азии. Строя там платформу, которая обрабатывает десятки тысяч RPS, мы набили много "шишек", которые были учтены в qSOA.cloud. Сейчас на платформе поддерживаются только сервисы написанные на Go, но в дальнейшем появится поддержка и других ЯП.

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

Как это устроено (кратко)

Сервис - это приложение, принимающее запросы по HTTP или gRPC. Между собой сервисы общаются по gRPC, но не напрямую, а через специальные сервисы - Runner'ы. Каждый физический сервер имеет 1 запущенный Runner, который запускает сервисы и проксирует трафик через себя, за счёт чего вся инфраструктурная логика хранится в нём. Runner отвечает за discovery, routing, так как знает какие он сервисы запустил и в каком они состоянии и знает, что запущено на других серверах, он собирает и отправляет в хранилище логи, основные метрики, кастомные метрики сервисов, ... Между собой Runner'ы общаются по gRPC с TLS. Схематично это выглядит так:

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

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

Как написать сервис

Для примера возьмём задачу:

Нужен сервис, который будет принимать по HTTP 2 числа, складывать их и возвращать пользователю сумму, при этом параметры и результат должен логироваться в БД. Чтобы было интереснее, то предположим, что сумму он считать сам не умеет и ему нужен другой сервис, который будет по gRPC принимать 2 числа и возвращать их сумму.

Чтобы немного сократить повествование, я объединю оба сервиса в один и он будет вызывать сам себя по gRPC, так, как он вызывал бы другой сервис. Также я не буду рассказывать про имплементацию HTTP и gRPC хендлеров, они тривиальны, код можно посмотреть на GitHub. Всё самое интересное в main.go, код с подробными комментариями ниже:

package main

import (
	"database/sql"
	"log"

	// Очень простая сервисная обвязка
	"gopkg.qsoa.cloud/service"
	// Сервис предоставляет gRPC
	"gopkg.qsoa.cloud/service/qgrpc"
	// Сервис предоставляет HTTP
	"gopkg.qsoa.cloud/service/qhttp"
	// Драйвер облачного MySQL
	_ "gopkg.qsoa.cloud/service/qmysql"

	// Имплементация хендлеров
	"testservice/grpc"
	"testservice/grpc/pb"
	"testservice/http"
)

func main() {
	// Подготавливаем gRPC клиент для вызова самого себя. 
	// Обратите внимание на протокол qcloud:// и / в конце.
	conn, err := qgrpc.Dial("qcloud://" + service.GetService() + "/")
	if err != nil {
		log.Fatalf("Cannot dial grpc: %v", err)
	}
	defer conn.Close()

	grpcClient := pb.NewTestClient(conn)

	// Подготавливам подключение к MySQL.
	// Не нужен DSN, только имя БД, драйвер qmysql всё сделает
	db, err := sql.Open("qmysql", "example_db")
	if err != nil {
		log.Fatalf("Cannot open mysql database: %v", err)
	}
	defer db.Close()

	// Регистрируем HTTP хендлер
	qhttp.Handle("/", http.New(grpcClient, db))

	// Регистрируем gRPC сервис
	pb.RegisterTestServer(qgrpc.GetServer(), grpc.Server{})

	// Заупскаем
	service.Run()
}

Вот и всё, отправляем в Git и запускаем в облаке.

Проекты, окружения и сервисы

Перед тем, как запустить сервис в qSOA.cloud, надо создать проект. Проект объединяет в себе набор сервисов (сервисы из разных проектов не видят друг друга) и набор окружений. Окружения нужны для того, чтобы иметь несколько наборов сервисов с разными версиями. Например есть стабильное окружение - Production, в нём протестированные версии сервисов, к которым обращаются реальные пользователи, есть тестовое окружение, куда выкладываются готовые к тестированию версии сервиса и в которое ходят тестировщики, и так далее. Структурно это выглядит так:

Сервисы из разных окружений не видят друг друга. Внутри одного окружения одновременно могут быть запущены разные версии одного сервиса.

Из git в облако

Для примера я создал проект Example с ID example. Теперь в нём нужно создать новый сервис:

Если код лежит в приватном репозитории, то адрес можно передать в формате https://<login>:<password>@<domain>/<repo>.

После этого его нужно скомпилировать:

Для этого нужно кликнуть по иконке молотка справа от версии. Версии могут быть в любом формате, задаются тегами в git. Процесс сборки и ошибки можно посмотреть в логе:

В случае наличия GoDep.* файлов будет выполнено go dep ensure.

После успешной сборки сервис готов к запуску, для этого нужно создать окружение, например Production. После создания окружения надо кликнуть по кнопке Deploy:

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

Для каждого сервиса можно и нужно запускать несколько копий (instance'ов). Они будут распределяться по разным физическим серверам и, в дальнейшем, ДЦ для повышения отказоустойчивости. Но при этом балансировка запросов будет происходит к оптимальным instance'ам.

Каждый instance в интерфейсе представлен набором основных метрик, обновляющихся практически в реальном времени. Среди них количество запросов, количество успешных/ошибочных/прочих ответов, среднее время ответа, нагрузка на CPU, потребляемая память, ...

Доступ из Internet

Сейчас запущенный сервис живёт внутри облака и может обращаться сам к себе, но из внешнего мира к нему не добраться. Для открытия доступа надо создать шлюз. При создании проекта выделяется домен вида <project_id>.qsoa.cloud, можно использовать его или его поддомены для организации доступа к сервису:

При создании шлюза просто выбираете окружение, сервис и пишите доменное имя. Домен может быть своим, не обязательно в зоне <project_id>.qsoa.cloud.

После создания можно открыть https://example.qsoa.cloud, сертификат выпишется и будет перевыпускаться автоматически через Let's Encrypt. Это работает и для кастомных доменов:

Базы данных

По условиям задачи, сервис должен логировать в БД аргументы с суммой. Создадим БД с нужным именем:

Базы данных можно использовать в нескольких окружениях, поэтому при создании нужно выбрать в каких из них она будет доступна, в нашем случае только в Production.

В платформу встроен простейший UI для управления БД, сейчас он пригодится для создания таблички:

Его также можно использовать для вывода данных:

Внутри имена баз данных не совпадают с запрошенными, поэтому имя БД в выводе странное.

Трейсинг и логи

Теперь сервис полностью готов к эксплуатации. Если отправить запрос на https://example.qsoa.cloud/?n1=10&n2=20, то получите ответ:

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

Базовый интерфейс предоставляет список span'ов:

В таком виде он сейчас полезен для, например, поиска медленных запросов. Фильтр поддерживает сложные выражения, включая скобки, подробности можно посмотреть кликнув на знак ?

Для анализа одного конкретного трейса есть древовидное представление:

В нём, помимо стандартных полей span'ов, можно увидеть их иерархию и какое влияние оказывает каждый вложенный span на длительность родителя (тонкая жёлтая линия).

Используя OpenTracing разработчики сервисов могут добавлять свои span'ы и отслеживать важные для бизнеса вещи.

Помимо трейсинга, на соседней вкладке можно посмотреть логи, причём как и те, что пришли из span'ов, так и те, что просто были выведены в STDOUT/STDERR. В данный момент сервис ничего не выводит, поэтому там пусто:

Метрики

Для любого запущенного сервиса собираются базовые метрики по запросам/ответам и производительности:

Counters:

Посмотреть их можно на встроенных дашбордах:

Набор дашбордов можно редактировать, пока без редактора, в виде JSON:

Помимо стандартных метрик, можно делать свои, используя клиента Prometheus, они также будут доступны для построения графиков по префиксу prometheus вместо internal.

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

Конец

Вот и всё, с помощью простых шагов сервис написан, запущен, для него доступны инструменты анализа, при этом разработчик не задумывался о том как настроть Nginx, Docker, Kubernates, Prometheus, Grafana, ..., или где найти DevOps'а, который это сделает.

История и текущее состояние проекта

Проектом я начал заниматься больше года назад в качестве pet'а. Сейчас его можно классифицировать как MVP, в нём работают несколько моих сервисов, Текущее состояние - хороший "скелет", на который нужно наращивать "тело", но для понимания в какую сторону двигаться мне нужны внешние живые проекты. Есть большой бэклог, из ближайших планов в нём:

Планов очень много и есть огромное желание дальше развивать qSOA.cloud, для этого нужны живые проекты и дополнительные руки и головы. Сейчас прямой регистрации на сайте нет, но если платформа заинтересовала, то со мной можно связаться через ЛС Хабра или любыми другими способами, указанными на https://svistunov.pro. Я буду рад пообщаться по любым формам сотрудничества.

Источник: https://habr.com/ru/post/525000/


Интересные статьи

Интересные статьи

В этой инструкции показывается как настроить пользователей только для чтения в PostgreSQL для Redash. Читать дальше →
Недавно на проекте интегрировал модуль CRM Битрикса c виртуальной АТС Ростелеком. Делал по стандартной инструкции, где пошагово показано, какие поля заполнять. Оказалось, следование ей не гаран...
Сегодня поговорим об измерении производительности рендеринга React-компонентов с использованием API React Profiler. Ещё мы будем оценивать взаимодействия с компонентом, применяя новый эксперимент...
Возможность интеграции с «1С» — это ключевое преимущество «1С-Битрикс» для всех, кто профессионально занимается продажами в интернете, особенно для масштабных интернет-магазинов.
В данной статье мы рассмотрим основной механизм локализации интерфейса приложений Splunk (в т.ч. стандартных элементов приложения Search) — gettext internationalization and localization (i18n)....