2026年版 NestJS マイクロサービス:アーキテクチャ、gRPC、面接対策ガイド

NestJS マイクロサービスアーキテクチャと gRPC の実践ガイド。サービス境界、トランスポートレイヤー、ストリーミングパターン、2026年の面接頻出質問を解説します。

NestJS マイクロサービスアーキテクチャと gRPC の解説図

NestJS マイクロサービスは、2026年現在、分散型 Node.js バックエンド構築の標準的なアプローチとなっています。NestJS 12 では、強化されたトランスポーターレイヤー、gRPC のファーストクラスサポート、RPC 呼び出し用の例外フィルター、自動トレース ID 伝播などが提供されており、開発者体験を損なうことなくモノリスを適切に境界付けられたサービスに分割するために必要な機能がすべて揃っています。

内部サービス間通信における gRPC と REST の比較

gRPC は Protocol Buffers と HTTP/2 を使用し、JSON over REST と比較して最大10倍高速なシリアライゼーションとネイティブな双方向ストリーミングを提供します。クラスター内のサービス間通信では、gRPC によりレイテンシが削減され、.proto ファイルを通じて厳格なコントラクトが強制されます。ブラウザやサードパーティが利用するパブリック API には、REST が引き続き適切な選択肢です。

NestJS マイクロサービスのトランスポートレイヤーアーキテクチャ

@nestjs/microservices パッケージは、HTTP コントローラーをメッセージ指向のハンドラーに置き換えます。URL パスによるルーティングの代わりに、各ハンドラーはメッセージパターン(操作を識別する文字列またはオブジェクトキー)に応答します。この抽象化により、同じハンドラーロジックが TCP、Redis、NATS、Kafka、RabbitMQ、gRPC のいずれでもコード変更なしで動作します。

NestJS 11 では、すべてのトランスポーターに unwrap() メソッドが導入され、基盤となるクライアントインスタンスへの直接アクセスが可能になりました。これにより、接続状態の確認、keepalive 間隔の調整、NestJS の抽象化では公開されていないブローカー固有の機能へのアクセスといった長年の課題が解決されます。NestJS 12 では、プリリクエストフックが追加され、認証チェックやメトリクス収集などの横断的関心事のために、ハンドラー呼び出しの直前にカスタムロジックを実行できるようになりました。

NestJS マイクロサービスを駆動する2つの通信パターン:

  • リクエスト-レスポンス(@MessagePattern):クライアントがメッセージを送信し、返信を待ちます。ユーザープロファイルの取得やトークンの検証などの同期クエリに適しています。
  • イベントベース(@EventPattern):クライアントがイベントを発行し、処理を続行します。レスポンスは期待されません。監査ログ、通知、下流ワークフローのトリガーに最適です。
orders.controller.tstypescript
import { Controller } from '@nestjs/common';
import { MessagePattern, EventPattern, Payload } from '@nestjs/microservices';
import { OrdersService } from './orders.service';
import { CreateOrderDto } from './dto/create-order.dto';

@Controller()
export class OrdersController {
  constructor(private readonly ordersService: OrdersService) {}

  // Request-response: caller waits for the created order
  @MessagePattern('order.create')
  async createOrder(@Payload() data: CreateOrderDto) {
    return this.ordersService.create(data);
  }

  // Event-based: fire and forget, no response returned
  @EventPattern('order.shipped')
  async handleOrderShipped(@Payload() data: { orderId: string }) {
    await this.ordersService.markAsShipped(data.orderId);
  }
}

@MessagePattern ハンドラーは自動的に戻り値をシリアライズし、トランスポートを通じて送り返します。@EventPattern ハンドラーは何も返しません:NestJS は戻り値を破棄します。

NestJS 12 における EventPattern の非推奨化

NestJS 12 以降、TCP、Redis、NATS、MQTT、RabbitMQ トランスポートでは、@EventPattern ハンドラーが ClientProxy#send() に応答する際に非推奨警告がログに記録されます。この動作は次のメジャーバージョンで変更され、Kafka の既存のアプローチに合わせられます。イベントハンドラーを真のファイア・アンド・フォーゲットセマンティクスに移行するか、リクエスト-レスポンスフローには @MessagePattern に切り替えてください。

NestJS マイクロサービストランスポートとしての gRPC の設定

