Я пишу очень простую программу-паук для получения веб-страниц с одного сайта.
Вот минимизированная версия.
from twisted.internet import epollreactor
epollreactor.install()
from twisted.internet import reactor
from twisted.web.client import Agent, HTTPConnectionPool, readBody
baseUrl = 'http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode='
start = 1001
end = 3500
pool = HTTPConnectionPool(reactor)
pool.maxPersistentPerHost = 10
agent = Agent(reactor, pool=pool)
def onHeader(response, i):
deferred = readBody(response)
deferred.addCallback(onBody, i)
deferred.addErrback(errorHandler)
return response
def onBody(body, i):
print('Received %s, Length %s' % (i, len(body)))
def errorHandler(err):
print('%s : %s' % (reactor.seconds() - startTimeStamp, err))
def requestFactory():
for i in range (start, end):
deferred = agent.request('GET', baseUrl + str(i))
deferred.addCallback(onHeader, i)
deferred.addErrback(errorHandler)
print('Generated %s' % i)
reactor.iterate(1)
print('All requests has generated, elpased %s' % (reactor.seconds() - startTimeStamp))
startTimeStamp = reactor.seconds()
reactor.callWhenRunning(requestFactory)
reactor.run()
Для нескольких запросов, например 100, он работает нормально. Но для массовых запросов это не удастся.
Я ожидаю, что все запросы (около 3000) должны быть автоматически объединены в пул, запланированы и конвейеризированы, поскольку я использую HTTPConnectionPool
, устанавливаю maxPersistentPerHost
, создаю с ним экземпляр Agent
и постепенно создаю соединения.
Но это не так, соединения не поддерживаются и не объединяются.
В этой программе соединения устанавливаются постепенно, но соединения не объединяются в пул, каждое соединение закрывается после получения тела, а более поздние запросы никогда не ждут в пуле доступного соединения.
Таким образом, потребуются тысячи сокетов, и, в конце концов, произойдет сбой из-за тайм-аута, потому что на удаленном сервере тайм-аут соединения установлен на 30 с. Тысячи запросов не могут быть выполнены в течение 30 секунд.
Не могли бы вы помочь мне в этом?
Я старался изо всех сил, вот мои находки.
- Ошибка произошла ровно через 30 секунд после запуска реактора, на нее не будут влиять другие факторы.
- Let the spider fetch my server, I find something interesting.
- The HTTP protocol version is 1.1 (I check the twisted document, the default HTTPClient is 1.0 rather than 1.1)
- Если бы я не добавлял какой-либо явный заголовок (как и в минимизированной версии), заголовок запроса не содержал бы
Connection: Keep-Alive
, либо заголовок ответа. - Если я добавлю явный заголовок, чтобы убедиться, что это постоянное соединение, заголовок запроса будет содержать
Connection: Keep-Alive
, но заголовок ответа по-прежнему не будет. (Я уверен, что мой сервер ведет себя правильно, другие вещи, такие как Chrome, wget действительно получили заголовокConnection: Keep-Alive
.)
- Я проверяю
/proc/net/sockstat
во время бега, сначала он быстро увеличивается, а потом быстро уменьшается. (я увеличил ulimit для поддержки большого количества сокетов) - I write a similar program with treq, a twisted based request library). The code is almost the same, so not paste here.
- Link: https://gist.github.com/Preffer/dad9b1228fcd75cebd75
- Его поведение почти такое же. Не объединение. Ожидается, что он будет объединяться, как описано в списке функций treq.
- Если я добавлю к нему явный заголовок,
Connection: Keep-Alive
никогда не появится в заголовке ответа.
Основываясь на всем вышесказанном, я весьма подозрительно отношусь к заголовку Connection: Keep-Alive
, который портит программу. Но этот заголовок является частью стандарта HTTP 1.1 и сообщается как HTTP 1.1. Я совершенно озадачен этим.
pooling
. Любые советы для моей проблемы? - person Eugene   schedule 29.08.2014