楽しんでください!
過去 10 年間、私たちはフォーチュン 500 企業およびユーザー数 500 人以下の企業向けのアプリケーションを開発してきました。これまで、当社のエンジニアは主に PHP を使用してバックエンドを開発してきました。しかし 2 年前、当社製品のパフォーマンスだけでなくスケーラビリティにも深刻な影響を与えるいくつかの問題が発生しました。そこで、当社は Golang (Go) を当社のテクノロジー スタックに導入しました。
ほぼ同時に、Go を使用すると大規模なアプリケーションを作成できるだけでなく、パフォーマンスが最大 40 倍向上することもわかりました。これにより、PHP で書かれた既存の製品を拡張し、両方の言語の長所を組み合わせて改良することができます。
Go と PHP の豊富な経験を通じて、実際の開発上の問題を解決するために Go と PHP を使用する方法、および PHP デス モデルに関連する問題の一部を解消するツールに変える方法について説明します。 。
推奨学習: 「PHP ビデオ チュートリアル 」
一般的な PHP 開発環境
では、改善方法について説明しています。 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 でのプリロードの登場により、この問題は部分的に解決されます) 複数のリクエストを処理しますか?
Cron ジョブ、CSV パーサー、キュー ハンドラーなど、数分を超える (最大で数時間または数日) 持続する PHP スクリプトを作成できます。これらのジョブはすべて、タスクを取得して処理し、次のタスクを取得するというパターンに従います。コードはメモリ内に常駐するため、フレームワークやアプリケーションを読み込むための追加操作が回避され、貴重な時間を節約できます。
しかし、長時間実行されるスクリプトの開発はそれほど簡単ではありません。エラーが発生するとプロセスが強制終了され、メモリ オーバーフローが発生するとクラッシュが発生し、F5 キーを使用してプログラムをデバッグすることはできません。 PHP 7 以降、状況は改善されました。信頼できるガベージ コレクターが登場し、エラーの処理が容易になり、カーネルの拡張によりメモリ リークを回避できるようになりました。はい、エンジニアは依然としてメモリとコード内の状態を記憶する問題に注意深く対処する必要があります (これらのことに注意を払わずに済む言語は何でしょうか?) もちろん、PHP 7 では、驚くべきことはそれほど多くありません。 HTTP リクエストの処理など、より簡単なタスクに常駐 PHP スクリプトのモデルを採用して、リクエストごとにすべてを最初からダウンロードする必要をなくすことは可能でしょうか?この問題を解決するには、まず、HTTP リクエストを受信し、毎回 PHP ワーカーを強制終了するのではなく、HTTP リクエストを 1 つずつリダイレクトできるサーバー アプリケーションを実装する必要があります。
Web サーバーは純粋な PHP (PHP-PM) または C 拡張機能 (Swoole) で作成できることがわかっています。それぞれのアプローチには利点がありますが、どちらのオプションも私たちにとってはうまくいきませんでした。私はもっと何かが欲しかったのです。私たちは単なる Web サーバー以上のものを必要としていました。PHP の「再起動」に関連する問題を回避しながら、特定のアプリケーションに簡単に適応および拡張できるソリューションを求めていました。つまり、アプリケーションサーバーが必要です。
Go はこの問題の解決に役立つでしょうか?この言語がアプリケーションを単一のバイナリにコンパイルすること、クロスプラットフォームであること、HTTP を処理するために独自の並列処理モデル (同時実行性) とライブラリを使用すること、そして最終的には、より多くのオープン ソース ライブラリをプログラム。
2 つのプログラミング言語をマージする際に遭遇する問題
まず、2 つ以上のアプリケーションが相互に通信する方法を決定する必要があります。
たとえば、Alex Palaestras の go-php ライブラリを使用すると、PHP と Go プロセス (Apache の mod_php など) の間でメモリ共有を実現できます。ただし、このライブラリの機能により、問題を解決するための使用が制限されます。
私たちは、ソケット/パイプラインを使用してプロセス間の対話を構造化するという、別のより一般的なアプローチを使用することにしました。このアプローチは過去 10 年間にわたってその信頼性が証明されており、オペレーティング システム レベルで適切に最適化されています。
まず、プロセス間でデータを交換し、送信エラーを処理するための単純なバイナリ プロトコルを作成しました。最も単純な形式では、このタイプのプロトコルは、パケットのタイプ、サイズ、データの整合性をチェックするために使用されるバイナリ マスク情報に関する情報を含む固定サイズのパケット ヘッダー (この例では 17 バイト) を持つネットストリングに似ています。
PHP 側では Pack 関数を使用し、Go 側ではエンコーディング/バイナリ ライブラリを使用します。
1 つのプロトコルは私たちにとって少し時代遅れになっており、PHP から net/rpc Go サービスを直接呼び出す機能を追加しました。この機能は、Go ライブラリを PHP アプリケーションに簡単に統合できるため、後の開発で非常に役立ちました。この作業の結果は、当社のもう 1 つのオープンソース製品である Goridge で見ることができます。
複数の PHP ワーカー間でタスクを分散する
対話メカニズムが実装された後、タスクを PHP プロセスに適切に転送する方法を検討し始めました。タスクが到着すると、アプリケーション サーバーはそれを実行するためにアイドル状態のワーカーを選択する必要があります。ワーカー プロセスがエラーで終了するか、「終了」した場合は、ワーカー プロセスをクリアして新しいプロセスを作成します。ワーカー プロセスが正常に実行されると、ワーカー プロセスがワーカー プールに返され、そこでタスクの実行に使用できるようになります。
アクティブなワーカー プロセス プールを保存するには、バッファ チャネルを使用します。予期しない「デッド」ワーカー プロセスをプールからクリアするには、追跡エラーを追加します。ワーカー プロセスステータスの仕組み。
ついに、バイナリ形式でレンダリングされたあらゆるリクエストを処理できる、動作する PHP サーバーが完成しました。
アプリケーションが Web サーバーとして動作できるようにするには、受信 HTTP リクエストを処理するための信頼できる PHP 標準を選択する必要があります。私たちの場合、単純な net/http リクエストを Go から PSR-7 形式に変換するだけで、現在利用可能な PHP フレームワークのほとんどと互換性があります。
PSR-7 は不変であると考えられているため (技術的に不変であるという人もいます)、開発者は原則としてリクエストをグローバル エンティティとして扱わないアプリケーションを作成する必要があります。これは、PHP 常駐プロセスの概念と完全に一致しています。最終的な実装 (名前はまだありません) は次のようになります:
RoadRunner - 高性能 PHP アプリケーション サーバー
us 私の最初のテスト タスクは API バックエンドで、定期的に (通常よりも頻繁に) 予測できないリクエストのバーストが発生しました。ほとんどの場合、nginx の機能で十分ですが、予想される負荷の増加に応じてシステムのバランスを迅速にとることができないため、502 エラーが発生することがよくあります。
この問題を解決するために、2018 年初めに最初の PHP/Go アプリケーション サーバーをデプロイしました。そしてすぐに驚くべき結果を達成しました! 502 エラーを完全に排除しただけでなく、サーバーの数を 3 分の 2 に減らし、大量のコストを節約し、エンジニアやプロダクト マネージャーの悩みを解決しました。
今年の半ばに、私たちはソリューションを改良し、MIT ライセンスの下で RoadRunner という名前で GitHub 上でリリースし、その驚くべきスピードと効率性を強調しました。
RoadRunner で開発スタックを改善できる方法
RoadRunner を使用すると、Go 側でミドルウェア net/http を使用でき、リクエストが送信される前に JWT を実行することもできます。 PHP 認証、および 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-RoadRunne...
翻訳アドレス: https://learnku.com/php/t/61733
以上がPHP と Go の強力な組み合わせ [RoadRunner] をお楽しみください。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。