Multi-Account AWS Mimarisi: Ölçeklenebilir Event-Driven Sistemler
Dayanıklı event-driven sistemler için multi-account AWS pattern'leri: hesap yapısı, EventBridge routing ve servisler arası iletişim.
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. Varsayılan olarak benimsenmeye değer yapı şu: servis takımı başına bir hesap, aralarında paylaşılan bir EventBridge bus’ı ve merkezi bir orchestrator yerine event choreography.
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 organizasyonlarda işe yarar, ancak ölçek arttıkça kritik sorunlar üretir.
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:
# Tek hesapta paylaşılan kaynaklar anti-pattern'i
Resources:
CustomerWebLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: platform-customer-web-api
Role: !GetAtt SharedLambdaRole.Arn
OrderProcessingLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: platform-order-processing
Role: !GetAtt SharedLambdaRole.Arn
PaymentLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: platform-payment-service
Role: !GetAtt SharedLambdaRole.Arn
SharedLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/PowerUserAccess
Bu yaklaşım birkaç sorun yaratır:
- Patlama Yarıçapı: Bir takımın kaynak değişiklikleri diğerlerini etkileyebilir
- İzin Karmaşıklığı: IAM policy’leri denetlenmesi zor hale gelir
- Maliyet Atfı: Takım veya servis başına kaynak kullanımını izlemek zorlaşır
- Deployment Çakışmaları: Paylaşılan CI/CD pipeline’lar darboğaz yaratır
- Güvenlik Sınırları: Tüm takımlar aynı güvenlik çevresinde çalışır
Multi-Account Mimari Deseni#
Multi-account mimarisi, merkezi altyapı üzerinden kontrollü iletişim sağlayarak servisler arasında net sınırlar sunar. Sorumlulukları ayrı AWS hesaplarına böler, sistem bütünlüğünü ise merkezi servisler üzerinden korur.
Etkili bir multi-account yapısı şöyle görünür:
Merkezi Identity Service: Güven Sınırı Deseni#
Multi-account mimariler, güvenlik sınırlarını korurken hesaplar arası iletişime izin vermek için merkezi authentication ve authorization gerektirir. Identity Service, tüm hesaplarda token doğrulama ve izinler için tek doğruluk kaynağı olarak çalışır:
{
"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",
"aws:SourceVpce": "vpce-0abc123def4567890"
}
}
}
]
}
Bu merkezileşme tutarlı kimlik doğrulama sağlarken dağıtık JWT validation karmaşıklığını önler. Müşteriye bakan her servis isteklerini merkezi identity service üzerinden doğrular ve güvenlik sınırları korunur.
EventBridge: İletişim Omurgası#
Event-driven mimari, EventBridge’i merkezi iletişim noktası olarak kullanarak servisler arasındaki doğrudan bağımlılıkları ortadan kaldırır. Servisler paylaşılan event bus’a event yayınlar, bus da tanımlı kurallara göre bunları ilgili subscriber’lara yönlendirir.
Order processing için örnek bir EventBridge rule konfigürasyonu:
// Cross-account event routing için CDK kodu
import { Duration } from 'aws-cdk-lib';
import { Rule, EventBus } from 'aws-cdk-lib/aws-events';
import { LambdaFunction } from 'aws-cdk-lib/aws-events-targets';
import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';
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.
Abonelik yükseltme event akışı şöyle işler:
Cross-Service Veri Senkronizasyonu#
Abonelik durumu, hesaplar arasında doğrudan veritabanı erişimi olmadan birden fazla serviste kullanılabilmeli. Çözüm, local cache’lerle birlikte event-sourced state replication.
// 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 Orchestration#
Tek bir servisin tüm akışı kontrol ettiği orchestration deseni, sıkı coupling ve tek bir arıza noktası yaratır. Kaçınılması gereken yaklaşım:
// Orchestration anti-pattern'i, bu yaklaşımdan kaçının
export class SubscriptionOrchestrator {
async upgradeSubscription(userId: string, planId: string) {
try {
// Her servis sırayla doğrudan çağrılıyor
await this.paymentService.processPayment(userId, planId);
await this.subscriptionService.create(userId, planId);
await this.inventoryService.allocatePrioritySlots(userId);
await this.orderService.enablePriorityProcessing(userId);
} catch (error) {
// Her adım için karmaşık rollback mantığı gerekir
await this.rollbackEverything(userId, planId);
}
}
}
Choreography, her servisin yalnızca kendi parçasını bilmesiyle daha gevşek coupling ve daha iyi dayanıklılık 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ırlar ve sorumluluklarla izole AWS hesaplarında çalışır:
# Multi-account organizasyon yapısı
platform-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]
Multi-Account Mimarinin Faydaları#
1. Takım Özerkliği#
Takımlar koordinasyon yükü olmadan bağımsız deploy edebilir. Farklı takımlar birbirlerini etkilemeden ayrı release döngüleri ve deployment takvimleri yürütebilir.
2. Patlama Yarıçapı Kontrolü#
Kaynak sorunları ve konfigürasyon hataları tek bir hesabın içinde kalır. Bir hesaptaki servis arızası diğer servislere yayılmaz, sistemin geneli ayakta kalmaya devam eder.
3. Net Maliyet Atfı#
Takım veya servis başına ayrılmış hesaplarla maliyet dağılımı doğrudan okunabilir hale gelir:
// Maliyet tahsis etiketleme stratejisi
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'
};
}
// Örnek aylık maliyet dağılımı:
// 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. Güvenlik Sınırları#
Her hesap kendi güvenlik çevresini korur. Compliance gereksinimleri, diğer hesapları etkilemeden yalnızca ilgili hesaplara uygulanabilir:
// Payment service hesap güvenlik baseline'ı.
// Bu stack yalnızca 999999999999 hesabına deploy edilir.
import { Stack } from 'aws-cdk-lib';
import { CfnHub, CfnStandard } from 'aws-cdk-lib/aws-securityhub';
const region = Stack.of(this).region;
// Standard'lar aşağıda tek tek tanımlandığı için hub varsayılanları atlıyor.
const hub = new CfnHub(this, 'SecurityHub', {
enableDefaultStandards: false
});
// CloudFormation aksi belirtilmedikçe kaynakları paralel oluşturur ve hub
// hazır olmadan bir standard etkinleştirilemez.
const pciDss = new CfnStandard(this, 'PciDss', {
standardsArn: `arn:aws:securityhub:${region}::standards/pci-dss/v/3.2.1`
});
pciDss.addDependency(hub);
const foundationalSecurity = new CfnStandard(this, 'FoundationalSecurity', {
standardsArn: `arn:aws:securityhub:${region}::standards/aws-foundational-security-best-practices/v/1.0.0`
});
foundationalSecurity.addDependency(hub);
Zorluklar ve Çözümler#
1. Event Schema Evolution#
Distributed sistemlerde event schema değişikliklerini yönetmek dikkatli versiyonlama stratejileri gerektirir. Schema’lar zaman içinde kaçınılmaz olarak evrilir:
// Versiyon 1
{
"orderId": "ord-123",
"customerId": "cust-456",
"items": ["item-1", "item-2"],
"total": 45.99
}
Birden fazla iterasyon ve gereksinim değişikliği sonrası:
// Versiyon 7, altı tur ekleme sonrası
{
"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"
}
}
Düzgün schema yönetimi olmadan consumer’lar hızla karmaşıklaşır:
// Schema registry olmadan versiyon yönetimi
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:
// Bilinmeyen versiyonları kontrollü şekilde ele al
console.error('Bilinmeyen order versiyonu:', event);
throw new Error('Bilinmeyen schema versiyonu');
}
};
2. Cross-Account Observability#
Bir isteği birden fazla AWS hesabı boyunca takip etmek kapsamlı observability altyapısı gerektirir. Distributed tracing burada zorunlu hale gelir:
Yaygın debugging zorlukları:
- Gecikme sorunu herhangi bir hesapta doğabilir
- Event routing hatalarının izini sürmek zordur
- Servis bağımlılıkları birden fazla hesaba yayılır
- Geleneksel monitoring araçları hesaplar arası görünürlük sunmaz
Distributed tracing bu zorlukları çözer:
// Distributed tracing implementasyonu
import { trace, context, propagation, 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 Optimizasyonu#
Multi-account mimariler, dikkatli yönetilmesi gereken ek maliyetler getirir. Cross-account data transfer, event işleme ve kaynak tekrarı faturayı büyütür:
# Dokuz hesaplı bir kurulum için örnek aylık ek maliyet
EventBridge Events: $345 # Milyon başına $1.00 üzerinden 345 milyon custom event
Cross-AZ Data Transfer: $2,100 # Event'ler regional kalmak yerine AZ'ler arası geçiyor
NAT Gateway (9 hesap): $315 # Hesap başına ayda ~$35
CloudWatch Logs: $4,500 # Varsayılan retention, log seviyesi filtresi yok
Secrets Manager: $1,800 # Aynı secret'lar her hesapta kopyalanıyor
Parameter Store API calls: $890 # Cache yok, her invocation yeniden çekiyor
Toplam: $9,950
Maliyet optimizasyon stratejileri:
// Ö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!;
}
}
// Caching, Secrets Manager API çağrılarını belirgin ölçüde azaltır
Operasyonel İzleme Desenleri#
Monitoring burada monolitte olduğundan daha fazla ağırlık taşır, çünkü duran bir event bus sağlıklı raporlamaya devam ederken hiçbir teslimat yapılmaz. Tek bir routing kesintisi aynı anda tüm subscriber’lara ulaşır.
Yaygın arıza modları:
- Devre dışı bırakılmış event routing kuralları
- Yanlış yapılandırılmış event pattern’leri
- Cross-account izin sorunları
- Servis throttling ve limitleri
Kapsamlı monitoring bu sorunları önler:
// Event bus sağlığı için otomatik monitoring
const eventBusMonitor = new Function(this, 'EventBusMonitor', {
runtime: Runtime.NODEJS_22_X,
handler: 'monitor.handler',
code: Code.fromAsset('lambda/event-bus-monitor'),
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!)) {
// On-call mühendisi çağır
await sendSlackAlert({
text: `[ALERT] EVENT BUS KRİTİK: Son dakikada sadece ${eventCount} event!`,
color: 'danger'
});
// Otomatik iyileşme denemesi
await enableAllRules();
}
};
Erken Benimsemeye Değer Uygulamalar#
Dört uygulama, ilk günde benimsendiğinde sonradan eklenmesinden çok daha ucuza gelir:
1. Schema Registry’yi Erken Kurun#
EventBridge Schema Registry kontratı saklar ve versiyonlar, ancak PutEvents sırasında hatalı event’leri reddetmez. Kontratın event’in yayınlandığı yerde uygulanması için client-side doğrulamayla birlikte kullanın:
// Kontratı kaydet, sonra yayınlamadan önce ona karşı doğrula
import { SchemasClient, CreateSchemaCommand } from '@aws-sdk/client-schemas';
import { EventBridgeClient, PutEventsCommand } from '@aws-sdk/client-eventbridge';
import Ajv from 'ajv';
const schemas = new SchemasClient({});
const eventBridge = new EventBridgeClient({});
const ajv = new Ajv();
// 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'
}
}
}
}
}
};
// Schema'yı deploy zamanında bir kez kaydet
await schemas.send(new CreateSchemaCommand({
RegistryName: 'quickgrocer-events',
SchemaName: 'OrderPlaced',
Type: 'OpenApi3',
Content: JSON.stringify(orderSchema)
}));
// Yayınlamadan önce, registry'den üretilen JSON Schema ile doğrula
const validateOrderPlaced = ajv.compile(orderPlacedJsonSchema);
const validateAndPublish = async (entry: { Source: string; DetailType: string; Detail: string }) => {
if (!validateOrderPlaced(JSON.parse(entry.Detail))) {
throw new Error(`Schema doğrulama başarısız: ${ajv.errorsText(validateOrderPlaced.errors)}`);
}
return await eventBridge.send(new PutEventsCommand({ Entries: [entry] }));
};
2. Observability-First Mimari#
Monitoring ve tracing mimariye baştan gömülmeli:
// Kapsamlı observability implementasyonu
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. Otomatik Hesap Yönetimi#
Manuel hesap oluşturma ölçeklenmez. Otomatik account vending zorunlu hale gelir:
// Otomatik account vending implementasyonu
import { OrganizationsClient, CreateAccountCommand } from '@aws-sdk/client-organizations';
class AccountVendingMachine {
private organizations = new OrganizationsClient({});
async createTeamAccount(team: TeamConfig): Promise<AWSAccount> {
// 1. Hesabı talep et. CreateAccount asenkrondur, bu yüzden durum
// IN_PROGRESS'ten çıkana kadar DescribeCreateAccountStatus ile bekle.
const { CreateAccountStatus } = await this.organizations.send(new CreateAccountCommand({
AccountName: `quickgrocer-${team.name}-${team.environment}`,
Email: `aws+${team.name}+${team.environment}@quickgrocer.com`,
RoleName: 'OrganizationAccountAccessRole'
}));
const account = await this.waitForAccount(CreateAccountStatus!.Id!);
// 2. Doğru OU'ya taşı ve baseline servisleri aç
await this.moveToOrganizationalUnit(account.id, this.getOUForTeam(team));
await this.enableBaselineServices(account.id, {
cloudTrail: true,
config: true,
securityHub: true,
guardDuty: true,
budgetLimit: team.monthlyBudget
});
// 3. Takıma özel SCP'leri uygula
await this.applyServiceControlPolicies(account.id, team.permissions);
// 4. 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'
});
// 5. 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. Multi-Region Mimari Planlaması#
Bölgesel genişleme, tasarımın erken aşamasında düşünülmeli:
// Multi-region mimari tasarımı
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)
}
});
});
Multi-Account Ne Zaman Karşılığını Verir#
Varsayılan, bağımsız deployment temposu paylaşılan hesabın kolaylığından daha önemli hale geldiğinde geçerlidir: servis takımı başına bir hesap, aralarında paylaşılan bir EventBridge bus’ı ve merkezi bir orchestrator yerine choreography. Bu noktadan sonra tek bir hesabın koordinasyon maliyeti, ek IAM, ağ ve observability düzeneğini işletme maliyetini aşar.
Bu eşiğin altındaysanız varsayılanı bırakın. Tek bir ürünü çıkaran iki üç takımın cross-account rollere, account vending machine’e veya “bu istek nereye gitti” sorusunu yanıtlamak için distributed tracing’e ihtiyacı yok. Ortam başına tek hesapla başlayın, bir takım ilk kez başka bir takımın deploy’unu blokladığında bölün.
Hangi tarafta olursanız olun, event kontratlarını baştan açık tutun. Schema versiyonlama ve trace propagation, her consumer’ın etrafında sabit kod yazdığı iki parçadır; bunu bir kez yaptıklarında değişiklik artık bir kod değişikliği değil, bir migration olur.
Kaynaklar#
- AWS Ortamınızı Birden Fazla Hesapla Düzenleme (yeni sekmede açılır) - OU yapıları, hesap izolasyonu avantajları ve çok hesaplı tasarım prensiplerini kapsayan AWS teknik belgesi
- Çok hesaplı ortam için en iyi uygulamalar - AWS Organizations (yeni sekmede açılır) - Hesap ayrımı, SCP’ler ve merkezi yönetim için resmi AWS Organizations rehberi
- Amazon EventBridge’de AWS hesapları arasında olay gönderme ve alma (yeni sekmede açılır) - Cross-account event bus izinleri ve EventBridge yönlendirmesi için IAM rolleri yapılandırması
- IAM’de güvenlik en iyi uygulamaları (yeni sekmede açılır) - Çok hesaplı kurulumlarda kullanılan en az ayrıcalık prensipleri, cross-account roller ve geçici kimlik bilgileri
- AWS Secrets Manager nedir? (yeni sekmede açılır) - Hesaplar arasında otomatik rotasyonla gizli bilgi ve kimlik bilgisi yönetimi
- Amazon EventBridge nedir? (yeni sekmede açılır) - Gevşek bağlı cross-account iletişim için event bus kavramları, kurallar ve şema kaydı
- AWS CDK v2 Geliştirici Rehberi (yeni sekmede açılır) - Çok hesaplı stack’ler, cross-account kaynaklar ve CDK Pipelines için altyapı-kod tanımlaması
İlgili yazılar
Çok takımlı AWS organizasyonları için platform varsayılanı: tek event, birçok consumer, her biri kendi hesabında SQS ve DLQ'suyla; fan-out bus katmanında.
aws · eventbridge · event-driven +4
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-systems · microservices · event-driven +5
Event sourcing, CQRS ve event-driven pattern'leri kullanarak müşteri ilişkileri yönetimi, marketing otomasyonu ve consent yönetimi için pratik bir rehber
event-driven · architecture · microservices +3
Kimlik okumaları DynamoDB'de kalsın; keyfi sıralama, filtre, facet ve tam metin arama zero-ETL OpenSearch okuma modeline gitsin. Bazen tek PostgreSQL ikisini de yener.
dynamodb · aws · architecture +2
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ı.
messaging · event-driven · aws +4