スピードのために生まれた: PHP と Golang の組み合わせ - RoadRunner

青灯夜游
リリース: 2023-04-11 07:56:01
転載
5755 人が閲覧しました

スピードのために生まれた: PHP と Golang の組み合わせ - RoadRunner

過去 10 年間、当社は Fortune 500 企業 およびユーザー数 500 人以下の企業向けのアプリケーションを開発してきました。これまで、当社のエンジニアは主に PHP を使用してバックエンドを開発してきました。しかし 2 年前、当社製品のパフォーマンスだけでなくスケーラビリティにも深刻な影響を与えるいくつかの問題が発生しました。そこで、当社は Golang (Go) を当社のテクノロジー スタックに導入しました。

ほぼ同時に、Go を使用すると大規模なアプリケーションを作成できるだけでなく、パフォーマンスが最大 40 倍向上することもわかりました。これにより、PHP で書かれた既存の製品を拡張し、両方の言語の長所を組み合わせて改良することができます。

Go と PHP の豊富な経験を通じて、それを実際の開発上の問題を解決するために使用する方法、およびそれを PHP Death Model を排除するツールに変える方法を説明します。いくつかの質問。

一般的な PHP 開発環境

#Go が PHP デス モデルをどのように改善するかを説明する前に、まず一般的な PHP 開発環境について理解しましょう。

通常、アプリケーションは nginx と PHP-FPM で実行されます。 nginx は静的リクエストを処理しますが、動的リクエストは PHP コードを実行する PHP-FPM にリダイレクトされます。おそらく Apache と mod_php を使用していると思いますが、原理は同じで、動作方法にわずかな違いがあるだけです。

PHP-FPM がコードをどのように実行するかを見てください。リクエストを受信すると、PHP-FPM は PHP サブプロセスを初期化し、ステータス (_GET、_POST、_SERVER など) の一部としてリクエストの詳細を転送します。

PHP スクリプトの実行中に状態を変更することはできないため、新しい入力データのセットを取得する唯一の方法は、プロセス メモリをクリアして再度初期化することです。

このパフォーマンス モデルには多くの利点があります。メモリ消費についてあまり心配する必要はありません。すべてのプロセスは完全に分離されており、プロセスの 1 つが「停止」しても、自動的に再作成され、他のプロセスには影響しません。ただし、アプリケーションを拡張しようとする場合、このアプローチには欠点があります。

一般的な PHP 環境の欠点と非効率

PHP で専門的に開発している場合は、新しいプロジェクトを作成するときにどこから始めるべきか、つまり フレームワークの選択 を知っています。これは、依存関係注入、ORM、変換、およびテンプレート メソッドのライブラリです。もちろん、ユーザーが入力したすべてのデータは単一のオブジェクト (Symfony / HttpFoundation または PSR-7) に簡単に配置できます。これらのフレームは素晴らしいです!

しかし、何事にも代償はつきものです。どのようなエンタープライズ フレームワークでも、単純なユーザー リクエストを処理したりデータベースにアクセスしたりするには、少なくとも数十個のファイルをロードし、多くのクラスを作成し、複数の構成を解析する必要があります。しかし最悪なのは、各タスクが完了した後、すべてをリセットして再起動する必要があることです。開始したばかりのコードはすべて役に立たなくなり、その助けを借りて別のリクエストを処理できなくなります。これを他の言語で書いているプログラマーに伝えてみると、彼の顔が混乱しているのがわかるでしょう。

長年にわたり、PHP エンジニアは、遅延読み込み技術、マイクロフレーム、最適化ライブラリ、キャッシュなどを使用して、この問題を解決する方法を探してきました。しかし、最終的にはアプリケーション全体を放棄して最初からやり直す必要があります* (翻訳者注: PHP7.4 でのプリロードの登場により、この問題は部分的に解決されます)

PHP プロセスで処理できる処理複数のリクエスト?

Cron ジョブ、CSV パーサー、キュー ハンドラーなど、数分を超える (最大で数時間または数日) 持続する PHP スクリプトを作成できます。これらのジョブはすべて、タスクを取得して処理し、次のタスクを取得するというパターンに従います。コードはメモリ内に常駐するため、フレームワークやアプリケーションを読み込むための追加操作が回避され、貴重な時間を節約できます。

