13 min czytaniaInżynieria
Kluczowa

Osiąganie p95 < 15ms dla przekierowań z FRA, ASH i SGP

Jak ścieżka edge-redirect Elido utrzymuje budżet p95 15ms przy trafieniu w cache w trzech regionach - architektura, strategia cache'owania, pomiary w rzeczywistych regionach

Marius Voß
DevRel · edge infra
World map showing Elido edge POPs in Frankfurt, Ashburn, and Singapore with p95 latency annotations of 12ms, 13ms, and 14ms respectively

Przekierowanie to synchroniczna blokada. Użytkownik klika skrócony link, przeglądarka zatrzymuje się i nic innego się nie dzieje, dopóki nie nadejdzie odpowiedź 302 i nie rozpocznie się ładowanie kolejnej strony. Przekierowanie to nie zadanie w tle, które można odłożyć na później. Każdy milisekunda dodana w tym miejscu to milisekunda odjęta od strony, która naprawdę się liczy.

Dlatego ustaliliśmy twardy budżet, zanim napisaliśmy pierwszą linię services/edge-redirect: p50 5ms, p95 15ms przy trafieniu w cache, mierzone w POP, z wyłączeniem pełnego uzgadniania TLS. Nie jako cel aspiracyjny. Jeśli coś przekroczy ten limit, zostaje usunięte lub przeniesione na ścieżkę asynchroniczną.

Od kilku miesięcy działamy w trzech regionach produkcyjnych - Frankfurt (FRA), Ashburn (ASH) i Singapur (SGP). Ten wpis to pełne omówienie działania gorącej ścieżki, powodów, dla których liczby wyglądają tak jak wyglądają, oraz tego, co za pierwszym razem zrobiliśmy źle.

TL;DR#

  • Gorąca ścieżka to Go + fasthttp na Hetzner FRA/ASH i OVH SGP, za Caddy z routingiem anycast. Żadnego synchronicznego scoringu botów, żadnego wyzwania JS na ścieżce przekierowania.
  • Dwupoziomowy cache: in-process ristretto LRU (L1, ~88% trafień) wsparty Redis Cluster (L1+L2 łącznie ~99,4%). Gw wywoływania gRPC do api-core wyłącznie przy zimnym chybieniu (~0,6% żądań).
  • 90-dniowe p95 według regionu: FRA 12,1ms, ASH 13,4ms, SGP 14,2ms. Zimne chybienie dodaje ~22ms przy p95 - nadal w granicach budżetu.
  • Invalidacja cache przy mutacji linku przez Redis pub/sub, propagacja p99 poniżej sekundy. TTL L1 to 60 sekund jako zabezpieczenie.

Dlaczego pułap 15ms#

Zanim przejdziemy do architektury: dlaczego 15ms, a nie 50ms lub 5ms?

Dolny limit 5ms jest oczywisty - to mniej więcej koszt transmisji sieciowej dla europejskiego użytkownika trafiającego do POP we Frankfurcie. Fizyki nie da się ominąć. Pułap 50ms jest zbyt luźny - przy p95 na poziomie 50ms dodajesz wyczuwalną przerwę przed każdym wyświetleniem strony dla znacznej części ruchu. Badania nad wydajnością webową konsekwentnie pokazują, że opóźnienia sieciowe poniżej 50ms zaczynają być odczuwalne na urządzeniach mobilnych, gdzie opóźnienie radiowe kumuluje się z czasem przetwarzania - co jest punktem wyraźnie podkreślanym w wytycznych Apple dotyczących programowania z uwzględnieniem sieci.

Liczba 15ms wynikła z kilku konkretnych ograniczeń. Po pierwsze, przekierowania się kumulują. Jeśli kampania marketingowa kieruje ruch przez skrócony link, który następnie przekierowuje na stronę produktu, opóźnienie przekierowania dodaje się do TTFB strony docelowej. Core Web Vitals Google używają LCP jako głównego sygnału, a łańcuch przekierowań dodający 50ms przy p95 jest mierzalny. Po drugie, chcieliśmy mieć wystarczający margines budżetu, by uruchamiać ewaluację reguł dla inteligentnych linków inline na gorącej ścieżce - wymiary routingu (kraj, urządzenie, system operacyjny, język, czas, referrer) muszą działać w tym samym zakresie opóźnień co zwykłe przekierowanie, albo musielibyśmy usunąć obsługę inteligentnych linków z edge. Przy 15ms i koszcie ewaluacji reguł ~0,3ms jest jeszcze miejsce.

