PHPおよびLumenに基づくシンプルなAPIゲートウェイ

今日の「マイクロサービス」という用語は誰にでもよく知られています-突然非常にファッショナブルになり、多くの企業がこのアーキテクチャパターンへの移行を実際に理解しなくても発表しています。 ただし、この記事の範囲外のマイクロサービスの有用性については説明しません。



従来、マイクロサービスのコレクションの前に、追加のレイヤーが提案されています-いわゆるAPIゲートウェイは、いくつかの問題を一度に解決します(それらは後でリストされます)。 この記事の執筆時点では、このようなゲートウェイのオープンソース実装はほとんどないため、Lumenマイクロフレームワーク(Laravelの一部)を使用してPHPで独自に記述することにしました。



この記事では、このタスクが最新のPHPにとっていかに簡単かを示します。



ゲートウェイAPIとは何ですか?



要するに、 APIゲートウェイは、ユーザーと任意の数のサービス(API)の間のスマートプロキシサーバーであるため、名前です。



この層の必要性は、マイクロサービスパターンに切り替えるとすぐに現れます。





さらに利点があります-これらは、10〜20秒で思い浮かんだものです。



Nginxは、マイクロサービスとAPIゲートウェイ専用の優れた無料の電子書籍をリリースしました。このパターンに興味のあるすべての人に読むことをお勧めします。



既存のオプション





上で言ったように、選択肢は非常に少なく、比較的最近登場しました。 それらにはまだ多くの機会がありません。



なぜPHPとLumenなのか?



バージョン7のリリースで、PHPは高性能になり、LaravelやSymfonyなどのフレームワークの出現により、PHPは美しく機能することが世界に証明されました。 Laravelの「クリーン」な高速バージョンであるLumenは、フルスタックアプリケーションのセッション、テンプレート、またはその他の機能を必要としないため、ここでの使用に最適です。



さらに、PHPとLumenの経験が豊富であり、作成されたアプリケーションをDockerを介してデプロイする場合、将来のユーザーは作成される言語をまったく気にしません。 これはその役割を果たす単なるレイヤーです!



選択された用語



次のアーキテクチャと対応する用語を提案します。 コードでは、混乱しないようにこれらの用語を厳守します。





ロシア語の「ゲート」はほとんど「ゲートウェイ」であり、世界にはロシア語の名前を持つアプリケーションがないため、アプリケーション自体がVrataを呼び出すことにしました)



「ゲート」のすぐ後ろには、N個のマイクロサービス(Web要求に応答できるAPIサービス)の数があります。 各サービスは任意の数のインスタンスを持つことができるため、APIゲートウェイは、いわゆるサービスレジストリを通じて特定のインスタンスを選択します。



各サービスは一定量のリソースを(REST言語で)提供し、各リソースはいくつかの可能なアクションを持つことができます。 経験豊富なRESTプログラマー向けの非常にシンプルで論理的な構造。



Vrataの要件



コードを開始する前に、将来のアプリケーションの要件をすぐに判断できます。





ほとんどの項目はすでに機能しており、それらを実装するのは非常に簡単でした。 結局のところ、彼らは真実を語っています-私たちはプログラマーにとって最高の時代に生きています!



実装



認証



私はほとんどこの方向で作業する必要はありませんでした-Laravel Passport for Lumenを修正するだけで十分であり、JWTを含むすべての最新のOAuth2機能のサポートを得ました。 私の小さなパッケージポートはGitHub / Packagist公開されおり、誰かが既にインストールしています。



ルートとコントローラー



マイクロサービスからの下位ルートはすべて、JSON形式の構成ファイルからVrataにインポートされます。 起動時に、これらのルートがサービスプロバイダーに追加されます。



//    –     $registry = $this->app->make(RouteRegistry::class); //   Lumen   ,      $registry->bind(app());
      
      





