13 min de lectureFonctionnalités
Pilier

Smart links expliqués : routage edge sans service supplémentaire

Ce qu'est un smart link, où il tourne et les dimensions de routage qu'Elido supporte. Plongée ingénierie sur l'invalidation de cache edge, la sémantique first-match et quand ne pas en utiliser un

Marius Voß
DevRel · edge infra
Diagram of a single short link branching into three destinations based on country, device, and language

Nous avons imprimé 18 000 flyers pour un lancement produit DACH en mars. Un seul lien court au dos, trois landing pages régionales vers lesquelles nous voulions envoyer les gens : /de pour les visiteurs allemands, /fr pour la petite tranche française, /en pour tout le monde. Le lead marketing a posé la question évidente : on imprime trois flyers ou un ?

Vous en imprimez un. Le lien fait le routage.

Un « smart link » est une seule URL courte dont la destination est calculée au moment de la redirection, pas au moment de la création du lien. Il y a un slug. Il y a plusieurs destinations possibles. La décision se passe dans le même handler qui émettrait autrement un 302 plat - pas de service séparé à appeler, pas de shim JS sur une landing page, pas de saut supplémentaire. Ce billet porte sur ce à quoi cela ressemble réellement sous le capot, les six dimensions sur lesquelles Elido route, et les cas où vous devriez plutôt atteindre un autre outil.

Les gens atteignent les smart links depuis trois expériences antérieures différentes, et les compromis sont différents dans chacune.

Redirection plate. Un slug, une destination, zéro logique. Le handler de redirection fait un lookup cache et écrit un 302. Vous ne pouvez pas le battre en latence ; vous ne pouvez pas non plus le rendre conditionnel. C'est le plancher - quelque chose de plus sophistiqué coûte quelque chose.

Smart link à l'edge. Un slug, plusieurs destinations possibles, une petite étape d'évaluation de règle insérée entre le lookup cache et la réponse. Parce que la règle vit dans le même processus que le lookup cache, le coût est sub-millisecond (0.3ms p50 / 1ms p95 dans le cas d'Elido). Le visiteur voit un seul round trip HTTP. Le cache du navigateur n'est pas pollué, parce que les réponses 302 ne sont pas cacheables par défaut selon la RFC 7234 §4.2.2 - un fait qui compte ici, parce que le routage per-request n'a de sens que si chaque requête est autorisée à choisir sa propre destination.

Routeur A/B JavaScript sur une landing page. Une page HTML neutre s'affiche, JS examine navigator.userAgent ou un service geo-IP, puis window.location = '/foo'. C'est la pire option des trois. Le visiteur voit un rendu HTML, puis une redirection, puis la page réelle - au moins un round trip supplémentaire, souvent deux si le lookup géo est tiers. L'indexation SEO est embrouillée parce que les crawlers voient la page neutre. Les navigateurs qui bloquent les cookies et les extensions de confidentialité cassent la moitié JS. Les notes de release Intelligent Tracking Prevention 2.3 d'Apple appellent exactement ce pattern : les liens de tracking côté client via document referrer sont étranglés, et la mitigation nécessite une participation côté serveur. Si vous routez en JS aujourd'hui, vous payez déjà la facture.

Le bon endroit pour mettre une décision de routage est le même saut qui émet déjà la redirection. C'est ce que font les smart links edge.

Pourquoi ça vit à l'edge - le budget de latence#

Le tier de redirection Elido a un budget de latence dur : p50 5ms, p95 15ms sur un cache hit, excluant le handshake TLS. Ce nombre n'est pas aspirationnel - tout ce qui nous pousse au-dessus est arraché. SQL synchrone sur le hot path, compilation regex par requête, I/O bloquant sur l'événement de clic : tout parti, tout déplacé vers les workers cold-path.

Les deux raisons pour lesquelles ce budget existe :

  1. Les réseaux mobiles ajoutent leur propre taxe. Le guide « Reducing Network Latency » d'Apple parcourt comment les délais réseau cellulaires se composent à travers les chaînes de redirection. Chaque saut supplémentaire ajoute du RTT que le réseau du visiteur a déjà gonflé. Moins nous ajoutons de sauts, moins leur réseau les punit.
  2. La proximité edge est le vrai levier. Le primer de Cloudflare sur le routage edge-side le formule de la même façon : la décision la moins chère est celle prise dans le même processus que le writer de réponse, dans le POP le plus proche du visiteur. Nous ne sommes pas uniques à faire du routage edge ; ce qui est unique c'est de l'intégrer au raccourcisseur d'URL au lieu de vous demander de déployer une fonction Workers / Lambda@Edge séparée.

Si nous esquivions l'évaluation des règles vers un service en aval - disons, un hypothétique « rules-api » joignable via HTTP - nous ajouterions un round trip same-region sur chaque requête. En région c'est environ 5ms minimum (un saut same-region sur un réseau privé), et sur le trafic cross-region la queue devient vite moche. Le p95 de 15ms ne survit pas au round trip. Donc les règles de smart link sont inline, dans le binaire edge, s'évaluant contre des matchers compilés qui ont été construits quand le lien a été chargé dans le cache. Tout le moteur de règles fait environ 400 lignes de Go.

Ce couplage serré est aussi pourquoi nous pouvons faire des éditions de règles en temps réel : les changements de règles se propagent via un canal pub/sub du cache en mémoire (link:invalidate) auquel chaque POP edge s'abonne. Le LRU L1 évince dans la seconde de la publication, la requête suivante repopule depuis L2, et la nouvelle règle est live. Plus à ce sujet ci-dessous.

Les six dimensions de routage#

Les smart links Elido matchent sur six choses. Chacune se mappe à une entrée spécifique à laquelle l'edge a accès par requête.

Country. ISO 3166-1 alpha-2 à deux lettres, dérivé de l'IP du visiteur via geoip. Utile quand vous avez des vitrines régionales et que l'uplift par pays en conversion vaut la complexité de routage. Le piège classique ici est les voyageurs - un Allemand en vacances en Espagne tape la destination espagnole si vous routez sur country seul. Si la préférence de langue compte plus que la localisation géographique, routez sur languages à la place. Nous discutons du flux geoip complet dans le billet sur la confidentialité des analytics - l'IP est tronquée avant stockage donc le côté RGPD reste propre.

Device. mobile, tablet, desktop, parsé à partir de la chaîne User-Agent au moment de la requête. Le cas d'usage que les marketeurs atteignent pour ceci : les bannières d'installation d'app qui vont sur l'App Store sur iOS, Play Store sur Android, et une page marketing sur desktop. Ce qu'il faut surveiller : les chaînes User-Agent sur iPad sont une cible mobile depuis qu'iPadOS a commencé à présenter le UA Safari desktop par défaut, et notre détection de tablette accommode cela, mais ce n'est pas 100 % sur chaque version de navigateur. Si la différence entre trafic tablette et desktop compte pour vous en dollars, instrumentez la destination et vérifiez.

OS. ios, android, macos, windows, linux. Même source User-Agent que device, partition plus étroite. Le cas deep-link : routez les visiteurs iOS vers un Universal Link que l'app intercepte et retombe vers l'App Store ; routez Android vers le Play Store avec les données referrer préservées. C'est ce pour quoi nous avons construit l'intégration Apple App Site Association.

Language. Tag de langue principale du header Accept-Language du visiteur. Codes ISO 639-1 comme de, fr, pt. Le piège : Accept-Language est la préférence du navigateur, qui souvent désaccorde avec le géo IP. Un expat français à Berlin obtient country: DE, languages: ["fr", "en"] - si vous voulez qu'il soit sur /fr, routez sur language ; si vous voulez qu'il soit sur la vitrine allemande parce que vous testez A/B la tarification localisée, routez sur country. Séquencez les règles en conséquence.

Time of day et day of week. Fenêtre HH:MM dans n'importe quelle timezone IANA, plus un bitmap days_of_week. Les deals fenêtrés dans le temps - une landing page « happy hour » qui passe en live à 17:00 Europe/Berlin du Lun au Ven et retombe sur la page régulière en dehors de cette fenêtre - sont l'adéquation naturelle. La fenêtre time_start / time_end supporte le wraparound (22:0002:00), ce qui sonne évident mais nous a attrapés quand nous avons porté le moteur de règles depuis le prototype qui ne le gérait pas. Le schéma complet est dans le guide smart links.

Referrer host. La portion hostname du header Referer, normalisée. Utile pour les destinations partner-aware : les visiteurs arrivant de partner.example obtiennent une landing page co-brandée ; tout le monde obtient le défaut. Moins utile qu'avant - les navigateurs modernes retirent Referer agressivement quand la page référente définit Referrer-Policy: no-referrer ou quand la navigation traverse des contextes HTTPS d'une façon que la politique ne permet pas. Traitez les règles referrer comme un signal soft, jamais comme une authentification.

C'est tout. Six dimensions couvrent les décisions de routage marketing que nous avons vues en trois ans de conversations clients. Les omissions délibérées sont l'identité utilisateur (nous ne la connaissons pas à la redirection), les headers HTTP arbitraires (le coût-payoff n'y est pas pour les quelques équipes qui ont demandé), et les splits aléatoires (utilisez plutôt la rotation de variantes, qui est une fonctionnalité séparée).

Sémantique first-match ; fallback toujours requis#

Les règles sont un tableau. L'edge les parcourt dans l'ordre. La première règle dont le bloc match est entièrement satisfait gagne, et son destination_url est la cible de redirection. Le destination_url de premier niveau du lien est le fallback inconditionnel. Nous refusons de créer un smart link sans un - un smart link ne produit jamais de 404, par conception.

La forme minimale viable :

{
  "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"
    }
  ]
}

