Данный проект рассматривается как pet-project. Любую критику и советы готов увидеть в комментариях. Репозиторий с исходным кодом: https://github.com/theartofdevel/notes_system Под катом текстовая расшифровка с картинками. Давайте придумаем техническое задание и спроектируем систему на бумаге. Первым делом распишем функциональность, чтобы было понятно, что получится в итоге. Основные возможности: регистрация и авторизация в системе, создание/изменение/удаление заметок, прикрепление файла, категоризация и тегирование заметок, полнотекстовый поиск. Сделаем версию под браузер, приложения на Android и iOS могут появиться в будущем. Основные страницы UI: авторизация, регистрация, список заметок, карточка заметки. Заметки должны поддерживать формат Markdown и состоять из заголовка и тела. В ТЗ намеренно нет нефункциональных требований, таких как производительность, надёжность, катастрофоустойчивость и так далее, чтобы не усложнять систему. Итак, функциональность нам известна, давайте проектировать. Начнём с выбора инфраструктуры. Собирать систему и деплоить код будем при помощи CircleCI или GitHub Actions. Все сервисы будем упаковывать в Docker-контейнеры и запускать при помощи Docker-compose.​ Уже есть репозиторий на GitHub. Он будет использоваться как монорепозиторий. Это ускорит разработку и уменьшит количество дополнительной работы с гитом. Весь код будет в свободном доступе под лицензией GPLv3. Нам нужно дебажить сетевое взаимодействие между сервисами, поэтому мы используем стандарт Opentracing и в качестве реализации возьмем Zipkin. У него много готовых библиотек и для Python, и для Golang. Для полнотекстового поиска и фильтрации мы возьмём стек ELK, а именно Elasticsearch и Logstash. На данном этапе это как стрелять из пушки по воробьям, вполне можно было организовать этот функционал на хранилище, но: в качестве обучения и демонстрации возможностей микросервисов это будет отличным примером; если сервисом начнут пользоваться люди, то мы уже подумали о масштабировании и производительности. Для наполнения Elasticsearch данными будем настраивать ETL-процессы и использовать Apache Airflow. Так как у нас уже есть Elasticsearch, мы будем туда заливать логи всех сервисов. Чтобы отслеживать пересечения логов бизнес-процессов по разным сервисам, будем добавлять в лог TraceId, который нам останется от Zipkin. Логи будем собирать агентом Telegraf или FileBeat. Для Service Discovering используем Consul и его DNS-сервер. Логика следующая: сервис обращается к другому сервису по хостнейму, а резолвить хостнейм будет Consul. Для конфигурации всех сервисов будем использовать встроенное в Consul key-value-хранилище. Возьмём утилиту Consul Template. Она будет следить за файлом шаблона и генерировать конфигурацию сервиса, которую он будет использовать при старте, а при изменении значений в Consul Consul Template будет рестартовать сервис. Теперь посмотрим, какие сервисы у нас будут. Сервис с бизнес-логикой основной сущности. Реализуем основные операции: получение, создание, обновление и удаление. Использовать будем Golang, REST API, формат данных — JSON. У сервиса будет своё хранилище. Возьмем документоориентированную MongoDB. Она легко масштабируется, формат данных — документ в виде JSON плюс шардирование «из коробки» — опять же пригодится, если будет нагрузка. Для управления файлами заметок сделаем отдельный сервис. Скорее всего, это будет совместимое с S3 хранилище MinIO. Файлы будем хранить на файловой системе. Для управления категориями сделаем отдельный сервис со своим хранилищем. Категории будем хранить в древовидной структуре, поэтому возьмем Neo4j — графовую базу данных. Её основная особенность в том, что коннекты между данными хранятся, а не вычисляются во время запроса. Также она использует язык запросов Cypher, который гораздо проще, чем SQL для написания запросов с неограниченной вложенностью. Сервис будем делать на языке Python 3 и фреймворке Flask. Асинхронность здесь не так важна, к тому же запускать приложение мы будем при помощи Gunicorn, который сможет распараллелить инстансы сервиса. Мы будем делать только веб-приложение без мобильных клиентов, но так как в будущем они могут появиться, нам нужен отдельный сервис с API. API у нас по большей степени простой CRUD, различного функционала немного, и весь он вращается вокруг заметок. Основных сущностей также мало, поэтому будем готовить обычный REST API. Для полнотекстового поиска сделаем SearchService. Именно он будет обладать доступом в Elasticsearch. Работать с Elasticsearch проще на Python, поэтому выбор очевиден. Для пользователей системы будет отдельный сервис также с REST API и хранилищем PostgreSQL. Для создания веб-приложения используем Vue.js или React.js. В итоге мы получили такую архитектуру: Если в системе появятся асинхронные операции, например, отчёты, то мы легко внедрим в эту архитектуру очереди событий. В следующей части мы начнём разработку системы. Будут показаны основные моменты процесса разработки и конфигурации используемых продуктов.