あるネットゲーマーの日常

プレイしているネットゲームの話題を中心にまったりと

【特別編】なぜMMORPGは重くなるのか(後編)~アイテムロスト編~

ここ数日、帰りが遅かったうえに、長文を勢いで書いてしまい、
少々おつかれモードではあるのですが、
頭に書きたいことが残っているうちに書いちゃいましょう...φ(・ω・`)

前編では、MMORPG特有の難しさについて書きました

netgamer.hateblo.jp

長い文章なのでざっくりまとめると、以下がポイントになります...φ(・ω・`)

  • MMORPGは主に「ゲームサーバ」と「データベースサーバ」で動いている
  • MMORPG特有の問題は、「データベースへの書き込みの多さ」にある
  • データベースに「書き込む処理」は遅い

後編ではこれらをふまえつつ、以下の問題を順に考えていきたいと思います

  • なぜ、サーバキャンセル(鯖缶)が起こるのか?
  • なぜ、巻き戻りが起こるのか?
  • なぜ、アイテムロストが起こるのか?

最後の項目はかなりのレベルで推測が含まれるのですが、
前二つの項目の延長として考えると、こうなんじゃないかな・・・という感じで

まずは鯖缶の話からなのですが、
その説明に必要な「マルチプレイの仕組み」からいってみましょう...φ(・ω・`)

マルチプレイの通信とつじつま合わせ

例えば、二人のプレイヤーが、それぞれの端末でマルチプレイをしているとしましょう

最近はスマホゲーでもマルチプレイが可能になってますし、
二人でなんらかの「クエスト」をプレイしている・・・と思ってください

当然ながら、それぞれ同じ状況を共有できないとゲームになりませんので、
どこかで「状態」を管理しなければなりません

この場合の選択肢はだいたい以下のどちらかです

  • マスタープレイヤー(部屋主)を決め、その端末のメモリ空間で管理
  • サーバに二人のためのメモリ空間(=部屋)を作成し、そこで管理

ネットを介さず、ローカルでマルチプレイする場合は前者しか不可能なのですが、
スマホゲーの場合はたいてい後者の仕組みです

前者の場合、マスター側に対して他のプレイヤーの情報が一斉に集まるため、
通信が集中してしまいますし、マスターの端末が落ちると全員切断されてしまうので、
通信が不安定なスマホではさすがに無理があります(´-ω-)

サーバと二人の端末の三者が、状態の変更や操作情報をやり取りするわけですが、
「お互いのメモリを正しく書き換えました」という「結果」を待っていたら、
一度通信するごとに応答待ちが発生してしまうので、リアルタイムに動かせません

なので、「きっと通信相手は正しく受け取ってくれる」と信じて、
端末からサーバも、サーバから端末も「一方的に」データを投げますΣ(・ω・ノ)ノ *1

その結果、全員からバラバラに情報が送られてくるので、
それをどう補正するか・・・が、マルチプレイ最大の肝といってもいいでしょう

例えば、端末Aで敵Xを倒し、その少し後で端末Bで敵Yを倒したとしましょう

端末A側の処理はたぶんこんな感じです

Xを倒したという情報をサーバに送る
-> サーバの応答を待たずに、Xが消える演出を展開する
-> サーバから「Yが倒された」という情報が届く
-> Yが消える演出を展開する

一方、端末Bではこんな動きになると思われます

Yを倒したという情報をサーバに送る
-> サーバの応答を待たずに、Yが消える演出を展開する
-> サーバから「Xが倒された」という情報が届く
-> Xが消える演出を展開する

正式な時系列でいえば、「Xが倒されてからY」なのですが、
Bの端末からみると「Yが倒されてからX」に見えています

しかし、結果を見れば、「XもYも倒された」という状態は一致するので、
問題ないとしてゲームを進めてしまうわけですΣ(・ω・ノ)ノ

このように、マルチプレイでは個々の端末で細かい差違があるものの、
大枠で一致していればOKとしてゲームを進めてしまい、
NGだった場合は何らかの補正をする・・・という処理をします

アクション性の高いゲームほど、このあたりがシビアだったりしますので、
興味があれば前回紹介した本だけでなく、こちらの本なども参考に(´・ω・)っ
(今だともっといい本があるかもしれませんが・・・)

オンラインゲームを支える技術  ??壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

オンラインゲームを支える技術  ??壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

ちなみに、前者は主にスクエニに絡んでる方、
後者はバンナムの方の本です(`・ω・´)

なぜ、サーバキャンセル(鯖缶)が起こるのか?

先ほどのマルチプレイが数百人単位になったのがMMORPGですが、
基本的な原理は同じです

