Я прохожу курс Event-Driven Microservices: Spring Boot, Kafka and Elastic на платформе Udemy.com.
Курс посвящён созданию приложения, в котором будут взаимодействовать между собой несколько микросервисов под управлением Spring Cloud, с использованием паттернов Event Sourcing и Event Driven.
С большинством технологий, которые будут применяться в проекте, я так или иначе знакома. Новыми для меня станут Keycloak, Kafka Streams, ELK-stack.
Курс неактуальный, 2020 года (судя по версии Spring Boot 2.3.4). Прохожу я его летом 2025 года. Писать буду на Java 17 и Spring Boot 3.5.0, меняя библиотеки и технологии на ходу. Поэтому готовлюсь много гуглить, особенно по работе со Spring Cloud (там чуть ли не все компоненты кардинально поменялись) 😄.
Решила вести таблицу, какие более новые технологии я использовала.
| Что было в курсе | Что я использовала |
|---|---|
| Java 11 | Java 17 |
| Spring Boot 2.3.4 | Spring Boot 3.5.0 |
| Spring Cloud 2.2.6.RELEASE | Spring Cloud 4.3.0 |
| Logback | Log4j2 |
| Apache Httpclient | Apache Httpclient5 |
| Apache Kafka + Zookeeper | Apache Kafka KRaft mode |
| springdoc-openapi-ui | springdoc-openapi-starter-webmvc-ui |
Перед запуском микросервисов необходимо развернуть инфраструктуру с помощью Docker Compose и настроить Keycloak для аутентификации.
Запуск Docker Compose
В терминале войти в директорию `docker-compose`, запустить контейнер, содержащий сервисы:docker-compose up -dСписок запущенных сервисов:
| Сервис | Порт | Назначение |
|---|---|---|
| Kafka Brokers | 9091-9093 | Брокеры сообщений |
| Schema Registry | 8181 | Реестр схем Avro |
| Elasticsearch | 9200 | NoSQL база данных для поиска и аналитики |
| Postgres | 5433 | База данных для Keycloak |
| Keycloak | 8080 | Сервер аутентификации |
Настройка Keycloak
- В браузере войти в UI Keycloak (
http://localhost:8080/) под учётными данными администратора:
- 🔑
admin - 🔒
admin
- Создать realm (область/домен):
- левое меню: "Manage realms"
- выбрать "Create realm"
- в поле "Realm name" name ввести имя домена (например,
twitter-service-realm) → "Create"
- Настроить roles (уровни доступа):
- левое меню: "Realm roles"
- выбрать "Create role"
- в поле "Role name" ввести название роли для пользователя (например,
app_user_role) → "Save" - аналогичным способом создать роли для пользователя с расширенными привилегиями и администратора
(например,
app_super_user_roleиapp_admin_role)
- Создать groups (группы уровней доступа):
- левое меню: "Groups"
- выбрать "Create group"
- в поле "Name" ввести название группы для пользователей (например,
app_user_group) → "Create" - кликнуть на имя созданной группы → "Role mapping" → "Assign role" → "Realm roles" → выбрать соответствующую роль
- аналогично создать группы для привилегированных пользователей и администраторов (например,
app_super_user_groupиapp_admin_group), назначить им соответствующие роли
- Создать users (пользователей):
- левое меню: "Users"
- выбрать "Create new user"
- в поле "Username" ввести имя пользователя (например,
app_user) → "Join Groups" → выбрать соответствующую группу → "Join" → "Create" - выбрать "Credentials" → "Set password" → дважды ввести пароль пользователя, перевести "Temporary" в положение "Off" → "Save" → "Save password"
- аналогично создать администратора и пользователя с расширенными привилегиями (например,
app_adminиapp_super_user), включить их в соответствующие группы
- Создать Client (клиента):
- левое меню: "Clients"
- выбрать "Create client", заполнить настройки нового клиента:
- "Client ID" -
elastic-query-web-client - "Client authentication" - перевести в положение "On"
- "Home URL" -
http://localhost:8184/elastic-query-web-client - "Valid Redirect URIs":
http://localhost:8184/elastic-query-web-client/login/oauth2/code/keycloakhttp://localhost:8184/elastic-query-web-client
- "Web origins" -
http://localhost:8184
- "Client ID" -
- сохранить клиента кнопкой "Save"
- Настроить Client Scopes (области доступов клиентов):
- левое меню: "Client scopes"
- выбрать "Create client scope", заполнить настройки:
- "Name" - ввести название роли для пользователя (например,
app_user_role) - "Type" - из выпадающего меню выбрать "Default"
- "Name" - ввести название роли для пользователя (например,
- сохранить область доступа кнопкой "Save"
- перейти на вкладку "Scope" → "Assign role" → "Realm roles" → выбрать ранее созданную роль пользователя → "Assign"
- аналогично создать области доступов для администратора и привилегированного пользователя (например,
app_admin_roleиapp_super_user_role), назначить им соответствующие роли
- Создать ещё одного Client (клиента):
- левое меню: "Clients"
- выбрать "Create client", заполнить настройки:
- "Client ID" -
elastic-query-service - "Client authentication" - перевести в положение "On"
- "Valid Redirect URIs" -
http://localhost:8184/elastic-query-service/login/oauth2/code/keycloak
- "Client ID" -
- сохранить клиента кнопкой "Save"
- Настроить Mappers (мапперы) для
elastic-query-web-client:
- левое меню: "Clients"
- кликнуть на имя клиента → "Client scopes" →
elastic-query-web-client-dedicated→ "Add predefined mappers" - найти маппер под названием "groups" → "Add"
- "Add mapper" → "By configuration" → выбрать "Audience", заполнить настройки:
- "Name" -
elastic-query-service - "Include Client Audience" - выбрать "elastic-query-service" из выпадающего меню
- "Add to ID token" - перевести в положение "On"
- "Add to access token" - перевести в положение "On"
- "Name" -
- сохранить маппер кнопкой "Save"
- "Add mapper" → "By configuration" → выбрать "User Session Note", заполнить настройки:
- "Name" - client-id
- "User Session Note" - clientID
- "Token Claim Name" - clientID
- аналогично создать ещё два маппера "User Session Note" со следующими настройками:
- "Name" - client-host, "User Session Note" - clientHost, "Token Claim Name" - clientHost
- "Name" - client-ip, "User Session Note" - clientIPAddress, "Token Claim Name" - clientIPAddress
- Настроить мапперы для
elastic-query-service(аналогично описанным в пункте 9):
- маппер "groups"
- три маппера "User Session Note"
- два маппера "Audience" с полями "Name":
kafka-streams-serviceanalytics-service
Микросервис предназначен для получения потока твитов из социальной сети X (ex-Twitter) по заданным ключевым
словам. Работает как kafka-producer, отправляет полученные/сгенерированные твиты в топик twitter-topic.
Поработать с настоящим потоком твитов мне так и не удалось. Я зарегистрировала аккаунт разработчика в
X, но, как оказалось, с 2023 года на бесплатном аккаунте получение стриммингового потока
недоступно. Ни с помощью библиотеки twitter4j-stream, ни с помощью класса TwitterV2StreamHelper,
написанного мною по аналогии с репозиторием Twitter V2 API от самих разработчиков Twitter 😠
Единственное, что мне удалось получить, это десяток твитов через одноразовый REST-запрос в Postman.
Минимальный базовый тарифный план, на котором доступен стримминговый поток твитов, стоит 175-200$/месяц.
Тем не менее, классы и конфигурации я сохранила:
- класс
TwitterKafkaStreamRunnerработает на основе библиотекиtwitter4j-stream. Для организации стримминга твитов следует поместить в папку resources конфигурационный файлtwitter4j.properties. Ключи и токены нужно сгенерировать в аккаунте разработчика. Пример файла:
debug=true
oauth.consumerKey=*********************
oauth.consumerSecret=******************************************
oauth.accessToken=**************************************************
oauth.accessTokenSecret=******************************************-
класс
TwitterV2KafkaStreamRunnerработает на основе классаTwitterV2StreamHelper. В этом случае для организации стримминга твитов не нужен отдельный файл конфигурации, достаточно настроек вapplication.yaml. Но потребуется BearerToken, который также генерируется в аккаунте разработчика. -
класс
MockKafkaStreamRunnerгенерирует поток псевдотвитов, собираемых из набора слов с добавлением одного случайно выбранного ключевого слова.
Микросервис получает потоки твитов, индексирует их и сохраняет в Elasticsearch (индекс twitter-index).
Работает как kafka-consumer, принимает твиты из топика twitter-topic.
Серверные микросервисы предоставляют доступ к содержимому индекса twitter-index по запросу:
- модуль
elastic-query-serviceреализован с использованием традиционного (блокирующего) подхода.
Базовый URL:http://localhost:8183/elastic-query-service. - модуль
elastic-query-service-reactiveреализован в реактивном (неблокирующем) стиле.
Базовый URL:http://localhost:8183/elastic-query-service-reactive.
| Функция | Описание | Блокирующая версия | Реактивная версия |
|---|---|---|---|
| Авторизация | Доступ к API | 🔑 test 🔒 test1234 |
🔓 Не требуется |
GET /documents |
Получение всех твитов | ✅ | ❌ |
GET /documents/{id} |
Получение твита по id | ✅ | ❌ |
POST /documents/by‑text |
Поиск твитов по тексту. Пример запроса JSON: { "text": "java" } |
✅ | ✅ |
Swagger UI /swagger‑ui.html |
Интерактивная документация | ✅ | ❌ |
Клиентские микросервисы предоставляют минималистичный UI-интерфейс для поиска твитов по тексту:
- модуль
elastic-query-web-client- блокирующий, Spring MVC.
Базовый URL:http://localhost:8184/elastic-query-web-client. - модуль
elastic-query-web-client-reactive- реактивный, Spring WebFlux.
Базовый URL:http://localhost:8184/elastic-query-web-client-reactive.
| Страница | Описание | Блокирующая версия | Реактивная версия |
|---|---|---|---|
/home |
Авторизация и/или вход на главную страницу | 🔑 test 🔒 test1234 |
🔓 Не требуется |
/documents/by‑text |
Поиск твитов по тексту | ✅ | ✅ |
/error |
Обработка ошибок | ✅ | ✅ |
Видео (.gif) работы UI выложу позже, когда проект будет закончен.
Микросервис является сервером общих конфигураций для остальных микросервисов. Традиционно при работе со
spring-cloud-config-server используется удалённый приватный git-репозиторий на GitHub/GitLab/BitBucket,
в котором хранятся сами файлы с общими настройками для микросервисов проекта.
Но на моём бесплатном аккаунте на GitHub единственный доступный приватный репозиторий уже занят -
как раз-таки репозиторием с конфигурациями spring-cloud-config-server для другого проекта наSpring Cloud
🙂 Поэтому в качестве репозитория я использую директорию (не модуль!)
config-server-repository.
Чтобы сделать из директории git-репозиторий, нужно перейти внутрь этой директории в терминале и выполнить следующие команды:
git init
git status
git commit -am "Initial commit"
git branch -M main
git update-ref refs/remotes/origin/main refs/heads/mainЕсли впоследствии вносятся какие-либо изменения внутри git-репозитория, то для их применения нужно выполнить в терминале команды:
git add .
git commit -m "Add new configs"