La migliore architettura software per un efficiente tunneling di rete in C ++

2

Prima di saltare alle mie domande, lascia che ti spieghi lo sfondo del mio progetto.

Io faccio parte di un team che organizza la rete di un famoso evento LAN. La maggior parte dei giochi al giorno d'oggi non funziona in realtà ma usa alcuni server remoti. Disponiamo di una connessione di gigabyte con un unico IP pubblico a nostra disposizione e non possiamo permetterci altre soluzioni tecniche. Purtroppo, la maggior parte dei server di gioco / protezioni di rete reagiscono davvero male quando improvvisamente più di 500 utenti accedono a un corto da un singolo IP pubblico. Una società di hosting ci presta con grazia un cosiddetto cloud composto da alcuni dispositivi con CPU ARM (4 core) e quindi abbiamo un enorme numero di IP pubblici. Fino ad ora il nostro trucco consisteva nell'usare OpenVPN per il tunneling di alcune connessioni tramite il cloud, ma OpenVNP non è ottimale per alcune ragioni, in particolare sulle nostre CPU ARM: OpenVPN gira su un core saturo (mono-thread) con una bassa larghezza di banda.

Per prima cosa non ci interessa la sicurezza o l'alta resilienza di OpenVPN, vogliamo un tunnel spoglio. Le prime azioni che hanno visto questi risultati negativi consistevano nel ritoccare, utilizzando i file di configurazione, tutte le opzioni di consumo della CPU (crittografia ...), utilizzare UDP, avviare un'istanza per core ... Anche con tutte queste azioni, il throughput è un po ' deludente. È qui che iniziamo a pensare di creare un tunnel altamente specializzato in C ++ per le nostre esigenze. Nessuna grande ingegneria come OpenVPN fa il suo lavoro perfettamente bene come VPN generica.

Prima domanda: c'è già qualche buona soluzione che risolva il nostro problema? Non vogliamo ricreare la ruota.

Abbiamo iniziato a lavorare su una versione userland del tunnel usando i dispositivi linux tun / tap. Un modulo del kernel sembra un'idea più brillante? Parlando di tecnologie, molto probabilmente userò C ++ 11 e boost.

Ho creato due architetture, entrambe divise in circa 4 componenti: - Uno che riceve / invia alcuni dati dall'interfaccia di rete. Un socket UDP. - Uno che alloca alcuni blocchi di memoria per i pacchetti che vengono ricevuti o inviati. - Uno che indirizza i pacchetti. - Uno che scrive sull'interfaccia tun / tap.

La mia prima architettura avrebbe usato boost :: asio per il socket UDP, il router e l'interfaccia (nota: un'interfaccia può essere descritta in più descrittori di file che possono essere incapsulati per asio). Ognuno di questi componenti avrebbe il proprio asio :: filo per evitare le condizioni di gara e tutti i problemi di threading. Creerei da 4 a 8 thread per i loop degli eventi. Asio ei metodi asincroni sembrano stupendi e facilitano il passaggio del messaggio tra i miei componenti. Ma prima epoll / select potrebbe non essere super efficiente per un singolo socket UDP e pochi descrittori di flusso. Non abbiamo a che fare con il problema C10k qui, non c'è bisogno di ridimensionare il numero di client come un tunnel è solo 1 < == > 1. In secondo luogo, temo che le code dei messaggi asi non siano realmente efficienti, vogliamo una larghezza di banda elevata e la larghezza di banda strettamente legata alla latenza. Ultimo ma non meno importante, asio ha alcuni meccanismi di blocco interni che temo un po '.

La mia seconda architettura userebbe 3-4 thread dedicati (uno per componenti) che giravano come pazzi e facevano i rispettivi lavori. Bloccare l'IO o non dovrebbe avere importanza. I messaggi che passano tra i componenti utilizzano alcune code bloccate. Questa soluzione sembra più difficile da codificare. Il throughput dovrebbe essere veramente alto e stabile (resistente a picchi / raffiche) ma significa anche che tutte le risorse del server verranno masterizzate con i nostri thread che girano come pazzi. Dato che il nostro tunnel non farà molto di più del routing, il tempo potrebbe essere speso di più sull'IO che sulla CPU.

Per quanto riguarda i componenti di allocazione: ho pensato di utilizzare un pool di oggetti (pacchetti) combinato con alcuni shared_ptr come questo: link

O per usare un ring buffer, alcuni pacchetti potrebbero essere eliminati nel processo pensato.

Hai qualche altra idea per un'architettura efficiente, o qualche recensione o preferenza per le idee menzionate in precedenza? Stiamo cercando di trovare il meglio tra una soluzione elegante ed efficiente.

Qualsiasi altro suggerimento per un tunnel efficiente è il benvenuto! (Come non usare TCP su TCP).

    
posta Jiwan 10.06.2015 - 19:21
fonte

0 risposte

Leggi altre domande sui tag