2026'da NestJS ile Mikroservisler: Mimari, gRPC ve Mülakat Soruları

gRPC ile NestJS mikroservis mimarisine yönelik pratik bir rehber: servis sınırları, taşıma katmanları, akış desenleri ve 2026 için sık karşılaşılan mülakat soruları.

Dağıtık arka uç servisleri arasında gRPC iletişimiyle NestJS mikroservis mimarisi

NestJS mikroservisleri, 2026'da dağıtık Node.js arka uçları kurmanın standart yaklaşımı haline geldi. NestJS 11'in geliştirilmiş taşıyıcı katmanı, birinci sınıf gRPC desteği ve otomatik trace ID yayılımı sayesinde framework, geliştirici deneyiminden ödün vermeden bir monolitin iyi sınırlandırılmış servislere bölünmesi için gereken her şeyi sağlar.

Dahili servisler için gRPC ve REST karşılaştırması

gRPC, Protocol Buffers ve HTTP/2 kullanır; REST üzerinden JSON'a kıyasla 10 kata kadar daha hızlı serileştirme ve yerel çift yönlü akış sunar. Bir küme içindeki servisten servise iletişimde gRPC, gecikmeyi azaltır ve .proto dosyaları aracılığıyla katı sözleşmeleri zorunlu kılar. REST, tarayıcılar ve üçüncü taraflarca tüketilen herkese açık API'ler için daha iyi bir seçim olmaya devam eder.

NestJS Mikroservis Taşıma Katmanı Mimarisi

@nestjs/microservices paketi, HTTP denetleyicilerini mesaj odaklı işleyicilerle değiştirir. URL yoluna göre yönlendirme yerine her işleyici bir mesaj desenine (message pattern) yanıt verir — bu, işlemi tanımlayan bir dize ya da nesne anahtarıdır. Bu soyutlama sayesinde aynı işleyici mantığı, kod değişikliği olmadan TCP, Redis, NATS, Kafka, RabbitMQ veya gRPC üzerinde çalışır.

NestJS 11, tüm taşıyıcılarda alttaki istemci örneğine doğrudan erişim sağlayan unwrap() yöntemini tanıttı. Bu, uzun süredir devam eden bir sıkıntıyı çözer: bağlantı durumunu incelemek, keepalive aralıklarını ayarlamak veya NestJS soyutlamasının açığa çıkarmadığı aracıya özgü özelliklere erişmek.

NestJS mikroservislerini iki iletişim deseni yönlendirir:

  • İstek-yanıt (@MessagePattern): istemci bir mesaj gönderir ve bir yanıt bekler. Kullanıcı profili getirme veya bir token'ı doğrulama gibi senkron sorgular için uygundur.
  • Olay tabanlı (@EventPattern): istemci bir olay yayar ve devam eder — yanıt beklenmez. Denetim günlükleri, bildirimler veya alt akış iş akışlarını tetiklemek için idealdir.
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 işleyicisi, dönüş değerini otomatik olarak serileştirir ve taşıma üzerinden geri gönderir. @EventPattern işleyicisi hiçbir şey döndürmez — NestJS herhangi bir dönüş değerini atar.

gRPC'yi NestJS Mikroservis Taşıması Olarak Yapılandırmak

NestJS'te gRPC entegrasyonu, servis sözleşmesini tanımlayan bir .proto dosyasıyla başlar. Protocol Buffers, kablo düzeyinde tür güvenliğini zorunlu kılar — hem istemci hem de sunucu, tek bir bayt ağdan geçmeden önce her mesajın tam biçimi üzerinde anlaşmalıdır.

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;
}

Sunucu tarafında NestJS uygulaması, proto dosyasına işaret edip bir ağ adresine bağlanarak bir gRPC mikroservisini başlatır:

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();

Denetleyici, @MessagePattern yerine @GrpcMethod kullanır. Dekoratör, servis adını ve RPC yöntem adını argüman olarak alır ve doğrudan proto tanımıyla eşler:

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 yüklemeyi, serileştirmeyi ve HTTP/2 bağlantı yönetimini otomatik olarak halleder. Denetleyici yöntemi, düz TypeScript nesneleri alır — elle proto çözümlemesine gerek yoktur.

NestJS'te gRPC Akış Desenleri

Sunucu akışı, tek bir isteğin zamanla birden çok sonuç ürettiği senaryolara uyar — gerçek zamanlı fiyat akışları, sayfalı veritabanı imleçleri veya uzun süren bir görev sırasındaki ilerleme güncellemeleri gibi. İşleyici bir RxJS Observable döndürür ve NestJS, yayılan her değeri ayrı bir gRPC mesajı olarak istemciye akıtır:

users.controller.ts — server streamingtypescript
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,
    })),
  );
}