Budżet 15ms dotyczy ruchu trafiającego w cache. Zimne chybienia mogą być wolniejsze - wywołanie gRPC do origin dodaje opóźnienie - ale zimne chybienia są z założenia na tyle rzadkie, że nie wpływają znacząco na p95.

Architektura#

Trzy POPy, każdy z tym samym binarnym plikiem: services/edge-redirect, napisany w Go z użyciem fasthttp. Przepustowość serwera fasthttp jest około 8x wyższa niż net/http w zestawie benchmarków, a praktycznie dla nas ważniejsze jest to, że ścieżka żądań bez alokacji utrzymuje przewidywalne pauzy GC pod dużym obciążeniem. Standardowe net/http jest odpowiednie dla większości usług; dla handlera przekierowań, który musi utrzymać czas przetwarzania poniżej milisekund przy dużej współbieżności, unikanie alokacji na stercie per żądanie jest warte mniej ergonomicznego API.

Caddy stoi z przodu jako terminator TLS i reverse proxy. On-demand TLS dla domen niestandardowych najemców (szczegółowo opisane na stronie funkcji domen niestandardowych) provisionuje certyfikaty przy pierwszym żądaniu. Ocenialiśmy HAProxy i nginx jako alternatywy - obydwa są szybkie, obydwa mają dojrzałe wzorce wdrożeń anycast, ale on-demand TLS Caddy to najczystsze podejście do bezobsługowego cyklu życia certyfikatów dla dowolnej liczby domen klientów, co ma dla nas większe znaczenie niż wyciśnięcie kolejnej ułamkowej milisekundy na warstwie proxy.

Routing anycast oznacza, że gdy odwiedzający trafia na f.elido.me, s.elido.me lub b.elido.me, DNS rozwiązuje nazwę do wspólnego prefiksu anycast, a sieć kieruje połączenie TCP do najbliższego POPu. Nie ma żadnej logiki geo-routingu na poziomie aplikacji: sieć wybiera POP. Wprowadzenie do anycast od Cloudflare to najbardziej przejrzyste publiczne wyjaśnienie, dlaczego to jest ważne - kluczową właściwością jest to, że przełączenie awaryjne jest obsługiwane na poziomie BGP, nie przez wygasanie TTL DNS. Jeśli FRA straci łączność, ASH staje się najkrótszą ścieżką dla ruchu europejskiego w ciągu sekund, nie minut. Dokumentacja infrastruktury chmury Hetzner obejmuje podstawową konfigurację routingu dla ich regionów FRA i ASH.

Co ważne: na gorącej ścieżce nie ma synchronicznego scoringu botów. Sprawdzenie scoringu bota zajmujące 10ms samo w sobie zniszczyłoby budżet p95. Wszystkie sygnały jakości ruchu - wykrywanie anonimizatorów, scoring ASN hostingu, deduplikacja kliknięć - działają w url-scanner i click-ingester jako asynchroniczne workery na zimnej ścieżce. Przekierowanie jest wykonywane, a kliknięcie trafia do kolejki Redpanda; ocena jakości następuje po fakcie.

Dwupoziomowy cache#

W cache'u mieszka budżet. Logika:

// Simplified cache lookup: L1 → L2 → origin, with singleflight dedup
func (h *RedirectHandler) resolve(ctx *fasthttp.RequestCtx, slug string) (*Link, error) {
    // L1: in-process ristretto LRU - sub-microsecond on hit
    if link, ok := h.l1.Get(slug); ok {
        return link.(*Link), nil
    }

    // L2 + origin share a singleflight group to prevent thundering herd
    // on concurrent cold misses for the same slug
    val, err, _ := h.sf.Do(slug, func() (interface{}, error) {
        // L2: Redis Cluster - single RTT, typically 0.3–0.8ms within POP
        if data, err := h.redis.Get(ctx, cacheKey(slug)).Bytes(); err == nil {
            link, err := unmarshalLink(data)
            if err == nil {
                h.l1.Set(slug, link, linkCost(link))
                return link, nil
            }
        }

        // Origin: gRPC to api-core - cold miss, ~20ms extra
        link, err := h.origin.GetLink(ctx, &pb.GetLinkRequest{Slug: slug})
        if err != nil {
            return nil, err
        }
        payload, _ := marshalLink(link)
        h.redis.Set(ctx, cacheKey(slug), payload, redisTTL)
        h.l1.Set(slug, link, linkCost(link))
        return link, nil
    })
    if err != nil {
        return nil, err
    }
    return val.(*Link), nil
}

