web-dev-qa-db-ja.com

Java接続モデルごとのスレッドとNIO

非ブロッキングJava NIOは、接続非同期ソケットごとの標準スレッドよりも遅いですか?

さらに、接続ごとにスレッドを使用する場合、新しいスレッドを作成するだけですか、それとも非常に大きなスレッドプールを使用しますか?

MMORPG server in Javaこれは、強力な十分なハードウェアがあれば10000クライアントを簡単にスケーリングできるはずですが、クライアントの最大数は24000( Javaでは15000スレッドの制限があるため、接続モデルごとのスレッドに到達することは不可能だと思います。3年前の記事から、ブロックIO接続モデルはNIO(つまり、このドキュメント http://www.mailinator.com/tymaPaulMultithreaded.pdf )よりも25%高速でしたが、この日でも同じことを達成できますか?Javaはそれ以来大幅に変更されており、使用されたVMはSun Javaではなかったため、実際のシナリオを比較すると結果が疑わしいと聞きました。また、これは、MMORPGサーバーであり、多くの同時ユーザーが相互に対話しているため、同期とスレッドセーフティを使用すると、10000のクライアントにサービスを提供する単一のスレッドNIOセレクターまでパフォーマンスが低下しますw病気は速くなる? (すべての作業は、セレクターを使用してスレッドで処理する必要はありません。MINA/ Nettyが機能する方法のように、ワーカースレッドで処理できます)。

ありがとう!

39
Kevin Jin

NIOのメリットは、1粒の塩で摂取する必要があります。

HTTPサーバーでは、ほとんどの接続はキープアライブ接続であり、ほとんどの場合アイドル状態です。それぞれにスレッドを事前に割り当てることは、リソースの無駄になります。

MMORPG=の場合、状況は大きく異なります。ユーザーからの指示の受信と最新のシステム状態のユーザーへの送信で、接続は常にビジー状態です。接続には、ほとんどの場合、スレッドが必要です。

NIOを使用する場合、接続用のスレッドを常に再割り当てする必要があります。これは、単純な接続ごとの固定スレッドソリューションよりも劣ったソリューションである可能性があります。

デフォルトのスレッドスタックサイズはかなり大きい(1/4 MB?)。これが、限られたスレッドしか存在できない主な理由です。それを減らして、システムがさらにサポートできるかどうかを確認してください。

ただし、ゲームが実際に非常に「ビジー」である場合、最も心配する必要があるのはCPUです。 NIOであろうとなかろうと、マシン上で何千人ものハイパーアクティブゲーマーを処理することは非常に困難です。

23
irreputable

実際には3つのソリューションがあります。

  1. 複数のスレッド
  2. 1つのスレッドとNIO
  3. 両方のソリューション1と2を同時に

パフォーマンスを向上させるための最善の方法は、少数の限られた数のスレッドを用意し、ネットワーク経由で新しいメッセージが到着したときにNIOを使用してこれらのスレッドにネットワークイベントを多重化することです。


1つのスレッドでNIOを使用することは、いくつかの理由で悪い考えです。

  • CPUまたはコアが複数ある場合、スレッドが1つしかない場合は一度に1つのコアしか使用できないため、リソースはアイドル状態になります。
  • 何らかの理由で(ディスクアクセスを行うために)ブロックする必要がある場合、ディスクを待機している間に別の接続を処理している可能性があるとき、CPUはアイドル状態です。

スケーリングしないため、接続ごとに1つのスレッドを使用することはお勧めできません。持っているとしましょう:

  • 10 000接続
  • それぞれ2コアの2 CPU
  • 常に100スレッドのみがブロックされます

次に、必要なスレッドは104だけであることを確認できます。これ以上、必要のない追加のスレッドを管理するリソースを浪費しています。 10 000スレッドを管理するために必要な内部には、多くの簿記があります。これはあなたを遅くします。


これが、2つのソリューションを組み合わせる理由です。また、VMが最速のシステムコールを使用していることを確認してください。すべてのOSには、高性能ネットワークIOのための独自のシステムコールがあります。VMがLinuxでのepoll()だと思います。

さらに、接続ごとにスレッドを使用する場合、新しいスレッドを作成するだけですか、それとも非常に大きなスレッドプールを使用しますか?

最適化に費やす時間によって異なります。最も迅速な解決策は、必要に応じてスレッドや文字列などのリソースを作成することです。次に、ガベージコレクションがそれらを使い終わったらそれらを要求します。リソースのプールを用意することで、パフォーマンスを向上させることができます。新しいオブジェクトを作成する代わりに、プールにオブジェクトを要求し、完了したらプールに戻します。これにより、同時実行制御の複雑さが増します。これは 非ブロッキングアルゴリズム のような高度な同時実行アルゴリズムでさらに最適化できます。 Java APIの新しいバージョンには、これらのいくつかが含まれています。これらの最適化を1つのプログラムで実行することで、残りの人生を過ごすことができます。特定のアプリケーションに最適なソリューションは何でしょう。独自の投稿に値する質問。

12
Jay

十分に強力なハードウェアにいくらでもお金を費やすことをいとわないのであれば、サーバーを1つに制限してください。 googleは1つのサーバーを使用せず、サーバーの1つのデータセンターも使用しません。

よくある誤解は、NIOが非ブロッキングを許可するということですIOそのため、ベンチマークに値する唯一のモデルです。ブロッキングNIOをベンチマークすると、古いIOより30%速くなります。つまり、同じモデルをスレッド化し、IOモデルのみを比較します。

洗練されたゲームの場合、1万の接続に到達する前に、CPUが不足する可能性がはるかに高くなります。この場合も、水平方向にスケーリングするソリューションを使用する方が簡単です。そうすれば、取得できる接続の数を気にする必要はありません。

何人のユーザーが合理的に対話できますか? 24?その場合、相互作用する1000個の独立したグループがあります。 1台のサーバーにこれほど多くのコアはありません。

ユーザーごとにサーバーに費やす予定の金額はどれくらいですか? 5000 GB未満で64 GBのメモリを搭載した12コアサーバーを購入できます。このサーバーに2500人のユーザーを配置すると、ユーザーあたり2ポンドが費やされます。

編集:私はリファレンスがあります http://vanillajava.blogspot.com/2010/07/Java-nio-is-faster-than-Java-io-for.html これは私のものです。 ;)私はこれをJavaネットワーキングの達人である誰かにレビューしてもらいました。

9
Peter Lawrey

接続がビジーな場合、つまり接続が常にデータを送信し、それらを送り返す場合は、Akkaと組み合わせてnon-Blocking IOを使用できます。

Akkaはオープンソースのツールキットおよびランタイムであり、JVM上での並行および分散アプリケーションの構築を簡素化します。 Akkaは並行性のために複数のプログラミングモデルをサポートしていますが、Erlangからインスピレーションを得て、アクターベースの並行性を強調しています。言語バインディングは、JavaとScalaの両方に存在します。

Akkaのロジックはノンブロッキングなので、非同期プログラミングに最適です。 Akka Actorsを使用すると、Thread overheadを削除できます。

しかし、ソケットストリームがより頻繁にブロックする場合は、Blocking IOQuasarと組み合わせて使用​​することをお勧めします

Quasarは、JVMに真の軽量スレッド(AKAファイバー)を実装する、シンプルで軽量なJVM並行性のためのオープンソースライブラリです。 Quasarファイバーは、単純なJavaスレッドと同じように動作しますが、実質的にメモリとタスク切り替えのオーバーヘッドがないため、単一のJVMで数十万または数百万のファイバーを簡単に生成できます。 。Quasarはまた、Go言語によって提供されるものをモデルにしたファイバー間通信用のチャネルを提供し、チャネルセレクターを備えています。また、Erlangに厳密にモデル化されたアクターモデルの完全な実装も含まれています。

クエーサーのロジックがブロックしているため、別の接続で待機している24000ファイバーをスポーンできます。 Quasarの良い点の1つは、ファイバーがプレーンスレッドと非常に簡単に相互作用できることです。また、QuasarはApache HTTP clientまたはJDBCまたはJerseyなどの一般的なライブラリと統合されているため、プロジェクトのさまざまな側面でFibersを使用する利点を活用できます。
これらの2つのフレームワーク ここ の良い比較を見るかもしれません。

3

皆さんのほとんどが、サーバーはCPU使用率が10kの同時ユーザーに到達する前にロックアップされることになっていると言っているので、この特定のことを考慮して、スレッドブロック(N)IOアプローチを使用する方が良いと思いますMMORPG、各プレーヤーで1秒あたり数パケットを取得することは珍しいことではなく、セレクターが使用された場合にセレクターがダウンする可能性があります。

Peterは、NIOのブロックが古いライブラリよりも高速であるという興味深い点を提起しましたが、評判が悪いのは、ビジーなMMORPGサーバーの場合、プレーヤーごとに受信される命令の数が多いため、スレッドを使用する方が良いということです。あまりにも多くのプレーヤーがこのゲームでアイドル状態になることを期待しないので、実行していないスレッドがたくさんあることは問題にはなりません。クライアントから受信したパケットを同時に実行するいくつかのワーカースレッドを使用するため、NIOに基づくフレームワーク。コンテキストの切り替えは高額になる可能性がありますが、このソリューションを試してみることにします。コードをリファクタリングするのは比較的簡単なので、ボトルネックがある場合、NIOフレームワークを使用できます。

私の質問には答えがあったと思います。より多くの人々からより多くの洞察を受け取るために、私はもう少し待つだけにします。たくさんのご回答ありがとうございます!

編集:私は最終的に私の行動方針を選択しました。私は実際には優柔不断であり、JBoss Nettyを使用して、ユーザーがクラスを使用してoioまたはnioを切り替えることができるようにすることにしました

org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;

Nettyが両方をサポートしていることは非常に素晴らしいことです。

2
Kevin Jin

以前はSunがスポンサーを務めていたプロジェクト(現在はRed Dwarfという名前)からインスピレーションを受けるかもしれません。 http://www.reddwarfserver.org/ の古いWebサイトがダウンしています。
Githubで救出: https://github.com/reddwarf-nextgen/reddwarf

1

クライアント側のネットワーク呼び出しを行う場合は、ほとんどの場合、プレーンソケットioが必要です。

サーバー側のテクノロジーを作成している場合、NIOはネットワークIO部分をフルフィルメント/処理作業から分離するのに役立ちます。 IOネットワークIOの1または2として構成されたスレッド。ワーカースレッドは、実際の処理パーツ用です(マシンの機能に基づいて、1からNの範囲です)。

0