Multi-Account AWS Mimarisi: 10x Trafik Artışı için Event-Driven Sistem Tasarımı

"QuickGrocer" örneği üzerinden single-account monolith'ten event-driven sistemlere geçiş sürecini inceleyin. Multi-account AWS mimarisi, pattern'ler ve mimari kararları hakkında detaylı rehber.

Her Şeyin Değiştiği Gün#

15 Mart 2020. CloudWatch dashboard'umuzun yeşilden koyu kırmızıya döndüğünü izlerken telefona bakıyordum. Market teslimat startup'ımız "QuickGrocer", 50.000 kullanıcıdan tek saatte 500.000 giriş denemesine çıkmıştı. Pandemi gelmişti, market rafları boştu ve herkes aynı anda online market alışverişini keşfetmişti.

Tek AWS hesabındaki monolith'imiz – on sekiz aydır düzeltmeyi planladığımız "geçici" mimari – Phoenix'te bırakılmış dondurma gibi eriyordu. RDS instance çığlık atıyordu, Lambda concurrent execution'lar hesap limitlerini vuruyordu ve tek deployment pipeline'ımızda on yedi takım acil düzeltmeleri push etmek için sırada bekliyordu.

Bu, uçarken uçağı yeniden inşa etme hikayemiz. Tek AWS hesabındaki kaostan, lockdown sırasında herkesin can damarı olmayı kaldırabilecek multi-account, event-driven mimariye geçiş.

Problem: Hepsini Yönetecek Tek Hesap (Ve Muhteşem Başarısızlık)#

Dokuz geliştirme takımının hepsinin aynı AWS hesabına deploy ettiğini düşünün. Dokuz ailenin stüdyo dairede yaşaması gibi – teorik olarak mümkün, pratikte delilik. Migration öncesi CloudFormation stack'lerimiz böyle görünüyordu:

YAML
# "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

Problemler domino gibi devrildi:

  1. Patlama Yarıçapı: Payment processing takımı yanlışlıkla production DynamoDB tablosunu sildiğinde (evet, gerçekten), aynı hesabı paylaştıkları için customer web app çöktü
  2. İzin Kaosu: IAM policy'leri kimsenin tam anlamadığı 6.000+ satır JSON'a ulaşmıştı
  3. Fatura Gizemi: "Geçen ay Lambda'ya neden $47.000 harcadık?" İyi soru. Dokuz takım, tek fatura, sıfır hesap verebilirlik
  4. Deployment Tıkanıklığı: CI/CD pipeline'ımız darboğaz oldu, takımlar Slack üzerinden deployment zamanlaması yapıyordu

Bizi Kurtaran Mimari (Sonunda)#

Multi-account mimarisini o stüdyo daireden düzgün bir apartman binasına taşınmak gibi düşünün. Her takım kendi dairesini (AWS hesabı) alıyor, ama ortak hizmetleri (merkezi servisler) paylaşıyorlar ve uygun kanallardan (EventBridge) iletişim kurabiliyorlar.

İşte inşa ettiğimiz:

Loading diagram...

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:

JSON
{
  "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ığı
          ]
        }
      }
    }
  ]
}

Identity service bizim fedai oldu – customer-facing servislerden gelen her istek kapıda kimlik göstermek zorundaydı. Bu merkezileşme bizi JWT validation kabusundan kurtardı.

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:

TypeScript
// 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'
      ]
    }
  }
});

Hesap Yapısı ve İzolasyon#

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

Bash
# 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ü:

Python
# Maliyet tahsis etiketlerimiz
def apply_cost_tags(resource, team_name, service_name):
    return {
        'Team': team_name,
        'Service': service_name,
        'Environment': os.environ['ENVIRONMENT'],
        'CostCenter': TEAM_COST_CENTERS[team_name],
        'Owner': TEAM_LEADS[team_name],
        'CreatedDate': datetime.now().isoformat(),
        '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:

TypeScript
// 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ı:

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

Aralık 2020'de, birçok "hızlı düzeltme" sonrası:

JSON
// 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ı:

TypeScript
// "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 dokuz AWS hesabı boyunca takip etmek karınca kolonisinde tek bir karıncayı takip etmek gibi. Her şeyi değiştiren sabah 3 production olayımız:

Olay Zaman Çizelgesi:

  • 3:17: PagerDuty alert - "Order processing latency > 30 saniye"
  • 3:23: Order processing hesabını kontrol et - her şey normal görünüyor
  • 3:35: Customer web hesabını kontrol et - normal
  • 3:47: Inventory service kontrol et - normal
  • 4:15: Sonunda bulduk - delivery orchestration hesabında sonsuz retry döngüsünde Lambda function
  • 4:45: Kök neden - merkezi hesaptaki EventBridge rule, event pattern'deki typo nedeniyle event'leri yanlış target'a yönlendiriyordu
  • 5:30: Düzeltildi ve deploy edildi
  • 6:00: Post-mortem planlandı
  • Ertesi gün: Distributed tracing'e yoğun yatırım

Çözüm her yerde OpenTelemetry oldu:

TypeScript
// 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ı:

Bash
# "Faturamız neden bu kadar yüksek" dökümü (Aralık 2020)
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:

TypeScript
// Ö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ı

Her Şeyi Değiştiren Sabah 3 Olayı#

Multi-account operasyonlarına yaklaşımımızı tamamen yeniden düşünmemize neden olan olayı anlatayım.

23 Aralık 2020'ydi - Noel'den iki gün önce. En yoğun teslimat sezonu. Sabah 3:14'te telefonum alert'lerle patladı. Bir veya iki değil, 3 dakikada sonradan saydığımız 1.247 PagerDuty bildirimi. Her servis alert veriyordu.

Belirtiler garipti:

  • Order processing: dahili olarak iyi çalışıyor, ama yeni sipariş gelmiyor
  • Delivery orchestration: eksik inventory güncellemeleri için çığlık atıyor
  • Payment service: ödemeleri işliyor ama onay almıyor
  • Customer web: kullanıcılar gezinebiliyor ama checkout yapamıyor

Event bus'ımız sessizleşmişti. Çökmemiş - sessiz. Merkezi EventBridge bus sağlıklı görünüyordu, hata yok, ama sıfır event teslim ediliyordu. Dokuz AWS hesabında 90 dakika panik güdümlü debugging'den sonra sorunu bulduk:

JSON
// $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ı:

TypeScript
// 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: `🚨 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:

TypeScript
// 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ı:

TypeScript
// 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:

TypeScript
// 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:

TypeScript
// İ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)
    }
  });
});

Mevcut Durum: Üç Yıl Sonra#

Bugün "QuickGrocer" 15 AWS hesabında 2.3 milyon aktif kullanıcıya hizmet veriyor. Kriz modunda inşa ettiğimiz multi-account mimari sağlam bir platforma evrildi:

Sayılarla:

  • 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)

Pandemi kaynaklı krize umutsuz yanıt olarak başlayan mimari, mühendislik kültürümüzün temeli oldu. Takımlar kaderlerini sahipleniyor, hatalar izole ve geceleri uyuyabiliyoruz.

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 patlayıcı büyüme sırasında monolithic karmaşa hepsinden zor.

Loading...

Yorumlar (0)

Sohbete katıl

Düşüncelerini paylaşmak ve toplulukla etkileşim kurmak için giriş yap

Henüz yorum yok

Bu yazı hakkında ilk düşüncelerini paylaşan sen ol!

Related Posts