レガシーソフトウェアの最新化:ErlangとCloudIを使用したMUDプログラミング

公開: 2022-03-11

レガシーモダナイゼーションとは何ですか?

レガシーコードはいたるところにあります。 そして、コードの増殖率が指数関数的に増加し続けるにつれて、そのコードのますます多くがレガシーステータスに追いやられています。 多くの大規模な組織では、レガシーシステムのメンテナンスは情報システムリソースの90%以上を消費します。

現在のパフォーマンスと処理の要求を満たすために、レガシーコードとシステムを最新化する必要性は広範囲に及んでいます。 この投稿では、Erlangプログラミング言語とErlangベースのCloudIサービス指向アーキテクチャー(SOA)を使用して、レガシーコード(特に数十年前のCソースコードのコレクション)を21世紀に適応させるケーススタディを提供します。 。

多くの大規模な組織では、レガシーシステムのメンテナンスは情報システムリソースの90%以上を消費します。

ソースコードドラゴンを倒す

数年前、私はマルチユーザーダンジョン(MUD)として知られるテキストベースのマルチプレイヤーオンラインゲームの大ファンでした。 しかし、彼らは常にパフォーマンスの問題に悩まされていました。 私は、数十年前のCソースコードの山に戻って、このレガシーコードを最新化し、これらの初期のオンラインゲームを限界まで押し上げる方法を確認することにしました。 大まかに言えば、このプロジェクトは、アーランを使用してレガシーソフトウェアを21世紀の要件に適合させる良い例でした。

簡単な要約:

  • 目標:古い50人限定のMUDビデオゲームを使用して、そのソースコードをプッシュし、数千から数千の同時接続をサポートします。
  • 問題:レガシーのシングルスレッドCソースコード。
  • ソリューション:CloudI、フォールトトレランスとスケーラビリティを提供するErlangベースのサービス。

レガシーソフトウェアの最新化:ErlangとCloudIを使用したMUDプログラミング

テキストベースのMUDとは何ですか?

World of WarcraftやEverQuestのようなすべての大規模マルチプレイヤーオンラインロールプレイングゲーム(MMORPG)は、マルチユーザーダンジョン(MUD)として知られる古いテキストベースのマルチプレイヤーオンラインゲームにその初期の起源をさかのぼることができる機能を開発しました。

最初のMUDはRoyTrubshawのEssexMUD(またはMUD1)で、元々はDEC PDP-10でMARO-10アセンブラー言語を使用して1978年に開発されましたが、Cプログラミング言語の前身であるBCPLに変換されました( 1987)。 (ご覧のとおり、これらのものはほとんどのプログラマーよりも古いものです。)

MUDは、1980年代後半から1990年代初頭にかけて、Cで記述されたさまざまなMUDコードベースで徐々に人気を博しました。たとえば、DikuMUDコードベースは、派生MUDソースコードの最大のツリーの1つのルートとして知られており、少なくとも51の固有のバリアントがあります。同じDikuMUDソースコードに基づいています。 (ちなみに、この時間枠の間に、MUDは、彼らへの執着のために学校を卒業しなかった大学の学部生の数のために、「マルチ学部デストロイヤー」としても知られるようになりました。)

従来のMUDの問題

過去のCMUDソースコード(DikuMUDとそのバリアントを含む)は、作成時の既存の制限により、パフォーマンスの問題に悩まされています。

糸脱毛の欠如

当時、簡単にアクセスできるスレッドライブラリはありませんでした。 さらに、スレッド化により、ソースコードの保守と変更がより困難になります。 その結果、これらのMUDはすべてシングルスレッドでした。

コードのすべての部分は、単一のティックの処理を遅くします。 また、計算によって処理が1ティックより長くなると、MUDが遅れ、接続されているすべてのプレーヤーに影響を与えます。

1回の「ティック」(すべてのゲームイベントの進行を追跡する内部クロックの増分)中に、MUDソースコードは、接続されているすべてのソケットのすべてのゲームイベントを処理する必要があります。 言い換えると、コードのすべての部分が1つのティックの処理を遅くします。 また、計算によって処理が1ティックより長くなると、MUDが遅れ、接続されているすべてのプレーヤーに影響を与えます。

