Ми надрукували 18 000 флаєрів для запуску продукту в регіоні DACH у березні. Один короткий лінк на звороті, три регіональні цільові сторінки, на які ми хотіли спрямувати людей: /de для відвідувачів з Німеччини, /fr для невеликої частини франкомовних та /en для всіх інших. Маркетинг-лід поставив очевидне запитання: ми друкуємо три флаєри чи один?
Ви друкуєте один. Лінк виконує маршрутизацію.
«Смарт-лінк» - це одна коротка URL-адреса, призначення якої обчислюється під час перенаправлення, а не в момент створення лінка. Є один слаг. Є кілька можливих призначень. Рішення приймається в тому самому обробнику, який інакше просто видав би звичайний 302 - не потрібно викликати окремий сервіс, використовувати JS-заглушки на лендінгу чи робити додатковий перехід. Цей пост про те, як це виглядає «під капотом», про шість параметрів, за якими Elido маршрутизує запити, та про випадки, коли варто обрати інший інструмент.
Три речі, якими не є смарт-лінк#
Люди приходять до смарт-лінків з трьома різними попередніми сценаріями, і в кожному з них компроміси відрізняються.
Звичайний редирект. Один слаг, одне призначення, нуль логіки. Обробник редиректу виконує пошук у кеші та видає 302. Це неперевершено за затримкою; але ви не можете зробити його умовним. Це база - все, що складніше, має свою ціну.
Смарт-лінк на edge. Один слаг, кілька можливих призначень, крихітний крок перевірки правил, вставлений між пошуком у кеші та відповіддю. Оскільки правило живе в тому самому процесі, що й пошук у кеші, вартість становить менше мілісекунди (0.3ms p50 / 1ms p95 у випадку Elido). Відвідувач бачить один HTTP-запит. Кеш браузера не «отруюється», оскільки відповіді 302 за замовчуванням не підлягають кешуванню згідно з RFC 7234 §4.2.2 - факт, який має значення, бо маршрутизація для кожного запиту має сенс лише тоді, коли кожному запиту дозволено вибрати власне призначення.
JavaScript A/B роутер на лендінгу. Рендериться нейтральна HTML-сторінка, JS перевіряє navigator.userAgent або сервіс geo-IP, потім window.location = '/foo'. Це найгірший варіант із трьох. Відвідувач бачить рендеринг HTML, потім редирект, потім фактичну сторінку - як мінімум один додатковий запит, часто два, якщо пошук геоданих виконується стороннім сервісом. SEO-індексація плутається, тому що пошукові роботи бачать нейтральну сторінку. Браузери, що блокують cookie, та розширення для приватності ламають JS-частину. У примітках до випуску Apple Intelligent Tracking Prevention 2.3 прямо згадується цей патерн: лінки відстеження на стороні клієнта через реферер документа обмежуються, і для виправлення потрібна участь сервера. Якщо ви використовуєте JS-маршрутизацію сьогодні, ви вже платите за це часом очікування.
Правильне місце для прийняття рішення про маршрутизацію - це той самий крок, який вже видає редирект. Це те, що роблять смарт-лінки на edge.
Чому це живе на edge - бюджет затримок#
Рівень редиректів Elido має суворий бюджет затримок: p50 5ms, p95 15ms при попаданні в кеш, без урахування TLS-handshake. Це число не просто побажання - все, що виходить за ці межі, видаляється. Синхронний SQL на гарячому шляху, компіляція регулярних виразів для кожного запиту, блокуючий ввід/вивід для події кліку: все це прибрано та перенесено у фонові воркери.
Дві причини існування цього бюджету:
- Мобільні мережі додають власні затримки. Посібник Apple «Reducing Network Latency» пояснює, як затримки стільникової мережі накопичуються в ланцюжках редиректів. Кожен додатковий крок додає RTT, який мережа відвідувача вже збільшила. Чим менше кроків ми додаємо, тим менше їхня мережа карає їх.
- Близькість edge - це справжній важіль. Посібник Cloudflare з маршрутизації на стороні edge формулює це так само: найдешевше рішення - це те, що приймається в тому самому процесі, що й обробник відповіді, у POP, найближчому до відвідувача. Ми не єдині, хто робить маршрутизацію на edge; унікальним є те, що ми вбудували її в сервіс скорочення URL замість того, щоб просити вас розгортати окрему функцію Workers / Lambda.
Якби ми перенесли оцінку правил на дочірній сервіс - скажімо, гіпотетичний «rules-api», доступний через HTTP - ми б додавали запит у тому самому регіоні для кожного запиту. У ЄС це мінімум 5 мс (регіон ЄС → регіон ЄС через приватну мережу), а у трафіку США-Азійсько-Тихоокеанський регіон ситуація може стати дуже поганою. 15ms p95 не витримає такого запиту. Тому правила смарт-лінків є вбудованими, в бінарному файлі edge, і оцінюються за допомогою скомпільованих матчерів, які створюються під час завантаження лінка в кеш. Весь двигун правил займає близько 400 рядків коду на Go.
Цей тісний зв'язок також дозволяє редагувати правила в реальному часі: зміни правил поширюються через канал in-memory кеш pub/sub (link:invalidate), на який підписаний кожен POP edge. L1 LRU очищується протягом секунди після публікації, наступний запит оновлюється з L2, і нове правило стає активним. Детальніше про це нижче.
Шість параметрів маршрутизації#
Смарт-лінки Elido можуть порівнювати запити за шістьма параметрами. Кожен з них відповідає конкретним вхідним даним, до яких edge має доступ для кожного запиту.
Країна. Двобуквений код ISO 3166-1 alpha-2, отриманий з IP-адреси відвідувача через geoip. Корисно, коли у вас є регіональні вітрини магазинів, і зростання конверсії в окремій країні варте складності маршрутизації. Класична проблема тут - мандрівники: німець у відпустці в Іспанії потрапить на іспанське призначення, якщо ви маршрутизуєте лише за країною. Якщо мовні вподобання важливіші за географічне розташування, маршрутизуйте за languages. Ми обговорюємо повний потік geoip у пості про приватність аналітики - IP скорочується перед зберіганням, щоб відповідати вимогам GDPR.
Пристрій. mobile, tablet, desktop, отримані з рядка User-Agent під час запиту. Сценарій використання, який обирають маркетологи: банери для встановлення додатків, які ведуть до App Store на iOS, Play Store на Android та маркетингову сторінку на desktop. На що слід звернути увагу: рядки User-Agent на iPad постійно змінюються з того часу, як iPadOS почала представляти стандартний Safari для робочого столу за замовчуванням, і наше виявлення планшетів враховує це, але воно не на 100% точне для кожної версії браузера. Якщо різниця між трафіком з планшетів та робочих столів має для вас фінансове значення, налаштуйте аналітику призначень та перевіряйте дані.
ОС. ios, android, macos, windows, linux. Те саме джерело User-Agent, що і для пристрою, але більш вузький поділ. Випадок з диплінками: спрямовуйте відвідувачів iOS на Universal Link, який додаток перехоплює, з поверненням до App Store; Android - до Play Store зі збереженням даних реферера. Саме для цього ми створили інтеграцію Apple App Site Association.
Мова. Основний мовний тег із заголовка Accept-Language відвідувача. Коди ISO 639-1, такі як de, fr, pt. Пастка: Accept-Language - це налаштування браузера, яке часто не збігається з географією IP. Французький експат у Берліні отримує country: DE, languages: ["fr", "en"] - якщо ви хочете, щоб він потрапив на /fr, маршрутизуйте за мовою; якщо на німецьку вітрину через A/B тестування локальних цін, маршрутизуйте за країною. Відповідно налаштовуйте черговість правил.
Час доби та день тижня. Вікно HH:MM у будь-якому часовому поясі IANA, плюс бітова маска days_of_week. Акції, обмежені за часом - лендінг «щаслива година», який активується о 17:00 Europe/Berlin з понеділка по п'ятницю і повертається до звичайної сторінки поза цим вікном - це ідеальний варіант. Вікно time_start / time_end підтримує перехід через опівночі (22:00 → 02:00), що здається очевидним, але ми це помітили лише під час перенесення двигуна правил з прототипу, який цього не вмів. Повна схема знаходиться в посібнику зі смарт-лінків.
Хост реферера. Нормалізована частина імені хоста заголовка Referer. Корисно для призначень, що залежать від партнерів: відвідувачі, які приходять з partner.example, бачать кобрендингову цільову сторінку; всі інші - сторінку за замовчуванням. Це менш корисно, ніж раніше - сучасні браузери агресивно видаляють Referer, коли сторінка, що посилається, встановлює Referrer-Policy: no-referrer або коли перехід між контекстами HTTPS не дозволений політикою. Ставтеся до правил реферера як до допоміжного сигналу, а не як до аутентифікації.
Це все. Шість параметрів охоплюють усі маркетингові рішення щодо маршрутизації, які ми бачили за три роки спілкування з клієнтами. Свідомо пропущені: ідентифікація користувача (ми не знаємо її під час редиректу), довільні заголовки HTTP (витрати на реалізацію не виправдовують вигоду для тих кількох команд, які запитували про це) та рандомні спліти (замість цього використовуйте ротацію варіантів, яка є окремою функцією).
Семантика першої відповідності; фолбек завжди обов'язковий#
Правила - це масив. Edge перевіряє їх по черзі. Перше правило, блок match якого повністю задовольняється, перемагає, а його destination_url стає ціллю редиректу. destination_url лінка верхнього рівня є безумовним фолбеком. Ми не дозволяємо створювати смарт-лінк без нього - за дизайном смарт-лінк ніколи не видає 404.
Мінімально життєздатна форма:
{
"destination_url": "https://acme.example/en",
"targeting_rules": [
{
"match": { "countries": ["DE", "AT", "CH"] },
"destination_url": "https://acme.example/de"
},
{
"match": { "languages": ["fr"] },
"destination_url": "https://acme.example/fr"
}
]
}
Відвідувачі з регіону DACH потрапляють на /de, тому що правило 1 спрацьовує першим. Французький експат у Берліні має country=DE, тому він також потрапляє на /de - правило 1 спрацьовує раніше, ніж правило 2 отримає шанс. Якщо ви хочете, щоб французький експат потрапив на /fr, поміняйте правила місцями, щоб мовне правило перевірялося першим. Порядок у дашборді - це порядок, за яким ми проводимо оцінку.
Дві речі, які з цього випливають і про які варто сказати вголос:
- Більш загальні правила мають бути останніми. Правило без умов
matchвідповідає всьому; якщо воно перше, жодне правило під ним ніколи не спрацює. Дашборд перевіряє це і попереджає вас, але API - ні, тому правила, створені скриптами, потребують перевірки. - Взаємовиключення - на вашій совісті. Якщо два правила відповідають одному відвідувачу, перше з них просто виграє. Немає жодної помилки, прапорця чи метрики. Ми розглядали можливість видачі попередження під час завантаження лінка, коли два правила можна визначити як такі, що перекриваються, і це є в планах на наступний мінорний реліз. Наразі: читайте ваші правила зверху вниз і довіряйте порядку.
Вартість: поширення інвалідації кешу#
Кожне рішення про маршрутизацію має вікно поширення. Правила смарт-лінків, відредаговані в дашборді, поширюються через кеші L1 у всіх трьох POP Elido приблизно за 1 секунду за ідеальних умов. Приблизно, тому що:
- L1 LRU у кожному POP зберігає лінки з правилами з TTL 60 секунд (архітектура кешу задокументована тут). TTL - це верхня межа; навіть без публікації інвалідації застарілий запис зникне протягом хвилини.
- Публікація інвалідації відбувається через in-memory кеш pub/sub. POP у регіоні ЄС та US East мають спільний кластер in-memory кеш; Азійсько-Тихоокеанський регіон має власний. Міжрегіональне поширення - це, по суті, затримка реплікації in-memory кеш плюс обробка pub/sub нашим підписником, яка була менше 1 секунди p99 у наших метриках за останній квартал.
- POP, який втратив підписку на in-memory кеш, повертається до 60-секундного TTL. Ми сповіщаємо про втрату підписки; у чергового інженера є 5 хвилин буферизованих кліків до того, як запрацює WAL.
Переклад: для маркетингових потоків, де 60 секунд застарілої маршрутизації є прийнятними, вам не потрібно про це думати. Для потоків, де актуальність має значення - ротація юридичної інформації, розподіл когорт білінгу, де неправильне призначення стягує кошти в неправильній валюті - варто спочатку вставити status=disabled, зачекати хвилину, а потім опублікувати нове правило та увімкнути лінк. Ми додали ендпоінт GET /v1/links/{id}/status, щоб пайплайн CI міг перевірити завершення поширення перед зміною налаштувань.
Коли не варто використовувати смарт-лінк#
Три випадки, коли правильним інструментом є не смарт-лінк.
Краще використовувати рендеринг призначення на стороні сервера (SSR). Якщо варіант має бути вставлений у відповідь HTML - скажімо, локалізація ціни, яка залежить від статусу авторизації відвідувача, або лендінг, який підтягує специфічний для когорти контент із вашої CMS - це робота для сервера самого призначення, а не для редиректу. Редирект вибирає, куди відправити відвідувача; призначення вибирає, що рендерити. Логіка маршрутизації, яка живе на edge, не бачить вашу сесію авторизації, і намагання втиснути її туди призведе або до витоку сесії в шлях редиректу (чого ми не робитимемо), або до проксіювання через edge (чого ми не робимо через бюджет затримок). Рендеріть варіанти на сервері походження (origin).
Статистично строге A/B тестування. Смарт-лінки маршрутизують кожен запит, а не кожного відвідувача. Якщо відвідувач заходить двічі протягом п'яти хвилин з одного пристрою, він може побачити два різних призначення за рандомним правилом. Це правильна поведінка для «відправити 50% мобільного трафіку на А і 50% на Б», але неправильна для «виміряти, чи конвертується варіант А краще за варіант Б протягом 4-тижневого вікна». Для останнього вам потрібен стабільний cookie варіанту та інструмент експериментів, який правильно обробляє статистику. PostHog, GrowthBook та LaunchDarkly роблять це. Ми - ні, і не збираємося - цей інструментарій має іншу задачу. Використовуйте ротацію варіантів з round_robin для вибірки з низькими ставками та звертайтеся до платформи експериментів, коли вам потрібно захистити результат дослідження.
Маршрутизація на основі ідентичності. Смарт-лінки свідомо не зберігають стан (stateless). Вони оцінюють запит за country | device | OS | language | time | referrer і нічим іншим. Якщо вам потрібно маршрутизувати на основі рівня доступу залогіненого користувача, його прапорців функцій (feature flags) або будь-чого, що вимагає пошуку «хто ця людина», шлях редиректу - це неправильний рівень. Вирішуйте ідентичність на origin і подавайте варіант звідти. Або, якщо вам дійсно потрібне рішення під час редиректу, створюйте короткі лінки для кожного користувача через API - кожен автентифікований користувач отримує власний слаг, призначення якого є правильним для цього користувача в момент створення, і вам ніколи не доведеться вирішувати ідентичність на гарячому шляху.
Що далі#
Якщо ви хочете спробувати структуру правил на власних даних, посібник у документації містить JSON-схему та опис редактора в дашборді. Конструктор правил знаходиться на сторінці редагування будь-якого лінка в дашборді - Links → ⋯ → Targeting.
Два покращення, які з'являться в наступному мінорному релізі: ієрархія фолбеків для languages (щоб pt-BR плавно переходив у pt, потім в en, без написання трьох правил) та етап статичного аналізу під час збереження лінка, який позначатиме правила, що перекриваються, щоб дашборд міг попередити про це перед активацією правила. Обидва - це робота над імплементацією, без змін у схемі. Якщо у вас є форма правила, яку ми не підтримуємо, і ви вважаєте, що ми повинні, канал зворотного зв'язку знаходиться внизу сторінки функцій смарт-лінків.
Пов'язане в блозі#
Спробуйте Elido
Вставте URL - отримайте коротке посилання
Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.
Безкоштовно, без реєстрації · 2 на день