つまり、クライアントは「見込み」でキャラを描画し、
ゲームサーバは時間差でクライアントからの通信を受け取って、
自身のメモリを書き換える・・・ということをしています(`・ω・´)

通信に障害がなく、ゲームサーバにも余裕があれば、
通常はこれで問題ないのですが、ゲームサーバの処理が限界を超えていたり、
通信がうまくいってない場合、クライアントとサーバの状態にずれが生じます

プレイヤーが座標Aをクリック
-> クライアントが座標Aへの移動をサーバに通知
-> サーバの応答を待たずに、見込みでクライアントは座標Aへの移動を開始
-> プレイヤーが座標Bをクリック
-> クライアントが座標Bへの移動をサーバに通知
-> クライアントが周辺の情報をサーバに要求
-> サーバは「最初にいた座標」を返す
-> クライアント「あれ? まだ移動完了してなかった?」
-> クライアントはキャラを最初の座標に戻す(ヨーヨー現象)
-> サーバに移動処理が到達し、キャラの座標が書き換えられる
-> むかついたプレイヤーが今度はCをクリック
-> サーバから「Bにいる」と通知
-> クライアント「わけわからん\(^o^)/」
-> 「サーバーとの接続がキャンセルされました。」

要は、ゲームサーバとクライアントの間で情報に齟齬が出て、
しかもそれをお互いに補正しきれない場合に、
いったん切断してゲームサーバの状態からやり直すわけです
(あくまで主体はゲームサーバ=データベースサーバのデータです)

なので、重いときにあせっていろいろクリックせず、
待っているのが大事なわけです(´-ω-)

なぜ、巻き戻りが起こるのか?

鯖缶の説明にあったように、クライアントとゲームサーバの間では、
「相手を待たずに一方的なやりとり」で通信がおこなわれています

待っていればデータに齟齬が出ない*2ものの、
データの書換が数百人単位でおこなわれている状況で、
それぞれの通信を待っていたらえらいことになります(lll゚Д゚)

では、「ゲームサーバ」と「データベースサーバ」はどうでしょうか?

もし、キャラの座標が変わるたびに、いちいちデータベースサーバに保存していると、
データベースの書き込みが大量になりすぎてしまい、詰まってしまいます(lll゚Д゚)

実際は、状態の変更をゲームサーバのメモリ領域だけで留めておき、
定期的にデータベースサーバに書き込みを依頼する・・・という動作をしています

ブレスを受けた直後にログアウトしようとすると拒否されたりするのは、
データの保存を待っているから・・・と推測されます
前編で書いたように、「ブレスを受けた」というキャラの状態を保存しないといけないので

もし何らかの原因で、保存する前にゲームサーバがダウンしてしまうと、
ゲームサーバはデータベースサーバの情報から読み直しをするので、
保存する前のデータは失われてしまいます

これが、プレイヤーから見ると「巻き戻った」と見える現象です

もし、カードを拾ったにもかかわらず、それが書き込まれる前に、
ゲームサーバがダウンしてしまった場合、
カードGETはなかったことになるわけです(ノ゚Д゚)ノ彡┻━┻

しかも、この現象の問題は、メモリ内にしかない情報が、
どこかに書き込まれる前に消えてしまっている・・・というところです
つまり、データベースはもちろん、ログにも残ってない可能性があります *3

だからといって、厳密にどこかにデータを残そうとすれば、
今度はゲームとして遅くなりすぎるわけで、設計上のトレードオフとして、
「何か障害があれば巻き戻るけど、それは仕方ない」としているわけです(´-ω-)

それでも、昔に比べればだいぶ巻き戻りが減っているので、
内部的に何らかの効率化が計られていたり、
問題が起こっても対応できる仕組みが追加されていると思われます

なぜ、アイテムロストが起こるのか?

さて・・・ここまでで説明の前提条件が揃いました(`・ω・´)

いよいよ本命の「アイテムロストの仕組み」なのですが・・・
昔ならいざしらず、最近のサーバ技術やスペック、
ゲームサーバの効率化の結果、通常のプレイでロストはほぼ発生しないはずです

「倉庫からアイテムを取り出し中に鯖缶」はよくありますが、
それでロストする可能性は、現在ではほとんどないのではないかと思われます

だからこそ、最初に話を聞いた際には、
どうしてそれが起こったのか・・・と気になっていたのですが、
被害に遭った方がBlogに詳細な状況を残しておりました

168ro.blog.fc2.com

これに沿って、何が起こったのかを推測してみると、こんな感じになるかと
(【】内はBlogにあった状況)

  • 【プロで鯖缶
  • データベース上のキャラ座標は「プロンテラ」
  • プロを含むゲームサーバAが過負荷のため、他のゲームサーバを案内される
  • 【脱出場所として伊豆を選択】(他多数)
  • 伊豆を含むゲームサーバBに多数のキャラがIN
  • おそらく、急激にゲームサーバBの負荷が上昇し、データベースへの書き込みが滞る
  • 【倉庫から装備を取り出す】
  • 倉庫のデータはゲームサーバ間で共通なので、おそらく「取り出した」という情報は先に書き込まれた(この辺の理屈がかなり怪しい)
  • キャラのイベントリに装備が移動するが、この時点ではまだ「ゲームサーバBのメモリ上」
  • 通常であれば、時間差でキャラ情報がデータベースに書き込まれるはずだが、過負荷で遅れていたと推測
  • 【サーバキャンセル】->【再ログイン】
  • キャラの情報をデータベースから読み込むが、キャラの最終書き込み情報はプロンテラ
  • 先ほどまでいたゲームサーバBではなく、ゲームサーバAにログイン
  • 【なぜかプロンテラにいる】
  • この時点で、「倉庫から取り出した」という情報は書き込まれ、「キャラが持っている」という情報が書き戻されていない状況
  • プロにいる状態=アイテムを持たない状態をデータベースに書き込まれてしまう
  • データベースに書き込まれた時点でその情報が「真」となり、アイテムの情報を消失
  • 【倉庫にアイテムがない(イベントリにもない)】