Les visiteurs DACH tapent /de parce que la règle 1 matche en premier. Un expat français à Berlin a country=DE, donc il tape aussi /de - la règle 1 matche avant que la règle 2 n'ait sa chance. Si vous voulez l'expat français sur /fr, échangez les règles pour que la règle language soit vérifiée en premier. L'ordre dans le dashboard est l'ordre que nous évaluons.

Elido dashboard rule builder, three rules stacked in evaluation order: DACH visitors, French speakers, iOS app fallback. Each rule has country / device / browser / destination / label fields, with an Advanced toggle for OS, language, time-of-day, and regex

Deux choses que ceci implique qui valent d'être dites à voix haute :

  • Les règles plus larges vont en dernier. Une règle sans conditions match matche tout ; si elle est en premier, aucune règle en dessous ne se déclenche. Le dashboard valide contre ceci et vous avertit, mais l'API ne le fait pas, donc les règles construites par script ont besoin d'une vérification de sanité.
  • L'exclusion mutuelle est sur vous. Si deux règles matchent toutes deux un seul visiteur, la première gagne silencieusement. Pas d'erreur, pas de flag, pas de métrique. Nous avons considéré émettre un avertissement au chargement du lien quand deux règles sont détectables comme se chevauchant, et c'est sur la roadmap pour la prochaine release mineure. Pour l'instant : lisez vos règles de haut en bas et faites confiance à l'ordre.

Le coût : propagation d'invalidation de cache#

