Elido
9 хв читанняІнженерія

Як працюють скорочувачі URL? Механіка пояснена

Як працюють скорочувачі URL? Зберігають відповідність слага та призначення, шукають ключ при кожному кліку, повертають HTTP-перенаправлення. Механіка від початку до кінця

Marius Voß
DevRel · edge infra
Конвеєр від запиту до пошуку слагу до відповіді 302 з переходом на URL-адресу призначення, у кольоровій палітрі Elido

Відкрийте elido.me/abc123 - і щось має перетворити цей короткий рядок на повну веб-адресу, перш ніж браузер зможе завантажити щось. Механізм простіший, ніж більшість людей припускає. Скорочувач URL зберігає відповідність між коротким кодом та довгою URL-адресою призначення. Коли ви клікаєте на коротке посилання, сервіс використовує код як ключ пошуку, знаходить призначення і повертає HTTP-перенаправлення, яке вказує браузеру, куди насправді йти. Один запит всередину, одне перенаправлення назовні.

Це вся ідея. Все інше - інженерія навколо трьох задач: зробити пошук швидким, зберігати коди короткими та унікальними, та записувати клік, не сповільнюючи нікого. Ця стаття проходить по всьому ланцюгу роботи скорочувача URL від початку до кінця, використовуючи граничну архітектуру Elido як конкретний приклад, залишаючись водночас правдивою для скорочувачів загалом. Ми розглянемо відповідність слага та URL, як генеруються короткі коди, де живуть дані, вибір між перенаправленням 301 та 302 (який плутає більше людей, ніж будь-що інше), як виглядає HTTP-перенаправлення на рівні мережевих пакетів, чому важливе кешування на граничних серверах, та як клік підраховується асинхронно.

Як працюють скорочувачі URL: відповідність у центрі#

Усуньте інфраструктуру - і скорочувач URL виявиться сховищем ключ-значення з підключеним обробником перенаправлень. Ключ - це слаг, короткий код після домену. Значення - це призначення, довга URL-адреса, яку ви спочатку вставили.

Коли ви створюєте коротке посилання, скорочувач записує один рядок: цей слаг вказує на це призначення. Коли хтось заходить за коротким посиланням, скорочувач зчитує цей рядок і діє відповідно до нього. Створення посилань - рідкість; читання - постійне. Одне маркетингове посилання може бути записане один раз, а потім зчитане кілька сотень тисяч разів протягом свого життя. Це співвідношення з переважанням читань є найважливішим фактом про навантаження, і воно визначає кожне наступне архітектурне рішення - особливо кешування.

Сама відповідність може містити більше, ніж просто призначення. В Elido слаг може містити правила таргетування, тому одне коротке посилання перенаправляє на різні призначення залежно від країни, пристрою, мови або часу. Це те, що ми називаємо розумним посиланням, і це всё той самий пошук, просто з невеликою оцінкою правила після читання. Базова залежність ніколи не змінюється: слаг на вхід, призначення на виході.

Генерація короткого коду#

Якщо слаг - це ключ, звідки він береться? Є два перевірених підходи, і більшість скорочувачів використовують один або їх поєднання.

Перший - кодування ідентифікатора бази даних у base62. Кожне нове посилання отримує автоінкрементний цілочисловий ідентифікатор від бази даних. Ви кодуєте це ціле число у base62, який використовує 62 безпечних для URL символи a-z, A-Z та 0-9. Ідентифікатор 1 стає b, ідентифікатор 125 - двосимвольним кодом, і так далі. Base62 щільний: три символи охоплюють близько 238 000 посилань, п'ять - приблизно 916 мільйонів, шість - близько 56 мільярдів. Коди залишаються короткими, а оскільки вони однозначно відповідають унікальним ідентифікаторам, вони ніколи не стикаються. Недоліком є те, що послідовні ідентифікатори можна передбачити, тому багато систем перемішують або зміщують простір ідентифікаторів перед кодуванням.