L1 to ristretto, cache LRU z kontrolą dopuszczeń od Dgraph. Kontrola dopuszczeń jest istotna: naiwny LRU pod obciążeniem skanowaniem (bot trafiający w tysiące unikalnych slugów) będzie wypierać gorące wpisy, robiąc miejsce dla zimnych, które nigdy nie zostaną ponownie żądane. Polityka dopuszczeń oparta na TinyLFU stosowana przez ristretto jest odporna na to - śledzi liczniki częstotliwości tanio i odmawia dopuszczenia wpisu, który nigdy wcześniej nie był widoczny, gdy cache jest pod presją. Efektem netto jest to, że współczynnik trafień cache pod adversarialnym ruchem skanującym pozostaje bliski organicznemu współczynnikowi, zamiast się załamywać.

L2 to Redis Cluster. Każdy POP ma własną instancję klastra, by wykluczyć ruch między regionami z gorącej ścieżki. FRA i ASH współdzielą oddzielną instancję Redis dla sygnałów invalidacji pub/sub (więcej o tym poniżej); SGP ma własną. Pojedyncze Redis GET w tym samym centrum danych jest niezawodnie poniżej 1ms. Łączny współczynnik trafień L1+L2 wynosi około 99,4% przez ostatnie 90 dni - co oznacza, że wywołania do origin zdarzają się mniej więcej raz na 167 żądań.

W przypadku zastosowania solutions/developers - zespołów używających API do masowego tworzenia linków - praktyczną konsekwencją jest to, że świeżo utworzony link doświadczy jednego zimnego chybienia na POP, po czym będzie ciepły przez czas trwania TTL. Linki bez ruchu wygasają z obu cache'y bez ręcznego usuwania.

Na co idzie 15ms#

Poniższy diagram rozkłada budżet p95 przy trafieniu w cache na fazy:

Poziomy skumulowany pasek pokazujący 15ms budżet p95 przy trafieniu w cache podzielony na: wznowienie TLS 2ms, wyszukiwanie L1 0,4ms, budowanie nagłówka 1ms, powrót sieciowy 9ms i margines 2,6ms. Ilustracyjne wartości mediany FRA.

Dominującym segmentem jest powrót sieciowy - około 9ms mediany, co oznacza, że fizyczna odległość między odwiedzającym a POPem odpowiada za 60% budżetu. Tego nie da się skompresować. Wdrożenie wieloregionowe to jedyna dźwignia: dodanie POPu zmniejsza medianę RTT dla odwiedzających w danym regionie. Następny region w harmonogramie zmniejsza p95 SGP dla ruchu z Azji Południowej, gdzie aktualnie routujemy 14ms, ponieważ Singapur jest najbliższym POPem.

Wznowienie sesji TLS przy 2ms zakłada TLS 1.3 0-RTT z biletem sesji już w ręku. Przy pierwszej wizycie z danego urządzenia pełne uzgadnianie TLS dodaje mniej więcej 10-15ms na wierzchu - stąd budżet 15ms wyraźnie odnosi się do ruchu trafień w cache + wznowionej sesji, który stanowi zdecydowaną większość ruchu kliknięć w praktyce. RFC 7234 reguluje semantykę buforowania dla warstwy HTTP; warto zauważyć, że odpowiedzi 302 domyślnie nie są przechowywane przez cache przeglądarki (§4.2.2), co jest właściwym zachowaniem dla naszego przypadku - każde żądanie przekierowania dociera do edge, każde przekierowanie ma własną decyzję routingową, żadnego przestarzałego miejsca docelowego w cache przeglądarki.

Margines 2,6ms to realna przestrzeń operacyjna, nie wypełniacz. Pod kontrolerem GC Go, sporadyczne pauzy stop-the-world rzędu 0,5-1ms są oczekiwane nawet przy dostrojonych ustawieniach GOGC. Narzut proxy Caddy dodaje mały stały koszt. Margines utrzymuje nas poza granicą budżetu, gdy te efekty się kumulują.

Invalidacja cache#

Redis pub/sub jest mechanizmem. Gdy link jest mutowany w api-core - zmienione miejsce docelowe, zaktualizowane reguły targetowania, zarchiwizowany link - handler mutacji publikuje do kanału link:invalidate ze slugiem jako ładunkiem. Każdy edge POP subskrybuje ten kanał. Po odebraniu subskrybent wywołuje l1.Del(slug) i redis.Del(cacheKey(slug)). Następne żądanie dla tego slugu ponownie wypełnia oba poziomy z origin.

