[Tips] RPCメッセージの送信量・頻度の軽減
目次
概要
送受信ロジックについて
Tips(1) : シーン内の情報同期が目的である場合、MonobitView コンポーネントを持つ、単独の静的シーンオブジェクトでRPCメッセージをやり取りする
Tips(2) : ある特定のオブジェクト(prefab)の情報同期が目的である場合、RPCメッセージを使わず、OnMonobitSerializeView() を使う
RPCメッセージに関するパフォーマンス改善方法について
ここでは、MUN における RPCメッセージの送受信処理にてパフォーマンスの低下が感じられる場合、
MUN クライアント側で対処可能なテクニックについて紹介します。
当然のことながら、RPCメッセージの送信データを削減すればパフォーマンスは向上します。
ここではそれ以外の、RPC送受信に伴うスパイク(大きな負荷)への対策として、効果的な手段を触れたいと思います。
送受信ロジックについて▲
RPCメッセージの送信方式
MUN のRPCメッセージ送信は、MonobitNetwork.sendRate に設定された値に基づいて実行されます。
(MonobitNetwork.sendRate の初期値は20で、1秒間に20回送信します)
設定された送信間隔までの間、各種RPC送信命令にて実行されたRPCメッセージはRPCメッセージキューに蓄積され、
送信タイミングに合わせ、RPCメッセージキューに登録された順に送信されます。
MUN 2.2.0 以降の場合、RPCの送信帯域制限以上のRPCメッセージデータについては、次フレームまで送信が保留されます。
MUN クライアント側から送信されたRPCメッセージは mun_room サーバが受信し、受信を受け取った段階で
即時他の MUN クライアントにリレー送信します。
RPCメッセージの受信方式
RPCメッセージを受信した MUN クライアント側では、受信後に「どのオブジェクトに登録されたRPCのメソッドを呼び出すのか」を検索します。
この検索処理は以下のようなロジックで実行されるため、RPCメッセージの送受信処理において最も負荷が高くなってしまいます。
RPCメッセージによる負荷対策として最も効果的なのは、RPC の受信メソッドの検索回数を減らすことです。
// シーン内の全てのMonoBehaviourからRPCメソッドを探索してコルーチンを実行する
// methodName - RPCメソッド名
// methodArgs - RPCメソッドパラメータの型
// methodParams - RPCメソッドパラメータの実値
// behaviourInScene - シーン内に存在する、すべての MonobitView コンポーネントと同列に存在する MonoBehaviourの派生インスタンス
public void ReceiveRpcMethod(string methodName, Type[] methodArgs, object[] methodParams, MonobitEngine.MonoBehaviour[] behaviourInScene)
{
foreach(MonoBehaviour behaviour in behaviourInScene)
{
Type monoType = behaviour.GetType();
List<MethodInfo> methodList;
// シーン内の全てのMonoBehaviourから[MunRPC]のアトリビュート付きのメソッドを探索する
var result = MethodsCache.TryGetValue(monoType, out methodList);
if (result != true)
{
MethodInfo[] methods = monoType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo method in methods)
{
if (method.IsDefined(typeof(MunRPC), false))
methodList.Add(method);
}
MethodsCache[monoType] = methodList;
}
if (methodList == null || methodList.Count == 0)
continue;
// メソッド名が同一であるものを抽出する
var selectInfo = methodList.Where(m => m.Name.Equals(methodName));
if (selectInfo == null) continue;
// パラメータが同一であるものを抽出し、コルーチンを実行する
foreach (MethodInfo info in selectInfo)
{
var paramInfo = info.GetParameters();
if (paramInfo.Length == methodParams.Length && VerifyArgType(paramInfo, methodArgs))
{
object retValue = info.Invoke(behaviour, methodParams);
if (retValue is System.Collections.IEnumerator)
{
behaviour.StartCoroutine(retValue as System.Collections.IEnumerator);
}
}
}
}
}
Tips(1) : シーン内の情報同期が目的である場合、MonobitView コンポーネントを持つ、
単独の静的シーンオブジェクトでRPCメッセージをやり取りする▲
受信時に呼び出されるメソッド検索対象の「インスタンス」を少なくする
RPC の受信メソッドの所持候補となる、シーン内に存在するすべての MonobitView コンポーネント、
および MonoBehaviourの派生インスタンスの実数を出来るだけ少なくする ことがまず第一の目標です。
あるシーン内で、オブジェクトに依存しない情報の同期、例えば
・スコアやタイマーなどの数値計算、およびそのデータ共有
・NPCやアイテムなどの出現管理(スポーン処理)
・チャットの会話文の送受信
といった機能については、すべて1つの MonoBehaviour を継承したクラスで実装することが肝要です。
複数の MonoBehaviour を継承したクラスで実装することは、パフォーマンス低下につながります。
【避けるべきこと】
× 1つのシーンに対し、「MonobitView コンポーネントを持つ静的オブジェクト」を2つ以上作る
× 単独または複数の静的オブジェクトに対し、「MonoBehaviour を継承したクラス(スクリプト)」を2つ以上コンポーネントに持たせる
× 単独または複数のMonoBehaviourに対し、「RPC 受信メソッド」を2つ以上作る
【推奨されるべきこと】
〇 1つのシーンに対し、「MonobitView コンポーネントを持つ静的オブジェクト」を1つだけ作る
〇 単独または複数の静的オブジェクトに対し、「MonoBehaviour を継承したクラス(スクリプト)」を1つだけコンポーネントに持たせる
〇 単独または複数のMonoBehaviourに対し、「RPC 受信メソッド」を1つだけ作る
Tips(2) : ある特定のオブジェクト(prefab)の情報同期が目的である場合、
RPCメッセージを使わず、OnMonobitSerializeView() を使う▲
オブジェクトの位置情報以外のデータ同期について、RPCメッセージによるオーバーヘッドから脱する
一方、ある特定のオブジェクトの情報同期が目的である場合、RPCメッセージによる情報共有は推奨されません。
もちろん RPC メッセージによるデータ共有は可能ですが、情報量と伝送効率を考えた場合、RPCメッセージを用いるのは効果的ではありません。
MonobitTransformView で送信されるオブジェクトの位置姿勢情報、ならびに MonobitAnimatorView で送信される
オブジェクトのアニメーション情報を除いた
・オブジェクト単体のステータス(体力値や攻撃力などの、一般的なキャラステータスデータ)
・キャラクタの特定操作に伴う挙動フラグなど
の情報については、すべて OnMonobitSerializeView() の接続コールバックメソッド で実装することが理想的です。
RPCメッセージで送信するのは、パフォーマンスチューニングから考えた場合、あまり効率的な対応方法ではありません。
【避けるべきこと】
× オブジェクトの特定情報の同期について RPC メソッドを使う
【推奨されるべきこと】
〇 オブジェクトの特定情報の同期については OnMonobitSerializeView() メソッドを使う
なお、RPCメッセージ本来の同期タイミングについては MonobitNetwork.sendRate に依存しますが、
OnMonobitSerializeView() メソッドを利用した場合、MonobitNetwork.updateStreamRate に依存します。
あまり致命的な問題にはなりませんが、同期されるタイミングが本来の RPC メッセージと異なる場合がありますので注意してください。