Se tutti i dati vengono inviati attraverso il processo del coordinatore, il processo di coordinamento diventa un collo di bottiglia e un livello di buffering completamente inutile. Quindi la tua prima soluzione dovrebbe essere evitata.
Ci sono un paio di alternative per distribuire il carico su più processi di lavoro:
-
Avere un ciclo accept()
nel processo coordinatore, quindi fork()
di un processo di lavoro all'interno di quel ciclo per gestire il socket accettato. Questo è il classico design del demone ed è facile da implementare in C o Perl. Ma può essere difficile da implementare correttamente con Python perché la biforcazione ha interazioni sorprendenti con il multithreading e il tuo programma Python potrebbe eseguire più thread di quanto ti aspetteresti.
-
Avere un ciclo accept()
nel processo coordinatore, quindi inviare il descrittore di file del socket accettato al processo di lavoro su un socket AF_UNIX con un messaggio SCM_RIGHTS. Questo è simile a dup()
in fd attraverso un limite di processo. Questa può essere una soluzione elegante che consente al processo del coordinatore di decidere quale processo di lavoro gestirà la connessione.
-
Tutti i processi di lavoro eseguono il proprio ciclo accept()
, ma consentono loro di ascoltare su una porta condivisa utilizzando il flag SO_REUSEPORT. Il kernel decide quindi quale processo di lavoro riceve una connessione in entrata. Questo è più appropriato per uno scenario di bilanciamento del carico perché il processo del coordinatore non interferisce con la connessione, ma questo non funziona con tutti i tipi di socket.
Questo è simile alla seconda soluzione in cui si inizia ad ascoltare su una porta e poi si biforcano i processi di lavoro, tranne che non è necessario iniziare ad ascoltare prima di biforcarsi e che entrambe funzioneranno solo con SO_REUSEPORT.