94 lines
4.7 KiB
Markdown
94 lines
4.7 KiB
Markdown
# Thinking Log — 2026-04-06
|
||
## Агент: GitHub Copilot (Claude Sonnet 4.6)
|
||
|
||
---
|
||
|
||
## Архитектурные обсуждения перед началом Kafka
|
||
|
||
### Контекст
|
||
Пользователь обсуждал будущую prod-архитектуру IoT сервиса.
|
||
Никакого кода не менялось — чистое планирование.
|
||
|
||
### Итоги обсуждений
|
||
|
||
**Три отдельных кластера (принято):**
|
||
1. IoT кластер — EMQX, bridge, Kafka, iot-consumer, Postgres, REST API
|
||
2. Serverless кластер — operator, builder, event-dispatcher, Functions
|
||
3. Infra/Control кластер — Terraform для provisioning кластеров 1 и 2, DNS, TLS, auth, billing
|
||
|
||
Это классическая схема "control plane отдельно от data plane".
|
||
|
||
**Kafka — выбор подтверждён:**
|
||
- Сейчас: bridge → Postgres напрямую (синхронно, без буфера)
|
||
- Prod: bridge → Kafka → {consumer → Postgres, event-dispatcher → Functions}
|
||
- Dev/test: Kafka через Helm (bitnami, KRaft mode, 1 нод, PVC)
|
||
- Prod: managed Kafka (Confluent/Aiven) — только меняется KAFKA_BROKERS в Secret
|
||
|
||
**Postgres → managed облачный: легко**
|
||
- bridge и API используют DATABASE_URL из env
|
||
- Для переключения: только заменить Secret в кластере
|
||
- Код не трогается
|
||
|
||
**Состояние RabbitMQ для IoT (важное открытие):**
|
||
- Bridge сейчас пишет в RabbitMQ очередь `iot.{namespace}.telemetry`
|
||
- НО event-dispatcher эту очередь не читает — он настроен на serverless functions triggers
|
||
- То есть IoT-сообщения в RabbitMQ лежат мёртвым грузом — никто не читает
|
||
- Kafka заменяет RabbitMQ для IoT-части полностью
|
||
|
||
**Что проверяли в кластере:**
|
||
- 2026-04-05: только один активный тенант `sless-16367aacb67a4a01` (созданный после инцидента)
|
||
- Устройство `device2`, одно сообщение: `{"msg":"hello1dddd1777"}` от 14:34 UTC
|
||
- 2026-04-06: kubeconfig истёк → обновил → тот же один тенант, никто новый не входил
|
||
|
||
---
|
||
|
||
## План интеграции Kafka
|
||
|
||
### Анализ текущего bridge
|
||
|
||
Читал `iot/cmd/mqtt-bridge/main.go`. Текущая логика в `buildMQTTMessageHandler`:
|
||
1. Получает MQTT сообщение
|
||
2. Публикует в RabbitMQ (бесполезно — никто не читает)
|
||
3. Пишет напрямую в Postgres через iotpg.Store
|
||
|
||
С Kafka нужно:
|
||
1. Получает MQTT сообщение
|
||
2. Публикует в Kafka топик `iot.telemetry` (единый топик, namespace в payload)
|
||
3. Убрать прямой INSERT в Postgres из bridge
|
||
|
||
### Что создаётся заново
|
||
|
||
**`iot/cmd/kafka-consumer/main.go`** — новый сервис:
|
||
- Читает из Kafka топика `iot.telemetry`
|
||
- Пишет в Postgres (та же логика что сейчас в bridge)
|
||
- Consumer group: `iot-pg-consumer`
|
||
|
||
**Изменения в bridge:**
|
||
- Убрать RabbitMQ
|
||
- Добавить Kafka producer (библиотека `github.com/segmentio/kafka-go`)
|
||
- Env var: `KAFKA_BROKERS` вместо `RABBITMQ_URL`
|
||
|
||
**Новые env vars:**
|
||
- bridge: `KAFKA_BROKERS=kafka.sless.svc.cluster.local:9092`
|
||
- consumer: `KAFKA_BROKERS=...`, `IOT_PG_DSN=...`
|
||
|
||
### Что НЕ меняется
|
||
- EMQX, operator, REST API, IoT Console — не трогаются
|
||
- `iotpg` storage package — используется consumer-ом напрямую
|
||
- ACL, auth, namespace-изоляция — не меняются
|
||
|
||
### Порядок работы
|
||
1. Документация + коммит (сейчас)
|
||
2. Ветка `iot-kafka`
|
||
3. Helm: установить Kafka в namespace `sless`
|
||
4. Переписать bridge: убрать RabbitMQ, добавить Kafka producer
|
||
5. Создать `iot/cmd/kafka-consumer/main.go`
|
||
6. Обновить Dockerfile (добавить сборку consumer)
|
||
7. Обновить deployment манифесты
|
||
8. Сборка v0.1.67, деплой, тест
|
||
|
||
### Риски
|
||
- `kafka-go` vs `confluent-kafka-go` — выбираем `segmentio/kafka-go` (pure Go, без CGO, совместим с alpine)
|
||
- KRaft mode в Helm bitnami — убедиться что включён (без Zookeeper)
|
||
- Topic `iot.telemetry` — создаётся автоматически при первой публикации (auto.create.topics.enable=true по умолчанию)
|