この遅れにより、ゲームはすぐに魅力がなくなります。 プレイヤーは、自分のコマンドが未処理のままで、キャラクターが死ぬとどうしようもなく見つめます。

SillyMUDの紹介

このレガシーアプリケーションの最新化実験の目的で、私はSillyMUDを選択しました。これは、最新のMMORPGとそれらが共有するパフォーマンスの問題に影響を与えたDikuMUDの歴史的な派生物です。 1990年代に、私はSillyMUDコードベースから派生したMUDをプレイしたので、ソースコードが興味深く、やや馴染みのある出発点になることを知っていました。

私は何を継承しましたか?

SillyMUDのソースコードは、他の従来のC MUDのソースコードと似ており、同時プレイヤーは約50人に制限されています(正確には、ソースコードに基づいて64人)。

ただし、パフォーマンス上の理由(つまり、同時プレーヤーの制限をプッシュするため)でソースコードが変更されていることに気付きました。 具体的には:

  • ソースコードには、接続IPアドレスでのドメイン名ルックアップがありませんでした。ドメイン名ルックアップによって強制される遅延のために存在しませんでした(通常、古いMUDは、悪意のあるユーザーを禁止しやすくするためにドメイン名ルックアップを望んでいます)。
  • ソースコードでは、寄付されたアイテムの長いリンクリストが作成される可能性があるため、「寄付」コマンドが無効にされていました(少し珍しい)。 これらは、順番に、他のすべてのプレーヤーのゲームパフォーマンスを損ないます(シングルスレッド、覚えていますか?)。

CloudIの紹介

CloudIは、フォールトトレランスとスケーラビリティを提供するため、ポリグロット開発のソリューションとして以前に説明されていました。

CloudIは、CloudIフレームワーク内でソフトウェア障害を分離したまま、Erlang、C / C ++、Java、Python、およびRubyでサービス抽象化(サービス指向アーキテクチャー(SOA)を提供するため)を提供します。 フォールトトレランスは、CloudIのErlang実装を通じて提供され、Erlangのフォールトトレラント機能とアクターモデルの実装に依存しています。 すべてのソフトウェアにバグが含まれているため、このフォールトトレランスはCloudIのErlang実装の重要な機能です。

CloudIは、サービス実行の存続期間とサービスプロセスの作成を制御するアプリケーションサーバーも提供します(Erlang以外のプログラミング言語のオペレーティングシステムプロセスとして、またはErlangで実装されたサービスのErlangプロセスとして)。これにより、外部の状態に影響を与えることなくサービスの実行が行われます。信頼性。 詳細については、以前の投稿を参照してください。

CloudIはどのようにしてレガシーテキストベースのMUDを最新化できますか?

歴史的なCMUDソースコードは、信頼性の問題を考えると、CloudI統合に興味深い機会を提供します。

  • ゲームサーバーの安定性は、ゲームの仕組みの魅力に直接影響します。
  • サーバーの安定性のバグの修正にソフトウェア開発を集中させると、結果として得られるゲームのサイズと範囲が制限されます。

CloudI統合を使用すると、サーバーの安定性のバグは通常どおり修正できますが、その影響は限定的であるため、以前に発見されなかったバグが原因で内部ゲームシステムに障害が発生した場合でも、ゲームサーバーの操作が常に影響を受けるとは限りません。 これは、レガシーコードベースでフォールトトレランスを適用するためのErlangの使用の優れた例を提供します。

どのような変更が必要でしたか?

元のコードベースは、シングルスレッドであり、グローバル変数に大きく依存するように記述されていました。 私の目標は、現在の使用に合わせて最新化しながら、レガシーソースコード機能を維持することでした。

CloudIを使用すると、ソケット接続のスケーラビリティを提供しながら、ソースコードをシングルスレッドに保つことができました。

私の目標は、従来のソースコード機能を維持しながら、最新の使用法に適合させることでした。

必要な変更を確認しましょう。

コンソール出力

SillyMUDコンソール出力(多くの場合Telnetに接続されているターミナルディスプレイ)のバッファリングはすでに行われていますが、ファイル記述子を直接使用する場合は、バッファリングが必要でした(コンソール出力がCloudIサービス要求への応答になるようにするため)。

ソケットの取り扱い

元のソースコードでのソケット処理は、 select()関数呼び出しに依存して、入力、エラー、出力の可能性を検出し、保留中のゲームイベントを処理する前に250ミリ秒のゲームティックを一時停止しました。

