15

私は、サーバー コンポーネントが完全に erlang で書かれている既存の (ゲーム) プロジェクトに参加しています。場合によっては、このシステムからデータを取得するのが非常に困難になることがあります (プレーヤー 56 がいくつのウィジェットを持っているかに興味があります)。それを所有するプロセスから取得します。データを所有するプロセスを見つけることができると仮定すると、そのプロセスにメッセージを渡してメッセージが返されるのを待つことができますが、これは複数のマシンにうまく拡張できず、応答時間が長くなります。

このゲームに存在するタスクの多くを、複数のプロセスによって頻繁にアクセスされる情報が保護された ets テーブルに格納されるシステムに置き換えることを検討してきました。テーブルの所有者は、更新メッセージ (プレーヤーが 5 つのウィジェットを使用したばかり) を受信し、それに応じてテーブルを更新するだけです。すべての例外をキャッチし、単純に次の更新メッセージに進みます。プレーヤーが愚か者を購入するのに十分なウィジェットを持っているかどうかを知りたいプロセスは、テーブルをのぞくだけで済みます。(はい、ウィジェットの数を減らすメッセージがバッファーにある可能性があることは理解していますが、その問題は制御下にあります。)

残念ながら、私の質問は質問ではなく、コメントのリクエストです。役に立ち、十分に説明または参照されているものは何でも賛成します。

そのような実装の可能性のある欠点は何ですか? 私が興味を持っているのは、ライターが 1 人で複数のリーダーがいる場合に見られる可能性が高いロック競合の詳細、これを複数のマシンに分散する際にどのような問題が発生するか、および特に:この前。

4

3 に答える 3

8

まず第一に、 Erlang ETSのドキュメントでわかるように、デフォルトの ETS の動作は一貫しています。これは原子性と分離を提供し、同じ関数で実行された場合は複数の更新/読み取りも提供します (Erlang では、関数呼び出しはリダクションとほぼ同等であり、Erlang スケジューラーがプロセス間で時間を共有するために使用する測定単位であることを思い出してください。したがって、複数の関数 ETS操作がより多くの部分に分割される可能性があり、競合状態が発生する可能性があります)。

複数ノードの ETS アーキテクチャに興味がある場合、ETS: Mnesiaで OOTB 複数ノードの同時実行が必要な場合は、mnesia を参照する必要があります。(ヒント: 特に ram_copies テーブル、add_table_copy および change_config メソッドについて話している)。

そうは言っても、プロセスの問題を理解していません(名前のないetsテーブルによってバックアップされている可能性があります)。あなたのプロジェクトの主な問題は、最初の基本的な仮定です。それは簡単です: 単一の書き込みプロセスはありません!

プレイヤーがオブジェクトを取得したり、プレイヤーを攻撃したりするたびに、ゲームの状態を更新する副作用のない関数が呼び出されるため、ゲームの状態を管理するプロセスが 1 つしかない場合でも、他のプレイヤー クライアントに「やあ、あなた」と伝えなければなりません。あの物体を覚えていますか?それを忘れて!'; これが、多くのマルチプレイヤー ゲームの主な問題がラグである理由です。ネットワーキングが主な問題ではない場合、ラグは多くの場合、送受信ルーチンのブロックが原因です。

この観点からすると、ETS テーブルを直接使用すること、永続テーブルを使用すること、プロセス ディクショナリ (BAD!!!) などを使用することは同じことです。メモリ(Java、みんな?)。

最後に、アプリケーションを開発する際の主な関心事は 1 つだけです。それは一貫性です。一貫性のあるアプリケーションが開発された後、パフォーマンス チューニングに専念する必要があります。

それが役に立てば幸い!

注: MMORPG サーバーのようなものについて話しているのは、あなたが似たようなことを話していると思ったからです。

于 2011-08-02T22:11:27.867 に答える
7

その点では、ETS テーブルは問題を解決しません。コード (プレーヤー ウィジェットの数を取得または設定する) は常にプロセスで実行され、データをそこにコピーする必要があります。

それがプロセス ヒープからのものであろうと ETS テーブルからのものであろうと、ほとんど違いはありません (とはいえ、ETS からの読み取りは、適切に最適化されており、データの取得と設定以外の作業を実行しないため、多くの場合高速です)。特にリモートノードからデータを取得する場合。複数のリーダーの場合、プロセスが要求を順番に処理するため、ETS の方がおそらく高速です。

ただし、違いは、データがローカル ノードにキャッシュされているかどうかです。そこで、Mnesia、Riak、CouchDB などの自己複製データベース システムの出番です。実際、Mnesia は ETS テーブルを使用して実装されています。

ロックに関しては、Erlang の最新バージョンでは ETS が強化されており、複数のリーダーがテーブルから同時に読み取ることができ、さらに 1 つのライターが書き込みを行うことができます。唯一のロックされた要素は、書き込まれている行です (したがって、1 つのデータ ポイントに対して多数の同時読み取りが予想される場合、通常のプロセスよりも優れた同時実行パフォーマンスが得られます)。

ただし、ETS テーブルとのやり取りはすべて非トランザクションであることに注意してください。つまり、値がその間に変更されている可能性があるため、以前の読み取りに基づいて値を書き込むことに依存することはできません。Mnesia は、トランザクションを使用してそれを処理します。dirty_*何をしているのか分かっていれば、Mneisaの関数を使用して、ほとんどの操作から ETS に近いパフォーマンスを絞り出すことができます。

于 2011-08-03T09:23:11.717 に答える
4

いつでも発生する可能性のある多くのことがあり、安全で統一された方法でデータを集約する必要があるようです。Generic Eventの動作を見てみましょう。これを使用してイベントサーバーを作成し、これらすべてのプロセスがイベントを介してこの情報をサーバーに共有することをお勧めします。その時点で、ログに記録するか、どこかに保存するか (ETS テーブルなど) を選択できます。余談ですが、ETS テーブルは、プレーヤーが持っている「ウィジェット」の数などの永続的なデータには適していません。MnesiaCouchDBのような優れたクラッシュのみのデータベースを検討してください。これらは両方とも、マシン間で非常によく複製されます。


ロックの競合が発生します。ロックは必要ありません。メッセージは、各プロセスで受信されると同期順に処理されます。実際、言語に組み込まれたメッセージ パッシング セマンティクスの要点は、共有状態の同時実行を回避することです。
要約すると、通常、プロセス間でメッセージをやり取りします。あちこちに散らばっているプロセスからの情報が必要なため、これは面倒です。そのため、元のプロセスの外部にある「興味深い」すべての情報を単一のリアルタイム ソースに集中させるという考えに基づいて、私が推奨することは、あなたにとっては難しいことです。 .

于 2011-08-02T22:02:28.457 に答える