Почему Twitch режет качество через датацентр-прокси: анализ маршрутизации видеопотока
Содержание
Как Twitch выбирает маршрут до зрителя
Twitch отдаёт видео не с одного сервера. Поток идёт через CDN-прослойку, которую они сами называют Twitch Video Distribution Network. Внутри неё десятки точек присутствия: Ashburn, Dallas, Chicago, Amsterdam, Frankfurt, Singapore, Tokyo. Зрителя привязывают к ближайшей точке не по географии, а по результатам замеров RTT и по BGP-анонсам его сети.
Когда вы сидите за домашним провайдером, Twitch видит реальный ASN и префикс. Допустим, Ростелеком, AS12389, префикс 5.16.0.0/16. CDN понимает: это крупный eyeball-провайдер, у него есть прямые пиринги в Москве и Питере, туда и надо отдавать поток. Плеер получает hostname вида `video-edge-abc123.msk01.justin.tv` и тянет HLS-сегменты с него.
Датацентр-прокси ломает эту картину полностью. Twitch видит ASN хостера — Hetzner, OVH, DigitalOcean, Selectel. Это уже не eyeball-сеть, а транзитная. Алгоритм привязки пересчитывает маршрут и часто ставит точку выдачи далеко от вас. Иногда — на другом континенте.
Почему ASN важнее геолокации
Многие думают: поставлю прокси в Германии, и Twitch отдаст немецкий узел. Не работает так. CDN смотрит в первую очередь на ASN и префикс источника. Если прокси живёт в Hetzner (AS24940), Twitch видит именно Hetzner, а не «Германию». А у Hetzner с Twitch может быть плохой или вообще отсутствующий прямой пиринг.
Дальше вступает BGP. Twitch анонсирует свои префиксы через IX-точки: DE-CIX во Франкфурте, AMS-IX в Амстердаме, Equinix в разных городах. Если ваш прокси-провайдер подключён к DE-CIX, маршрут до Frankfurt PoP будет коротким. Если у него только транзит через Cogent — пакет пойдёт через пол-Европы, собирая 15-20 хопов.
Есть ещё фактор anycast. Часть инфраструктуры Twitch использует anycast-адресацию. Один и тот же IP анонсируется из десятка локаций, и BGP-маршрутизация решает, куда именно попадёт ваш запрос. Из датацентра маршрут до anycast-IP может оказаться длиннее, чем из дома, потому что у хостера другой набор upstream-провайдеров.
Что происходит с HLS-сегментами
Twitch отдаёт видео по HLS. Плейлист `.m3u8` содержит ссылки на сегменты по 2 секунды (для low-latency — по 1 секунде). Плеер скачивает их параллельно, 3-6 потоков. Каждый сегмент — отдельный HTTP-запрос, и каждый проходит тот же путь маршрутизации.
Если RTT до PoP вырос с 15 мс до 120 мс, это бьёт по всему. TCP handshake на каждый новый коннект — 3 RTT. TLS 1.3 — ещё 1 RTT. При 120 мс это уже 480 мс только на установку соединения. Дальше идёт передача сегмента, и тут в дело вступает congestion control.
Twitch использует QUIC для части трафика. QUIC стартует с окном 10 пакетов, дальше растёт по алгоритму. При высоком RTT и потерях окно растёт медленно. Если сегмент 500 КБ не успевает за 2 секунды — плеер переключается на нижний битрейт. Так вы и получаете 480p вместо 1080p60.
```bash
curl -w "dns: %{time_namelookup} connect: %{time_connect} tls: %{time_appconnect} ttfb: %{time_starttransfer} total: %{time_total}\n" \
-o /dev/null -s "https://video-edge-abc123.msk01.justin.tv/segment.ts"
```
Запустите такой curl с домашнего IP и через прокси. Разница в `time_connect` и `time_starttransfer` покажет реальную картину. Часто `time_connect` отличается в 5-8 раз, а `ttfb` — в 3-4.
Кейс: Selectel и Frankfurt PoP
Пример: сервер на Selectel, Санкт-Петербург, AS49505. Настроен HTTP-прокси, трафик Twitch идёт через него. С домашнего Ростелекома плейер стабильно брал 1080p60, RTT до московского PoP — 12 мс. Через прокси Twitch привязал зрителя к Frankfurt PoP, RTT вырос до 47 мс.
Проблема вылезла на переключении качества. Плейлист содержал 6 вариантов: 160p, 360p, 480p, 720p, 936p, 1080p60. Плеер начинал с 1080p60, но через 8-12 секунд падал до 720p, потом до 480p. Причина — не RTT сам по себе, а jitter. Маршрут через Франкфурт шёл через 14 хопов, на двух из них была перегрузка в вечерние часы. Jitter достигал 30-40 мс.
HLS-плеер Twitch использует буфер на 3-4 сегмента. При jitter 40 мс и потере 0.5% пакетов буфер не успевал наполняться. Плеер видел, что скачивание сегмента занимает 2.8 секунды вместо 1.5, и решал понизить битрейт. Решение — либо прямой маршрут без прокси, либо прокси с хорошим пирингом к Twitch в том же регионе.
Кейс: DigitalOcean и anycast-петля
Другой пример: дроплет в DigitalOcean, Frankfurt, AS14061. Прокси для Twitch. Пользователь из Новосибирска. Twitch anycast-IP `185.42.204.x` анонсируется из нескольких точек. Из Новосибирска BGP-маршрут до этого IP шёл через Москву, RTT 55 мс. Через DO-дроплет — через Амстердам, RTT 130 мс.
Дальше интереснее. Плейлист Twitch содержал ссылки на `video-weaver` хосты. Плеер запрашивал их через прокси, но сами сегменты шли с других доменов. Один из них резолвился в IP, который из DO-сети маршрутизировался через Лондон, потом обратно во Франкфурт. Петля добавляла 90 мс. Итоговый RTT до сегмента — 220 мс.
Результат: 1080p60 не запускался вообще. Максимум 720p, и то с буферизацией каждые 30 секунд. Причина — не пропускная способность (у дроплета 1 Гбит/с), а именно маршрутная петля. Решение: сменить регион дроплета на тот, откуда маршрут до Twitch PoP короче, либо использовать прокси с BGP-настройкой под конкретные префиксы Twitch.
Таблица: RTT и стабильное качество
| RTT до PoP | Jitter | Стабильный битрейт | Буферизация |
|------------|--------|-------------------|-------------|
| 10-20 мс | <5 мс | 1080p60 (6000 kbps) | нет |
| 30-50 мс | 5-15 мс | 936p (4500 kbps) | редко |
| 60-90 мс | 15-30 мс | 720p (3000 kbps) | каждые 2-3 мин |
| 100-150 мс | 30-50 мс | 480p (1500 kbps) | каждые 30-60 сек |
| >150 мс | >50 мс | 360p и ниже | постоянно |
Цифры приблизительные, зависят от congestion control и загрузки PoP. Но общая зависимость именно такая. Jitter важнее среднего RTT: ровные 80 мс лучше, чем 40 мс с скачками до 150.
Почему IPv6 меняет картину
Twitch поддерживает IPv6 на части инфраструктуры. Если ваш прокси умеет IPv6, маршрут может оказаться короче. У IPv6 другая таблица маршрутизации, меньше NAT, часто лучше пиринг. Некоторые PoP Twitch доступны только по IPv6 или отдают через IPv6 более близкий узел.
Проверить просто:
```bash
curl -6 -w "connect: %{time_connect} ttfb: %{time_starttransfer}\n" \
-o /dev/null -s "https://video-edge-abc123.msk01.justin.tv/segment.ts"
curl -4 -w "connect: %{time_connect} ttfb: %{time_starttransfer}\n" \
-o /dev/null -s "https://video-edge-abc123.msk01.justin.tv/segment.ts"
```
Если IPv6 даёт `time_connect` в 2-3 раза меньше — есть смысл гонять Twitch через IPv6-прокси. Именно на этом построена работа lexic.ml: IPv6-туннели с прямыми маршрутами до CDN-узлов, без NAT-прослоек и лишних хопов. Для Twitch это критично, потому что каждый лишний хоп — это +5-15 мс и потенциальный jitter.
Python-скрипт для замера маршрута
Собрать статистику по хопам и RTT можно так:
```python
import subprocess
import statistics
def measure_rtt(host, count=20):
result = subprocess.run(
["ping", "-6", "-c", str(count), host],
capture_output=True, text=True
)
times = []
for line in result.stdout.splitlines():
if "time=" in line:
t = float(line.split("time=")[1].split()[0])
times.append(t)
if not times:
return None
return {
"min": min(times),
"max": max(times),
"avg": statistics.mean(times),
"jitter": statistics.stdev(times) if len(times) > 1 else 0
}
for host in ["video-edge-abc123.msk01.justin.tv", "185.42.204.1"]:
stats = measure_rtt(host)
print(f"{host}: {stats}")
```
Запускайте с домашней машины и с прокси-сервера. Сравнивайте avg и jitter. Если jitter через прокси выше в 3+ раза — маршрут нестабилен, качество будет падать.
Что делать на практике
Первое — не гнать весь трафик через прокси. Разделяйте: Twitch идёт напрямую, остальное через туннель. В nginx это делается через `map` по `\$host`:
```nginx
map \$host \$upstream {
default "direct";
~\.twitch\.tv\$ "proxy_pool";
~\.jtvnw\.net\$ "proxy_pool";
~\.ttvnw\.net\$ "proxy_pool";
}
upstream proxy_pool {
server 2001:db8::1:8080;
server 2001:db8::2:8080;
}
```
Второе — выбирайте прокси-провайдера с прямым пирингом к Twitch. Смотрите на PeeringDB: есть ли у провайдера сессии на AMS-IX, DE-CIX, Equinix. Если нет — маршрут пойдёт через транзит, и вы получите лишние 40-80 мс.
Третье — тестируйте в разное время суток. Вечерний пик (19:00-23:00 MSK) меняет картину радикально. Маршрут, который днём даёт 30 мс, вечером может дать 90 из-за перегрузки транзитных линков.
Четвёртое — смотрите на MTU. Если прокси использует PPPoE или GRE-туннель, MTU падает до 1400-1460 байт. Фрагментация добавляет задержку и потери. Для видео это заметно: сегмент 500 КБ при MTU 1400 вместо 1500 — это +7% пакетов, +7% overhead на заголовки.
Итог
Twitch режет качество через датацентр-прокси не из вредности. Алгоритмы CDN видят чужой ASN, пересчитывают маршрут и ставят точку выдачи туда, откуда пакет идёт дольше. Добавьте сюда BGP-петли, anycast-непредсказуемость и jitter на транзитных линках — и плеер честно понижает битрейт, чтобы не буферизовать.
Лечится это не «ускорением интернета», а нормальной маршрутизацией. IPv6-туннели, прямой пиринг, разделение трафика, замеры RTT и jitter в разное время. Без этого любой прокси будет работать как лотерея: сегодня 1080p60, завтра 480p.