しかし、長時間実行されるスクリプトの開発はそれほど簡単ではありません。エラーが発生するとプロセスが強制終了され、メモリ オーバーフローが発生するとクラッシュが発生し、F5 キーを使用してプログラムをデバッグすることはできません。

PHP 7 以降、状況は改善されました。信頼できるガベージ コレクターが登場し、エラーの処理が容易になり、カーネルの拡張によりメモリ リークを回避できるようになりました。はい、エンジニアは依然としてメモリとコード内の状態を記憶する問題に注意深く対処する必要があります (これらのことに注意を払わずに済む言語は何でしょうか?) もちろん、PHP 7 では、驚くべきことはそれほど多くありません。

HTTP リクエストの処理など、より簡単なタスクに常駐 PHP スクリプトのモデルを採用して、リクエストごとにすべてを最初からダウンロードする必要をなくすことは可能でしょうか?

この問題を解決するには、まず、HTTP リクエストを受信し、毎回 PHP ワーカーを強制終了するのではなく、1 つずつリダイレクトできるサーバー アプリケーションを実装する必要があります。

Web サーバーは純粋な PHP (PHP-PM) または C 拡張機能 (Swoole) で作成できることがわかっています。それぞれのアプローチには利点がありますが、どちらのオプションも私たちにとってはうまくいきませんでした。私はもっと何かが欲しかったのです。私たちは単なる Web サーバー以上のものを必要としていました。PHP の「再起動」に関連する問題を回避しながら、特定のアプリケーションに簡単に適応および拡張できるソリューションを求めていました。つまり、アプリケーションサーバーが必要です。

Go はこの問題の解決に役立つでしょうか?この言語がアプリケーションを単一のバイナリにコンパイルすること、クロスプラットフォームであること、HTTP を処理するために独自の並列処理モデル (同時実行性) とライブラリを使用すること、そして最終的には、より多くのオープン ソース ライブラリをプログラム。

2 つのプログラミング言語をマージする際に遭遇する問題

まず、2 つ以上のアプリケーションが相互に通信する方法を決定する必要があります。

たとえば、Alex Palaestras の go-php ライブラリを使用すると、PHP と Go プロセス (Apache の mod_php など) の間でメモリ共有を実現できます。ただし、このライブラリの機能により、問題を解決するための使用が制限されます。

私たちは、ソケット/パイプラインを使用してプロセス間の対話を構造化するという、別のより一般的なアプローチを使用することにしました。このアプローチは過去 10 年間にわたってその信頼性が証明されており、オペレーティング システム レベルで適切に最適化されています。

まず、プロセス間でデータを交換し、送信エラーを処理するための単純なバイナリ プロトコルを作成しました。最も単純な形式では、このタイプのプロトコルは、固定サイズのパケット ヘッダー (この例では 17 バイト) を持つ netstring に似ています。ここで含まれる情報は、パケット タイプ、そのサイズ、およびバイナリ マスクです。データの整合性をチェックするために使用される情報。

PHP 側では

pack 関数 を使用し、Go 側では encoding/binary ライブラリを使用しました。

1 つのプロトコルは私たちにとって少し時代遅れになっており、

net /rpc Go サービス を PHP から直接呼び出す機能を追加しました。この機能は、Go ライブラリを PHP アプリケーションに簡単に統合できるため、後の開発で非常に役立ちました。この作業の結果は、当社の別のオープンソース製品 Goridge で見ることができます。

複数の PHP ワーカー間でタスクを分散する

対話メカニズムが実装された後、タスクを PHP プロセスに適切に転送する方法を検討し始めました。タスクが到着すると、アプリケーション サーバーはそれを実行するためにアイドル状態のワーカーを選択する必要があります。ワーカー プロセスがエラーで終了するか、「終了」した場合は、ワーカー プロセスをクリアして新しいプロセスを作成します。ワーカー プロセスが正常に実行されると、ワーカー プロセスがワーカー プールに返され、そこでタスクの実行に使用できるようになります。

スピードのために生まれた: PHP と Golang の組み合わせ - RoadRunner

アクティブなワーカー プロセス プールを保存するために、

バッファ チャネル を使用します。予期しない「デッド」ワーカー プロセスをプールに、エラーとワーカー プロセスのステータスを追跡するメカニズムを追加しました。

