메인 콘텐츠로 바로가기

개요

AWS는 두 가지 주요 데이터베이스 서비스를 제공합니다: **RDS(Relational Database Service)**와 DynamoDB.

RDS는 전통적인 관계형 데이터베이스를 관리형 서비스로 제공하며, DynamoDB는 NoSQL 키-값 스토어로 대규모 확장성을 제공합니다. 이 가이드에서는 두 서비스의 핵심 개념, 동작 원리, 그리고 프로젝트에 맞는 데이터베이스를 선택하는 방법을 알아봅니다.


Part 1: AWS RDS 이해하기

RDS란?

Amazon RDS(Relational Database Service)는 클라우드에서 관계형 데이터베이스를 쉽게 설정, 운영, 확장할 수 있게 해주는 관리형 서비스입니다.

지원하는 데이터베이스 엔진

RDS는 다음 6가지 인기 있는 데이터베이스 엔진을 지원합니다:

  • MySQL - 가장 널리 사용되는 오픈소스 데이터베이스
  • PostgreSQL - 고급 기능을 제공하는 오픈소스 데이터베이스
  • MariaDB - MySQL의 커뮤니티 기반 포크
  • Oracle - 엔터프라이즈급 상용 데이터베이스
  • SQL Server - Microsoft의 관계형 데이터베이스
  • Amazon Aurora - AWS가 개발한 MySQL/PostgreSQL 호환 고성능 데이터베이스

핵심 특징

1. 완전 관리형 서비스

RDS는 다음 작업을 자동으로 처리합니다:

  • 자동 백업: 매일 자동으로 전체 백업 수행
  • 소프트웨어 패칭: 데이터베이스 엔진 업데이트 자동 적용
  • 장애 복구: Multi-AZ 배포로 자동 페일오버
  • 모니터링: CloudWatch를 통한 성능 지표 추적
# RDS 인스턴스 생성 예시 (AWS CLI) aws rds create-db-instance \ --db-instance-identifier mydb \ --db-instance-class db.t3.micro \ --engine mysql \ --master-username admin \ --master-user-password mypassword \ --allocated-storage 20 \ --backup-retention-period 7 \ --multi-az

2. 확장성

수직 확장 (Vertical Scaling): 인스턴스 타입을 변경하여 CPU, 메모리 증가

# 인스턴스 타입 변경 aws rds modify-db-instance \ --db-instance-identifier mydb \ --db-instance-class db.t3.medium \ --apply-immediately

읽기 복제본 (Read Replicas): 읽기 성능 향상을 위한 복제본 생성

# 읽기 복제본 생성 aws rds create-db-instance-read-replica \ --db-instance-identifier mydb-replica \ --source-db-instance-identifier mydb

3. 보안

  • VPC 격리: 데이터베이스를 프라이빗 서브넷에 배치
  • 암호화: 저장 데이터 및 전송 중 데이터 암호화
  • IAM 통합: AWS IAM을 통한 접근 제어
// Node.js에서 RDS MySQL 연결 예시 const mysql = require('mysql2/promise'); async function connectToRDS() { const connection = await mysql.createConnection({ host: 'mydb.abc123.us-east-1.rds.amazonaws.com', port: 3306, user: 'admin', password: process.env.DB_PASSWORD, database: 'myapp', ssl: { rejectUnauthorized: true } }); console.log('RDS 연결 성공'); return connection; } // 쿼리 실행 async function getUsers() { const connection = await connectToRDS(); try { const [rows] = await connection.execute( 'SELECT * FROM users WHERE active = ?', [true] ); console.log('사용자 목록:', rows); return rows; } catch (error) { console.error('쿼리 실패:', error); throw error; } finally { await connection.end(); } }

