Задать вопрос
@antobra

Деградация передачи данных через php stream_socket_server и неблокируемый режим?

Подскажите решение двух вопросов, касающихся PHP и портов.

Предыстория для понимания:

Простейший код клиент-сервер, общающейся через порт на 127.0.0.1 (код ниже в пункте 2). Работает, но с двумя проблемами, которые описаны ниже:

1. Один и тот же код работает по-разному на Debian 11 и MacOs Big Sur, а именно...

Так сложилось, что пишу и тестирую код на macOS. Скрипт работает идеально и никаких проблем нет. Но как только загружаю на Debian, на котором в будущем и будет работать код, то появляется интересное: При каждом запросе снижается пропускная способность порта. Вот пример самописного бенчмарка, на котором результаты 1000 запросов через порт. Можно заметить, что после каждого теста по 1000 запросов время обработки увеличивается и количество пропускаемых запросов деградирует. То есть к 5 тесту вместо 1 секунды требуется уже почти 9. А время выполнения одного обращения к порту с 0.001 сек становится 0.008. Сразу должен пояснить: На сервере ничего ресурсоемкого не происходит, сервер просто возвращает строку типа hello world (см код ниже в п. 2).

Test #1:
Queries: 1000
One query (sec): 0.001090964
Requests Per Sec: 916
Time: 1.090964

Test #2:
Queries: 1000
One query (sec): 0.002816856
Requests Per Sec: 355.00572269225
Time: 2.816856

Test #3:
Queries: 1000
One query (sec): 0.004799131
Requests Per Sec: 208.37105717681
Time: 4.799131

Test #4:
Queries: 1000
One query (sec): 0.006820563
Requests Per Sec: 146.61546268248
Time: 6.820563

Test #5
Queries: 1000
One query (sec): 0.00859813
Requests Per Sec: 116.30435920369
Time: 8.59813


При этом тот же код на MacOs:

Test #1
Queries: 1000
One query (sec): 0.000561929
Requests Per Sec: 1779.5842535267
Time: 0.561929

Test #3
Queries: 1000
One query (sec): 0.000506018
Requests Per Sec: 1976.2142848673
Time: 0.506018

Test #3
Queries: 1000
One query (sec): 0.000501011
Requests Per Sec: 1995.9641604675
Time: 0.501011

Test #4
Queries: 1000
One query (sec): 0.000495605
Requests Per Sec: 2017.7358985482
Time: 0.495605

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

Очевидно, что дело в ОС. Но в чем именно? Подскажите, если кто знает

2. Неблокирующий режим (и снова история с ОС)

Вторая проблема заключается в том, что не работает неблокирующий режим. То есть: запускается сервер, запускается несколько десятков клиентов. И по тому, как клиенты выполняют запросы заметно, что они все-таки ожидают, пока соседние клиенты закончат соединение. Подскажите, как поправить код, чтобы ситуация разрешилась. Но это еще не все: Нижеследующий код работает в неблокирующем режиме на MacOs без проблем, но не работает в неблокирующем режиме на Debian.

Важно: в коде убраны строки с проверками результатов выполнения функций для повышения читаемости. Они на общую логику никак не влияют, но существенно усложняют чтение.


А вот и сам код Server:

$server = stream_socket_server ( 'tcp://127.0.0.1:30000', $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN );

stream_set_blocking ( $server, false );

while ( true ) {

	$connections = [];

	if ( $c = @stream_socket_accept ( $server, -1, $peer ) ) {
	
		$connections[ $peer ] = $c; 
		
		$read = $connections;

		if ( stream_select ( $read, $write, $except, 5 ) ) {

		    foreach ( $read as $connection ) {
		        
		        $peer = stream_socket_get_name ( $connection, true );
		        echo "\nNew message. Peer: " . $peer;

		        $stream_socket_recvfrom = stream_socket_recvfrom ( $connection, 8192 );

		        echo "\nIncoming message: " . $stream_socket_recvfrom;

		        $response = "Hello world";

		        echo "\nResponse: " . $response;

			fwrite ( $connection, $response );
			    
			stream_socket_shutdown( $connection, STREAM_SHUT_RDWR );
			fclose ( $connection );
			unset ( $connection );

		    }

		}

	}

}

stream_socket_shutdown( $server, STREAM_SHUT_RDWR );
fclose ( $server );
unset ( $server );


Client:

$client = @stream_socket_client ( 'tcp://127.0.0.1:30000', $errno, $errstr, 30, STREAM_CLIENT_CONNECT );

$message = "Hiii";

fwrite ( $client, $message );

$stream_socket_recvfrom = stream_socket_recvfrom ( $client, 8192 );
echo "\n" . $stream_socket_recvfrom;

stream_socket_shutdown( $client, STREAM_SHUT_RDWR );
fclose ( $client );
unset ( $client );


Во всех случаях стоит PHP 8.1, код запускается через консоль, настройки по умолчанию (в обеих случаях). Честно говоря, голову сломал. Даже перелопатил React PHP, но никаких особенностей не заметил.

Буду рад всем мнениям. Спасибо
  • Вопрос задан
  • 341 просмотр
Подписаться 2 Простой 23 комментария
Решения вопроса 1
@antobra Автор вопроса
Решение:
1. Убедиться, что PHP-код исправен
2. Настроить ulimit -u, ulimit -n
3. Настроить sysctl для highload
4. Reboot
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы