Zpět na domů

Titanium: backend messengera na Erlang

Článek rozebírá evoluci backendu Titanium pro vlastní messenger: odmítnutí XMPP/FastAPI ve prospěch Erlang/OTP. Popsány pts-synchronizace, sharding, benchmarky do 5k RPS. Pro senior vývojáře.

Jak postavit škálovatelný backend messengera na Erlang
Advertisement 728x90

Titanium: serverové jádro pro vlastní messenger – od prototypu k škálovatelnosti

Vývojáři, kteří staví vlastní messengery, často začínají s XMPP/ejabberd nebo Matrix/Synapse. Tyto platformy nabízejí připravený transport, federaci a E2E šifrování. Při úpravě pro moderní UX však narazí na limity.

XMPP s ejabberd na Erlangu je kompaktní a odolný vůči zátěži, ale:

  • XML stanzky přidávají režii při parsování.
  • MUC místnosti se nelineárně škálují: s rostoucím počtem účastníků roste zátěž CPU.
  • XEP rozšíření jsou částečně implementována, což způsobuje race conditions v obchodní logice.

Matrix je silný, ale vrstvená architektura ztěžuje změny: Synapse na Pythonu trpí GIL při real-time úlohách.

Google AdInline article slot

Hybridní přístup – ejabberd pro transport + FastAPI pro API/OTP/reakce – vedl k split-brain v stavu, převodům XML<->JSON a dalším frontám. Zdroj pravdy se rozptýlil mezi komponenty.

Závěr: Jednodušší je postavit backend od nuly pro plnou kontrolu nad stavem a výkonem.

Titanium v1: FastAPI pod zátěží

První verze Titanium na FastAPI s WebSocket pokryla základní funkce: chaty, UIN, média, pts-synchronizace. Prototyp zvládl 500 RPS ve scénáři s 1000 uživateli, 120 zpráv/s, 40 médií/min, 7 % odpojení.

Google AdInline article slot

RPS měřili ne podle /health, ale po celé cestě: odeslání -> doručení -> potvrzení -> synchronizace. To zahrnovalo:

  • Validaci oprávnění.
  • Aktualizaci pts (message points pro delta-synchronizaci).
  • Real-time push přes WebSocket.
  • Retry na špatné síti.
  • Žurnál aktualizací pro offline klienty.

Problémy se projevily při růstu:

  • GIL omezoval souběžnost v WebSocket.
  • Databáze (PostgreSQL) se blokovala při vysoké konkurenci v pts-tabule.
  • Úložiště médií potřebovalo dočasné odkazy, ne věčné.

Architektura Titanium: kde žije pravda

Titanium definuje pravidla správy stavu:

Google AdInline article slot
  • Server – zdroj pravdy: klientům nedůvěřujeme, všechny změny jdou přes API.
  • Pts mechanismus: delta-synchronizace podle message points, jako v Telegramu.
  • Žurnál aktualizací: neměnný log pro replay stavů.
  • Distribuovaný stav: sharding podle UIN, bez sticky sessions.
  • Média: dočasné podpisy S3-like úložiště, TTL 24 h.

Klíčové komponenty:

  • Gateway: WebSocket + HTTP/2, rate limiting, JWT.
  • Core: obchodní logika, pts, oprávnění (ACL podle UIN/skupin).
  • Storage: PostgreSQL (stavy) + Redis (sessions/fronty) + S3 (média).
  • Workers: Celery/RQ pro async (zpracování médií, boty).

Příklad pts-synchronizace (pseudokód):

% Klient žádá delta
handle_get_updates(ReqPts) ->
  Updates = db:fetch_updates_after(ReqPts, UserId),
  NewPts = lists:max([U#update.pts || U <- Updates]),
  {reply, #{updates => Updates, pts => NewPts}}.

Přechod na Erlang/OTP: škálovatelnost a odolnost

Python nezvládl 10k souběžných WebSocket. Přechod na Erlang/OTP problémy vyřešil:

  • Actor model: každý UIN – supervisor tree s gen_server.
  • VM hot-reload bez výpadků.
  • Vestavěné Mnesia/ETS pro low-latency úložiště.
  • Cowboy pro WebSocket s 1M+ spojeními na uzel.

Benchmarky:

| Scénář | FastAPI (Python) | Titanium (Erlang) |

|----------|-------------------|--------------------|

| 1k uživatelů, 120 zpráv/s | 500 RPS | 5k RPS |

| 10k WS | 20 % CPU | 5 % CPU |

| Média 100/min | 2s latence | 200ms |

Implementace gen_server pro session:

-module(session).
-export([start_link/1, handle_message/2]).

handle_call({send_message, Msg}, _From, State) ->
  case validate_rights(Msg) of
    ok ->
      NewPts = State#state.pts + 1,
      save_update(Msg#update{pts=NewPts}),
      broadcast_to_peers(Msg),
      {reply, ok, State#state{pts=NewPts}};
    {error, Reason} -> {reply, {error, Reason}, State}
  end.

Skupinové chaty a hraniční případy

Skupiny jsou samostatnou výzvou. Místo MUC:

  • Sharded rooms: leader podle hash(UIN_list), followers replikují delta.
  • Presence: ETS pro online/offline, pubsub při reconnect.
  • Špatná síť: optimistické odeslání + server ACK, vyplnění mezer z žurnálu.

Seznam zpracování:

  • Duplicitní odeslání (idempotence podle msg_id).
  • Přeuspořádání paketů (timestamp + seq).
  • Spánek/probudení karet (long-poll fallback).
  • Bot webhooks s retry (dead letter queue).

Co je důležité

  • Titanium není klon MTProto, ale minimální sada pro real-time: pts, žurnál, sharding.
  • Erlang/OTP zajišťuje 10x růst RPS při 1/4 CPU oproti Pythonu.
  • Zdroj pravdy na serveru zabraňuje nesrovnalostem na straně klienta.
  • Média a boty async přes workery, core se soustředí na doručení.
  • Škálování: 3 uzly zvládnou 50k uživatelů, 1k zpráv/s bez federace.

— Editorial Team

Advertisement 728x90

Číst dál