Chaque décision de routage a une fenêtre de propagation. Les règles de smart link éditées dans le dashboard se propagent à travers les caches L1 dans les trois POPs Elido en environ 1 seconde sur le happy path. Environ, parce que :

  • Le LRU L1 à chaque POP tient les liens portant des règles avec un TTL de 60 secondes (l'architecture de cache est documentée ici). Le TTL est la borne supérieure - même sans une publication d'invalidation, une entrée périmée disparaît dans la minute.
  • La publication d'invalidation est via le pub/sub du cache en mémoire. Les POPs UE et US Est partagent un cluster de cache ; Asie-Pacifique a le sien. La propagation cross-region est essentiellement la latence de réplication du cache plus le traitement pub/sub de notre subscriber, qui a été sous 1 seconde p99 dans nos métriques du trimestre dernier.
  • Un POP qui a perdu son abonnement au cache retombe sur le TTL de 60 secondes. Nous alertons sur la perte d'abonnement ; l'astreinte a 5 minutes de clics bufférisés avant que le WAL ne prenne le relais.

Traduction : pour les flux marketing où 60 secondes de routage périmé est bien, vous n'avez pas à y penser. Pour les flux où la péremption compte - une rotation de disclaimer légal, un split de cohort de facturation où la mauvaise destination facture la mauvaise devise - le play est status=disabled d'abord, puis réactiver après une minute, puis publier la nouvelle règle. Nous avons ajouté un endpoint GET /v1/links/{id}/status pour qu'un pipeline CI puisse poller pour que la propagation se termine avant de flipper un switch en aval.

Trois cas où le bon outil n'est pas un smart link.

Le rendu côté serveur de la destination est meilleur. Si la variante doit être injectée dans la réponse HTML - disons, une localisation de prix qui dépend de l'état authentifié du visiteur, ou une landing page qui tire un hero cohort-spécifique depuis votre CMS - c'est un travail pour le propre serveur de la destination, pas la redirection. La redirection choisit où envoyer le visiteur ; la destination choisit quoi rendre. La logique de routage qui vit à l'edge ne peut pas voir votre session auth, et l'enfoncer nécessiterait soit de fuiter la session dans le chemin de redirection (ce que nous ne ferons pas) soit de proxifier à travers l'edge (ce que nous ne faisons pas à cause du budget de latence). Rendez les variantes sur origin.

Test A/B statistiquement rigoureux. Les smart links routent par requête, pas par visiteur. Si un visiteur atterrit deux fois en cinq minutes depuis le même appareil, il pourrait voir deux destinations différentes sous une règle aléatoire, ce qui est le bon comportement pour « envoyer 50 % du trafic mobile vers A et 50 % vers B » mais le mauvais comportement pour « mesurer si la variante A convertit mieux que la variante B sur une fenêtre de 4 semaines ». Pour ce dernier, vous avez besoin d'un cookie de variante stable et d'un outil d'expérimentation qui fait les statistiques correctement. PostHog, GrowthBook et LaunchDarkly font tous cela. Nous ne le faisons pas, et nous n'allons pas le faire - l'outillage est un travail différent. Utilisez la rotation de variantes avec round_robin pour l'échantillonnage à faibles enjeux et atteignez une plateforme d'expérimentation quand vous avez besoin de défendre le résultat.

Routage identity-aware. Les smart links sont délibérément stateless. Ils s'évaluent contre country | device | OS | language | time | referrer et rien d'autre. Si vous devez router en fonction du tier d'un utilisateur loggé, de ses feature flags, ou de tout ce qui nécessite de chercher « qui est cette personne », le chemin de redirection est la mauvaise couche. Résolvez l'identité sur origin et servez la variante de là. Ou, si vous avez vraiment besoin d'une décision au moment de la redirection, mintez des liens courts par utilisateur via l'API - chaque utilisateur authentifié obtient son propre slug, la destination du slug est correcte pour cet utilisateur au moment de la création, et vous n'avez jamais à faire de résolution d'identité sur le hot path.

Quoi de neuf ensuite#

Si vous voulez essayer la forme de règle sur vos propres données, le guide doc parcourt le schéma JSON et l'éditeur dashboard. Le rule builder vit sous la page d'édition de n'importe quel lien dans le dashboard - Links → ⋯ → Targeting.

Deux améliorations qui atterrissent dans la prochaine release mineure : une hiérarchie de fallback pour languages (pour que pt-BR dégrade proprement vers pt, puis vers en, sans écrire trois règles), et une passe d'analyse statique au moment de l'enregistrement du lien qui signale les règles qui se chevauchent pour que le dashboard puisse avertir avant que la règle ne passe en live. Les deux sont du travail d'implémentation, pas de changement de schéma cassant. Si vous avez une forme de règle que nous ne supportons pas et que vous pensez que nous devrions, le canal de feedback est en bas de la page produit smart links.

Pour aller plus loin sur le blog#

Essayer Elido

Collez une URL, obtenez un lien court

Sans inscription. Lien actif 30 jours. Inscrivez-vous pour le garder pour toujours.

Gratuit, sans inscription · 2 par jour

Essayer Elido

Raccourcisseur d'URL hébergé en UE : domaines personnalisés, analyses approfondies et API ouverte. Forfait gratuit - sans carte bancaire.

Tags
smart links
edge routing
url shortener
conditional links
device targeting

Lire la suite