TTL L1 wynoszący 60 sekund to fallback, nie mechanizm podstawowy. Jeśli subskrybent pub/sub nie działa - powiedzmy, że Redis miał chwilę przestoju lub nastąpiła partycja sieciowa między POPem a instancją pub/sub - wpis wygasa z L1 w ciągu co najwyżej 60 sekund. TTL L2 wynosi 300 sekund, więc awaria subskrybenta oznacza do 5 minut potencjalnie nieaktualnych danych L2, podczas których TTL L1 jest jedynym zabezpieczeniem. Alarmujemy przy utracie subskrypcji pub/sub w ciągu 30 sekund.

W przypadku inteligentnych linków z regułami okienkowanymi czasowo, nieaktualność ma konkretną konsekwencję: jeśli reguła aktywuje się o 17:00, a L1 edge POPu ma poprzednią wersję reguły z cache'owaną z do 60 sekundami pozostałego TTL, ruch między 17:00 a 17:01 może trafiać do miejsca docelowego sprzed aktualizacji. Ścieżka pub/sub eliminuje to w typowym przypadku; TTL 60 sekund łapie przypadki brzegowe. Dla kampanii, gdzie granica czasowa ma precyzyjne znaczenie, zalecanym wzorcem jest użycie status=disabled dla starej reguły, odczekanie jednego cyklu TTL (60 sekund), a następnie aktywacja nowej. Dodaliśmy endpoint odpytywania pod GET /v1/links/{id}/cache-status, żeby pipeline'y mogły potwierdzić propagację przed kontynuowaniem.

Pomiary w rzeczywistych regionach#

Poniższe liczby pochodzą z danych demo-workspace zebranych przez 90 dni kończących się 2026-05-12. Dotyczą wyłącznie ruchu trafiającego w cache. Wszystkie znaczniki czasu są UTC.

RegionPOPp50p95p99
EU (Frankfurt)FRA · Hetzner4,8ms12,1ms18,4ms
US East (Ashburn)ASH · Hetzner5,2ms13,4ms20,1ms
SE Asia (Singapore)SGP · OVH5,6ms14,2ms22,8ms

FRA jest najszybszy, bo większość obciążenia to ruch europejski, więc mediana RTT jest niższa. SGP obsługuje szersze rozproszenie geograficzne - ruch z Azji Południowo-Wschodniej ma niższe RTT, podczas gdy ruch z Azji Południowej i Wschodniej wydłuża ogon.

Liczby p99 przekraczają budżet 15ms. To celowe. Budżetem jest p95, nie p99. Wartości p99 są kształtowane przez warunki odstające: przełączenia połączeń komórkowych, retransmisje TCP, sporadyczne skoki opóźnień Redis. Monitorujemy p99, ale nie mamy wobec niego SLA. Decyzja inżynierska polega na tym, że p95 uchwytuje doświadczenie „prawie każdego prawie przez cały czas", a optymalizowanie ostatniego 1% wymagałoby eliminowania źródeł naturalnej zmienności sieciowej, która nie jest pod naszą kontrolą.

p95 zimnego chybienia wynosi około 22ms. To dolna granica, którą możemy osiągnąć biorąc pod uwagę, że origin gRPC dodaje round trip w tym samym centrum danych (FRA → FRA przez sieć prywatną to około 0,3ms) plus wyszukiwanie Postgres w api-core (zazwyczaj 1-3ms dla kluczowanego wyszukiwania slugu). Wartość 22ms jest zmierzona, nie szacowana; mieści się w budżecie, jaki dopuszczamy dla ścieżek zimnych chybień, który ustalono na p95 35ms.

Dla zespołów oceniających analitykę wieloregionową, te liczby opóźnień są dostępne jako metryka Prometheus (redirect_duration_seconds z etykietami region i cache_tier) z endpointu metryk.

Tryby awarii, o których nie napisaliśmy za pierwszym razem#

Thundering herd przy wygasaniu klucza#

