İçeriğe atla

2025-09-04

Multi-Account AWS Mimarisi: Ölçeklenebilir Event-Driven Sistemler

Dayanıklı event-driven sistemler için multi-account AWS mimari pattern'lerini öğrenin. Hesap yapısı, EventBridge routing, servisler arası iletişim ve dağıtık sistemlerde operasyonel zorlukları keşfedin.

Single-Account Mimarisinin Sınırları

Multi-account AWS mimarisi, organizasyonlar belirli ölçek ve karmaşıklık eşiklerine ulaştığında gerekli hale gelir. Bu pattern’i ne zaman ve nasıl implement edeceğinizi anlamak, sürdürülebilir büyüme ile operasyonel kaos arasındaki farkı belirleyebilir.

Dokuz geliştirme takımının aynı AWS hesabına deploy ettiği çok servisli bir platform düşünün. Bu yaklaşım küçük organizasyonlar için işe yarayabilen, ölçek arttıkça çeşitli kritik zorluklar yaratır.

Yaygın Single-Account Anti-Pattern’leri

Birden fazla takımın aynı AWS hesabını paylaşması kaynak çakışmalarına, güvenlik sorunlarına ve operasyonel karmaşıklığa yol açar. Örnek bir anti-pattern konfigürasyonu:

# "Her-şey-tek-hesapta" anti-pattern
Resources:
  CustomerWebLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: quickgrocer-customer-web-api
      # Umarım başka kimsenin bu role ihtiyacı yoktur...
      Role: !GetAtt SharedLambdaRole.Arn

  DriverAppLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: quickgrocer-driver-app-api
      # Aynı rol, çünkü kimin least privilege için zamanı var?
      Role: !GetAtt SharedLambdaRole.Arn

  OrderProcessingLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: quickgrocer-order-processing
      # Tahmin ettiniz...
      Role: !GetAtt SharedLambdaRole.Arn

  SharedLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        # Herkes her şeyi alıyor!
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        # "Sonra düzeltiriz" policy'si
        - arn:aws:iam::aws:policy/PowerUserAccess

Bu yaklaşım birkaç sorun yaratır:

  1. Patlama Yarıçapı: Bir takımın kaynak değişiklikleri diğerlerini etkileyebilir
  2. İzin Karmaşıklığı: IAM policy’leri denetlenmesi zor hale gelir
  3. Maliyet Atfı: Takım veya servis başına kaynak kullanımını izlemek zorlaşır
  4. Deployment Çakışmaları: Paylaşılan CI/CD pipeline’lar darboğaz yaratır
  5. Güvenlik Sınırları: Tüm takımlar aynı güvenlik çevresinde çalışır

Multi-Account Mimari Paterni

Multi-account mimarisi, merkezi altyapı üzerinden kontrollü iletişim sağlayarak servisler arasında net sınırlar sunar. Etkili bir yapı:

Production Organization Unit

Paylaşılan Servisler

Core Servis Hesapları

Müşteri Yüzlü Hesaplar

Events

Events

Events

Events

Events

Routed Events

Routed Events

Routed Events

Routed Events

Identity Service

Hesap: 000000000000

Customer Web

Hesap: 111111111111

Mobile Apps

Hesap: 222222222222

Partner Portal

Hesap: 333333333333

Driver App

Hesap: 444444444444

Merchant Dashboard

Hesap: 555555555555

Event Bus

Hesap: 121212121212

Order Processing

Hesap: 777777777777

Delivery Orchestration

Hesap: 888888888888

Payment Service

Hesap: 999999999999

Inventory Management

Hesap: 666666666666

Merkezi Identity Service: Güven Sınırımız

Her multi-account mimarisinin authentication ve authorization için tek doğruluk kaynağına ihtiyacı var. Identity Service’imizi tüm servislerin token’ları ve izinleri doğruladığı tek nokta olarak inşa ettik. Kullandığımız gerçek trust policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowIdentityServiceToAssumeRole",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::000000000000:role/identity-service-validator"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "${IDENTITY_SERVICE_EXTERNAL_ID}",
          "aws:PrincipalOrgID": "o-quickgrocer123"
        },
        "IpAddress": {
          "aws:SourceIp": [
            "10.0.0.0/8"  // VPC CIDR aralığı
          ]
        }
      }
    }
  ]
}

