Шипы в исполнении Socket - PullRequest
1 голос
/ 26 марта 2010

Мы сталкиваемся со случайными скачками в системе обработки транзакций с высокой пропускной способностью, используя сокеты для IPC.

Ниже приведена настройка, используемая для прогона:

  1. Клиент открывает и закрывает новое соединение для каждой транзакции, и между сервером и клиентом существует 4 обмена.
  2. Мы отключили TIME_WAIT, установив параметр socket linger (SO_LINGER) с помощью getsockopt, поскольку мы думали, что пики были вызваны из-за ожидающих сокетов в TIME_WAIT.
  3. Обработка транзакции не производится. Передаются только сообщения.
  4. ОС использовала Centos 5.4

Среднее время прохождения туда и обратно составляет около 3 миллисекунд, но иногда время прохождения туда и обратно колеблется от 100 миллисекунд до пары секунд.

Шаги, используемые для выполнения и измерения и вывода

  1. Запуск сервера

    $ python sockServerLinger.py> / dev / null &

  2. Запуск клиента для отправки 1 миллиона транзакций на сервер. И записывает время транзакции в файл client.log.

    $ python sockClient.py 1000000> client.log

  3. Как только выполнение завершится, следующая команда покажет время выполнения более 100 миллисекунд в формате <line_number>:<execution_time>.

    $ grep -n "0. [1-9]" client.log | меньше

Ниже приведен пример кода для сервера и клиента.

Сервер

# File: sockServerLinger.py
import socket, traceback,time
import struct
host = ''
port = 9999

l_onoff = 1
l_linger = 0
lingeropt = struct.pack('ii', l_onoff, l_linger)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, lingeropt)
s.bind((host, port))
s.listen(1)

while 1:
    try:
        clientsock, clientaddr = s.accept()
        print "Got connection from", clientsock.getpeername()
        data = clientsock.recv(1024*1024*10)
        #print "asdasd",data
        numsent=clientsock.send(data)
        data1 = clientsock.recv(1024*1024*10)
        numsent=clientsock.send(data)
        ret = 1
        while(ret>0):
            data1 = clientsock.recv(1024*1024*10)
            ret = len(data)
        clientsock.close()
    except KeyboardInterrupt:
        raise
    except:
        print traceback.print_exc()
        continue

Клиент

# File: sockClient.py

import socket, traceback,sys
import time
i = 0
while 1:
    try:
        st = time.time()
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        while (s.connect_ex(('127.0.0.1',9999)) != 0):
            continue
        numsent=s.send("asd"*1000)
        response = s.recv(6000)
        numsent=s.send("asd"*1000)
        response = s.recv(6000)
        i+=1
        if i == int(sys.argv[1]):
            break
    except KeyboardInterrupt:
        raise
    except:
        print "in exec:::::::::::::",traceback.print_exc()
        continue
    print time.time() -st

1 Ответ

1 голос
/ 26 марта 2010

Вот одна возможность, которая приходит на ум:

1) Поскольку вы используете SOCK_STREAM, вы используете протокол TCP. 2) В качестве надежного протокола TCP будет повторно отправлять пакеты, для которых истекло время ожидания, чтобычто все в конечном итоге приходит.3) TCP использует динамическое значение тайм-аута, которое рассчитывается на основе того, что текущее время приема-передачи (RTT) оценивается как 4). Когда TCP-соединение запускается впервые, оно не знает, что такое RTT, поэтому оно используеточень большое начальное значение тайм-аута, иногда порядка нескольких секунд.

Итак ... если один из ранних пакетов TCP-рукопожатия будет отброшен, ваш сокет может долго ждать, прежде чем он решит, что пакетне попал туда, и это отправляет его.Это может происходить случайным образом, относительно редко, но определенно много раз при миллионах подключений.

Попробуйте использовать socket.settimeout () с относительно коротким значением и повторите попытку немедленно, если время подключения истекло.Таким образом, вы подделываете, имея более короткую начальную оценку RTT.

...