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: работа
March 2nd, 2013 at 10:24
Ако не е задължително да мериш трафика вътре в web server-a. Мисля, че най-добрият начин е да го мериш директно на interface-а. Така ще хванеш и неща като retransmited packets но пък доста по-трудно ще го вържеш към потребител :)
March 2nd, 2013 at 11:53
@HackMan, къде точно на интерфейса и как ще хващам кои пакети са retransmit-и?
March 4th, 2013 at 18:32
последно искаш raw traffic нa socket-a, заедно с ретрансмитите ли?
March 4th, 2013 at 18:40
@Georgisim, да. Retransmit-ите ми трябват най-вече за да следя колко добре се държи link-а.
March 5th, 2013 at 09:58
Попълва структура с доста статистики за TCP сесията:
getsockopt(fd, IPPROTO_TCP, TCP_INFO, &ti, &len)
Има екзампъли доста из нета как се ползва.
March 5th, 2013 at 09:59
Там ги има ретрансмитите като бройка, но мисля, че няма каунтър за броя ретрансмитнъти байтове. Има също и rtt и подобни. Ако ще мериш, колко то текущите кънекции са с бавни клиенти, май по-скоро rtt-то ще ти е по-интересно.
March 5th, 2013 at 11:36
@tolisoft, това го ползвам също, но то не решава точно тоя проблем с останалия в буфера трафик.