Bu merkezileşme tutarlı kimlik doğrulama sağlarken dağıtık JWT validation karmaşıklığını önler.

EventBridge: Sinir Sistemi

Servislerin birbirini doğrudan çağırması yerine (ve bağımlılık kabusunu yaratması), EventBridge’i iletişim omurgamız olarak kullandık. Her hesap merkezi event bus’a event’ler yayınlıyor, o da ilgilenen subscriber’lara yönlendiriyor.

Order processing akışımızdan gerçek bir EventBridge rule:

// Cross-account event routing için CDK kodu
import { Rule, EventBus } from 'aws-cdk-lib/aws-events';
import { LambdaFunction } from 'aws-cdk-lib/aws-events-targets';

const orderPlacedRule = new Rule(this, 'OrderPlacedRule', {
  eventBus: EventBus.fromEventBusArn(
    this,
    'CentralEventBus',
    'arn:aws:events:us-east-1:121212121212:event-bus/central-bus'
  ),
  eventPattern: {
    source: ['quickgrocer.customer-web'],
    detailType: ['Order Placed'],
    detail: {
      orderStatus: ['PENDING'],
      paymentMethod: ['CREDIT_CARD', 'DEBIT_CARD', 'APPLE_PAY']
    }
  },
  targets: [
    new LambdaFunction(orderProcessingLambda, {
      retryAttempts: 2,
      deadLetterQueue: orderProcessingDLQ,
      maxEventAge: Duration.hours(2)
    })
  ]
});

// Cross-account event publishing için izinler
const centralBusArn = 'arn:aws:events:us-east-1:121212121212:event-bus/central-bus';
const publishPolicy = new PolicyStatement({
  effect: Effect.ALLOW,
  actions: ['events:PutEvents'],
  resources: [centralBusArn],
  conditions: {
    StringEquals: {
      'events:detail-type': [
        'Order Placed',
        'Order Updated',
        'Order Cancelled'
      ]
    }
  }
});

Event-Driven Veri Akış Desenleri

Event-driven mimari servisler arası veri akışının dikkatli orkestrasyonunu gerektirir. Abonelik yükseltme iş akışı, event’lerin birden fazla hesapta durum değişikliklerini nasıl koordine ettiğini gösterir.

Order ProcessingInventory MgmtSubscription ServicePayment ServiceEvent BusIdentity ServiceCustomer WebOrder ProcessingInventory MgmtSubscription ServicePayment ServiceEvent BusIdentity ServiceCustomer WebEvent choreography ile eventual consistencyValidate user permissionsJWT with subscription scopesSubscriptionUpgradeRequestedRoute to payment processingRoute to subscription servicePaymentProcessed (success)SubscriptionActivatedUpdate inventory allocationsEnable priority ordering

Cross-Service Veri Senkronizasyonu

Abonelik durumu hesap veritabanları arasında doğrudan erişim olmadan birden fazla serviste kullanılabilir olmalı. Event-sourced state replication ve local cache ile çözülür.

// Subscription Service - authoritative event yayınlar
export class SubscriptionService {
  async upgradeSubscription(userId: string, planId: string) {
    const subscription = await this.subscriptionRepo.create({
      userId, planId, status: 'ACTIVE',
      startDate: new Date(), features: this.getFeaturesByPlan(planId)
    });
    await this.eventPublisher.publish({
      source: '"quickgrocer".subscription-service',
      detailType: 'Subscription Activated',
      detail: { userId, subscriptionId: subscription.id, plan: { id: planId, features: ['priority_delivery'] } }
    });
    return subscription;
  }
}

// Order Processor - local subscription cache ile
export class OrderProcessor {
  private subscriptionCache = new Map<string, SubscriptionInfo>();
  @EventHandler('Subscription Activated')
  async onSubscriptionActivated(event: SubscriptionEvent) {
    this.subscriptionCache.set(event.detail.userId, { plan: event.detail.plan, features: event.detail.plan.features });
  }
  async processOrder(order: Order) {
    const subscription = this.subscriptionCache.get(order.userId);
    if (subscription?.features.includes('priority_delivery')) order.priority = 'HIGH';
  }
}

Event Choreography vs Orkestrasyon

Orchestration tek bir servisin tüm akışı kontrol etmesi sıkı coupling ve single point of failure yaratır. Choreography her servisin kendi kısmını bilmesiyle daha gevşek coupling sağlar.

