PowerShell, Get-LiveJournal: соединения и запросы

Mar 15, 2023 07:52

Окружение: операционная система «Windows 10», программа-оболочка «PowerShell» версии 7, скрипт «Get-LiveJournal».

Не более 5 соединений в секунду и командлет «Start-Sleep»

В «Правилах LiveJournal для роботов» есть следующее требование:

...не устанавливайте более 5 соединений в секунду.

При общении с ЖЖ («Живым Журналом») по протоколу HTTP(S) из самописного веб-клиента нередко возникает необходимость отправлять серии HTTP(S)-запросов для решения различных задач (в качестве примера можно взять алгоритм скачивания всех постов журнала к себе на компьютер). Поначалу я невнимательно прочитал изложенное выше требование и решил, что для соблюдения этого требования следует контролировать, чтобы не было отправки более пяти HTTP(S)-запросов в секунду.

Я даже уже начал писать код, решив вставить между HTTP(S)-запросами искусственные паузы миллисекунд по 300. (Между пятью HTTP(S)-запросами есть четыре промежутка. Если сделать продолжительность каждого промежутка фиксированной и если сделать эти продолжительности равными друг другу, то для выполнения требования, как я думал, нужно будет, чтобы продолжительность каждого промежутка была более 250 миллисекунд. Я решил взять 300 миллисекунд, чтобы с запасом.) Для реализации пауз можно использовать командлет «Start-Sleep». Вот пример использования этого командлета:

PS C:\> Get-Date; Start-Sleep -m 1000; Get-Date

15 марта 2023 г. 4:42:17
15 марта 2023 г. 4:42:18

В блоке кода выше командлет «Get-Date» (возвращает текущие дату и время) используется для замера продолжительности паузы, сделанной командлетом «Start-Sleep». Название параметра -m командлета «Start-Sleep» является сокращением от -Milliseconds, то есть этот параметр принимает число, указывающее продолжительность паузы в миллисекундах. В примере задана пауза в 1000 миллисекунд, что равно 1 секунде.

Однако, позже я спохватился и заметил, что в требовании ЖЖ к роботам речь идет о соединениях, а не о запросах. Это, конечно же, разные вещи, если человек, составлявший упомянутые правила для роботов, действительно имел в виду соединения, а не перепутал соединения и запросы, как я.

TCP-соединения, HTTP(S)-запросы/ответы и версии протокола HTTP

Как известно, современное сетевое программное обеспечение организовано многоуровневой структурой, стеком (кому интересно, об этом можно узнать достаточно подробно в первой главе книги « Компьютерные сети», написанной несколькими авторами, начиная с Эндрю Таненбаума). Каждый уровень выполняет свою задачу, начиная от физического уровня до прикладного. На каждом уровне работа идет по протоколу, спроектированному для данного уровня. Для каждого уровня существует свой ряд протоколов. В данном случае нас интересует верхушка этого айсберга (стека): транспортный уровень и прикладной уровень. В нашем случае на транспортном уровне (более близком к железу, более низком) действует протокол TCP, а на прикладном уровне (более высоком) действует протокол HTTP(S).

В нашем контексте протокол TCP отвечает за организацию соединений, а по протоколу HTTP(S) формируются запросы/ответы. Когда протокол HTTP только был создан (версия 1.0) предполагалось, что каждая пара запрос-ответ будет выполняться в рамках одного TCP-соединения. Однако, вскоре выяснилось, что такая организация сетевого обмена неэффективна (особенно это верно для современных веб-сайтов, при открытии которых происходит множество HTTP(S)-запросов/ответов). Поэтому в версии 1.1 протокола HTTP появились два варианта решения этой проблемы: «конвейерная обработка» (pipelining), которая оказалась сложной в реализации и поэтому редко используется, и «постоянное соединение» (по-английски «persistent connection», также известное, как «keep-alive» и «connection reuse»), которое стало очень популярным и до сих пор используется повсеместно.

Программа-сервер ЖЖ работает по протоколу HTTP(S) версии 1.1 и использует «постоянное соединение». Разберемся, как это реализовано на практике. Я хочу детально посмотреть, как выглядит HTTP(S)-ответ программы-сервера ЖЖ. Для этого я отправил HTTP(S)-запрос, который использовал в самом начале проведения экспериментов с ЖЖ, то есть HTTP(S)-запрос на выполнение удалённой функции «getchallenge»:

$body = @{
mode = "getchallenge"
}
$Response = Invoke-WebRequest -URI "https://www.livejournal.com/interface/flat" `
-Body $body -Method "POST"

PS C:\> $Response.RawContent
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 15 Mar 2023 03:50:58 GMT
Connection: keep-alive
Keep-Alive: timeout=50
Referrer-Policy: no-referrer-when-downgrade
X-AWS-Id: 3dt-ws17
X-LJ-Flow-ID: ZBFAouBJRVgO@Idh-5Uc-wAAAAo
X-Varnish: 88994822
Age: 0
X-VWS-Id: kr-varn07.lj.rambler.tech
Accept-Ranges: bytes
Set-Cookie: luid=URNKImQRQKJIo12fCp2eAgB=; expires=Thu, 31-Dec-37 23:55:55 GMT; domain=.livejournal.com; path=/; secure; samesite=none
P3P: CP="NON DSP NID ADMa DEVa TAIa PSAa PSDa OUR IND UNI COM NAV"
Content-Type: text/plain; charset=UTF-8
Content-Length: 158

auth_scheme
c0
challenge
c0:1678849200:3058:60:bi0hfvZxPM3GIxw83b4u:739ff94711c5da769d9d380ec25714c4
expire_time
1678852318
server_time
1678852258
success
OK

Сейчас нас интересуют два HTTP-заголовка (я отметил их красным цветом) в HTTP-ответе, приведенном в блоке кода выше. Эти два HTTP-заголовка используются для организации «постоянного соединения».

Если HTTP-заголовок «Connection» содержит значение «close», это значит, что TCP-соединение будет закрыто после одной пары HTTP(S)-запроса и ответа. Если этот HTTP-заголовок содержит значение «keep-alive» (по-русски дословно «поддерживать в живых», то есть «держать соединение открытым»), то сервер и клиент должны поддерживать TCP-соединение открытым. В последнем случае в дополнительном HTTP-заголовке «Keep-Alive» может быть уточнено, сколько времени (минимум) сервер будет держать соединение открытым, если оно не используется, и сколько (максимум) HTTP-запросов может быть отправлено в рамках данного TCP-соединения без его закрытия.

Как видно из полученного HTTP-ответа в блоке кода выше, сервер ЖЖ установил продолжительность неиспользования соединения (паузы) в 50 секунд. Ограничения на максимальное количество HTTP-запросов в рамках одного TCP-соединения не установлено. Это означает, что для поддержания постоянного TCP-соединения с сервером ЖЖ нашему веб-клиенту достаточно не допускать перерыва между соседними парами HTTP(S)-запроса и ответа более 50 секунд.

Что это значит при написании скрипта, отправляющего множество HTTP(S)-запросов серверу ЖЖ, например, при написании моего скрипта «Get-LiveJournal», скачивающего все посты указанного журнала? Если мы хотим соблюсти процитированное в начале поста правило ЖЖ для роботов, мы должны не увеличивать паузы между соседними HTTP(S)-запросами, а, наоборот, уменьшать эти паузы, при этом стараясь не допускать того, чтобы какая-нибудь из этих пауз затянулась более 50 секунд. В этом случае всё множество HTTP(S)-запросов получится уместить в рамки одного TCP-соединения. В этом случае мы никак не выбьемся за ограничение в 5 соединений в секунду.

Таким образом, применение командлета «Start-Sleep» не требуется.

В уже приведенной ранее иллюстрации работы скрипта «Get-LiveJournal» все 6 HTTP(S)-запросов, по идее (с учетом вышеизложенного), происходят в рамках одного TCP-соединения:



На всякий случай я добавил в скрипт замер общего времени работы (это видно на иллюстрации выше) всего ряда HTTP(S)-запросов, используемых для скачивания всех постов указанного журнала, чтобы можно было хотя бы на глаз контролировать, сколько времени отбирает мой веб-клиент у сервера ЖЖ. Как видно из иллюстрации выше, 6 HTTP(S)-запросов были выполнены за 4 секунды (в это время еще входит обработка HTTP(S)-ответов и сохранение скачанных постов в текстовые файлы на жестком диске компьютера). Думаю, скрипт «Get-LiveJournal» не нарушает никаких правил ЖЖ для роботов.

Напоследок, думаю, следует добавить, что в протоколе HTTP версий 2.0 и 3.0 HTTP-заголовки «Connection» и «Keep-Alive» запрещены. В этих новых версиях работа с соединениями происходит по-другому, более эффективно. Я пробовал отправить серверу ЖЖ HTTP(S)-запрос по версии 2.0, но он возвратил HTTP(S)-ответ по версии 1.1. Так что при общении с ЖЖ из своего веб-клиента пока не получится использовать версии 2.0 и 3.0 протокола HTTP.

Полезная ссылка (на английском языке):

- «Connection management in HTTP/1.x» (по-русски «Управление соединением в протоколе HTTP версий 1.0 и 1.1») на известном сайте «MDN Web Docs», открытом сборнике учебников и документации по веб-технологиям.

Инструмент, Образование, Сайтостроение, Программирование, Английский язык, ЖЖ

Previous post Next post
Up