Обложка: Разработка системы заметок с нуля. Часть 1: проектирование микросервисной архитектуры

Разработка системы заметок с нуля. Часть 1: проектирование микросервисной архитектуры

Начинаем серию материалов, в которых мы спроектируем и разработаем систему заметок. Это история не про написание кода, а про микросервисную архитектуру и инфраструктурную обвязку вокруг нее.

Техническое задание

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

Основные возможности:

  • регистрация и авторизация в системе,
  • создание/изменение/удаление заметок,
  • прикрепление файла,
  • категоризация и тегирование заметок,
  • полнотекстовый поиск.

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

Основные страницы UI:

  • авторизация,
  • регистрация,
  • список заметок,
  • карточка заметки.

Заметки должны поддерживать формат Markdown и состоять из заголовка и тела. В ТЗ намеренно нет нефункциональных требований, таких как производительность, надёжность, катастрофоустойчивость и так далее, чтобы не усложнять систему.

Проектирование системы

Итак, функциональность нам известна, давайте проектировать. Начнём с выбора инфраструктуры.

CI/CD

Собирать систему и деплоить код будем при помощи CircleCI или GitHub Actions. Все сервисы будем упаковывать в Docker-контейнеры и запускать при помощи Docker-compose.​

Система контроля версий

Уже есть репозиторий на GitHub. Он будет использоваться как монорепозиторий. Это ускорит разработку и уменьшит количество дополнительной работы с гитом. Весь код будет в свободном доступе под лицензией GPLv3.

Zipkin

Нам нужно дебажить сетевое взаимодействие между сервисами, поэтому мы используем стандарт Opentracing и в качестве реализации возьмем Zipkin. У него много готовых библиотек и для Python, и для Golang.

Search and filter

Для полнотекстового поиска и фильтрации мы возьмём стек ELK, а именно Elasticsearch и Logstash. На данном этапе это как стрелять из пушки по воробьям, вполне можно было организовать этот функционал на хранилище, но:

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

Для наполнения Elasticsearch данными будем настраивать ETL-процессы и использовать Apache Airflow.

Logs

Так как у нас уже есть Elasticsearch, мы будем туда заливать логи всех сервисов. Чтобы отслеживать пересечения логов бизнес-процессов по разным сервисам, будем добавлять в лог TraceId, который нам останется от Zipkin. Логи будем собирать агентом Telegraf или FileBeat.

Service Discovering and Configuration

Для Service Discovering используем Consul и его DNS-сервер. Логика следующая: сервис обращается к другому сервису по хостнейму, а резолвить хостнейм будет Consul.

Для конфигурации всех сервисов будем использовать встроенное в Consul key-value-хранилище. Возьмём утилиту Consul Template. Она будет следить за файлом шаблона и генерировать конфигурацию сервиса, которую он будет использовать при старте, а при изменении значений в Consul Consul Template будет рестартовать сервис.

Сервисы

Теперь посмотрим, какие сервисы у нас будут.

NoteService

Сервис с бизнес-логикой основной сущности. Реализуем основные операции: получение, создание, обновление и удаление. Использовать будем Golang, REST API, формат данных — JSON.

У сервиса будет своё хранилище. Возьмем документоориентированную MongoDB. Она легко масштабируется, формат данных — документ в виде JSON плюс шардирование «из коробки» — опять же пригодится, если будет нагрузка.

FileService

Для управления файлами заметок сделаем отдельный сервис. Скорее всего, это будет совместимое с S3 хранилище MinIO. Файлы будем хранить на файловой системе.

CategoryService

Для управления категориями сделаем отдельный сервис со своим хранилищем. Категории будем хранить в древовидной структуре, поэтому возьмем Neo4j — графовую базу данных. Её основная особенность в том, что коннекты между данными хранятся, а не вычисляются во время запроса. Также она использует язык запросов Cypher, который гораздо проще, чем SQL для написания запросов с неограниченной вложенностью.

Сервис будем делать на языке Python 3 и фреймворке Flask. Асинхронность здесь не так важна, к тому же запускать приложение мы будем при помощи Gunicorn, который сможет распараллелить инстансы сервиса.

APIService

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

API у нас по большей степени простой CRUD, различного функционала немного, и весь он вращается вокруг заметок. Основных сущностей также мало, поэтому будем готовить обычный REST API.

SearchService

Для полнотекстового поиска сделаем SearchService. Именно он будет обладать доступом в Elasticsearch. Работать с Elasticsearch проще на Python, поэтому выбор очевиден.

UserService

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

WebApplication

Для создания веб-приложения используем Vue.js или React.js.

В итоге мы получили такую архитектуру:

Пример микросервисной архитектуры

Архитектура нашей системы

Если в системе появятся асинхронные операции, например, отчёты, то мы легко внедрим в эту архитектуру очереди событий.

В следующей части мы начнём разработку системы. Будут показаны основные моменты процесса разработки и конфигурации используемых продуктов.

Группа автора «ВКонтакте», Telegram, Twitter.

Хинт для программистов: если зарегистрируетесь на соревнования Huawei Cup, то бесплатно получите доступ к онлайн-школе для участников. Можно прокачаться по разным навыкам и выиграть призы в самом соревновании.

Перейти к регистрации