// Choreography - her servis kendi parçasını bilir
export class PaymentEventHandlers {
  @EventHandler('Subscription Upgrade Requested')
  async handleUpgradeRequest(event: UpgradeEvent) {
    const result = await this.processPayment(event.detail);
    await this.publishEvent('Payment Processed', { userId: event.detail.userId, amount: result.amount });
  }
}
export class SubscriptionEventHandlers {
  @EventHandler('Payment Processed')
  async activateSubscription(event: PaymentEvent) {
    const subscription = await this.create(event.detail.userId);
    await this.publishEvent('Subscription Activated', { userId: event.detail.userId, subscriptionId: subscription.id });
  }
}

Hesap Yapısı ve İzolasyon

Her takım net sınırlarla kendi kum havuzunu aldı:

# Hesap yapımız
quickgrocer-org/
├── production/
  ├── customer-facing/
  ├── customer-web-111111111111/
  ├── mobile-apps-222222222222/
  ├── partner-portal-333333333333/
  ├── driver-app-444444444444/
  └── merchant-dashboard-555555555555/
  ├── core-services/
  ├── inventory-mgmt-666666666666/
  ├── order-processing-777777777777/
  ├── delivery-orchestration-888888888888/
  └── payment-service-999999999999/
  └── shared-services/
  ├── identity-service-000000000000/
  ├── event-bus-121212121212/
  └── monitoring-131313131313/
├── staging/
  └── [production yapısını yansıtır]
└── development/
    └── [geliştirici takımı başına bir hesap]

Gerçekten İşe Yarayanlar (İyi Kısımlar)

1. Takım Özerkliği

Takımlar sonunda kendi hızlarında ilerleyebildi. Mobile takım Black Friday’de beş güncelleme yayınlarken order processing takımı code freeze’deydi. Slack’te artık “lütfen deploy etmeyin, production’ı debug ediyoruz” mesajları yok.

2. Patlama Yarıçapı Kontrolü

DynamoDB silme olayını hatırlıyor musunuz? Yeni mimaride, delivery orchestration takımı yanlışlıkla 100.000 duplicate event işlediğinde (başka bir günün hikayesi), sadece kendi hesapları Lambda concurrent execution limitini vurdu. Müşteri siparişleri akmaya devam etti.

3. Net Maliyet Atfı

CFO’muz hangi takımın AWS kredilerimizi yaktığını tam olarak görebildiğinde neredeyse sevinç gözyaşları döktü:

// Maliyet tahsis etiketlerimiz
function applyCostTags(resource: any, teamName: string, serviceName: string): Record<string, string> {
    return {
        'Team': teamName,
        'Service': serviceName,
        'Environment': process.env.ENVIRONMENT || 'dev',
        'CostCenter': TEAM_COST_CENTERS[teamName],
        'Owner': TEAM_LEADS[teamName],
        'CreatedDate': new Date().toISOString(),
        'ManagedBy': 'CDK'
    };
}

// Aylık maliyet dağılımı kristal berraklıkta oldu:
// Customer Web:  $12,450 (%25)
// Mobile Apps:  $8,230  (%17)
// Order Processing:  $15,670 (%32)
// Delivery Orchestration: $7,890 (%16)
// Identity Service:  $4,760  (%10)

4. Mantıklı Güvenlik Sınırları

Her hesabın kendi güvenlik çevresi vardı. Payment service takımı tüm şirketi compliance tiyatrosuna zorlamadan PCI compliance kontrollerini etkinleştirebildi:

// Payment service hesap güvenlik baseline'ı
const paymentServiceBaseline = new SecurityHub(this, 'PCICompliance', {
  standards: [
    SecurityHubStandard.PCI_DSS_V321,
    SecurityHubStandard.AWS_FOUNDATIONAL_SECURITY
  ],
  enabledRegions: ['us-east-1', 'us-west-2'],
  // Sadece payment service hesabı için
  accountId: '999999999999'
});

İşe Yaramayanlar (Acı Dersler)

1. Event Schema Evolution Cehennemi

Distributed sistemde event schema’ları değiştirmenin otoyolda giderken arabanın motorunu değiştirmek gibi olduğunu zor yoldan öğrendik. “Order Placed” event’imiz basit başladı:

// Versiyon 1 (Mart 2020)
{
  "orderId": "ord-123",
  "customerId": "cust-456",
  "items": ["item-1", "item-2"],
  "total": 45.99
}