Çift yönlü akış @GrpcStreamCall() kullanır. Hem istemci hem de sunucu bağımsız akışlar gönderir — sohbet sistemleri, ortak düzenleme veya çoğullanmış telemetri alımı için kullanışlıdır. İşleyici bir grpc.ServerDuplexStream örneği alır ve okuma/yazma döngüsünü elle yönetir.

Akışta hata yönetimi

gRPC akışı içinde çöken bir Observable, tüm çağrıyı CANCELLED durumuyla sonlandırır. Akış mantığını catchError operatörleriyle sarmalayın ve gRPC'ye uygun hata meta verileri yayın. İşlenmeyen akış hataları, üretimdeki NestJS gRPC servislerinde gizemli bağlantı kopmalarının bir numaralı nedenidir.

Hibrit Uygulamalar: Aynı Serviste HTTP ve gRPC

Gerçek dünyadaki birçok NestJS servisi hem herkese açık bir REST API'sine hem de dahili gRPC uç noktalarına ihtiyaç duyar. Hibrit uygulama deseni birden çok taşımayı tek bir NestJS örneğine bağlar:

main.ts — hybrid applicationtypescript
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();

Bu yaklaşım, tek bir sınırlandırılmış bağlam hem dış hem de dahili arayüzlere ihtiyaç duyduğunda ayrı servisler dağıtmaktan kaçınır. Aynı bağımlılık enjeksiyonu konteyneri, guard'lar, interceptor'lar ve pipe'lar her iki taşıma için de geçerlidir — bu da tekrarı azaltır ve davranışı tutarlı tutar.

Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

NestJS ile Servis Sınırları ve Alan Odaklı Tasarım

Bir monoliti net sınırlar olmadan mikroservislere bölmek, dağıtık bir monolit yaratır — her iki mimarinin en kötü yanı. Her NestJS mikroservisi tek bir sınırlandırılmış bağlama sahip olmalıdır: kendi veritabanı, kendi alan modelleri ve kendi dağıtım yaşam döngüsü.

NestJS'te servis sınırlarını çizmek için pratik yönergeler:

  • Her küme kökü (aggregate root) için bir NestJS modülü. Eğer Order ve OrderLine her zaman birlikte değişiyorsa aynı servise aittir. Eğer User ve Order bağımsız olarak değişiyorsa ayrı servisleri hak eder.
  • Alanlar arası yan etkiler için asenkron olaylar. Bir sipariş verildiğinde, Kafka veya RabbitMQ üzerinden bir order.created olayı yayın. Envanter servisi tepki verir; sipariş servisinin onun varlığından haberi olmaz.
  • Sözleşmeler için paylaşılan proto paketleri. .proto dosyalarını paylaşılan bir depoda saklayın. Hem üretici hem de tüketici, türleri aynı doğruluk kaynağından üretir — sapma bir üretim olayı değil, bir CI hatası haline gelir.

NestJS 11'in DI konteynerinden gelen mikroservis seçenekleri, servis yapılandırmasını test edilebilir kılar. Aracı URL'lerini main.ts içinde sabit kodlamak yerine bir ConfigService enjekte edin ve yeniden derleme olmadan ortam başına bağlantı dizelerini değiştirin.

Güvenilirlik Desenleri: Zaman Aşımları, Yeniden Denemeler ve Devre Kesiciler

Son teslim tarihleri (deadline) olmayan dahili gRPC çağrıları, tek bir yavaş bağımlılığı sistem genelinde bir kesintiye dönüştürür. Her ClientProxy.send() çağrısı bir zaman aşımı içermelidir:

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 };
  }
}

Yeniden denemeler yalnızca idempotent işlemlere uygulanmalıdır. Bir CreateOrder çağrısını yeniden denemek, yinelenen siparişler riskini taşır. Bir FindOne sorgusunu yeniden denemek güvenlidir çünkü hiçbir yan etkisi yoktur.

Devre kesici işlevselliği için opossum kütüphanesi NestJS ile iyi entegre olur. ClientGrpc çağrılarını, N ardışık hatadan sonra açılan ve yapılandırılabilir bir sıfırlama zaman aşımından sonra kapanan bir devre kesiciyle sarmalayın.

NestJS 11 trace yayılımı

NestJS 11, trace ID'leri Kafka, RabbitMQ ve gRPC taşımaları arasında otomatik olarak yayar. OpenTelemetry ile birleştiğinde bu, özel interceptor'lar olmadan tam dağıtık izleme sağlar — manuel bağlam yayılımının gerekli olduğu NestJS 10'a göre önemli bir iyileştirme.

NestJS Mikroservis Mülakat Soruları

Arka uç pozisyonları için teknik mülakatlar, framework'e özgü desenlerin yanı sıra giderek artan ölçüde mikroservis bilgisini test ediyor. Aşağıdaki sorular, NestJS odaklı mülakatlarda en sık sorulan kavramları kapsar.