Zanim dodaliśmy singleflight, slug wygasający jednocześnie z L1 i L2 pod umiarkowanym ruchem generował serię równoległych wywołań origin gRPC - każde wykonujące odczyt z Postgres dla tego samego slugu, wszystkie zwracające ten sam wynik. Pod testem obciążeniowym powodowało to skoki CPU api-core niezwiązane z wolumenem tworzenia linków. Grupa singleflight zwija równoległe chybienia dla tego samego slugu w jedno wywołanie do origin. Pozostałe oczekujące goroutines blokują na grupie i dostają ten sam wynik po jego rozwiązaniu. Implementacją jest standardowy pakiet Go golang.org/x/sync/singleflight.

Popełniliśmy ten błąd w pierwszym prototypie. Thundering herd przy wygasaniu klucza to jeden z tych trybów awarii, który nie pojawia się w testach jednostkowych - ujawnia się tylko pod realistyczną współbieżnością. Dodajemy to do tego wpisu, bo to częste przeoczenie w opisach architektur cache'owych, a naprawa jest genuinely prosta.

Fallback przy awarii Redis#

Jeśli POP utraci łączność ze swoim klastrem Redis, fallbackiem nie jest błąd - ścieżka kodu degraduje się do L1-only plus bezpośrednie origin gRPC przy chybieniu L1. POP kontynuuje obsługę. Współczynnik trafień spada, bo L2 jest niedostępny, więc wolumen wywołań do origin skacze, ale ścieżka przekierowania pozostaje funkcjonalna. Ścieżka awarii Redis była dwukrotnie testowana w produkcji (obydwa razy były to okna konserwacyjne Hetzner). Szczytowy wskaźnik wywołań do origin podczas drugiego incydentu wyniósł około 8x wartości bazowej przez czas trwania awarii (~4 minuty). api-core poradziło sobie bez zdarzeń skalowania.

Propagacja DNS podczas failoveru POP#

Failover anycast jest na poziomie BGP - nie trzeba czekać na wygaśnięcie TTL DNS, nie ma limitu czasu na sprawdzenie zdrowia na poziomie aplikacji w ścieżce żądania. POP przechodzący offline wyzwala wycofanie trasy BGP, a ruch sieciowy przechodzi do najbliższego POPu w oknie konwergencji BGP (zazwyczaj 15-90 sekund w zależności od liczby przeskoków sieciowych do dotkniętej ścieżki). Istotnym parametrem operacyjnym jest nasz interwał sprawdzania zdrowia: uruchamiamy sprawdzenia TCP co 10 sekund na POP. Niepowodzenie sprawdzenia wyzwala wycofanie. Interwał 10 sekund oznacza, że awaria POPu może obsługiwać do 10 sekund nieudanego ruchu przed wycofaniem. Testowaliśmy tę granicę celowo; rzeczywisty wpływ w dwóch produkcyjnych incydentach był poniżej interwału sprawdzania.

Czego nie robimy na gorącej ścieżce#

Każdy element, którego nie ma na gorącej ścieżce, to celowy wybór, nie przeoczenie.

Synchroniczne zapisywanie kliknięć. Kliknięcia są fire-and-forget do Redpanda. Handler przekierowania dołącza zdarzenie kliknięcia do tematu Kafka (clicks.raw) ze slugiem, znacznikiem czasu, obciętym IP i hashem user-agenta, a następnie odpowiada kodem 302. Zapis jest nieblokujący. Jeśli Redpanda jest niedostępna, kliknięcie jest tracone - nie przekierowanie. Świadomie zaakceptowaliśmy, że utrata kliknięć podczas awarii infrastruktury jest dopuszczalna, a awaria przekierowania nie jest. Konsument click-ingester przetwarza temat Redpanda i zapisuje do ClickHouse. To dlatego dane analityczne dla danego zdarzenia kliknięcia są dostępne z krótkim opóźnieniem (zazwyczaj poniżej 5 sekund), nie natychmiast.

Inline bot challenges. Wyzwanie dla bota dodaje co najmniej 10-50ms synchronicznej pracy - wyzwania JavaScript dodają pełny round trip. Na ścieżce przekierowania nie robimy ani jednego, ani drugiego. Usługa url-scanner przetwarza sygnały jakości ruchu asynchronicznie. Dla zespołów solutions/developers budujących kampanie linkowe oznacza to, że przekierowanie nigdy nie jest blokowane przez wyzwanie, które degraduje doświadczenie legalnego ruchu.