Birçok “hızlı düzeltme” sonrası:

// Versiyon 7 (Aralık 2020)
{
  "orderId": "ord-123",
  "customerId": "cust-456",
  "customerIdV2": "usr_cust-456",  // Yeni ID formatı
  "items": ["item-1", "item-2"],  // Deprecated, itemsV2 kullan
  "itemsV2": [
    {
      "id": "item-1",
      "quantity": 2,
      "price": 12.99,
      "modifiers": []  // v4'te eklendi
    }
  ],
  "total": 45.99,  // v5'te deprecated
  "totalAmount": {  // v5'te eklendi
    "value": 45.99,
    "currency": "USD"
  },
  "metadata": {  // v6'da eklendi
    "source": "mobile-app",
    "version": "2.3.1"
  }
}

Versiyonlama kabusu consumer’larımızda bu ucubeye yol açtı:

// "Schema registry kullanmalıydık" handler'ı
export const handleOrderPlaced = async (event: any) => {
  // Hangi versiyonla uğraştığımızı kontrol et
  const version = event.metadata?.schemaVersion ||
                  (event.customerIdV2 ? 7 :
                   event.totalAmount ? 5 :
                   event.items?.[0]?.modifiers ? 4 : 1);

  switch(version) {
    case 1:
    case 2:
    case 3:
      return handleLegacyOrder(event);
    case 4:
      return handleV4Order(migrateV4ToV7(event));
    case 5:
    case 6:
      return handleV5Order(migrateV5ToV7(event));
    case 7:
      return handleCurrentOrder(event);
    default:
      // Logla ve dua et
      console.error('Bilinmeyen order versiyonu:', event);
      throw new Error('Bilinmeyen schema versiyonu');
  }
};

2. Cross-Account Debugging Kabusu

Bir isteği birden fazla AWS hesabı boyunca takip etmek zordur. PagerDuty alert’inden Lambda retry döngüsüne, oradan EventBridge rule’daki typo’ya kadar iz sürmek saatler alabilir. Çözüm: OpenTelemetry ile distributed tracing.

// Distributed tracing akıl sağlığımızı kurtardı
import { trace, context, SpanStatusCode } from '@opentelemetry/api';

const tracer = trace.getTracer('quickgrocer-order-service', '1.0.0');

export const processOrder = async (event: any) => {
  // EventBridge event'inden trace context'i çıkar
  const traceParent = event.detail?.traceContext?.traceparent;
  const traceState = event.detail?.traceContext?.tracestate;

  // Upstream service'ten trace'i devam ettir
  const extractedContext = propagation.extract(context.active(), {
    traceparent: traceParent,
    tracestate: traceState
  });

  return context.with(extractedContext, () => {
    const span = tracer.startSpan('process-order', {
      attributes: {
        'order.id': event.detail.orderId,
        'order.account': process.env.AWS_ACCOUNT_ID,
        'order.region': process.env.AWS_REGION,
        'order.service': 'order-processing'
      }
    });

    try {
      // Siparişi işle
      const result = await actuallyProcessOrder(event);
      span.setStatus({ code: SpanStatusCode.OK });
      return result;
    } catch (error) {
      span.recordException(error);
      span.setStatus({
        code: SpanStatusCode.ERROR,
        message: error.message
      });
      throw error;
    } finally {
      span.end();
    }
  });
};

3. Maliyet Patlaması

Multi-account multi-budget anlamına gelmiyor, ama birisi AWS faturamıza söylemeyi unuttu. Cross-account data transfer, EventBridge maliyetleri ve duplicate kaynaklar toplandı:

# "Faturamız neden bu kadar yüksek" dökümü
EventBridge Events:  $3,450/ay  # 345 milyon event
Cross-AZ Data Transfer:  $2,100/ay  # Event'leri regional tutmalıydık
NAT Gateway (9 hesap):  $3,215/ay  # Hesap başına $35
CloudWatch Logs:  $4,500/ay  # Herkes her şeyi logluyordu
Secrets Manager:  $1,800/ay  # Secret'lar her yerde kopyalandı
Parameter Store API calls:  $890/ay  # Cache yok = API limit hit'leri

Toplam beklenmeyen maliyetler: $13,955/ay

Maliyet optimizasyon sprint’imiz:

// Önce: Her servis her istekte secret'ları çekiyor
const getSecret = async (secretName: string) => {
  const client = new SecretsManagerClient({});
  const response = await client.send(
    new GetSecretValueCommand({ SecretId: secretName })
  );
  return response.SecretString;
};

// Sonra: TTL ile caching
class SecretCache {
  private cache = new Map<string, {value: string, expiry: number}>();
  private ttl = 3600000; // 1 saat

  async getSecret(secretName: string): Promise<string> {
    const cached = this.cache.get(secretName);
    if (cached && cached.expiry > Date.now()) {
      return cached.value;
    }

    const client = new SecretsManagerClient({});
    const response = await client.send(
      new GetSecretValueCommand({ SecretId: secretName })
    );

    this.cache.set(secretName, {
      value: response.SecretString!,
      expiry: Date.now() + this.ttl
    });

    return response.SecretString!;
  }
}

// Secrets Manager maliyetlerini %94 azalttı

Kritik Olay: Event Bus Sessizliği

Yoğun bir dönemde merkezi EventBridge bus aniden event teslim etmeyi bıraktı. Bus sağlıklı görünüyordu ama sıfır event yönlendiriliyordu. Birden fazla hesapta saatler süren debugging sonucu kök neden bulundu:

// $2.3 milyon kayıp siparişe mal olan typo
{
  "eventBusName": "central-bus",
  "rules": [{
    "name": "route-all-events",
    "state": "DISABLED",  // <-- Birisi "hızlı düzeltme" sırasında yanlış tuşa bastı
    "eventPattern": {
      "source": [{ "prefix": "quickgrocer." }]
    }
  }]
}

Birisi alakasız bir sorunu debug ederken ana routing rule’u devre dışı bırakmış ve yeniden etkinleştirmeyi unutmuştu. Bir checkbox. Dokuz hesap etkilendi. Yoğun sezonda 90 dakika kesinti.

Bu “Bir Daha Asla” protokollerimize yol açtı:

// Event bus sağlığı için otomatik monitoring
const eventBusMonitor = new Lambda(this, 'EventBusMonitor', {
  runtime: Runtime.NODEJS_18_X,
  handler: 'monitor.handler',
  environment: {
    EXPECTED_EVENTS_PER_MINUTE: '1000',
    ALERT_THRESHOLD: '100',
    SLACK_WEBHOOK: process.env.SLACK_WEBHOOK
  }
});

// Her dakika çalıştır
new Rule(this, 'MonitorSchedule', {
  schedule: Schedule.rate(Duration.minutes(1)),
  targets: [new LambdaFunction(eventBusMonitor)]
});

// Gerçek monitoring mantığı
export const handler = async () => {
  const cloudWatch = new CloudWatchClient({});

  // Son dakikada yayınlanan event'leri kontrol et
  const metrics = await cloudWatch.send(new GetMetricStatisticsCommand({
    Namespace: 'AWS/Events',
    MetricName: 'SuccessfulRuleMatches',
    StartTime: new Date(Date.now() - 120000),  // 2 dakika önce
    EndTime: new Date(),
    Period: 60,
    Statistics: ['Sum']
  }));

  const eventCount = metrics.Datapoints?.[0]?.Sum || 0;

  if (eventCount < parseInt(process.env.ALERT_THRESHOLD!)) {
    // YÜKSEK SESLE BAĞIR
    await sendSlackAlert({
      text: `[ALERT] EVENT BUS KRİTİK: Son dakikada sadece ${eventCount} event!`,
      color: 'danger'
    });

    // Otomatik iyileşme denemesi
    await enableAllRules();
  }
};

Farklı Yapacaklarımız (Geçmişe Bakış 20/20)

Bu mimariyi üç yıl çalıştırdıktan sonra geriye bakınca, geçmişteki kendime şunları söylerdim:

1. İlk Günden Schema Registry ile Başla

Sonunda AWS EventBridge Schema Registry’yi implement ettik, ama migration acı vericiydi:

// Baştan yapmalıydık
import { SchemaRegistry } from '@aws-sdk/client-schemas';

const registry = new SchemaRegistry({});

