Несколько месяцев назад наша гильдия производительности и непрерывной доставки решила приобрести практический опыт работы с распределенными архитектурами программного обеспечения. Поскольку такие компании, как Twitter или Netflix, открыли множество компонентов из своих программных стеков с открытым исходным кодом, это казалось отличной идеей для начала. Хорошее введение — сообщение в блоге о программном стеке Twitter . Однако мы не хотели смотреть на архитектурные схемы, а скорее пачкать руки и сами что-то строить. Вы помните старые добрые времена, когда Java Pet Store был новым и модным? Нам нужно что-то подобное для современных распределенных архитектур и, наконец, мы решили создать клон популярного сайта Q & A для программистов Stackoverflow: Hash-Collision родился. С помощью Hash-Collision мы хотим решать различные проблемы в распределенных системах, такие как:
- Декомпозиция приложения на отдельные сервисы
- Начальная загрузка всей системы
- Маршрутизация
- Распределенная служба связи
- Безопасность среди сервисов
- Интеграция пользовательского интерфейса
Поскольку наша лабораторная идея вызвала определенный интерес в comSysto, у нас теперь есть несколько команд, работающих над различными аспектами. В первой лаборатории мы сконцентрировались на запуске минималистичных сервисов. Мы также выбрали JVM в качестве общей среды выполнения для всех сервисов, чтобы использовать одну и ту же цепочку инструментов и упростить настройку. Однако позже мы можем решить заменить существующий сервис языком, который не работает поверх JVM только ради него.
Структура системы
Мы разложили Hash-Collision на мелкозернистые сервисы, которые можно масштабировать независимо. Система разбита на эти вертикали:
- qa: обрабатывает обсуждения, состоящие из вопросов и ответов.
- пользователь: обрабатывает управление пользовательскими данными
- auth: обрабатывает учетные данные, аутентификацию и авторизацию.
Помимо этих сервисов пользовательский интерфейс, который интегрирует сервисы через конечные точки API (REST):
Сервисы
Мы хотим предоставлять полностью автономные сервисы, чтобы развертывание WAR не было возможным. После некоторых исследований мы наткнулись на Спарк и сразу поняли его простоту. Вот эхо-сервер:
import static spark.Spark.*;
public class Echo {
public static void main(String[] args) {
get("/echo", (req, res) -> req.queryParams("msg"));
}
}
Каждый сервис обеспечивает некоторую часть логики домена, имеет свое собственное хранилище данных и предоставляет конечную точку API через HTTP. Для простого развертывания он содержится в одном JAR, который можно легко запустить из командной строки.
Служба связи
Для простоты мы остановились на HTTP в качестве протокола связи для конечных точек API. Однако в более поздних версиях мы могли бы переключиться на двоичный протокол, такой как Thrift . Для асинхронного обмена услугами мы используем AMQP с кодировкой Msgpack .
Маршрутизация
Мы решили использовать Camel для реализации базового компонента балансировки нагрузки и маршрутизации для сервисного уровня. Экземпляры службы динамически регистрируются маршрутизатором. Экземпляр службы объявляет себя, периодически отправляя сообщения пульса, чтобы маршрутизатор мог отслеживать запущенные экземпляры, которые доступны. Однако в настоящее время мы сталкиваемся с проблемами доступности, когда экземпляр службы только что умер и еще не удален из списка узлов балансировщика нагрузки.
UI
В разделе Микросервисы: декомпозиция приложений для развертывания и масштабируемости Крис Ричардсон описывает различные варианты интеграции пользовательского интерфейса. Среди них — вызов служб непосредственно из пользовательского интерфейса или использование шлюза API. Хотя звонить в сервисы проще с начала, он может стать громоздким и запутанным довольно быстро. Кроме того, клиент выдает много подробных HTTP-запросов, которые могут снизить общую производительность. Хотя Hash-Collision вызывает сервисы напрямую из пользовательского интерфейса из-за ограничений по времени реализации, мы определенно признаем преимущества шлюза API и рассмотрим реализацию позже.
Сервисные API и общий код
В каждом проекте есть необходимость поделиться кодом. Команда разработчиков немецкого ритейлера Otto в статье об архитектуре своего магазина (PDF) описывает, что они вообще избегают внутреннего кода компании. Вместо этого они выпускают такой код всегда как проекты с открытым исходным кодом и интегрируют их. Из-за небольшого количества общего кода Hash-Collision в настоящее время использует общий проект, который включен в сборку отдельных сервисных модулей. В более поздних воплощениях мы могли бы также разделить циклы разработки и выпустить общий код во внутренний репозиторий Maven. Общий код также необходим для сервисных API. Поставщики услуг и потребители имеют общий API, который также состоит из транспортных объектов. Некоторые общие подходы:
- Дублирование кода
- Файл описания языка общего интерфейса и генерация кода
- Общий код на целевом языке (клиентский API)
Заключение и последующие шаги
В этой лаборатории мы создали очень простой технический прототип. Особенно в операциях мы сделали несколько компромиссов, таких как простые локальные сборки или инициализация с помощью сценариев оболочки. Далее другая команда займется:
- Непрерывная доставка услуг
- Предоставление и настройка системы с помощью таких инструментов, как Vagrant или Docker
В отношении развития мы хотели бы обратиться к:
- Сократите количество клиентских запросов, введя API-шлюз
- Включите распределенную трассировку и мониторинг, чтобы понять, как запросы проходят через всю систему
- Улучшить устойчивость
- Добавить реальное обслуживание постоянство
Следите за новыми сообщениями в блоге, поскольку мы улучшаем Hash-Collision.
Наконец, я бы хотел порекомендовать 2-дневный тренинг по архитектуре для непрерывной доставки и нулевого простоя с Акселем Фонтейном , который состоится 26 + 27 января 2015 года в comSysto. Узнайте больше об этом, нажав на ссылку или зарегистрируйтесь здесь ЗДЕСЬ !