@MessagePattern ile @EventPattern arasındaki fark nedir?

@MessagePattern istek-yanıt uygular: istemci bir mesaj gönderir ve bir yanıt alana kadar bloke olur. @EventPattern gönder-unut (fire-and-forget) uygular: istemci bir olay yayar ve yürütmeye hemen devam eder. Arka planda @MessagePattern işleyicinin sonucunu taşıma üzerinden döndürürken, @EventPattern dönüş değerlerini atar.

NestJS, gRPC için .proto dosyalarını nasıl yükler ve bağlar?

NestJS, başlangıçta .proto dosyalarını ayrıştırmak ve servis tanımlayıcıları oluşturmak için @grpc/proto-loader paketini kullanır. GrpcOptions yapılandırması proto yolunu ve paket adını belirtir. @GrpcMethod('ServiceName', 'MethodName') ile işaretlenmiş denetleyiciler, ayrıştırılan tanımlayıcılarla eşleştirilir. Proto'da bildirilen bir yöntemin eşleşen bir işleyicisi yoksa NestJS bootstrap sırasında hata fırlatır.

gRPC, mikroservisler arasında REST'in yerini ne zaman almalı?

gRPC, tür güvenliği, performans ve akışın önemli olduğu dahili servisten servise çağrılara uyar. Protocol Buffers, JSON'dan daha küçük yükler ve daha hızlı serileştirme üretir. HTTP/2 çoğullaması bağlantı yükünü azaltır. REST, insan tarafından okunabilirliğin ve geniş araç desteğinin ham performanstan daha ağır bastığı herkese açık API'ler, tarayıcı istemcileri ve üçüncü taraf entegrasyonlar için tercih edilir olmaya devam eder.

Hibrit uygulama deseni nasıl çalışır?

NestFactory.create() bir HTTP sunucusu başlatır. app.connectMicroservice() çağrısı, aynı NestJS uygulama örneğine ek taşımalar — gRPC, Kafka, Redis veya desteklenen herhangi bir taşıyıcı — ekler. Tüm taşımalar aynı modül ağacını, DI konteynerini ve middleware ardışık düzenini paylaşır. app.startAllMicroservices() bağlı tüm taşıyıcıları başlatır ve app.listen() HTTP katmanını başlatır.

Hangi güvenilirlik desenleri kademeli arızaları önler?

En önemli üç desen: zaman aşımları (her RPC çağrısının bir son teslim tarihine ihtiyacı vardır), jitter'lı yeniden denemeler (yalnızca idempotent işlemler için, sürü etkisinden kaçınmak amacıyla üstel geri çekilme artı rastgele jitter ile) ve devre kesiciler (N hatadan sonra açık, soğuma süresinden sonra yarı açık, sağlık kontrolleri geçtiğinde kapalı). NestJS'in RxJS entegrasyonu, zaman aşımlarını ve yeniden denemeleri pipe operatörleri aracılığıyla bileştirilebilir kılar.

NestJS mimari desenlerinde daha derin pratik için NestJS modülleri ve bağımlılık enjeksiyonu modülü, mikroservis kompozisyonunun temelini oluşturan DI esaslarını ele alır. Middleware ve interceptor'lar modülü, taşımalar arasında paylaşılan kesişen kaygıları işler.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Sonuç

  • NestJS 11'in taşıma soyutlaması, servislerin işleyici mantığını yeniden yazmadan TCP, gRPC, Kafka ve NATS arasında geçiş yapmasına olanak tanır — @MessagePattern ve @EventPattern dekoratörleri tüm taşımalarda aynı şekilde çalışır
  • Protocol Buffers'lı gRPC, .proto dosyaları aracılığıyla servisler arasında katı sözleşmeleri zorunlu kılar; entegrasyon hatalarını üretimde değil derleme zamanında yakalar
  • Hibrit uygulamalar HTTP ve gRPC'yi aynı NestJS örneğinde birleştirir; herkese açık ve dahili arayüzler için ayrı servisler dağıtma ihtiyacını ortadan kaldırır
  • RxJS Observable'ları aracılığıyla sunucu akışı, WebSocket karmaşıklığı olmadan gerçek zamanlı veri akışları sağlar — NestJS her Observable yayımını bir gRPC akış mesajına eşler
  • Her dahili RPC çağrısı bir son teslim tarihi gerektirir, yeniden denemeler yalnızca idempotent işlemlere uygulanır ve devre kesiciler tek bir yavaş servisin tam bir kesintiye kademeli olarak dönüşmesini önler
  • Servis sınırları alan odaklı tasarımı izler: servis başına bir sınırlandırılmış bağlam, alanlar arası iletişim için asenkron olaylar, sözleşme zorlaması için paylaşılan proto paketleri

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#nestjs
#microservices
#grpc
#nodejs
#typescript
#architecture

Paylaş

İlgili makaleler