NestJS における gRPC 統合は、サービスコントラクトを定義する .proto ファイルから始まります。Protocol Buffers はワイヤーレベルで型安全性を強制します:クライアントとサーバーの両方が、ネットワーク上で1バイトが送信される前に、すべてのメッセージの正確な形状に同意する必要があります。

proto/users.protoprotobuf
syntax = "proto3";

package users;

service UsersService {
  rpc FindOne (UserById) returns (User);
  rpc FindMany (UserFilter) returns (stream User);
}

message UserById {
  string id = 1;
}

message UserFilter {
  string role = 1;
  int32 limit = 2;
}

message User {
  string id = 1;
  string email = 2;
  string name = 3;
  string role = 4;
}

サーバー側では、NestJS アプリケーションが proto ファイルを指定し、ネットワークアドレスをバインドして gRPC マイクロサービスをブートストラップします:

main.tstypescript
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.GRPC,
      options: {
        package: 'users',
        protoPath: join(__dirname, 'proto/users.proto'),
        url: '0.0.0.0:5000',
      },
    },
  );
  await app.listen();
}
bootstrap();

コントローラーは @MessagePattern の代わりに @GrpcMethod を使用します。このデコレーターは、proto 定義に直接マッピングするサービス名と RPC メソッド名を引数として受け取ります:

users.controller.tstypescript
import { Controller } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { UsersService } from './users.service';

@Controller()
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @GrpcMethod('UsersService', 'FindOne')
  async findOne(data: { id: string }) {
    return this.usersService.findById(data.id);
  }
}

NestJS は proto の読み込み、シリアライゼーション、HTTP/2 接続管理を自動的に処理します。コントローラーメソッドはプレーンな TypeScript オブジェクトを受け取り、手動での proto デコードは不要です。

NestJS における gRPC ストリーミングパターン

サーバーストリーミングは、単一のリクエストが時間の経過とともに複数の結果を生成するシナリオに適しています:リアルタイム価格フィード、ページネーションされたデータベースカーソル、長時間実行タスク中の進捗更新など。ハンドラーは RxJS Observable を返し、NestJS は発行された各値を個別の gRPC メッセージとしてクライアントにストリーミングします:

users.controller.ts (server streaming)typescript
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { GrpcMethod } from '@nestjs/microservices';

@GrpcMethod('UsersService', 'FindMany')
findMany(data: { role: string; limit: number }): Observable<any> {
  // Stream users matching the filter one by one
  const users$ = from(this.usersService.findByRole(data.role, data.limit));
  return users$.pipe(
    map((user) => ({
      id: user.id,
      email: user.email,
      name: user.name,
      role: user.role,
    })),
  );
}

双方向ストリーミングは @GrpcStreamCall() を使用します。クライアントとサーバーが独立したストリームを送信するため、チャットシステム、コラボレーティブ編集、多重化されたテレメトリ取り込みに有用です。ハンドラーは grpc.ServerDuplexStream インスタンスを受け取り、読み取り/書き込みサイクルを手動で管理します。

NestJS 12 ではバックプレッシャー処理が追加されました:リクエストストリームは、返信の書き込みを待機している間一時停止するようになりました。これにより、遅いコンシューマーが高速なプロデューサーに追いつけない場合のバッファオーバーフローを防ぎます。

ストリーミングのエラー処理

gRPC ストリーム内で Observable がクラッシュすると、呼び出し全体が CANCELLED ステータスで終了します。ストリームロジックを catchError オペレーターでラップし、gRPC に適したエラーメタデータを発行してください。未処理のストリームエラーは、本番環境の NestJS gRPC サービスにおける謎の接続切断の最も一般的な原因です。

NestJS 12 における gRPC 例外フィルター

NestJS 12 では、既知の HTTP 例外フィルターパターンを反映した gRPC 専用の例外処理が導入されました。ステータス固有の例外クラスにより、ハンドラーは汎用的なエラーではなく gRPC ネイティブのエラーコードを返すことができます:

grpc-exception.filter.tstypescript
import { Catch, RpcExceptionFilter, ArgumentsHost } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { RpcException } from '@nestjs/microservices';
import { status } from '@grpc/grpc-js';