// Schema'yı versiyonlama ile tanımla
const orderSchema = {
  openapi: '3.0.0',
  info: {
    version: '1.0.0',
    title: 'OrderPlaced'
  },
  paths: {},
  components: {
    schemas: {
      OrderPlaced: {
        type: 'object',
        required: ['orderId', 'customerId', 'items', 'totalAmount'],
        properties: {
          orderId: { type: 'string', pattern: '^ord-[0-9a-f]{8} },
          customerId: { type: 'string', pattern: '^cust-[0-9a-f]{8} },
          items: {
            type: 'array',
            items: {
              $ref: '#/components/schemas/OrderItem'
            }
          },
          totalAmount: {
            $ref: '#/components/schemas/Money'
          }
        }
      }
    }
  }
};

// Yayınlamadan önce doğrula
const validateAndPublish = async (event: any) => {
  const validation = await registry.validateSchema(event, 'OrderPlaced', '1.0.0');
  if (!validation.valid) {
    throw new Error(`Schema doğrulama başarısız: ${validation.errors}`);
  }
  return await eventBridge.putEvents({ Entries: [event] });
};

2. Önce Observability’ye Yatırım Yap, Son Değil

Monitoring’i sonradan düşündük. Şöyle olmalıydı:

// Observability-first yaklaşım
class InstrumentedEventPublisher {
  private metrics: MetricsClient;
  private tracer: Tracer;

  async publish(event: Event): Promise<void> {
    const span = this.tracer.startSpan('event.publish');
    const timer = this.metrics.startTimer('event.publish.duration');

    try {
      // Event'e trace context ekle
      event.traceContext = {
        traceparent: span.spanContext().traceId,
        tracestate: span.spanContext().traceState
      };

      await this.eventBridge.putEvents({
        Entries: [{
          ...event,
          Detail: JSON.stringify({
            ...JSON.parse(event.Detail),
            _metadata: {
              timestamp: Date.now(),
              account: process.env.AWS_ACCOUNT_ID,
              service: process.env.SERVICE_NAME,
              version: process.env.SERVICE_VERSION,
              traceId: span.spanContext().traceId
            }
          })
        }]
      });

      this.metrics.increment('event.published', {
        type: event.DetailType,
        source: event.Source
      });

    } catch (error) {
      this.metrics.increment('event.publish.error', {
        type: event.DetailType,
        error: error.name
      });
      span.recordException(error);
      throw error;
    } finally {
      timer.end();
      span.end();
    }
  }
}

3. Baştan Account Vending Machine

İlk başta hesapları manuel oluşturduk. Büyük hata:

// Hemen inşa etmeliydik
import { Organizations } from '@aws-sdk/client-organizations';
import { ControlTower } from '@aws-sdk/client-controltower';

class AccountVendingMachine {
  async createTeamAccount(team: TeamConfig): Promise<AWSAccount> {
    // 1. Control Tower üzerinden hesap oluştur
    const account = await this.controlTower.createAccount({
      accountName: `quickgrocer-${team.name}-${team.environment}`,
      accountEmail: `aws+${team.name}+${team.environment}@quickgrocer.com`,
      organizationalUnit: this.getOUForTeam(team),

      // Baseline konfigürasyon
      baselineConfig: {
        enableCloudTrail: true,
        enableConfig: true,
        enableSecurityHub: true,
        enableGuardDuty: true,
        budgetLimit: team.monthlyBudget
      }
    });

    // 2. Takıma özel SCP'leri uygula
    await this.applyServiceControlPolicies(account.id, team.permissions);

    // 3. Cross-account rolleri kur
    await this.setupCrossAccountRoles(account.id, {
      identityServiceRole: 'arn:aws:iam::000000000000:role/identity-validator',
      eventBusRole: 'arn:aws:iam::121212121212:role/event-publisher'
    });

    // 4. Baseline altyapıyı deploy et
    await this.deployBaseline(account.id, {
      vpcCidr: this.allocateVpcCidr(team),
      eventBusArn: 'arn:aws:events:us-east-1:121212121212:event-bus/central-bus',
      logGroupRetention: 30
    });

    return account;
  }
}

4. Regional Strateji Global Olmalıydı

“Basit tutmak” için her şeyi us-east-1’de tuttuk. Sonra EU compliance’a ihtiyacımız oldu:

// İlk günden multi-region ayları kurtarırdı
const multiRegionStack = new Stack(app, 'MultiRegionInfra', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION
  }
});