一方、ルートデータベースでは:



  /** * @param Application $app */ public function bind(Application $app) { //   -      Lumen //           //  middleware   OAuth2,      $this->getRoutes()->each(function ($route) use ($app) { $method = strtolower($route->getMethod()); $app->{$method}($route->getPath(), [ 'uses' => 'App\Http\Controllers\GatewayController@' . $method, 'middleware' => [ 'auth', 'helper:' . $route->getId() ] ]); }); }
      
      





現在、マイクロサービスからの各パブリック(および構成で許可されている)ルートは、APIゲートウェイへのルートに対応しています。 さらに、このゲートウェイにのみ存在する合成クエリまたは結合クエリも追加されました。 すべてのリクエストは同じコントローラーに送られます:



これは、コントローラーがGET要求を処理する方法です。



  /** * @param Request $request * @param RestClient $client * @return Response */ public function get(Request $request, RestClient $client) { //     ,  -  $parametersJar = $request->getRouteParams(); //     N   $output = $this->actions->reduce(function($carry, $batch) use (&$parametersJar, $client) { //  N    $responses = $client->asyncRequest($batch, $parametersJar); //        $parametersJar = array_merge($parametersJar, $responses->exportParameters()); //     -  array reduce return array_merge($carry, $responses->getResponses()->toArray()); }, []); //    .    JSON return $this->presenter->format($this->rearrangeKeys($output), 200); }
      
      





GuzzleがHTTPクライアントとして選択されました。これは非同期リクエストに完全に対応し、統合テスト用の既製のツールも備えています。



複合クエリ



複雑な複合クエリはすでに機能しています-これは、異なるマイクロサービス上の任意の数のルートがゲートウェイ上の1つのルートに対応する場合です。 これが実際の例です:



 // Boolean-,    'aggregate' => true, 'method' => 'GET', //     ,       "jar" 'path' => '/v2/devices/{mac}/extended', //     'actions' => [ 'device' => [ //      'service' => 'core', 'method' => 'GET', 'path' => 'devices/{mac}', //        'sequence' => 0, //          -    'critical' => true ], 'ping' => [ 'service' => 'history', //         'output_key' => false, 'method' => 'POST', 'path' => 'ping/{mac}', 'sequence' => 0, 'critical' => false ], 'settings' => [ 'service' => 'core', //     JSON- 'output_key' => 'network.settings', 'method' => 'GET', //  ,     'device' 'path' => 'networks/{device%network_id}', 'sequence' => 1, 'critical' => false ] ]
      
      





ご覧のとおり、複雑なルートはすでに利用可能であり、優れた機能セットを備えています-重要なルートを選択したり、並列リクエストを作成したり、あるサービスの応答を別のサービスへのリクエストで使用したりできます。 とりわけ、出力は優れたパフォーマンスです-合計応答を受信するのにわずか56ミリ秒(Lumenと3つのバックグラウンドクエリ、すべてのデータベースを持つマイクロサービスをロードする)。



サービスレジストリ



これはこれまでで最も弱い部分です-非常に簡単な方法が1つだけ実装されています:DNS。 その原始性にもか​​かわらず、プロバイダー自体がサービスのグループを監視し、DNSレコードを動的に編集するDocker CloudやAWSなどの環境で正常に機能します。



現時点では、Vrataはサービスのホスト名を取得するだけで、クラウドか物理コンピューターかを詳しく調べることはありません。 おそらく今日の最も人気のあるレジストリはConsulであり、以下を追加する価値があります。



レジストリの本質は非常にシンプルです。サービスのライブインスタンスとデッドインスタンスのテーブルを保存し、必要に応じて特定のインスタンスのアドレスを提供する必要があります。 AWSとDocker Cloud(および他の多く)がこれを行うことができ、常に機能する1つの「魔法の」ホスト名を提供します。



Dockerイメージ



マイクロサービスについては、ここ数年で最もホットなテクノロジーの1つであるDockerに言及する必要があります。 原則として、マイクロサービスはDockerイメージとまったく同じようにテストおよびデプロイされます。これは標準的な手法になっているため、Docker Hubでパブリックイメージをすばやく準備しました。



OS X、Windows、またはLinuxマシンのターミナルに1つのコマンドを入力すると、Vrataゲートウェイが機能します。



 $ docker run -d -e GATEWAY_SERVICES=... -e GATEWAY_GLOBAL=... -e GATEWAY_ROUTES=... pwred/vrata
      
      





設定全体は、JSON形式の環境変数で渡すことができます。



あとがき



アプリケーション(ゲートウェイ)は、私が働いている会社ですでに実際に使用されています。 GitHubリポジトリ内のすべてのコード。 誰でも開発に参加したい場合-どういたしまして:)



理論と実装の両方での複合クエリは、FacebookのGraphQLクエリ形式(RESTとは対照的)に非常に似ているため、将来の優先機能の1つはGraphQLクエリのサポートです。



All Articles