244 lines
15 KiB
Markdown
244 lines
15 KiB
Markdown
<!-- ⚠️ ЛЕГАСИ — история версий разработки (апрель 2026).
|
||
ЭТИМ НЕ РУКОВОДСТВОВАТЬСЯ. Только для истории. Помечено 2026-08-13. -->
|
||
|
||
# SQS-service Progress
|
||
|
||
## Версия v0.1.x
|
||
|
||
### v0.1.24 (2026-04-12) — Prometheus metrics + Victoria Metrics integration
|
||
- ✅ Новый пакет `app/metrics/` — Prometheus counters, histograms, gauges
|
||
- ✅ Endpoint `/metrics` в формате Prometheus (promhttp.Handler)
|
||
- ✅ Метрики: sqs_requests_total, sqs_request_bytes_total, sqs_request_duration_seconds, sqs_errors_total, sqs_queues_count, sqs_messages_count
|
||
- ✅ Labels: tenant, operation — для фильтрации в Grafana
|
||
- ✅ Gauge updater: пересчёт очередей/сообщений per tenant каждые 15s
|
||
- ✅ VMServiceScrape создан в namespace shared-sqs — VMAgent скрейпит каждые 30s
|
||
- ✅ Go 1.23 в Dockerfile (требование prometheus client)
|
||
- ✅ Docker image `naeel/shared-sqs:v0.1.24` — собран и запушен
|
||
- ✅ Live deploy: все метрики отдаются, quick_test 31/31 PASS
|
||
|
||
#### Стресс-тест с нуля (2026-04-12)
|
||
- ✅ Namespace `shared-sqs` удалён и пересоздан с нуля
|
||
- ✅ Обнаружен и исправлен сменившийся пароль Redis (managed сервис обновил credentials)
|
||
- ✅ Обнаружено и исправлено: `server-snippet` аннотация заблокирована nginx ingress controller как "risky" — удалена из ingress.yaml
|
||
- ✅ Pod kill → восстановление за ~3 секунды, auto-reconnect Redis + PG
|
||
- ✅ Quick test: 31/31 PASS (приватная репа), 7/7 + 18/18 PASS (публичная репа)
|
||
- ✅ Нагрузка: 5 тенантов, 15 очередей, 120 сообщений (90 single + 30 batch), 90 received
|
||
- ✅ Billing PG: 176 записей, все 17 типов операций
|
||
- ✅ Prometheus /metrics: все sqs_* метрики заполнены реальными данными по тенантам
|
||
|
||
### v0.1.23 (2026-04-12) — billing: учёт SQS-операций в PostgreSQL
|
||
- ✅ Новый пакет `app/billing/` — подключение к PG, auto-migrate, async запись usage
|
||
- ✅ Интеграция в actionHandler — каждая успешная SQS-операция записывается
|
||
- ✅ Опциональность: если BILLING_PG_HOST не задан — billing выключен, SQS работает как раньше
|
||
- ✅ Helm chart: секция `billing:` в values.yaml, secret-billing.yaml, env в deployment.yaml
|
||
- ✅ Таблица `sqs_usage_records`: tenant_id, operation, queue_name, msg_count, msg_bytes, recorded_at
|
||
- ✅ Docker image `naeel/shared-sqs:v0.1.23` — собран и задеплоен с PG credentials
|
||
- ✅ Live: billing данные пишутся в PostgreSQL (17 типов операций за тест)
|
||
|
||
### v0.1.22 (2026-04-12) — demo UI showcase mode deployed
|
||
- ✅ Demo UI token поддержан сервером: `demo-ui-shared-sqs-ngcloud-2026`
|
||
- ✅ Реальный JWT login сохранён без изменений
|
||
- ✅ UI API ограничен текущим tenant-ом, без обзора всех tenant-ов
|
||
- ✅ Собран и запушен image `naeel/shared-sqs:v0.1.22`
|
||
- ✅ Live deployment обновлён до `naeel/shared-sqs:v0.1.22`
|
||
- ✅ Live smoke validation: `bash tests/quick_test.sh` → `31/31 PASS`
|
||
- ✅ Demo token на live `/ui/api/auth` возвращает demo tenant `t-demo-shared-sqs-ngcloud`
|
||
|
||
### v0.1.22-dev (2026-04-12) — demo UI login + UI tenant scoping
|
||
- ✅ Добавлен публичный UI demo token: `demo-ui-shared-sqs-ngcloud-2026`
|
||
- ✅ Demo token маппится на уже сидированный demo tenant `t-demo-shared-sqs-ngcloud`
|
||
- ✅ UI API больше не показывает чужие tenant-ы: `GET /ui/api/tenants` возвращает только текущий tenant
|
||
- ✅ UI health для авторизованного пользователя считает только его очереди и сообщения
|
||
- ✅ Создание и удаление tenant-а через UI отключены, чтобы demo/login-console не выглядела как admin panel
|
||
- ✅ Узкая валидация: `go test ./app/admin` PASS
|
||
- ✅ Публичный showcase README синхронизирован с новым demo UI token
|
||
|
||
### v0.1.21 (2026-04-11) — Redis schema v2 + per-message persistence
|
||
- ✅ Redis schema v2: metadata в HASH `ssq:queues`, сообщения в отдельных HASH `ssq:msg:{queueKey}`
|
||
- ✅ Per-message persistence: каждая операция (send/receive/delete/visibility) пишет только затронутое сообщение
|
||
- ✅ Migration v1→v2: автоматическая миграция при старте (59 очередей мигрировано)
|
||
- ✅ quick_test: 31/31 PASS
|
||
- ✅ shared_sqs_test: 28/28 PASS
|
||
- **Docker image:** `naeel/shared-sqs:v0.1.21`
|
||
|
||
### Производительность v0.1.21 (benchmark)
|
||
|
||
| Размер | shared-sqs | Yandex MQ | Сравнение |
|
||
|--------|-----------|-----------|-----------|
|
||
| 1KB | ~800ms | ~700ms | Паритет |
|
||
| 10KB | **880-965ms** | 916-996ms | **Быстрее** |
|
||
| 32KB | **883-939ms** | 905-948ms | **Быстрее** |
|
||
|
||
- Детальный сравнительный отчёт по API операциям: [doc/api/benchmark-comparison-2026-04-12.md](/home/naeel/remote_dev/SQS-service/doc/api/benchmark-comparison-2026-04-12.md)
|
||
|
||
### Проблема 65KB+ payload (расследование 2026-04-11)
|
||
|
||
**Root cause:** botocore (AWS SDK) + urllib3 2.0 + TLS record boundary.
|
||
- urllib3 2.0 отправляет headers и body двумя отдельными send() вызовами
|
||
- botocore убирает TCP_NODELAY (алгоритм Nagle включён)
|
||
- Последняя TLS-запись (~16KB) застревает из-за Nagle + delayed ACK
|
||
- nginx `client_body_timeout` срабатывает → HTTP 408
|
||
|
||
**Попытка фикса nginx:**
|
||
- ConfigMap: `client-body-timeout: "120"`, `client-body-buffer-size: "2m"` — применилось
|
||
- Аннотация `proxy-request-buffering: "off"` — НЕ подхватилась shturval controller
|
||
- pip boto3 (Python 3.12): исправлено (84ms → 13ms) ✅
|
||
- AWS CLI (Python 3.14.3 bundled): всё ещё зависает (51843ms) ❌
|
||
|
||
**Финальный вывод (2026-04-12):**
|
||
- проблема локализована на стороне platform ingress controller штурвала, а не в Go-сервисе shared-sqs;
|
||
- ingress приложения корректен, но controller выборочно применяет аннотации: `proxy-body-size` и `client-body-buffer-size` доходят до nginx.conf, а `proxy-request-buffering` остаётся `on`;
|
||
- upstream ingress-nginx эту аннотацию поддерживает, значит это platform-specific limitation/bug;
|
||
- hard-limit 32KB в код shared-sqs НЕ вводим;
|
||
- 32KB остаётся практической рекомендацией для AWS CLI / botocore в текущей инфраструктуре.
|
||
- внешние ссылки для повторного разбора сохранены в `doc/thinking/2026-04-12.md`, `doc/errors/65kb-payload-timeout-2026-04-11.md` и `doc/decisions/message-size-limit-2026-04-11.md`.
|
||
|
||
### v0.1.19 (2026-04-11) ✅ — ПРЕДЫДУЩАЯ DEPLOYED
|
||
- ✅ Валидация VisibilityTimeout (0–43200) в ReceiveMessage
|
||
- ✅ Валидация WaitTimeSeconds (0–20) в ReceiveMessage
|
||
- ✅ Пустой MessageBody → MissingParameter в SendMessage
|
||
- ✅ quick_test: **31/31** ✅
|
||
- ✅ hardcore_test: **114/116** ✅ (2 flaky — 100KB TLS, не баг сервера)
|
||
- ✅ stress_test: **21/23** ✅ (2 flaky — сеть/nginx, не баг сервера)
|
||
- **Docker image:** `naeel/shared-sqs:v0.1.19`
|
||
- **Helm:** `deployments/helm/shared-sqs/` appVersion v0.1.19
|
||
|
||
### v0.1.18 (2026-04-11) ✅
|
||
- ✅ 4 новые API команды: ChangeMessageVisibilityBatch, TagQueue, UntagQueue, ListQueueTags
|
||
- ✅ Итого API: **17 команд** (полная Yandex/AWS SQS совместимость)
|
||
- ✅ security: fix critical/high auth, idor, races and persistence
|
||
- ✅ security: address medium risks in jwt, redis ordering and body limit
|
||
- ✅ perf: optimize receive long polling and finalize formatting cleanup
|
||
|
||
### v0.1.15 (2026-04-10) ✅
|
||
- ✅ JWT auth через nubes API (deck-api-test.ngcloud.ru)
|
||
- ✅ Login page в UI (ввод токена → валидация → auto-provisioning tenant)
|
||
- ✅ /ui/api/* защищены JWT middleware
|
||
- ✅ TenantID совместим с sless namespace: sless-{SHA256(sub)[:8]}
|
||
|
||
### v0.1.14 (2026-04-10) ✅
|
||
- ✅ Фикс критического дедлока в `create_queue.go`
|
||
- ✅ Фикс UI: `m.sent` → `m.sent_at`
|
||
- ✅ Redis write-through persistence
|
||
- ✅ TLS Ingress: `qu.kube5s.ru`
|
||
|
||
### Security & Compatibility Wave (2026-04-10) ✅
|
||
- ✅ SigV4 подпись, IDOR fix, map race fix, persistence sync
|
||
- ✅ shared_sqs_test.sh PASS=28 FAIL=0
|
||
|
||
## Стресс-тестирование (2026-04-11) ✅
|
||
|
||
### Результаты stress_test.sh v2 (финальный прогон)
|
||
|
||
| # | Секция | Результат | Детали |
|
||
|---|--------|-----------|--------|
|
||
| 1 | Подготовка (тенанты, очереди) | ✅ | 3 тенанта, автогенерация AK/SK |
|
||
| 2 | Конкурентная отправка (10×20) | ✅ | 200/200 доставлено |
|
||
| 3 | Конкурентное чтение | ✅ | 200 прочитано, 200 удалено, 0 в очереди |
|
||
| 4 | Multi-tenant изоляция | ✅ | 0 чужих сообщений, 3×30=90 своих |
|
||
| 5 | Burst (50 одновременно) | ✅ | 50/50 доставлено |
|
||
| 6 | Kill pod + восстановление | ✅ | Данные из Redis — 100% recovery |
|
||
| 7 | Redis disconnect | ✅ | HTTP 200 из кеша, graceful degradation |
|
||
| 8 | Смешанная нагрузка (15s) | ✅* | send+recv+delete+attr, 1 flaky attr |
|
||
| 9 | Cleanup | ✅ | Тенанты и очереди удалены |
|
||
|
||
**Итого: 21/23 ✅, 2 ❌ (flaky сеть, не баги сервера)**
|
||
|
||
### Покрытие тестами
|
||
|
||
| Тест | Что проверяет | Результат |
|
||
|------|---------------|-----------|
|
||
| quick_test.sh | 17 SQS команд, smoke | 31/31 ✅ |
|
||
| hardcore_test.sh | Edge cases, лимиты, ошибки | 114/116 ✅ |
|
||
| stress_test.sh | Конкурентность, resilience, isolation | 21/23 ✅ |
|
||
| **Всего** | | **166/170 ✅ (97.6%)** |
|
||
|
||
## Next Steps
|
||
|
||
- [ ] Перед production без demo user удалить из кода demo UI token path, seeded demo tenant, demo credentials в README и все публичные demo-подсказки в UI
|
||
- [ ] Если demo path нужен дольше, сначала вынести его под явный feature flag с default=off для production окружения
|
||
- [ ] Per-queue locking (заменить глобальный мьютекс на per-queue sync.RWMutex)
|
||
- [ ] DLQ (Dead Letter Queue) — maxReceiveCount → перемещение в DLQ
|
||
- [ ] Rate limiting per tenant
|
||
- [ ] Prometheus метрики (exporter)
|
||
- [ ] Горизонтальное масштабирование (leader election или Redis-based state)
|
||
- [ ] Long polling оптимизация (channel-based вместо 100ms polling)
|
||
- [ ] Go unit tests (`go test ./...`)
|
||
|
||
### v0.1.15 (2026-04-10) ✅
|
||
- ✅ JWT auth через nubes API (deck-api-test.ngcloud.ru)
|
||
- ✅ Login page в UI (ввод токена → валидация → auto-provisioning tenant)
|
||
- ✅ Email пользователя в navbar
|
||
- ✅ /ui/api/* защищены JWT middleware (больше не публичные)
|
||
- ✅ TenantID совместим с sless namespace: sless-{SHA256(sub)[:8]}
|
||
- ✅ Сессия в localStorage (token + email)
|
||
- [ ] Docker build + deploy + E2E test
|
||
|
||
## Known Limitations
|
||
|
||
1. **Глобальный мьютекс** — SyncQueues.Lock() на весь сервис. При >50 rps — bottleneck.
|
||
Стресс-тест подтвердил: работает корректно (нет deadlock/race), но сериализует все операции.
|
||
2. **Нет DLQ** — сообщения после maxReceiveCount не перемещаются. Для production — must-have.
|
||
3. **Long Polling наивный** — polling каждые 100ms. При 20 клиентах = 200 poll/sec на пустую очередь.
|
||
4. **Нет rate limiting** — один тенант может degradировать сервис для остальных.
|
||
5. **Single pod** — replicas > 1 не работает из-за глобального мьютекса (два пода = два state).
|
||
6. **Нет метрик** — Prometheus exporter отсутствует.
|
||
7. **100KB сообщения** — 2/116 flaky в hardcore_test (TLS/nginx buffer, не баг сервера).
|
||
|
||
## Architecture
|
||
|
||
```
|
||
SQS-service/
|
||
├── app/
|
||
│ ├── cmd/main.go — точка входа
|
||
│ ├── models/model.go — Queue, Message, Tenant структуры
|
||
│ ├── gosqs/*.go — реализация SQS API операций
|
||
│ ├── admin/admin.go — Admin API (Create/List/Get Tenant)
|
||
│ ├── tenant/tenant.go — Multi-tenant изоляция
|
||
│ ├── auth/auth.go — AWS Signature V4 верификация
|
||
│ ├── persistence/redis.go — Redis adapter для persistence
|
||
│ ├── router/router.go — HTTP маршруты
|
||
│ └── ui/index.html — Web Console
|
||
├── deployments/k8s/ — Kubernetes манифесты
|
||
├── tests/ — E2E тесты
|
||
└── doc/ — Документация
|
||
```
|
||
|
||
## Technology Stack
|
||
|
||
- **Language**: Go 1.22
|
||
- **HTTP Server**: Go std net/http
|
||
- **Auth**: AWS Signature V4
|
||
- **Storage**: Redis (write-through)
|
||
- **Container**: Docker
|
||
- **Orchestration**: Kubernetes
|
||
- **DNS**: Ingress с TLS
|
||
|
||
## Demo Credentials (read-only для тестирования)
|
||
|
||
```
|
||
Access Key: SSAK-demo-shared-sqs
|
||
Secret Key: demo-secret-key-shared-sqs-ngcloud-2026
|
||
Endpoint: https://qu.kube5s.ru
|
||
```
|
||
|
||
TODO перед production без demo-доступа:
|
||
- удалить demo token path из [app/admin/admin.go](/home/naeel/remote_dev/SQS-service/app/admin/admin.go)
|
||
- выключить/удалить seeded demo tenant
|
||
- удалить публичные demo credentials и demo token из пользовательской документации
|
||
- убрать demo-подсказки из [app/ui/index.html](/home/naeel/remote_dev/SQS-service/app/ui/index.html)
|
||
|
||
## Deployment
|
||
|
||
```bash
|
||
# Kubernetes
|
||
kubectl apply -k deployments/k8s/
|
||
|
||
# Docker (local)
|
||
docker run -p 9090:9090 naeel/shared-sqs:v0.1.14
|
||
```
|
||
|
||
---
|
||
|
||
*Last updated: 2026-04-10*
|