Другий підхід - випадкова генерація. Обирається випадковий рядок фіксованої довжини з тього самого алфавіту, потім перевіряється в базі даних, щоб переконатися, що він ще не зайнятий. При колізії генерується інший. Колізії надзвичайно рідкісні при розумних довжинах, тому цикл повторної спроби майже ніколи не запускається. Випадкові слаги не перебираються, що є аргументом безпеки на їхню користь.

Кастомні слаги - брендовані на зразок elido.me/spring-sale - розміщуються поверх будь-якої зі схем. Користувач надає рядок; скорочувач перевіряє його на допустимі символи та перевіряє унікальність в тому самому індексі перед збереженням. Незалежно від того, чи згенерований слаг чи обраний вручну, він потрапляє в те саме місце: унікальний стовпець у сховищі даних.

Де живуть дані#

Відповідність слага та призначення потребує сховища, яке може швидко та стабільно відповідати на питання «куди вказує цей слаг». Для джерела правди таким сховищем майже завжди є реляційна база даних. Elido використовує Postgres, де слаг зберігається як унікальний індексований стовпець, тому пошук - це одиночне зчитування за ключем, а не сканування таблиці. Postgres зберігає канонічний запис для кожного посилання, користувача та робочого простору.

Але звертатися до Postgres при кожному кліку було б марнотратством, враховуючи переважання читань. Типовий пошук слага за ключем у Postgres займає від одної до трьох мілісекунд - це звучить швидко, поки не перемножите на обсяг кліків вірального посилання та не пригадаєте, що з'єднання з базою даних є обмеженим ресурсом. Тому виробничі скорочувачі ставлять кеш перед базою даних. Більшість читань фактично обслуговується кешем; база даних є резервним варіантом для того, чого в кеші ще немає.

Блок-схема: GET-запит браузера для elido.me/abc123 перевіряє вбудований кеш L1 LRU, при промахуванні переходить до кешу L2 Redis, потім до оригінального gRPC-виклику api-core при холодному промахуванні, і повертає перенаправлення 302 із призначенням у заголовку Location

Elido запускає двошаровий кеш перед Postgres. Перший рівень - вбудований LRU-кеш, що живе всередині бінарного файлу перенаправлення, який повертає призначення за кілька сотень наносекунд без жодного мережевого переходу. Другий рівень - кластер Redis у тому самому регіоні, що обслуговує за менш ніж мілісекунду. Тільки холодне промахування - слаг, якого жоден рівень не бачив нещодавно - проходить до оригінального gRPC-виклику до api-core, який читає Postgres. Загальний відсоток потрапляння в кеш по обох рівнях становить близько 99,4%, тому до бази даних звертаються приблизно на одному запиті з 167. Повний аналіз поведінки кешу, включно з його політикою виселення та збоями, на які ми натрапляли, є у нашій статті про стратегію кешування.

Що таке HTTP-перенаправлення насправді#

Отримавши призначення, скорочувач має передати його браузеру. Він робить це за допомогою HTTP-перенаправлення, яке є лише певним типом відповіді. Замість повернення вмісту сторінки зі статусом 200 OK, сервер повертає код статусу 3xx та заголовок Location із реальною URL-адресою. На рівні мережевих пакетів відповідь невелика:

HTTP/1.1 302 Found
Location: https://shop.example.com/spring-collection
Content-Length: 0

Браузер зчитує код статусу, бачить заголовок Location і одразу надсилає новий запит на цю адресу. Для тих, хто клікає, це виглядає як одна навігація; під капотом - це два запити, де коротке посилання виступає швидким довідником посередині. Семантика кожного коду 3xx визначена в RFC 7231, а посібник Mozilla з HTTP-перенаправлень є найзрозумілішим практичним довідником про те, що робить кожен код.

Тіло відповіді порожнє, бо нічого рендерити. Весь вміст - це рядок статусу та заголовок. Саме тому перенаправлення дешево обслуговувати: немає шаблону, немає об'єднання таблиць для вмісту, немає розмітки. Знайти слаг, встановити один заголовок, відправити.