CloudI SillyMUD統合は、C CloudI APIのcloudi_poll関数で一時停止している間(同じ保留中のゲームイベントを処理する前の250ミリ秒)、入力の着信サービス要求に依存します。 SillyMUDソースコードは、C CloudI APIと統合された後、CloudIサービスとしてCloudI内で簡単に実行されました(CloudIはCとC ++ APIの両方を提供しますが、C APIを使用すると、SillyMUDのCソースコードとの統合がより容易になります)。

サブスクリプション

CloudI統合は、接続、切断、およびゲームプレイイベントを処理するために、3つの主要なサービス名パターンにサブスクライブします。 これらの名前パターンは、統合ソースコードでsubscribeを呼び出すCCloudIAPIに由来します。 したがって、WebSocket接続またはTelnet接続のいずれかに、接続が確立されたときにサービス要求を送信するためのサービス名の宛先があります。

CloudIでのWebSocketとTelnetのサポートは、内部cloudi_service_http_cowboyサービス(WebSocketサポートの場合はcloudi_service_tcp 、Telnetサポートの場合はcloudi_service_tcp)によって提供されます。 内部CloudIサービスはErlangで記述されているため、Erlangの極端なスケーラビリティを活用すると同時に、CloudIAPI関数を提供するCloudIサービス抽象化を使用できます。

今後

ソケットの処理を回避することにより、ソケットエラーやリンクの停止(ユーザーがサーバーから切断される)などの状況で発生する処理が少なくなります。 したがって、低レベルのソケット処理を削除することで、主要なスケーラビリティの問題に対処しました。

低レベルのソケット処理を削除すると、主要なスケーラビリティの問題が解決されました。

しかし、スケーラビリティの問題は残っています。 たとえば、MUDは、静的および動的なゲームプレイ要素(つまり、プレイヤーとその進行状況、およびワールドゾーン、オブジェクト、モンスター)の両方のローカルデータベースとしてファイルシステムを使用します。 MUDのレガシーコードをリファクタリングして、代わりにデータベースのCloudIサービスに依存するようにすると、フォールトトレランスがさらに向上します。 ファイルシステムではなくデータベースを使用した場合、複数のSillyMUD CloudIサービスプロセスを別々のゲームサーバーとして同時に使用して、ユーザーをランタイムエラーから隔離し、ダウンタイムを減らすことができます。

MUDはどのくらい改善されましたか?

CloudIの統合により、接続数は3桁に拡大され、フォールトトレランスが提供され、同じレガシーゲームプレイの効率が向上します。

改善の3つの主要な領域がありました:

  1. フォールトトレランス。 最新のSillyMUDCloudIサービス統合により、SillyMUDソースコードからソケットエラーと遅延を分離することで、ある程度のフォールトトレランスが提供されます。
  2. 接続のスケーラビリティ。 内部CloudIサービスを使用すると、SillyMUD同時ユーザーの制限は、64(履歴)から16,384ユーザー(遅延の問題なし!)に簡単に移行できます。
  3. 効率とパフォーマンス。 シングルスレッドのSillyMUDソースコードではなくCloudI内で接続処理が行われるため、SillyMUDゲームプレイソースコードの効率が自然に向上し、より高い負荷を処理できます。

したがって、単純なCloudI統合により、接続数は3桁に拡大され、フォールトトレランスが提供され、同じレガシーゲームプレイの効率が向上します。

全体像

Erlangは、本番システムに99.9999999%のアップタイム(年間31.536ミリ秒未満のダウンタイム)を提供しています。 CloudIを使用すると、これと同じ信頼性を他のプログラミング言語やシステムにもたらします。

停滞しているレガシーゲームサーバーのソースコードを改善するためのこのアプローチの実行可能性を証明するだけでなく(SillyMUDは1993年に20年以上前に最後に変更されました!)、このプロジェクトは、ErlangとCloudIを活用してレガシーアプリケーションを最新化し、フォールトを提供する方法をより広いレベルで示します-許容範囲、パフォーマンスの向上、および一般的な高可用性。 これらの結果は、大規模なソフトウェアのオーバーホールを必要とせずに、レガシーコードを21世紀に適応させるための有望な可能性を秘めています。