Как gRPС обрабатывает большое кол-во подключений?

Не нашел нормального объяснения как gRPС обрабатывает большое кол-во одновременных подключений?

Нужно ли перед ним вешать веб сервер nginx и т.п. ? Или он сам выступает как веб сервер?

Нужно ли запускать большое кол-во потоков самому? Или это настраивается на уровне самого сервера gRPС кодом на том языке на котором пишешь?


Ответы (1 шт):

Автор решения: Pak Uula

Наверное, речь идёт о gRPC.

gRPC сервер при подключении клиента создаёт новый сокет и вешает на него обработчик сообщений. То, как именно работают эти обработчики, зависит от языка программирования.

В go это горутины, и сам рантайм go определяет, в каких потоках их выполнять. Соответственно, в go обработчики нескольких подключений могут работать параллельно.

В python это пайтоновский потоки, но так как пайтон работает в однопоточном режиме, то их переключение осуществляется внутри рантайма и по факту в каждый момент времени выполняется не более одного такого обработчика.

Краткий ликбез о том, как работают сокеты TCP

Раз у вас есть вопрос про "раздаёт на другие сокеты", то опишу кратенько как работают сервера поверх сокетов.

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

Как происходит подключение клиента к серверу.

На стороне сервера программа выполняет несколько системных вызовов: bind для связывания сокета с IP адресом и портом, и listen для переключения в hрежим серверного сокета, accept для ожидания подключений (в реальности, как правило, несколько сложнее, но для ликбеза несущественно).

Вызов accept блокируется до тех пор, пока не будет получен запрос на соединение от клиента. Когда клиент подключается, внутри ядра создаётся клиентский сокет для обмена данными с клиентом. Этот сокет прикрепляется к таблице файлов серверного процесса и его файловый дескриптор возвращается в вызове accept. Этот новосозданный сокет является клиентским, то есть через него можно ожидать данные (recv) или отправлять данные (send)

Что происходит дальше.

Все сервера устроены примерно одинаково. Как только accept где-то в дебрях серверного кода возвращает клиентский сокет, с ним связывается обработчик получаемых данных. Когда в сокет приходят данные от клиента, серверная инфраструктура находит обработчик и вызывает его (здесь я умышленно не пишу про select/poll). Так работает gRPC, так работает web-сервер.

Ограничения

Серверная инфраструктура может накладывать различные ограничения на число подключений и объем трафика.

Во-первых, ядро ОС лимитирует количество файлов, открытых одним процессом. Клиентский сокет с точки зрения ОС - файл, поэтому этот лимит может привести к тому, что accept вернёт ошибку too many open files. Я недавно на такое налетел. Забыл поднять через ulimit предел, и через пару дней работы сервер gRPC падал именно с этой ошибкой. Накапливалось число открытых файлов leveldb и в какой-то недетерминированный момент опс - и сервер аварийно завершался.

Во-вторых, библиотека gRPC, которой вы пользуетесь, может лимитировать число подключений. Если accept возвращает новый сокет, а число открытых клиентских сокетов уже достигло заданного предела, новый сокет просто закрывается без прикрепления к нему обработчика.

В-третьих, библиотека может накладывать ограничения на число данных, получаемых из сокета. Так как вся работа с сокетами, как правило, инкапсулирована, и обработчик получает уже готовые данные, то для слишком активных сокетов обращение за новыми данными может происходить по таймеру. Скажем, через пару-тройку секунд после завершения обработчика, а не сразу после его завершения.

Первое ограничение смотрите в документации на ОС. В частности в Linux это утилита ulimit. Второе и третье в документации на библиотеку gRPC, которой вы пользуетесь.

→ Ссылка