RDS의 장점

  • 익숙한 SQL: 기존 SQL 지식과 도구를 그대로 사용
  • ACID 트랜잭션: 강력한 일관성과 데이터 무결성 보장
  • 복잡한 쿼리: JOIN, 집계, 서브쿼리 등 복잡한 쿼리 지원
  • 관계형 데이터: 테이블 간 관계를 명확하게 정의
  • 성숙한 생태계: 풍부한 도구와 라이브러리

RDS의 한계

  • ⚠️ 확장 제약: 단일 인스턴스의 컴퓨팅 한계 존재
  • ⚠️ 비용: 대용량 데이터에서 스토리지 비용 증가
  • ⚠️ 복잡성: 스키마 설계 및 인덱스 최적화 필요
  • ⚠️ 응답 지연: 초고속 응답이 필요한 경우 부적합

Part 2: DynamoDB 이해하기

DynamoDB란?

Amazon DynamoDB는 완전 관리형 NoSQL 데이터베이스 서비스로, 어떤 규모에서도 일관된 한 자릿수 밀리초 응답 시간을 제공합니다.

핵심 개념

테이블과 항목

DynamoDB의 데이터 구조:

테이블 (Table) └── 항목 (Item) - RDS의 행(Row)과 유사 └── 속성 (Attribute) - RDS의 열(Column)과 유사

중요한 차이점: RDS와 달리 각 항목이 서로 다른 속성을 가질 수 있습니다 (스키마리스).

기본 키 (Primary Key)

DynamoDB는 두 가지 타입의 기본 키를 지원합니다:

1. 파티션 키 (Partition Key)

  • 단일 속성으로 구성
  • 데이터 분산의 기준
// 파티션 키만 사용하는 테이블 예시 { "userId": "user123", // 파티션 키 "name": "홍길동", "email": "hong@example.com" }

2. 복합 키 (Composite Key)

  • 파티션 키 + 정렬 키(Sort Key)
  • 같은 파티션 키를 가진 항목들을 정렬 키로 정렬
// 복합 키 사용 예시 (주문 테이블) { "userId": "user123", // 파티션 키 "orderId": "order-456", // 정렬 키 "amount": 50000, "status": "completed", "createdAt": "2024-01-15T10:30:00Z" }

읽기 일관성 모델

최종 일관된 읽기 (Eventually Consistent Read):

  • 기본 옵션
  • 빠르고 비용 효율적
  • 최신 데이터가 아닐 수 있음 (일반적으로 1초 이내 반영)

강력한 일관성 읽기 (Strongly Consistent Read):

  • 항상 최신 데이터 보장
  • 비용이 2배
  • 모든 리전에서 지원되지 않음
// AWS SDK를 사용한 DynamoDB 작업 const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); const { DynamoDBDocumentClient, GetCommand, PutCommand, QueryCommand } = require('@aws-sdk/lib-dynamodb'); const client = new DynamoDBClient({ region: 'us-east-1' }); const docClient = DynamoDBDocumentClient.from(client); // 1. 항목 추가 (PutItem) async function createUser(userId, userData) { const command = new PutCommand({ TableName: 'Users', Item: { userId, name: userData.name, email: userData.email, createdAt: new Date().toISOString() } }); try { await docClient.send(command); console.log('사용자 생성 완료:', userId); } catch (error) { console.error('사용자 생성 실패:', error); throw error; } } // 2. 항목 조회 (GetItem) async function getUser(userId) { const command = new GetCommand({ TableName: 'Users', Key: { userId }, ConsistentRead: true // 강력한 일관성 읽기 }); try { const response = await docClient.send(command); return response.Item; } catch (error) { console.error('사용자 조회 실패:', error); throw error; } } // 3. 쿼리 (Query) - 파티션 키로 여러 항목 조회 async function getUserOrders(userId) { const command = new QueryCommand({ TableName: 'Orders', KeyConditionExpression: 'userId = :userId', ExpressionAttributeValues: { ':userId': userId }, ScanIndexForward: false // 정렬 키 기준 내림차순 정렬 }); try { const response = await docClient.send(command); return response.Items; } catch (error) { console.error('주문 조회 실패:', error); throw error; } } // 4. 조건부 업데이트 async function updateUserEmail(userId, newEmail, currentEmail) { const command = new UpdateCommand({ TableName: 'Users', Key: { userId }, UpdateExpression: 'SET email = :newEmail', ConditionExpression: 'email = :currentEmail', // 조건: 현재 이메일이 일치할 때만 ExpressionAttributeValues: { ':newEmail': newEmail, ':currentEmail': currentEmail } }); try { await docClient.send(command); console.log('이메일 업데이트 완료'); } catch (error) { if (error.name === 'ConditionalCheckFailedException') { console.error('이메일이 이미 변경되었습니다'); } throw error; } }

용량 모드

1. 온디맨드 (On-Demand)

  • 언제 사용: 트래픽 예측이 어려운 경우
  • 과금 방식: 실제 요청 수에 따라 과금
  • 장점: 자동 확장, 관리 불필요
  • 단점: 예측 가능한 트래픽에서 비용 증가
// 온디맨드 테이블 생성 const createTableCommand = { TableName: 'Users', BillingMode: 'PAY_PER_REQUEST', // 온디맨드 모드 KeySchema: [ { AttributeName: 'userId', KeyType: 'HASH' } ], AttributeDefinitions: [ { AttributeName: 'userId', AttributeType: 'S' } ] };

2. 프로비저닝 (Provisioned)

  • 언제 사용: 안정적이고 예측 가능한 트래픽
  • 과금 방식: 설정한 읽기/쓰기 용량에 따라 과금
  • 장점: 비용 최적화 가능
  • 단점: 용량 계획 및 조정 필요
// 프로비저닝 모드 테이블 생성 const createTableCommand = { TableName: 'Users', BillingMode: 'PROVISIONED', ProvisionedThroughput: { ReadCapacityUnits: 5, // 초당 5회 읽기 WriteCapacityUnits: 5 // 초당 5회 쓰기 }, KeySchema: [ { AttributeName: 'userId', KeyType: 'HASH' } ], AttributeDefinitions: [ { AttributeName: 'userId', AttributeType: 'S' } ] };

글로벌 보조 인덱스 (GSI)

다른 속성으로 쿼리하기 위한 인덱스:

// GSI를 사용한 이메일 검색 const createTableWithGSI = { TableName: 'Users', BillingMode: 'PAY_PER_REQUEST', KeySchema: [ { AttributeName: 'userId', KeyType: 'HASH' } ], AttributeDefinitions: [ { AttributeName: 'userId', AttributeType: 'S' }, { AttributeName: 'email', AttributeType: 'S' } ], GlobalSecondaryIndexes: [ { IndexName: 'EmailIndex', KeySchema: [ { AttributeName: 'email', KeyType: 'HASH' } ], Projection: { ProjectionType: 'ALL' // 모든 속성 포함 } } ] }; // GSI를 사용한 쿼리 async function getUserByEmail(email) { const command = new QueryCommand({ TableName: 'Users', IndexName: 'EmailIndex', KeyConditionExpression: 'email = :email', ExpressionAttributeValues: { ':email': email } }); const response = await docClient.send(command); return response.Items[0]; // 첫 번째 항목 반환 }

DynamoDB의 장점

  • 무제한 확장성: 자동으로 데이터와 트래픽 분산
  • 빠른 응답: 일관된 한 자릿수 밀리초 응답 시간
  • 서버리스: 인프라 관리 불필요
  • 고가용성: 99.99% 가용성 SLA
  • 유연한 스키마: 항목마다 다른 속성 가질 수 있음

DynamoDB의 한계

  • ⚠️ 제한된 쿼리: JOIN, 복잡한 집계 불가능
  • ⚠️ 학습 곡선: NoSQL 모델링 패턴 학습 필요
  • ⚠️ 비용: 소규모에서는 RDS보다 비쌀 수 있음
  • ⚠️ 트랜잭션 제약: 제한적인 트랜잭션 지원 (최대 25개 항목)

Part 3: RDS vs DynamoDB 비교

상세 비교표

특성RDSDynamoDB
데이터 모델관계형 (테이블, 행, 열)NoSQL (키-값, 문서)
쿼리 언어SQLAWS SDK API
스키마고정 스키마 (사전 정의 필요)스키마리스 (유연함)
확장성수직 확장 (인스턴스 크기)수평 확장 (자동 파티셔닝)
트랜잭션완전한 ACID제한적 (최대 25개 항목)
JOIN✅ 지원❌ 미지원
인덱스B-Tree, Hash 등 다양GSI, LSI
응답 시간수십 밀리초한 자릿수 밀리초
백업자동 백업, 스냅샷자동 백업, PITR
관리관리형 (일부 설정 필요)완전 관리형
비용 모델인스턴스 시간 + 스토리지요청 수 + 스토리지

성능 비교

RDS 성능 특성

// RDS에서 사용자와 주문 조회 (JOIN 사용) async function getUserWithOrders(userId) { const query = ` SELECT u.user_id, u.name, u.email, o.order_id, o.amount, o.created_at FROM users u LEFT JOIN orders o ON u.user_id = o.user_id WHERE u.user_id = ? ORDER BY o.created_at DESC `; // 응답 시간: 일반적으로 20-50ms const [rows] = await connection.execute(query, [userId]); return rows; }

DynamoDB 성능 특성

// DynamoDB에서 같은 데이터 조회 (2번의 쿼리 필요) async function getUserWithOrders(userId) { // 1. 사용자 조회 (1-5ms) const user = await docClient.send(new GetCommand({ TableName: 'Users', Key: { userId } })); // 2. 주문 조회 (1-5ms) const orders = await docClient.send(new QueryCommand({ TableName: 'Orders', KeyConditionExpression: 'userId = :userId', ExpressionAttributeValues: { ':userId': userId }, ScanIndexForward: false })); // 총 응답 시간: 일반적으로 2-10ms return { ...user.Item, orders: orders.Items }; }

Part 4: 선택 가이드

RDS를 선택해야 하는 경우

✅ 이런 경우에 RDS 사용

1. 복잡한 관계형 데이터

// 예: 전자상거래 시스템 // 사용자 ↔ 주문 ↔ 상품 ↔ 카테고리 등 복잡한 관계
  • 다중 테이블 JOIN이 빈번한 경우
  • 데이터 간 참조 무결성이 중요한 경우

2. 기존 SQL 애플리케이션 마이그레이션

  • 기존 MySQL, PostgreSQL 애플리케이션을 클라우드로 이전
  • 최소한의 코드 변경으로 마이그레이션

3. 복잡한 쿼리 및 분석

-- 예: 월별 매출 분석 SELECT DATE_FORMAT(created_at, '%Y-%m') as month, category, COUNT(*) as order_count, SUM(amount) as total_amount FROM orders JOIN products ON orders.product_id = products.id WHERE created_at >= DATE_SUB(NOW(), INTERVAL 6 MONTH) GROUP BY month, category ORDER BY month DESC, total_amount DESC;

4. ACID 트랜잭션이 필수적인 경우

// 예: 금융 거래 async function transferMoney(fromAccount, toAccount, amount) { const connection = await getConnection(); try { await connection.beginTransaction(); // 1. 출금 await connection.execute( 'UPDATE accounts SET balance = balance - ? WHERE id = ?', [amount, fromAccount] ); // 2. 입금 await connection.execute( 'UPDATE accounts SET balance = balance + ? WHERE id = ?', [amount, toAccount] ); await connection.commit(); } catch (error) { await connection.rollback(); throw error; } }

적합한 사용 사례:

  • 전자상거래 플랫폼
  • ERP 시스템
  • CRM 시스템
  • 금융 애플리케이션
  • 콘텐츠 관리 시스템 (CMS)

