awesome-everything EN
↑ Обратно к восхождению

Сети и протоколы

QUIC внутри: чтение кода и трасс

Суть Прочитай реальную логику stream-ID QUIC, трассу пакетов, цикл отправки и раскладку фрейма, затем предскажи поведение и выбери фикс с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Проблемы QUIC диагностируются в логике stream-ID, трассах пакетов и пути отправки. Прочитай каждый сниппет, предскажи поведение и выбери фикс, к которому senior-инженер тянется первым.

Цель

Потренируй чтение QUIC на уровне провода и кода: декодируй stream ID, отличи здоровое рукопожатие от патологического в трассе, найди узкое место по syscall’ам на быстром линке и рассуди о нумерации пакетов при ретрансмите.

Сниппет 1 — классификация stream-ID

// Классифицировать QUIC stream ID по инициатору и направленности.
func classify(id uint64) (initiator string, bidi bool) {
    if id&0x1 == 0 {
        initiator = "client"
    } else {
        initiator = "server"
    }
    bidi = id&0x2 == 0
    return
}

// Вызывающий передаёт stream ID, увиденный на проводе:
i, b := classify(3)
Викторина

Для stream ID 3 что вернёт classify и какая реальная сущность HTTP/3 использует этот класс stream'а?

Сниппет 2 — трасса рукопожатия

t=0.000 dcid=a1b2 type=Initial    pkt=0 frames=[Crypto[0..120], Padding]
t=0.045 dcid=a1b2 type=Initial    pkt=1 frames=[Crypto[0..120], Padding]   # те же байты CRYPTO переотправлены
t=0.051 scid=c3d4 type=Initial    pkt=0 frames=[Crypto[0..200], Ack[0]]
t=0.052 scid=c3d4 type=Handshake  pkt=0 frames=[Crypto[200..360]]
t=0.101 type=1RTT  pkt=0 frames=[Stream(0, fin, 4096B)]
Викторина

Клиент переотправляет те же байты CRYPTO ClientHello на t=0.045 как новый пакет (pkt=1), до прихода Ack сервера на t=0.051. Что происходит и дефект ли это?

Сниппет 3 — цикл отправки

// Горячий путь: сбросить очередь QUIC-датаграмм в сокет.
for _, dgram := range batch {        // batch может держать 40+ датаграмм
    _, err := conn.WriteTo(dgram, peer)  // один syscall sendmsg на датаграмму
    if err != nil {
        return err
    }
}
Викторина

При 1 Gbps с датаграммами по 1500 байт этот цикл упирает ядро CPU и goodput рушится, а тот же код нормально работает на мобильном линке 10 Mbps. В чём узкое место и фикс с наибольшим рычагом?

Сниппет 4 — burst фреймов при миграции

# Взгляд сервера после прихода пакета клиента с НОВОГО source-адреса:
recv  src=203.0.113.50:55555 dcid=a1b2 bytes=1200
send  PATH_CHALLENGE token=0x9f3c...        # 64-байтный random
# у сервера всё ещё стоят в очереди данные stream'а для клиента
send  Stream(0, off=8192, 1500B)            # данные приложения в очереди
Викторина

Сервер получил 1200 байт с нового, невалидированного адреса и хочет сбросить PATH_CHALLENGE плюс 1500 байт стоящих в очереди данных stream'а. Что разрешает anti-amplification-лимит и почему это важно?

Итог

QUIC читается на проводе: два младших бита stream ID декодируют инициатора и направленность; трасса рукопожатия показывает ложные PTO-пробы как новые packet number (никогда не переиспользуются, поэтому Karn-неоднозначности нет); пер-датаграммный цикл отправки вскрывает узкое место по syscall’ам, которое схлопывает UDP GSO; а burst миграции ограничен бюджетом 3x anti-amplification, пока PATH_RESPONSE не валидирует новый адрес. Диагностируй по трассе и горячему пути, затем применяй структурный фикс — GSO, а не больше ядер; идемпотентность, а не отключение фич.

Продолжить восхождение ↑QUIC внутри: докажи на проводе
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.