@Catch(RpcException)
export class GrpcExceptionFilter implements RpcExceptionFilter<RpcException> {
  catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
    const error = exception.getError() as { code?: number; message?: string };
    return throwError(() => ({
      code: error.code ?? status.INTERNAL,
      message: error.message ?? 'Internal error',
    }));
  }
}

このフィルターをグローバルまたはコントローラー単位で適用することで、すべての gRPC エンドポイントで一貫したエラーレスポンスを確保できます。既存の RpcException クラスと組み合わせることで、HTTP トランスポートと gRPC トランスポート間のエラー処理の同等性が実現されます。

ハイブリッドアプリケーション:同一サービスでの HTTP と gRPC の提供

多くの実際の NestJS サービスでは、パブリック REST API と内部 gRPC エンドポイントの両方が必要です。ハイブリッドアプリケーションパターンは、単一の NestJS インスタンスに複数のトランスポートを接続します:

main.ts (hybrid application)typescript
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  // HTTP server on port 3000
  const app = await NestFactory.create(AppModule);

  // gRPC microservice on port 5000
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.GRPC,
    options: {
      package: 'users',
      protoPath: join(__dirname, 'proto/users.proto'),
      url: '0.0.0.0:5000',
    },
  });

  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();

このアプローチにより、単一の境界コンテキストが外部と内部の両方のインターフェースを必要とする場合に、別々のサービスをデプロイする必要がなくなります。同じ依存性注入コンテナ、ガード、インターセプター、パイプが両方のトランスポートに適用され、重複を減らして動作の一貫性を保ちます。

Node.js / NestJSの面接対策はできていますか?

インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。

NestJS 12 における Kafka 正規表現パターン

NestJS 12 では、@MessagePattern() と @EventPattern() が Kafka トピックの正規表現を受け入れることができるようになりました。単一のハンドラーで複数のトピックに動的にサブスクライブできます:

multi-topic.controller.tstypescript
import { Controller } from '@nestjs/common';
import { EventPattern, Payload, Ctx, KafkaContext } from '@nestjs/microservices';

@Controller()
export class AnalyticsController {
  // Matches analytics.pageview, analytics.click, analytics.purchase, etc.
  @EventPattern(/^analytics..*/)
  handleAnalyticsEvent(
    @Payload() data: Record<string, unknown>,
    @Ctx() context: KafkaContext,
  ) {
    const topic = context.getTopic();
    console.log(`Received event on ${topic}`, data);
  }
}

これにより、複数のトピックが同じハンドラーロジックを共有する場合のボイラープレートが削減されます。NestJS 12 のパターンキー検証では256文字の最大長が強制されることに注意してください:より長いパターンはサイレントに失敗し、ハンドラーにマッチしません。

NestJS 12 における NATS v3 への移行

NestJS 12 では、NATS クライアントが公式の @nats-io/transport-node パッケージに置き換えられました。これは破壊的変更です:デシリアライザーは生のペイロードではなく完全なメッセージオブジェクトを受け取るようになりました。

typescript
// Before (NestJS 11)
deserialize(value: any): any {
  return JSON.parse(value);
}

// After (NestJS 12): read payload via msg.json()
deserialize(msg: any): any {
  return msg.json();
}

NestJS 12 に移行する際は、すべてのカスタム NATS デシリアライザーを更新してください。新しいクライアントは、パフォーマンスの向上と公式 NATS エコシステムとの整合性を提供します。

サービス境界と NestJS によるドメイン駆動設計

明確な境界なしにモノリスをマイクロサービスに分割すると、分散モノリスが生まれます。これは両方のアーキテクチャの欠点を併せ持ちます。各 NestJS マイクロサービスは、単一の境界コンテキストを所有する必要があります:独自のデータベース、独自のドメインモデル、独自のデプロイメントライフサイクルを持ちます。

NestJS でサービス境界を決定するための実践的なガイドライン:

  • 1つの集約ルートにつき1つの NestJS モジュール。 Order と OrderLine が常に一緒に変更される場合、同じサービスに属します。User と Order が独立して変更される場合、別々のサービスにする価値があります。
  • ドメイン横断の副作用には非同期イベント。 注文が行われたら、Kafka または RabbitMQ を介して order.created イベントを発行します。在庫サービスは注文サービスの存在を知らずに反応します。
  • コントラクトには共有 proto パッケージ。 .proto ファイルを共有リポジトリに保存します。プロデューサーとコンシューマーの両方が同じ信頼できる情報源から型を生成するため、ずれは本番インシデントではなく CI の失敗になります。