DynamoDB를 선택해야 하는 경우

✅ 이런 경우에 DynamoDB 사용

1. 대규모 트래픽과 데이터

// 예: IoT 데이터 수집 // 초당 수만~수백만 건의 쓰기가 필요한 경우 async function logSensorData(deviceId, data) { await docClient.send(new PutCommand({ TableName: 'SensorLogs', Item: { deviceId, timestamp: Date.now(), ...data } })); }

2. 키-값 조회가 주된 액세스 패턴

// 예: 사용자 세션 관리 async function getSession(sessionId) { // 1-5ms의 빠른 응답 const response = await docClient.send(new GetCommand({ TableName: 'Sessions', Key: { sessionId } })); return response.Item; }

3. 서버리스 아키텍처

// Lambda + DynamoDB 조합 export const handler = async (event) => { const userId = event.requestContext.authorizer.claims.sub; // 사용자 데이터 조회 const user = await docClient.send(new GetCommand({ TableName: 'Users', Key: { userId } })); return { statusCode: 200, body: JSON.stringify(user.Item) }; };

4. 글로벌 확장

  • DynamoDB 글로벌 테이블로 다중 리전 복제
  • 낮은 지연 시간의 글로벌 애플리케이션

적합한 사용 사례:

  • 모바일 앱 백엔드
  • 게임 리더보드
  • IoT 데이터 저장
  • 실시간 채팅 애플리케이션
  • 사용자 세션 저장
  • 쇼핑 카트

하이브리드 접근 방식

많은 실제 애플리케이션은 두 서비스를 함께 사용합니다:

// 예: 전자상거래 플랫폼 // // RDS 사용: // - 제품 카탈로그 (복잡한 관계, JOIN 필요) // - 주문 관리 (트랜잭션 필수) // - 재고 관리 (정확성 중요) // // DynamoDB 사용: // - 사용자 세션 // - 쇼핑 카트 // - 제품 조회 캐시 (빠른 응답) // - 사용자 활동 로그 // RDS: 주문 생성 (트랜잭션) async function createOrder(orderData) { const connection = await getRDSConnection(); try { await connection.beginTransaction(); // 주문 생성 const [result] = await connection.execute( 'INSERT INTO orders (user_id, total_amount) VALUES (?, ?)', [orderData.userId, orderData.totalAmount] ); // 재고 차감 for (const item of orderData.items) { await connection.execute( 'UPDATE inventory SET quantity = quantity - ? WHERE product_id = ?', [item.quantity, item.productId] ); } await connection.commit(); return result.insertId; } catch (error) { await connection.rollback(); throw error; } } // DynamoDB: 쇼핑 카트 관리 (빠른 읽기/쓰기) async function updateCart(userId, cartItems) { await docClient.send(new PutCommand({ TableName: 'ShoppingCarts', Item: { userId, items: cartItems, updatedAt: new Date().toISOString() } })); } // DynamoDB: 제품 뷰 카운트 (높은 쓰기 처리량) async function incrementProductView(productId) { await docClient.send(new UpdateCommand({ TableName: 'ProductStats', Key: { productId }, UpdateExpression: 'ADD viewCount :inc', ExpressionAttributeValues: { ':inc': 1 } })); }

Part 5: 마이그레이션 고려사항

RDS에서 DynamoDB로 마이그레이션

데이터 모델링 재설계

RDS 스키마:

-- 정규화된 관계형 스키마 CREATE TABLE users ( user_id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100) ); CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, amount DECIMAL(10,2), created_at TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(user_id) );

DynamoDB 모델 (비정규화):

// 사용자 항목 { "PK": "USER#123", "SK": "PROFILE", "userId": 123, "name": "홍길동", "email": "hong@example.com" } // 주문 항목 (같은 테이블에 저장) { "PK": "USER#123", "SK": "ORDER#456", "orderId": 456, "amount": 50000, "createdAt": "2024-01-15T10:30:00Z" } // 단일 쿼리로 사용자와 모든 주문 조회 가능 const result = await docClient.send(new QueryCommand({ TableName: 'AppData', KeyConditionExpression: 'PK = :pk', ExpressionAttributeValues: { ':pk': 'USER#123' } }));

DynamoDB에서 RDS로 마이그레이션

스키마 정규화

// DynamoDB의 비정규화된 데이터 { "orderId": "order-123", "userId": "user-456", "userName": "홍길동", // 중복 데이터 "userEmail": "hong@example.com", // 중복 데이터 "items": [ { "productId": "prod-789", "productName": "노트북", // 중복 데이터 "quantity": 1 } ] } // RDS로 정규화 -- users 테이블 INSERT INTO users (user_id, name, email) VALUES ('user-456', '홍길동', 'hong@example.com'); -- products 테이블 INSERT INTO products (product_id, name) VALUES ('prod-789', '노트북'); -- orders 테이블 INSERT INTO orders (order_id, user_id) VALUES ('order-123', 'user-456'); -- order_items 테이블 INSERT INTO order_items (order_id, product_id, quantity) VALUES ('order-123', 'prod-789', 1);

Part 6: 비용 최적화

RDS 비용 최적화

// 1. 예약 인스턴스 사용 (최대 75% 절감) // AWS Console에서 1년 또는 3년 약정 // 2. 적절한 인스턴스 크기 선택 // CloudWatch 메트릭으로 사용률 모니터링 // 3. 스토리지 최적화 // - GP3로 전환 (GP2 대비 20% 저렴) // - 불필요한 스냅샷 삭제 // 4. 읽기 복제본 활용 // 읽기 전용 쿼리를 복제본으로 분산 const readConnection = await mysql.createConnection({ host: 'mydb-replica.abc123.us-east-1.rds.amazonaws.com', // 읽기 복제본 // ... }); // 5. Aurora Serverless v2 고려 // 사용량에 따라 자동 확장

DynamoDB 비용 최적화

// 1. 온디맨드 vs 프로비저닝 선택 // 예측 가능한 트래픽: 프로비저닝 모드 + 오토스케일링 // 2. TTL(Time To Live) 활용 async function createSession(sessionId, data) { await docClient.send(new PutCommand({ TableName: 'Sessions', Item: { sessionId, ...data, ttl: Math.floor(Date.now() / 1000) + (24 * 60 * 60) // 24시간 후 자동 삭제 } })); } // 3. 프로젝션 최소화 // 필요한 속성만 조회 const result = await docClient.send(new QueryCommand({ TableName: 'Users', ProjectionExpression: 'userId, #n, email', // 필요한 필드만 ExpressionAttributeNames: { '#n': 'name' }, // ... })); // 4. 배치 작업 활용 // 단일 요청 대신 배치로 처리 (비용 절감) const batchWrite = new BatchWriteCommand({ RequestItems: { 'Users': items.map(item => ({ PutRequest: { Item: item } })) } }); // 5. DAX(DynamoDB Accelerator) 고려 // 빈번한 읽기 작업에 캐싱 레이어 추가

Part 7: 모니터링 및 문제 해결

RDS 모니터링

// CloudWatch 메트릭 주요 지표 // // - CPUUtilization: CPU 사용률 (>80% 지속 시 확장 고려) // - DatabaseConnections: 연결 수 // - FreeableMemory: 사용 가능한 메모리 // - ReadLatency/WriteLatency: 읽기/쓰기 지연 시간 // - ReadIOPS/WriteIOPS: 초당 I/O 작업 // 슬로우 쿼리 로그 활성화 const enableSlowQueryLog = { DBInstanceIdentifier: 'mydb', CloudwatchLogsExportConfiguration: { EnableLogTypes: ['slowquery'] } }; // 일반적인 성능 문제 해결 async function optimizeQuery() { // ❌ 인덱스 없이 전체 테이블 스캔 const slowQuery = ` SELECT * FROM orders WHERE created_at > '2024-01-01' `; // ✅ 인덱스 추가 await connection.execute(` CREATE INDEX idx_orders_created_at ON orders(created_at) `); // ✅ 필요한 컬럼만 선택 const fastQuery = ` SELECT order_id, amount, created_at FROM orders WHERE created_at > '2024-01-01' `; }

DynamoDB 모니터링

// CloudWatch 메트릭 주요 지표 // // - ConsumedReadCapacityUnits/ConsumedWriteCapacityUnits // - ThrottledRequests: 제한된 요청 수 (0이어야 함) // - SystemErrors: 시스템 오류 // - UserErrors: 사용자 오류 (잘못된 요청) // 일반적인 문제: 핫 파티션 // ❌ 나쁜 설계: 날짜를 파티션 키로 사용 { "date": "2024-01-15", // 모든 오늘 데이터가 같은 파티션에 "eventId": "evt-123", // ... } // ✅ 좋은 설계: 높은 카디널리티의 파티션 키 { "deviceId": "device-abc-123", // 디바이스별로 분산 "timestamp": 1705315200, // ... } // 재시도 로직 구현 async function writeWithRetry(item, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { await docClient.send(new PutCommand({ TableName: 'MyTable', Item: item })); return; } catch (error) { if (error.name === 'ProvisionedThroughputExceededException') { // 지수 백오프로 재시도 await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 100) ); } else { throw error; } } } throw new Error('Max retries exceeded'); }

의사결정 플로우차트

시작 ├─ 복잡한 JOIN이 필요한가? │ ├─ Yes → RDS │ └─ No → 다음 ├─ ACID 트랜잭션이 필수인가? │ ├─ Yes → RDS │ └─ No → 다음 ├─ 초당 수천~수만 건의 요청? │ ├─ Yes → DynamoDB │ └─ No → 다음 ├─ 키-값 조회가 주된 패턴? │ ├─ Yes → DynamoDB │ └─ No → 다음 ├─ 복잡한 분석 쿼리 필요? │ ├─ Yes → RDS │ └─ No → 다음 ├─ 완전 서버리스 아키텍처? │ ├─ Yes → DynamoDB │ └─ No → RDS 또는 DynamoDB

추가 학습 자료

공식 문서

권장 학습 경로

  1. 기초: AWS 공식 문서 시작하기
  2. 실습: AWS Free Tier로 직접 테스트
  3. 심화: Re:Invent 세션 및 워크샵
  4. 실전: 작은 프로젝트로 실제 적용

관련 AWS 서비스

  • Amazon Aurora Serverless: RDS의 서버리스 옵션
  • DynamoDB Streams: 변경 데이터 캡처
  • AWS Database Migration Service: 데이터베이스 마이그레이션
  • Amazon ElastiCache: 인메모리 캐싱 (RDS 성능 향상)
  • DAX: DynamoDB 전용 캐싱

결론

RDS와 DynamoDB는 각각 고유한 장점을 가진 훌률한 데이터베이스 서비스입니다:

RDS를 선택하세요:

  • 복잡한 관계형 데이터와 쿼리
  • ACID 트랜잭션이 필수
  • 기존 SQL 애플리케이션 마이그레이션

DynamoDB를 선택하세요:

  • 대규모 확장성과 빠른 응답 시간
  • 키-값 기반 간단한 액세스 패턴
  • 서버리스 아키텍처

많은 경우, 두 서비스를 함께 사용하는 하이브리드 접근 방식이 최선의 선택이 될 수 있습니다. 각 데이터의 특성과 액세스 패턴을 분석하여 적절한 데이터베이스를 선택하세요.


버전 정보:

  • 작성일: 2026-01-27
  • AWS SDK 버전: v3 (JavaScript)
  • 대상 독자: 초급~중급 개발자

댓글

developjik
All content is licensed under CC BY-NC-SA 4.0 unless otherwise noted.