2013-02-25 22 views
11

Ich implementiere benutzerdefinierten Server, der eine sehr große Anzahl (100K oder mehr) langlebiger Verbindungen verwalten muss. Der Server übergibt einfach Nachrichten zwischen Sockets und führt keine ernsthafte Datenverarbeitung durch. Nachrichten sind klein, aber viele von ihnen werden jede Sekunde empfangen/gesendet. Reduzierung der Latenz ist eines der Ziele. Ich weiß, dass die Verwendung mehrerer Kerne die Leistung nicht verbessern wird und daher entschied ich mich, den Server in einem einzigen Thread auszuführen, indem ich run_one oder poll Methoden von io_service Objekt aufrufen. Anyway Multi-Thread-Server wäre viel schwieriger zu implementieren.Boost Asio single-threaded Leistung

Was sind die möglichen Engpässe? Syscalls, Bandbreite, Completion Queue/Event Demultiplexing? Ich vermute, dass Dispatching-Handler möglicherweise sperren müssen (das wird intern von Asio-Bibliothek getan). Ist es möglich, auch die Sperrung der Warteschlange (oder eine andere Sperrung) in boost.asio zu deaktivieren?

EDIT: bezogene Frage. Verbessert sich die syscall-Leistung mit mehreren Threads? Mein Gefühl ist, dass, weil syscalls vom Kernel atomisch/synchronisiert sind, das Hinzufügen von mehr Threads die Geschwindigkeit nicht verbessern wird.

+0

Wenn Sie alles in einem Thread ausführen, benötigen Sie keine (handgeschriebenen) Sperren. –

+1

Die Verwendung mehrerer Kerne wird wahrscheinlich die Leistung verbessern - siehe http://cmeerw.org/blog/748.html#748 und http://cmeerw.org/blog/746.html#746 für einige Benchmarks, die ich letztes Jahr gemacht habe. – cmeerw

Antwort

15

Vielleicht möchten Sie vor ein paar Jahren lesen my question, ich fragte es, wenn erste Untersuchung der Skalierbarkeit von Boost.Asio bei der Entwicklung der Systemsoftware für die Blue Gene/Q supercomputer.

Skalierung auf 100k oder mehr Verbindungen sollte kein Problem sein, obwohl Sie die offensichtlichen Ressourcenbeschränkungen wie die maximale Anzahl der geöffneten Dateideskriptoren beachten müssen. Wenn Sie das bahnbrechende C10K paper nicht gelesen haben, empfehle ich, es zu lesen.

Nachdem Sie Ihre Anwendung mit einem einzigen Thread und einen einzigen io_service umgesetzt haben, schlage ich vor, einen Pool von Threads untersuchen io_service::run() Aufruf, und nur dann untersuchen eine io_service zu einem bestimmten Thread und/oder CPU-Pinning. Es gibt mehrere Beispiele in der Asio-Dokumentation für alle drei dieser Designs und several questions auf SO mit mehr Informationen.Beachten Sie, dass Sie bei der Einführung mehrerer Threads, die io_service::run() aufrufen, möglicherweise strand s implementieren müssen, um sicherzustellen, dass die Handler exklusiven Zugriff auf gemeinsame Datenstrukturen haben.

9

Mit boost :: asio können Sie Single-Thread- oder Multi-Thread-Server ungefähr zu gleichen Entwicklungskosten schreiben. Sie können die Singlethread-Version als erste Version schreiben und sie bei Bedarf in Multithread konvertieren.

Normalerweise ist nur Engpass für boost :: asio epoll/kqueue Reaktor arbeitet in einem Mutex. Also macht nur ein Thread gleichzeitig epoll. Dies kann die Leistung verringern, wenn Sie einen Multithread-Server haben, der viele sehr kleine Pakete abgibt. Aber, imo sollte es sowieso schneller sein als nur einfach-einthread Server.

Nun zu Ihrer Aufgabe. Wenn Sie nur Nachrichten zwischen Verbindungen übergeben möchten - ich denke, es muss Multithread-Server sein. Das Problem ist syscalls (recv/send etc). Eine Anweisung ist sehr einfach zu tun für CPU, aber jeder Syscall ist nicht sehr "leichte" Operation (alles ist relativ, aber relativ zu anderen Jobs in Ihrer Aufgabe). Also, mit Single-Thread werden Sie große syscalls Overhead, weshalb ich empfehlen, Multithread-Schema zu verwenden.

Sie können auch trennen io_service und es als "io_service pro thread" idiom arbeiten. Ich denke, das muss die beste Leistung bringen, aber es hat einen Nachteil: Wenn einer von io_service zu große Warteschlange bekommt - andere Threads werden ihm nicht helfen, so dass einige Verbindungen langsamer werden können. Auf der anderen Seite, mit einzelnen io_service - Warteschlange Überlauf kann zu großen Sperraufwand führen. Alles, was Sie tun können - tun Sie die beiden Varianten und messen Sie Bandbreite/Latenz. Es sollte nicht zu schwierig sein, beide Varianten zu implementieren.