NestJS 12 の DI コンテナからのマイクロサービスオプションにより、サービス設定がテスト可能になります。main.ts でブローカー URL をハードコーディングする代わりに、ConfigService を注入し、再ビルドなしで環境ごとに接続文字列を切り替えます。

信頼性パターン:タイムアウト、リトライ、サーキットブレーカー

デッドラインのない内部 gRPC 呼び出しは、単一の遅い依存関係をシステム全体の障害に変えます。すべての ClientProxy.send() 呼び出しにはタイムアウトを含める必要があります:

orders.service.tstypescript
import { Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { firstValueFrom, timeout, retry } from 'rxjs';

@Injectable()
export class OrdersService {
  private usersService: any;

  constructor(@Inject('USERS_PACKAGE') private client: ClientGrpc) {}

  onModuleInit() {
    this.usersService = this.client.getService('UsersService');
  }

  async getOrderWithUser(orderId: string, userId: string) {
    // 3-second deadline, 2 retries with exponential backoff
    const user = await firstValueFrom(
      this.usersService.findOne({ id: userId }).pipe(
        timeout(3000),
        retry({ count: 2, delay: (err, retryCount) => {
          const jitter = Math.random() * 100;
          return new Promise(r => setTimeout(r, 1000 * retryCount + jitter));
        }}),
      ),
    );
    return { orderId, user };
  }
}

リトライは冪等な操作にのみ適用すべきです。CreateOrder 呼び出しをリトライすると重複注文のリスクがあります。FindOne クエリは副作用がないためリトライしても安全です。

サーキットブレーカー機能については、opossum ライブラリが NestJS とよく統合されます。N 回連続で失敗した後にオープンし、設定可能なリセットタイムアウト後にクローズするサーキットブレーカーで ClientGrpc 呼び出しをラップします。

NestJS 12 のトレース伝播

NestJS 12 は、NestJS 11 で導入された Kafka、RabbitMQ、gRPC トランスポート間の自動トレース ID 伝播を継続しています。OpenTelemetry と組み合わせることで、カスタムインターセプターなしで完全な分散トレーシングが可能になります。

NestJS マイクロサービスの面接質問

バックエンドポジションの技術面接では、フレームワーク固有のパターンとともにマイクロサービスの知識がますます問われるようになっています。これらの質問は、NestJS に焦点を当てた面接で最も頻繁に問われる概念をカバーしています。

@MessagePattern と @EventPattern の違いは何ですか?

@MessagePattern はリクエスト-レスポンスを実装します:クライアントがメッセージを送信し、返信を受け取るまでブロックします。@EventPattern はファイア・アンド・フォーゲットを実装します:クライアントがイベントを発行し、すぐに実行を継続します。内部的には、@MessagePattern はトランスポートを通じてハンドラーの結果を返し、@EventPattern は戻り値を破棄します。ほとんどのトランスポートで @EventPattern ハンドラーからの返信が NestJS 12 で非推奨になったことに注意してください。

NestJS は gRPC の .proto ファイルをどのように読み込んでバインドしますか?

NestJS は @grpc/proto-loader パッケージを使用して起動時に .proto ファイルを解析し、サービス記述子を生成します。GrpcOptions 設定で proto パスとパッケージ名を指定します。@GrpcMethod('ServiceName', 'MethodName') でアノテーションされたコントローラーは、解析された記述子と照合されます。proto で宣言されたメソッドに対応するハンドラーがない場合、NestJS はブートストラップ時にスローします。

マイクロサービス間で gRPC が REST を置き換えるべき場合はいつですか?

gRPC は型安全性、パフォーマンス、ストリーミングが重要な内部サービス間呼び出しに適しています。Protocol Buffers は JSON よりも小さなペイロードと高速なシリアライゼーションを生成します。HTTP/2 のマルチプレキシングにより接続のオーバーヘッドが削減されます。REST は、人間の可読性と幅広いツーリングサポートが生のパフォーマンスよりも重要なパブリック API、ブラウザクライアント、サードパーティ統合に適しています。

ハイブリッドアプリケーションパターンはどのように機能しますか?

NestFactory.create() が HTTP サーバーをブートします。app.connectMicroservice() を呼び出すと、追加のトランスポート(gRPC、Kafka、Redis、またはサポートされている任意のトランスポーター)が同じ NestJS アプリケーションインスタンスにアタッチされます。すべてのトランスポートは同じモジュールツリー、DI コンテナ、ミドルウェアパイプラインを共有します。app.startAllMicroservices() がすべての接続されたトランスポーターを開始し、app.listen() が HTTP レイヤーを開始します。

カスケード障害を防ぐ信頼性パターンは何ですか?

3つのパターンが最も重要です:タイムアウト(すべての RPC 呼び出しにはデッドラインが必要)、ジッター付きリトライ(冪等な操作のみ、サンダリングハードを避けるための指数バックオフとランダムジッター)、サーキットブレーカー(N 回失敗後にオープン、クールダウン後にハーフオープン、ヘルスチェック通過後にクローズ)。NestJS の RxJS 統合により、タイムアウトとリトライがパイプオペレーターを通じて組み合わせ可能になります。

NestJS 12 でマイクロサービスに関して何が変わりましたか?

NestJS 12 では、ステータス固有のエラー処理のための gRPC 例外フィルター、マルチトピックハンドラー用の Kafka 正規表現パターン、新しいクライアントパッケージを使用した NATS v3 サポート、マイクロサービスハンドラー用のプリリクエストフック、改善された gRPC ストリームバックプレッシャーが追加されました。@EventPattern の非推奨警告は、イベントハンドラーが send() 呼び出しに応答しなくなる将来の動作変更を示しています。

NestJS アーキテクチャパターンをより深く練習するために、NestJS モジュールと依存性注入モジュールはマイクロサービス構成の基盤となる DI の基礎をカバーしています。ミドルウェアとインターセプターモジュールは、トランスポート間で共有される横断的関心事に対処しています。NestJS と GraphQL ガイドは、型付きサービス API の gRPC の代替をカバーしています。

今すぐ練習を始めましょう!

面接シミュレーターと技術テストで知識をテストしましょう。

ソース

  • NestJS v12 is Now Available — gRPC 例外フィルター、Kafka 正規表現パターン、NATS v3、プリリクエストフックをカバーする公式アナウンス
  • NestJS Releases — gRPC ストリームバックプレッシャー、パターンキー制限、EventPattern 非推奨を含む変更履歴
  • NestJS Hybrid Application Documentation — HTTP とマイクロサービストランスポートの組み合わせに関する公式ガイド

2026年の NestJS マイクロサービスの重要ポイント

  • NestJS 12 のトランスポート抽象化により、ハンドラーロジックを書き換えることなく TCP、gRPC、Kafka、NATS 間でサービスを切り替え可能:@MessagePattern と @EventPattern デコレーターはすべてのトランスポートで同一に動作
  • Protocol Buffers を使用した gRPC は .proto ファイルを通じてサービス間の厳格なコントラクトを強制し、本番環境ではなくコンパイル時に統合エラーをキャッチ
  • ハイブリッドアプリケーションは同一の NestJS インスタンス上で HTTP と gRPC を組み合わせ、パブリックと内部インターフェース用に別々のサービスをデプロイする必要を排除
  • RxJS Observable を介したサーバーストリーミングにより、WebSocket の複雑さなしにリアルタイムデータフィードが可能になり、NestJS 12 では遅いコンシューマー向けのバックプレッシャー処理を追加
  • すべての内部 RPC 呼び出しにはデッドラインが必要、リトライは冪等な操作にのみ適用、サーキットブレーカーは単一の遅いサービスが完全な障害にカスケードするのを防止
  • サービス境界はドメイン駆動設計に従う:サービスごとに1つの境界コンテキスト、ドメイン間通信には非同期イベント、コントラクト強制には共有 proto パッケージ

今すぐ練習を始めましょう!

面接シミュレーターと技術テストで知識をテストしましょう。

今日のチャレンジ

Node.js / NestJS のバグを見つけられますか

実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

Anthony Fillion-Maillet

執筆

Anthony Fillion-Maillet

SharpSkill 創業者

10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。

2026年10月22日 更新

タグ

#nestjs
#microservices
#grpc
#node.js
#typescript
#architecture

共有

関連記事