301 vs 302: вибір, що визначає вашу аналітику#

Тут скорочувачі тихо приймають рішення, яке більшість користувачів ніколи не бачить, але яке визначає, чи є їхнє посилання редагованим та відстежуваним. Код статусу перенаправлення - це не формальність. Два поширені варіанти поводяться дуже по-різному.

301 Moved Permanently повідомляє браузеру, і кожному проксі та CDN між вами та сервером, що це коротке посилання завжди буде вказувати на те саме місце. Тому вони кешують його. 301 агресивно зберігається. Наступного разу, коли відвідувач клікне на це коротке посилання, браузер може вирішити його з кешу, не звертаючись до скорочувача взагалі. Це чудово для зменшення одного мережевого циклу, але є катастрофою для інструменту посилань, оскільки ламає дві речі. По-перше, аналітика сліпне: кліки, що обслуговуються з кешу браузера, ніколи не досягають вашого сервера, тому вони ніколи не підраховуються. По-друге, призначення фактично заморожується. Якщо ви зміните місце призначення посилання, всі, хто вже закешував 301, продовжуватимуть потрапляти на стару адресу, поки їх кеш не закінчиться - а ви не контролюєте це.

Порівняння поряд: постійне перенаправлення 301 (кешується браузером, аналітика не бачить кліків, призначення важко змінити) проти тимчасового перенаправлення 302 (запитується щоразу, аналітика працює, призначення редагується)

302 Found (і його суворіший варіант 307 Temporary Redirect) повідомляє браузеру, що це тимчасово: поверніться та запитайте знову наступного разу. Браузер не кешує відповідність, тому кожен клік повторно запитує коротке посилання у сервера. Цей додатковий мережевий цикл - саме те, що потрібно інструменту посилань. Кожен клік досягає вашої інфраструктури, тому кожен клік можна підрахувати, і оскільки сервер вирішує призначення щоразу свіжо, ви можете змінити куди веде посилання - і новий напрямок набере чинності з наступного кліку. Ціна - один мережевий цикл за клік, який добре побудована гранична мережа тримає в однозначних мілісекундах.

Саме тому Elido за замовчуванням використовує 302. Редаговані призначення та точні дані про кліки - це весь сенс керованого посилання, а 301 жертвує обома заради оптимізації кешу, яка зазвичай не потрібна. RFC 7231 пояснює, що 301 є кешованим за замовчуванням, а 302 не зберігається, якщо заголовки не кажуть інакше - саме така поведінка, яку потребують два варіанти використання. Є вузькі випадки, де постійне перенаправлення є правильним - наприклад, справжня міграція домену - але для відстежуваних, редагованих коротких посилань тимчасове перенаправлення є правильним вибором за замовчуванням.

Кешування на граничних серверах для мінімальної затримки#

Перенаправлення є синхронним та блокуючим. Браузер відвідувача очікує на коротке посилання, поки не отримає перенаправлення, і лише тоді може почати завантажувати сторінку, яка насправді має значення. Кожна мілісекунда, витрачена на вирішення слагу, - це мілісекунда, додана до часу очікування відвідувача. Саме тому серйозні скорочувачі переміщують пошук якомога ближче до відвідувача.

Elido запускає обробник перенаправлень на граничних точках присутності у Франкфурті, Ашберні та Сінгапурі, де трафік маршрутизується до найближчої. Обробник написаний на Go поверх fasthttp, вибраного тому, що його шлях запиту без виділення пам'яті підтримує передбачувані паузи збирача сміття під тривалим навантаженням. У поєднанні з кешем у пам'яті це утримує перенаправлення на p95 нижче 15мс при попаданні в кеш, виміряних на точці присутності: приблизно 4,8мс медіани у Франкфурті, до близько 14мс p95 в Сінгапурі, де географія ширша. Більша частина цього бюджету - фізичний мережевий транзит, невідворотня відстань між відвідувачем та найближчою точкою присутності, яку неможливо оптимізувати програмно. Ми задокументували повний бюджет затримки та вимірювання кожного регіону у статті про p95 нижче 15мс.