Walidacja schematu przy przekierowaniu. Docelowy URL i reguły targetowania są walidowane w czasie zapisu, gdy link jest tworzony lub aktualizowany przez api-core. Kiedy slug trafia do cache'u, jego struktura jest znana jako poprawna. Nie ma walidacji schematu JSON, kroku parsowania URL, sprawdzania składni reguł w czasie przekierowania. Binarna wersja edge'a w pełni ufa wpisowi z cache'a. Jest to bezpieczne tylko dlatego, że ścieżka zapisu waliduje przed dopuszczeniem do cache'a.

Nudne rzeczy#

Trzy kwestie, o których za mało piszemy, bo są nudne do czytania, a ważne, żeby zrobić je dobrze.

Budżety rozmiarów cache. ristretto jest inicjalizowany z wyraźnym budżetem kosztów w bajtach, nie prostą liczbą elementów. Każdy zbuforowany link jest kosztowany przez swój rozmiar po serializacji, który różni się w zależności od liczby reguł targetowania. Link bez reguł kosztuje około 200 bajtów; link z 6 regułami targetowania kosztuje bliżej 800 bajtów. Budżet jest ustawiony tak, aby zużywać co najwyżej 10% dostępnej pamięci RAM instancji, pozostawiając margines dla środowiska uruchomieniowego Go, Caddy i buforów połączeń. Błędne ustawienie powoduje thrashing cache: zbyt mały budżet wypiera wpisy przed upływem TTL, kierując ruch w stronę L2 i origin.

Dostrajanie GC pod obciążeniem. Garbage collector Go jest dobrze dostrojony domyślnie, ale domyślne GOGC=100 wyzwala GC przy dwukrotności rozmiaru żywej sterty. Dla handlera przekierowania, gdzie żywa sterta jest mała, ale wskaźnik alokacji jest umiarkowany (fasthttp nie alokuje na gorącej ścieżce, ale są alokacje obiektów dla zdarzeń kliknięć i wywołań gRPC), GC uruchamia się częściej niż potrzeba. W produkcji używamy GOGC=400. Efektem są dłuższe cykle GC, ale rzadsze - co ma znaczenie dla opóźnień w ogonie. Cykl GC zajmujący 2ms i zdarzający się raz na 4 sekundy wnosi mniejszy wkład do p99 niż cykl 1ms co sekundę. Zweryfikowaliśmy to empirycznie za pomocą make bench przed ustawieniem w konfiguracji wdrożenia.

Dyscyplina make bench. Binarna wersja edge'a ma zestaw benchmarków (go test -bench=. -benchmem ./... z poziomu services/edge-redirect). Każda proponowana zmiana w gorącej ścieżce - dodanie nowego nagłówka, zmiana formatu klucza cache'a, dostosowanie ewaluatora reguł - przechodzi przez benchmarki przed scaleniem. Zmiana, która dodaje 0,5ms do benchmarku p50, to zmiana przesuwająca p95 w produkcji. Benchmark jest bramą, nie sprawdzeniem post-hoc. Raz zbagatelizowaliśmy to przy refaktoringu, który zmienił logikę normalizacji slugów, i wysłaliśmy regresję o 1,2ms, która pojawiła się w dashboardach regionowych dwa dni później. Regresja była prawdziwa i lekcja pozostała.


Decyzje architektoniczne są szczegółowo udokumentowane pod adresem /docs/architecture/edge-redirect. Jeśli oceniasz Elido jako warstwę infrastruktury przekierowań dla kampanii o dużym wolumenie lub platformy deweloperskiej, strona solutions/developers opisuje powierzchnię API i opcje SDK. Aby dowiedzieć się, co dwupoziomowy cache oznacza dla zachowania inteligentnych linków - w szczególności okno propagacji dla zmian reguł - wpis o inteligentnych linkach omawia to dogłębnie.


Marius Voß jest DevRel i inżynierem infrastruktury edge w Elido. Był jednym z inżynierów, którzy doprowadzili binarny plik edge-redirect od prototypu do produkcji, i od tamtej pory nie spuszcza wzroku z jego dashboardów opóźnień.

Wypróbuj Elido

Wklej URL, otrzymaj krótki link

Bez rejestracji. Link działa 30 dni. Zarejestruj się, aby zachować go na zawsze.

Za darmo, bez rejestracji · 2 dziennie

Wypróbuj Elido

Skracarka URL hostowana w UE: własne domeny, głęboka analityka i otwarte API. Darmowy plan - bez karty kredytowej.

Tagi
url shortener performance
edge redirect latency
multi-region url shortener
redirect cache strategy
fasthttp
anycast routing

Czytaj dalej