かなりの部分が現象と環境からの推測ではありますが、
なんとなくこんな感じだったのではないかと(´・ω・`)

本来は保存タイミングをずらして効率化を図っていたとしても、
ほぼ問題なく保存され、状態の齟齬は起こらないはずなのですが、
B鯖が想定を超える過負荷になってしまい、こういった現象になったと推測されます

しかも、「メモリ上にしかない情報」が失われてしまうと、
問題を追うことが難しいので、復旧も難しいんだろうな・・・と(´-ω-)

そもそも、「倉庫を開く」というのは重たい処理です

最大600個分のアイテムデータを通信し、表示しなければならず、
これ以上増やすと通信が限界なので、「倉庫を増やす」という形で増強してくらいです
倉庫を開けるだけでもれなく鯖缶するようでは、ゲームになりませんからね(lll゚Д゚)

まとめ

前後編の話をまとめるとこんな感じになります...φ(・ω・`)

  • サーバが重い原因はデータベースサーバである可能性が高い
  • 多人数マルチプレイを実現するため、クライアントやサーバの通信は「投げっぱなし」である
  • その結果、どこかで「状況の不一致」が存在すると、いろいろ問題が発生する
  • その最悪のパターンが、データベースとの不一致による「アイテムロスト」である

エンジニア的な視点からすれば、設計上のトレードオフの結果、
そういう不具合はありえる・・・ということにはなりますが、
プレイヤーとしてみれば、どうしても納得できないですよね(´・ω・`)

正直、絶対的な回避方法はないですし、
現時点でとれる最大の回避策は「人があまりいない街の倉庫を使う」くらいでしょうか
さらにいえば、サーバ混雑時にINしない・・・なのですが、本末転倒ですよね

以前比べると、かなり詳細なログを取るように改善しているように見えますし、
ログのパターン解析からBOT対策したりしているように見えるので、
頑張ってはいると思うのですが、なかなか難しいですね・・・(´-ω-)

ちなみに、課金アイテムは「法的な理由」から、取引を保存する「義務」が存在するため、
ログから追って復旧・・・というのが可能なんだろうとは思います *4

スマホゲーであれば、課金ログも含めてかなり詳細なログをとっており、
問題があった場合のリカバリが比較的容易なのですが、
あくまで「一人のデータを確実に処理するため、待たせても良い」という設計だからです

アイテムロストが起こってしまうこと自体が避けられないにしても、
なんとかそれを復旧可能にする裏側の仕組みについて、
Gほーさんと重力には引き続き頑張っていただきたいところですね(´・ω・`)


以上、なんとも歯切れの悪い終わり方で申し訳ないですが、
B鯖への集中は別の問題*5もいろいろ発生しております

サーバの増強なども含めて、長期的には改善していくと思いますが、
せっかくの機会ですし、重い時間帯は他のワールドも見てみたりと、
いろいろ試してみてはいかがでしょう?


最後まで読んでいただいて、ありがとうございました(`・ω・´)ノ

*1: こういった、「相手を待たないで進める処理方式」を「非同期(的)」といいます

*2: このように、お互いに待ち合わせして、間違いないようにデータを処理するやり方を「同期(的)」といいます

*3: やり方にもよりますが、データベースに書き込むより、ログ=ファイルに書き込む方が、時間がかかってしまうことがありますΣ(・ω・ノ)ノ 「データベース」はその内部で非同期なI/Oによる効率化を図っていて、単純なファイル書き込みより「見かけ上」高速に見えるようになっているからです

*4: 事前にポイントを購入し、それを消費するタイプのゲーム・・・わかりやすい例だとスマホゲーの「石」・・・の取引履歴は、かなり厳密にログを残す必要があり、必要であればそれを提出する「法的義務」が存在します 詳しくは「資金決済法」を調べてみてください 完全に脱線ですが、「有料の石で引けるガチャ」みたいな仕様があると、課金の際のおまけ石が制限される・・・という法律もあったりします こちらは「景品表示法」で調べてみてください

*5: サーバ内の現金が増えないまま、品物だけが増えたので、レア価格の下落・・・「デフレ」が発生していますが、機会があればこういう話・・・は、他の専門家にお任せしますc(・ω・`c )っ 消耗品がワールド倉庫に入らないのは、サーバ内の経済を破壊しないための重要な仕様で、これが可能になると、別な形で既存B鯖住人の資産が崩壊しますΣ(・ω・ノ)ノ