// Birden fazla bölgeye deploy et
['us-east-1', 'eu-west-1', 'ap-southeast-1'].forEach(region => {
  new RegionalStack(app, `Regional-${region}`, {
    env: { region },
    eventBusArn: `arn:aws:events:${region}:121212121212:event-bus/central-bus`,
    // Regional event routing
    eventRouting: {
      primary: region,
      failover: getFailoverRegion(region)
    }
  });
});

Özet

Multi-account mimari üç yıl çalıştırıldığında tipik metrikler:

Örnek sayılar:

  • Günlük event: 450 milyon
  • Cross-account API çağrıları: 12 milyon/gün
  • Ortalama gecikme: 47ms (340ms’den düştü)
  • Deployment sıklığı: 340 deployment/hafta (12’den yükseldi)
  • Production olayları: 2/ay (31’den düştü)
  • AWS faturası: $127,000/ay (ama her doların nereye gittiğini biliyoruz)

Takımlar kendi hızlarında ilerleyebiliyor, hatalar izole kalıyor.

Ana Çıkarımlar

Organizasyonunuz için multi-account mimari düşünüyorsanız, üç yıl siperlerde geçirdikten sonra öğrendiklerim:

  1. İhtiyacınız Olmadan Başlayın: Krizi beklemeyin. Baskı altında migration 10 kat daha zor
  2. Event-Driven Opsiyonel Değil: Multi-account’ta doğrudan service-to-service çağrılar sizi rahatsız edecek
  3. İlk Günden Schema Registry: Versiyonlama olmadan event schema evrimi organizasyonel borç
  4. Observability Bir Özellik Değil: Temel. Önce inşa edin, sonra kendinize teşekkür edin
  5. Account Vending Kritik: Manuel hesap oluşturma 3-4 hesaptan fazlasında ölçeklenmiyor
  6. Maliyet Sizi Şaşırtacak: Multi-account overhead için %30 fazla bütçe ayırın, sonra optimize edin
  7. Takım Eğitimi Önemli: Herkes distributed sistemleri nasıl idare edeceğini bilmiyor. Eğitime yatırım yapın

Multi-account yolculuğu sadece teknoloji değil - takımlara organizasyonel tutarlılığı korurken yenilik yapma özerkliği vermek. Karmaşık, pahalı ve kompleks, ama bir sonraki 10x büyüme dalgası vurduğunda hazır olacaksınız.

Unutmayın: distributed sistemler zor, multi-account AWS daha zor, ama hızlı büyüme sırasında monolithic karmaşa hepsinden zor.

İlgili yazılar

İzole Consumer Hesaplarına Event Fan-Out: Sıfır Dokunuşlu Producer, Domain Başına Sahiplik

Çok takımlı AWS organizasyonları için platform mühendisliği varsayılanı: tek event, birçok consumer, her biri kendi hesabında kendi SQS ve DLQ'suyla; fan-out event bus katmanında yaşar.

awseventbridgeevent-driven+5
Transactional Outbox Pattern: Dağıtık Sistemlerde Güvenilir Event Publishing

Transactional Outbox Pattern'in dağıtık sistemlerdeki dual-write problemini nasıl çözdüğünü, PostgreSQL, DynamoDB ve CDC araçlarıyla pratik implementasyonlarını öğren.

distributed-systemsmicroservicesevent-driven+7
Kafka mı, Event Bus mı? SNS/SQS/EventBridge'i Aşmanız Gerektiğini Söyleyen Sinyaller

Yönetilen bir event bus'tan Kafka'ya geçişi hak eden sinyaller ve rip-and-replace yapmadan taşımak için outbox tabanlı dört aşamalı geçiş planı.

kafkaevent-drivenaws+4
Harici Yetkilendirme Yönetim Sistemleri: Mimarınız İçin Doğru Platformu Seçmek

AWS Verified Permissions, SpiceDB, OpenFGA, Cerbos ve OPA dahil harici yetkilendirme platformlarının tarafsız değerlendirmesi. Mimari desenler, maliyet analizi ve mühendislik ekipleri için karar çerçevesi.

authorizationsecurityarchitecture+5
AWS Control Tower Çoklu Hesap Stratejisi: Landing Zone'dan Kurumsal Governance'a

OU yapısı, SCP, RCP, Account Factory for Terraform, IAM Identity Center ve merkezi güvenlik mimarisi konularını kapsayan AWS Control Tower çoklu hesap stratejisi tasarımı ve uygulaması için pratik bir rehber.

awsaws-control-towermulti-account+6