ついに、バイナリ形式でレンダリングされたあらゆるリクエストを処理できる、動作する PHP サーバーが完成しました。

アプリケーションが Web サーバーとして動作できるようにするには、受信 HTTP リクエストを処理するための信頼できる PHP 標準を選択する必要があります。この例では、単純な net/http リクエストを Go

から PSR-7 形式に変換するだけで、現在利用可能な PHP フレームワークのほとんどと互換性があります。

PSR-7 は不変であると考えられているため (技術的に不変であるという人もいます)、開発者は原則としてリクエストをグローバル エンティティとして扱わないアプリケーションを作成する必要があります。これは、PHP 常駐プロセスの概念と完全に一致しています。最終的な実装 (まだ名前は付けられていません) は次のようになります:

スピードのために生まれた: PHP と Golang の組み合わせ - RoadRunner

RoadRunner - - パフォーマンス PHP アプリケーション サーバー

最初のテスト タスクは、定期的に (通常より頻繁に) 予測できないリクエストのバーストが発生する API バックエンドです。ほとんどの場合、nginx の機能で十分ですが、予想される負荷の増加に応じてシステムのバランスを迅速にとることができないため、502 エラーが発生することがよくあります。

この問題を解決するために、2018 年初めに最初の PHP/Go アプリケーション サーバーをデプロイしました。そしてすぐに驚くべき結果を達成しました! 502 エラーを完全に排除しただけでなく、サーバーの数を 3 分の 2 に減らし、大量のコストを節約し、エンジニアやプロダクト マネージャーの悩みを解決しました。

今年の半ばに、私たちはソリューションを改良し、#RoadRunner という名前で MIT ライセンスの下で GitHub 上でリリースし、その驚くべきスピードと効率性を強調しました。

RoadRunner で開発スタックを改善できる方法

RoadRunner を使用すると、Go 側でもミドルウェア net/http を使用できるようになります。リクエストが PHP に送信される前の JWT 検証、および Prometheus での WebSocket とグローバル集約状態の処理。

組み込み RPC のおかげで、拡張パッケージを作成しなくても、PHP で Go ライブラリの API を開くことができます。さらに、RoadRunner を使用すると、HTTP とは異なる新しいサーバーを展開できます。例には、PHP での AWS Lambda プロセッサの実行、強力なキュー セレクター、 の作成、さらにはアプリケーションへの gRPC の追加などが含まれます。

PHP と Go の両方を使用することで、ソリューションは着実に改善され、一部のテストではアプリケーションのパフォーマンスが 40 倍向上し、デバッグ ツールが改善され、Symfony フレームワークとの統合が可能になり、HTTPS、HTTP/2、プラグインのサポートが追加されました。そしてPSR-17。

結論

一部の人々は依然として PHP の時代遅れの概念に縛られており、PHP は遅くて扱いにくい言語であり、WordPress でプラグインを作成する場合にのみ適していると考えています。これらの人々は、PHP には限界があるとまで言います。アプリケーションが十分に大きくなると、より「成熟した」言語を選択し、長年にわたって蓄積されたコード ベースを書き直さなければなりません。

これらの質問に対する私の答えは、「もう一度考えてください」です。 PHP に制限を設けているのはあなただけだと思います。自分のニーズに完全に一致する言語を見つけようとして、ある言語から別の言語に人生を移すこともできますし、言語をツールとして扱うこともできます。 PHP のような言語では、その想定される欠陥が成功の本当の理由である可能性があります。 Go などの別の言語と組み合わせると、1 つの言語を使用するよりも強力な製品を作成できます。

Go と PHP を同じ意味で使用した後、私たちはそれらが好きだと言えます。私たちは一方を犠牲にして他方を犠牲にするつもりはありません。代わりに、この二重アーキテクチャからより多くを引き出す方法を見つけるつもりです。

英語の元のアドレス: https://sudonull.com/post/6470-RoadRunner-PHP-is-not-created-to-die-or-Golang-to-the-rescue

翻訳アドレス: https://learnku.com/php/t/61733

推奨学習: 「PHP ビデオ チュートリアル

以上がスピードのために生まれた: PHP と Golang の組み合わせ - RoadRunnerの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:learnku.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート