2013-02-28 колко трафик прави един tcp connection?

by Vasil Kolev

И още един интересен работен проблем.

Имаме следната стандартна задача – да log-нем колко трафик е направил даден HTTP request. Тривиалният начин:

while ( (len=write(...))>0  ) total+=len;

т.е. колкото сме подали на kernel-а, толкова.

Това води до проблем, когато срещу нас стои някой от т.нар. download manager-и. Те дават възможност даден файл да бъде точен с няколко паралелни връзки. Това се реализира с Range header-а в HTTP, и ако например искаме да свалим даден файл от 1MB с две паралелни връзки, едната трябва да подаде range от 0 до 524287, втората – от 524288 до 1048576.
Разбира се, авторите на тоя тип софтуер са идиоти, и вместо това подават request-и от 0 до края и от 524288 до края на файла, като просто прекъсват първата връзка, след като са получили каквото им трябва. Това обаче остава връзката с пълен буфер от данни (в ядрото), който в моя случай се мотае м/у 1MB и 2MB, което от своя страна в повечето случаи брои по 2MB отгоре на всеки такъв request.

Решението на този проблем е едно ioctl:

while ( (len=write(fd, ...))>0  ) total+=len;
ioctl(fd, SIOCOUTQ, &bytesunsent);
total-=bytesunsent;

… което е прекрасно, докато човек не тества с нормална връзка при по-голяма латентност и не открие, че в разни web сървъри всъщност като напишете последните данни и стигнете до логването (т.е. викнете ioctl()-то), буферът е все още пълен и ще log-нете по-малко трафик, отколкото е направен.
На теория можем да хванем момента, в който буферът е празен със SO_LINGER опцията – тогава close() ще block-не, но това не ни решава проблема, понеже пък след това file descriptor-а няма да го има. Има друго решение – с shutdown(), read докато получим 0, и тогава да видим тия данни, което обаче е криво за писане и вероятно има някакъв проблем.
В крайна сметка моето решение е “проверявай буфера само на връзки, които не са завършили нормално”, и това дава горе-долу верни стойности. Някой да му идва по-добра идея?

Tags:

7 Responses to “2013-02-28 колко трафик прави един tcp connection?”

  1. HackMan Says:

    Ако не е задължително да мериш трафика вътре в web server-a. Мисля, че най-добрият начин е да го мериш директно на interface-а. Така ще хванеш и неща като retransmited packets но пък доста по-трудно ще го вържеш към потребител :)

  2. Vasil Kolev Says:

    @HackMan, къде точно на интерфейса и как ще хващам кои пакети са retransmit-и?

  3. Georgisim Says:

    последно искаш raw traffic нa socket-a, заедно с ретрансмитите ли?

  4. Vasil Kolev Says:

    @Georgisim, да. Retransmit-ите ми трябват най-вече за да следя колко добре се държи link-а.

  5. tolisoft Says:

    Попълва структура с доста статистики за TCP сесията:

    getsockopt(fd, IPPROTO_TCP, TCP_INFO, &ti, &len)

    Има екзампъли доста из нета как се ползва.

  6. tolisoft Says:

    Там ги има ретрансмитите като бройка, но мисля, че няма каунтър за броя ретрансмитнъти байтове. Има също и rtt и подобни. Ако ще мериш, колко то текущите кънекции са с бавни клиенти, май по-скоро rtt-то ще ти е по-интересно.

  7. Vasil Kolev Says:

    @tolisoft, това го ползвам също, но то не решава точно тоя проблем с останалия в буфера трафик.

Leave a Reply