Skip to Content
Elido is in closed beta — APIs are stable but rate-limits and quotas may change before GA. Request access →
Архітектураedge-redirect (гарячий шлях)

edge-redirect

edge-redirect - це єдиний сервіс Elido на шляху запиту публічного перенаправлення. Він працює в Hetzner FRA, Hetzner ASH та OVH SGP за Caddy і відповідає на кожен запит https://elido.me/<slug> статусом 302 на цільовий URL. Все інше - це “холодний шлях” (cold-path).

Ця сторінка описує логіку дизайну: що є в бінарному файлі, чого немає і чому бюджет затримки визначає реалізацію.

1. Бюджет затримки

Етапp50p95Примітки
TLS-рукостискання (тепле)0.5мс2мсВідновлення сесії Caddy + TLS 1.3
Anycast DNS + вхідний трафік на межі (edge ingress)--Обмежено мережею відвідувача
Пошук у кеші L10.2мс0.5мсLRU всередині процесу, ristretto
Пошук у кеші L2 (при промаху L1)1.5мс3мсRedis Cluster, той самий дата-центр
Отримання з джерела (при промаху L2)12мс30мсgRPC до api-core, рідко
Обчислення правил смарт-лінків0.3мс1мсТой самий процес, без додаткових вузлів
Запис відповіді + публікація кліку1мс3мсredpanda працює за принципом “відправив і забув”
Загалом при попаданні в кеш5мс15мсБез урахування TLS

Показник 15мс p95 є жорстким. Усе, що виходить за ці межі - синхронне читання з БД, блокуючий I/O на події кліку, компіляція регулярних виразів (regex) на запит - безжально видаляється.

2. Що в бінарному файлі

Лише три важливі пакети:

  • internal/cache - клієнт L1 LRU + L2 Redis, ~600 рядків коду (LOC)
  • internal/rules - обчислювач правил смарт-лінків, ~400 LOC
  • internal/redirect - обробник запитів + публікатор кліків, ~300 LOC

Плюс невеликий cmd/edge-redirect main та стандартна бібліотека. Бінарний файл займає 18МБ (stripped); холодний старт <200мс. Поступові перезапуски (rolling restarts) завершуються за 30 секунд по всьому кластеру.

3. Чого НЕМАЄ в бінарному файлі

За задумом, на “гарячому шляху” (hot path):

  • Без SQL - Postgres знаходиться у джерелі на холодному шляху, він ніколи не використовується при попаданні в кеш.
  • Без парсингу JSON на гарячому шляху - метадані посилання зберігаються в Redis у упакованому бінарному форматі (msgpack) і декодуються без виділення пам’яті (zero-allocation).
  • Без компіляції регулярних виразів (regex) на кожен запит - регулярні вирази user-agent із правил смарт-лінків компілюються один раз під час завантаження посилання; скомпільовані матчери зберігаються у записі кешу.
  • Без вихідного HTTP - кліки записуються в redpanda, а не в зовнішні пікселі. Розсилка по пікселях (fan out) виконується пізніше воркерами на холодному шляху.
  • Без автентифікації - кінцева точка перенаправлення є публічною за визначенням. Єдине, що ми робимо - це обмеження швидкості (rate-limit) за IP через Caddy ще до того, як запит потрапить до нас.

Усе перелічене вище або працює у воркерах на холодному шляху, або не працює взагалі.

4. Архітектура кешу

Два рівні, обидва ліниві (lazy).

L1 - ristretto LRU на процес. ~50,000 записів за замовчуванням, TTL 60 секунд для посилань із правилами та 5 хвилин для звичайних. Різниця в TTL важлива, оскільки зміни правил мають поширюватися швидко; цілі звичайних посилань змінюються рідко.

L2 - Redis Cluster, один кластер на регіон. Ті самі TTL, але є авторитетним джерелом. При промаху L1 запит отримує дані з L2 і на зворотному шляху наповнює L1; при промаху L2 він переходить до api-core через gRPC, наповнює обидва рівні та повертає перенаправлення.

Інвалідація кешу - це публікація в канал Redis pub/sub (link:invalidate); кожна точка присутності (edge POP) підписана на нього і видаляє відповідні записи L1 протягом 1 секунди.

5. Публікація кліків

Кліки працюють за принципом “відправив і забув” у redpanda. Виклик публікації є async з точки зору обробника запиту - він додає подію в буфер кожного процесу і негайно повертає відповідь. Окрема goroutine очищає буфер кожні 100мс або після 1000 подій, залежно від того, що настане раніше.

Якщо redpanda недоступна, буфер заповнюється, і goroutine скидає надлишок у локальний WAL на диску. Коли redpanda відновлюється, WAL очищається. Ми допускаємо до 5 хвилин буферизованих кліків перед надсиланням сповіщення.

Це означає, що жоден клік не буде втрачено при збої redpanda в одному регіоні, а шлях перенаправлення не сповільнюється.

6. Правила смарт-лінків

Двигун правил є частиною того ж процесу - немає окремого “сервісу правил”, до якого треба звертатися. Обчислення правил додає <1мс навіть коли посилання має шість правил, тому що скомпільовані матчери знаходяться безпосередньо в записі кешу.

Перемагає перший збіг (First-match). Правило спрацьовує, коли всі його умови match є істинними (країни, пристрої, ОС, браузери, мови, часові вікна, реферер-хости). Правила обчислюються в порядку, встановленому в дашборді.

Якщо жодне правило не підходить, використовується default_destination_url посилання. Типове значення обов’язкове - смарт-лінк ніколи не повертає 404.

Див. Смарт-лінки для ознайомлення зі схемою правил та деталями їх створення.

7. Топологія розгортання

Три точки присутності (POP) станом на травень 2026 року:

  • FRA (Франкфурт, Hetzner) - основний в ЄС
  • ASH (Ешберн, Hetzner) - основний у США
  • SGP (Сінгапур, OVH) - основний в APAC, регіон Business+

Кожен POP запускає 4-12 подів edge-redirect на bare metal (не віртуальні машини - бюджет затримки не витримує віртуалізацію на мережевому шляху). Caddy попереду обробляє термінацію TLS, Brotli та обмеження швидкості.

Anycast DNS (BGP через Hetzner + OVH) спрямовує відвідувачів до найближчого POP. Перемикання (failover) між POP відбувається автоматично через BGP withdraw; перемикання на основі DNS не використовується.

8. Що ми вимірюємо

Метрики, що мають значення:

  • elido_redirect_latency_seconds{cache="l1|l2|origin"} - розділено за шарами кешу, оскільки ці три групи абсолютно різні
  • elido_redirect_requests_total{status,cache} - частота помилок + коефіцієнт попадання в кеш
  • elido_link_cache_size - підтримуйте коефіцієнт попадання в L1 вище 95% при стабільному трафіку
  • elido_click_publish_lag_seconds - має бути близьким до нуля; сповіщення при >5с

Див. Спостережуваність для перегляду повного дашборду Grafana.

Див. також