Розміщення пошуку на граничних серверах замість одного центрального - це різниця між перенаправленням, яке відчувається миттєвим, і тим, яке додає помітну паузу. Це також причина, чому anycast-маршрутизація на граничних серверах перевершує налаштування лише DNS для цього навантаження - порівняння, яке ми розглядаємо у статті граничні точки присутності проти маршрутизації лише DNS. Коротко: мережа вирішує географію, а кеш - швидкість.

Підрахунок кліку без сповільнення перенаправлення#

Скорочувач, який лише перенаправляє, був би лише сервісом перенаправлень. Те, що робить його інструментом управління посиланнями - це підрахунок кожного кліку та інформування про те, хто клікав, звідки, з якого пристрою. Складна частина - зробити це, не змушуючи відвідувача чекати.

Відповідь - повністю відокремити два процеси. Коли обробник перенаправлень вирішує слаг, він надсилає відповідь 302 одразу. Запис кліку відбувається після, у режимі «відправив і забув». Обробник додає подію кліку - слаг, мітку часу, скорочений IP, хеш user-agent - до черги повідомлень і рухається далі. Він не чекає підтвердження запису. Якщо черга тимчасово недоступна, клік втрачається, а не перенаправлення затримується; ми свідомо вирішили, що втрата кліку при збої інфраструктури є прийнятною, а відмова перенаправлення - ні.

Elido використовує Redpanda як цю чергу. Окремий споживач - ingester кліків - зчитує події з черги та записує їх до ClickHouse, колонкової бази даних, побудованої для типового для аналітики кліків навантаження з великим обсягом додавань та агрегацій. Перенаправлення відвідувача вже завершилося мілісекундами раніше; рядок аналітики потрапляє через кілька секунд, повністю поза гарячим шляхом. Ми пояснюємо проектування черги у статті вхідний потік кліків у режимі «відправив і забув» та чому колонкова база даних краща за Postgres для цього - у статті чому ми використовуємо ClickHouse для аналітики кліків.

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

Підсумок#

Скорочувач URL від початку до кінця - це коротка послідовність. Ви створюєте посилання - і скорочувач зберігає відповідність слага та призначення в Postgres, генеруючи або перевіряючи слаг як унікальний ключ. Відвідувач клікає, запит потрапляє до найближчої граничної точки присутності, і обробник вирішує слаг з кешу в пам'яті, при промахуванні переходячи до Redis, а потім до бази даних. Він повертає 302 із призначенням у заголовку Location, щоб клік був підрахованим, а призначення залишалося редагованим. Потім він відправляє подію кліку до черги для зберігання окремим споживачем, не змушуючи нікого чекати.

Кожна частина індивідуально проста. Інженерія полягає у відношеннях та бюджетах: навантаження з переважанням читань, яке потребує кешу; стеля затримки, яка потребує граничних серверів; вимога до аналітики, яка потребує залишатися поза гарячим шляхом. Якщо ви хочете будувати на основі цього безпосередньо, функція розумних посилань надає доступ до рівня правил, API та SDK дозволяють створювати посилання з коду, а сторінка рішень для розробників та документація архітектури edge-redirect йдуть глибше у деталі. Якщо ви зважуєте інструмент, а не будуєте один, наші статті про що таке скорочувач URL та чи безпечні скорочувачі URL охоплюють тему з боку користувача, а сторінка ціноутворення показує, де закінчується безкоштовний рівень.

Схожі статті в блозі#

Спробуйте Elido

URL-скорочувач із хостингом у ЄС: власні домени, глибока аналітика, відкритий API. Безкоштовний тариф - без кредитної картки.

Теги
how do url shorteners work
url shortener mechanics
301 vs 302 redirect
url shortener database
short link lookup
url shortener architecture

Читати далі