면접 준비 1

공보경·2025년 6월 23일

면접 준비

목록 보기
1/5

웹 기술 면접 준비 가이드

30초~1분 내외 답변 가능한 핵심 내용 정리

목차

웹 기술

  1. SPA vs MPA 관련 프레임워크
  2. CSS Grid Layout 활용 경험
  3. 브라우저 저장소 4가지
  4. 백엔드-프론트엔드 통신 프로토콜 4가지
  5. 웹팩(Webpack) 번들링
  6. Critical Rendering Path
  7. www.google.com 입력 시 일어나는 과정
  8. 웹 렌더링 방식 (CSR, SSR, SSG)
  9. REST API 개념
  10. API 설계 방법과 경험
  11. UML (Unified Modeling Language)

네트워크/보안

  1. HTTP, TCP, UDP의 차이점
  2. 세션 쿠키 vs JWT

시스템/인프라

  1. 컴퓨터 프로그램 실행 시 메모리/CPU 동작 원리
  2. 도커 컨테이너 사용 이유 (OS 측면)
  3. 프로세스와 스레드 차이점
  4. 스레드의 정의와 특징
  5. C언어와 C++ 차이점
  6. C언어와 Java 차이점
  7. 인터넷과 인트라넷 차이점
  8. AWS VPC CIDR 개념

알고리즘/자료구조

  1. 시간 복잡도의 정의와 표기법

데이터베이스

  1. CAP 이론
  2. MongoDB와 NoSQL 개념
  3. LEFT JOIN 개념
  4. 오라클 윈도우 함수
  5. 메인쿼리와 서브쿼리 실행 순서
  6. 오라클 vs MySQL 차이점
  7. 트랜잭션 ACID 개념
  8. DB 모델링 툴
  9. 인덱스 사용의 이점과 주의사항

1. SPA vs MPA 관련 프레임워크

SPA (Single Page Application) 프레임워크

프레임워크특징
React• 컴포넌트 기반 아키텍처
• Virtual DOM 사용으로 성능 최적화
• 단방향 데이터 플로우
Vue.js• 점진적 프레임워크
• 러닝커브가 낮음
• 템플릿 기반 문법
Angular• 완전한 프레임워크 (Full Framework)
• TypeScript 기반
• 의존성 주입, RxJS 내장

MPA (Multi Page Application) 프레임워크

프레임워크특징
Next.js• React 기반 SSR/SSG 프레임워크
• 파일 기반 라우팅
• 자동 코드 분할
Nuxt.js• Vue 기반 SSR/SSG 프레임워크
• 규약 기반 개발
• 자동 라우팅 생성
SvelteKit• Svelte 기반 풀스택 프레임워크
• 컴파일 타임 최적화
• 번들 크기 최소화

📚 참고 링크


2. CSS Grid Layout 활용 경험

핵심 개념

CSS Grid는 2차원 레이아웃 시스템으로 행과 열을 동시에 제어할 수 있습니다.

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 20px;
}

주요 구성 요소

  • Grid Container: display: grid가 적용된 부모 요소
  • Grid Items: Grid Container의 직접 자식 요소들
  • Grid Lines: 그리드를 구분하는 선들
  • Grid Areas: 그리드 셀들로 이루어진 사각형 영역

강력한 기능들

  • fr 단위: 사용 가능한 공간의 비율 할당
  • minmax() 함수: 최소/최대 크기 제한
  • repeat() 함수: 반복 패턴 정의
  • Grid Areas: 의미있는 이름으로 영역 정의

실무 활용 예시

  • 📱 반응형 카드 레이아웃
  • 📊 대시보드 및 관리자 패널
  • 🖼️ 이미지 갤러리
  • 📄 신문/매거진 스타일 레이아웃

📚 참고 링크


3. 브라우저 저장소 4가지

저장소용량지속성서버 전송특징
쿠키(Cookie)4KB만료일까지✅ 자동 전송• HTTP 헤더에 포함
• 인증, 세션 관리용
로컬스토리지5-10MB영구 저장❌ 수동 전송• 같은 도메인 내 공유
• 사용자 설정 저장
세션스토리지5-10MB탭 종료시 삭제❌ 수동 전송• 탭 단위 저장
• 임시 데이터 저장
인덱스드DB용량 큼영구 저장❌ 수동 전송• NoSQL 데이터베이스
• 복잡한 데이터 저장

사용 예시

// 로컬스토리지
localStorage.setItem('theme', 'dark');

// 세션스토리지
sessionStorage.setItem('tempData', JSON.stringify(data));

// 쿠키
document.cookie = "username=john; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/";

📚 참고 링크


4. 백엔드-프론트엔드 통신 프로토콜 4가지

1. HTTP/HTTPS

  • 특징: 웹의 기본 프로토콜, 상태가 없는(Stateless) 프로토콜
  • 사용 사례: RESTful API, 일반적인 웹 통신
  • 장점: 간단하고 널리 지원됨
  • 단점: 실시간 통신에는 부적합

2. WebSocket

  • 특징: 실시간 양방향 통신 프로토콜
  • 사용 사례: 채팅, 게임, 실시간 알림
  • 장점: 지연시간 최소화, 서버에서 클라이언트로 푸시 가능
  • 단점: 연결 유지로 인한 리소스 소모

3. GraphQL

  • 특징: 쿼리 언어 및 런타임, 필요한 데이터만 요청 가능
  • 사용 사례: 복잡한 데이터 요구사항, 모바일 앱
  • 장점: Over-fetching 방지, 강력한 타입 시스템
  • 단점: 학습 곡선, 캐싱 복잡성

4. gRPC

  • 특징: 고성능 RPC 프레임워크, Protocol Buffers 사용
  • 사용 사례: 마이크로서비스 간 통신, 고성능 API
  • 장점: 빠른 성능, 강력한 타입 안정성
  • 단점: 브라우저 지원 제한적

5. 웹팩(Webpack) 번들링

핵심 개념

웹팩은 모듈 번들러로, 여러 파일을 하나의 번들로 결합합니다.

// webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      { test: /\.js$/, use: 'babel-loader' },
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  }
};

주요 장점

  • 🌐 네트워크 요청 최소화: 여러 파일 → 1개 파일
  • 📦 의존성 관리: 모듈 간 관계 자동 처리
  • ⚡ 최적화: 코드 분할, Tree Shaking 지원
  • 🔥 개발 편의성: Hot Module Replacement (HMR)

최적화 기능

  • Code Splitting: 필요한 코드만 로드
  • Tree Shaking: 사용하지 않는 코드 제거
  • Minification: 코드 압축
  • Lazy Loading: 지연 로딩

📚 참고 링크


6. Critical Rendering Path

정의

브라우저가 HTML, CSS, JavaScript를 화면에 픽셀로 변환하는 일련의 과정

렌더링 과정 (5단계)

graph LR
    A[HTML 파싱] --> B[DOM 구성]
    C[CSS 파싱] --> D[CSSOM 구성]
    B --> E[Render Tree]
    D --> E
    E --> F[Layout 계산]
    F --> G[Paint 실행]
단계설명특징
1. DOM 구성HTML 파싱 → DOM 트리 생성점진적 처리 가능
2. CSSOM 구성CSS 파싱 → CSSOM 트리 생성전체 CSS 처리 후 진행
3. Render TreeDOM + CSSOM 결합보이는 요소만 포함
4. Layout요소 위치/크기 계산Reflow 발생 지점
5. Paint화면에 픽셀 그리기Repaint 발생 지점

최적화 방법

  • Critical CSS: 첫 화면 렌더링에 필요한 CSS만 인라인으로 포함
  • 📦 리소스 압축: CSS, JS 파일 크기 최소화
  • 지연 로딩: 중요하지 않은 리소스는 나중에 로드
  • 🚀 리소스 힌트: preload, prefetch, preconnect 활용

📚 참고 링크


7. www.google.com 입력 시 일어나는 과정

전체 과정 (6단계)

sequenceDiagram
    participant U as 사용자
    participant B as 브라우저
    participant D as DNS 서버
    participant S as 웹 서버
    
    U->>B: www.google.com 입력
    B->>D: DNS 조회 요청
    D->>B: IP 주소 반환
    B->>S: TCP 연결 설정
    B->>S: HTTP GET 요청
    S->>B: HTML 응답
    B->>B: 렌더링 시작

상세 단계별 설명

1. 🔍 DNS 조회

  • 목적: 도메인 이름을 IP 주소로 변환
  • 과정: Local Cache → Router → ISP DNS → Root DNS → TLD DNS → Authoritative DNS
  • 결과: www.google.com172.217.175.4

2. 🤝 TCP 연결

  • 방식: 3-way handshake
  • 과정: SYN → SYN-ACK → ACK
  • 목적: 안정적인 연결 설정

3. 📤 HTTP 요청

GET / HTTP/1.1
Host: www.google.com
User-Agent: Mozilla/5.0...
Accept: text/html,application/xhtml+xml...

4. 📥 서버 응답

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 12345
Set-Cookie: ...

<!DOCTYPE html>
<html>...

5. 🎨 브라우저 렌더링

  • Critical Rendering Path 실행
  • DOM 구성 → CSSOM 구성 → Render Tree → Layout → Paint

6. 📦 리소스 로딩

  • CSS, JavaScript, 이미지 등 추가 리소스 병렬 다운로드
  • 렌더링과 병행하여 진행

📚 참고 링크


8. 웹 렌더링 방식 (CSR, SSR, SSG)

렌더링 방식 비교

방식렌더링 위치초기 로딩SEO사용자 경험
CSR클라이언트느림불리빠른 페이지 전환
SSR서버빠름유리매번 서버 요청
SSG빌드 타임매우 빠름매우 유리빠름 + 캐싱 가능

1. CSR (Client-Side Rendering)

  • 특징: 브라우저에서 JavaScript로 렌더링
  • 장점:
    • 빠른 페이지 전환
    • 서버 부하 감소
    • 풍부한 사용자 상호작용
  • 단점:
    • 초기 로딩 시간 길음
    • SEO 어려움
    • JavaScript 비활성화 시 동작 불가

2. SSR (Server-Side Rendering)

  • 특징: 서버에서 HTML을 완성해서 전달
  • 장점:
    • 빠른 초기 로딩
    • SEO 친화적
    • 검색엔진 크롤러가 완성된 HTML 확인 가능
  • 단점:
    • 서버 부하 증가
    • 매 요청마다 서버 처리 필요
    • TTFB(Time To First Byte) 증가

3. SSG (Static Site Generation)

  • 특징: 빌드 시점에 정적 HTML 생성
  • 장점:
    • 매우 빠른 로딩 속도
    • CDN 캐싱 최적화
    • 서버 부하 최소화
    • SEO 완벽 지원
  • 단점:
    • 동적 콘텐츠 처리 어려움
    • 빌드 시간 증가 (대규모 사이트)
    • 실시간 데이터 업데이트 제한

SSR이 SEO에 유리한 이유

1. 🤖 검색엔진 크롤링

  • 완성된 HTML: 검색엔진이 페이지 내용을 바로 읽을 수 있음
  • 메타 태그: <title>, <meta description> 등이 서버에서 생성되어 즉시 확인 가능
  • 구조화된 데이터: JSON-LD, Open Graph 등이 HTML에 포함되어 전달

2. ⚡ 빠른 초기 렌더링

  • First Contentful Paint (FCP) 개선
  • Largest Contentful Paint (LCP) 최적화
  • Core Web Vitals 점수 향상으로 검색 순위 개선

3. 🔗 소셜 미디어 최적화

  • Open Graph: Facebook, LinkedIn 등에서 링크 미리보기 가능
  • Twitter Cards: 트위터에서 풍부한 콘텐츠 표시
  • 즉시 메타데이터: JavaScript 실행 없이 소셜 미디어가 콘텐츠 인식

실무 선택 기준

CSR 적합한 경우

  • 대시보드, 관리자 패널
  • 사용자 인터랙션이 많은 애플리케이션
  • SEO가 중요하지 않은 내부 도구

SSR 적합한 경우

  • 블로그, 뉴스 사이트
  • 전자상거래 사이트
  • SEO가 매우 중요한 웹사이트

SSG 적합한 경우

  • 기업 소개 사이트
  • 문서화 사이트
  • 블로그 (정적 콘텐츠)

📚 참고 링크


9. REST API 개념

REST API 정의

Representational State Transfer API - 웹의 기본 원칙을 활용한 아키텍처 스타일

REST 6가지 원칙

1. 균등한 인터페이스 (Uniform Interface)

GET /users/123        # 사용자 조회
POST /users          # 사용자 생성
PUT /users/123       # 사용자 수정
DELETE /users/123    # 사용자 삭제

2. 무상태성 (Stateless)

// ❌ Bad: 세션 의존적
GET /api/next-page
Cookie: session=abc123

// ✅ Good: 자체 포함된 요청
GET /api/users?page=2&limit=10

HTTP 메소드별 특징

HTTP 메소드목적안전성멱등성캐시 가능
GET조회OOO
POST생성XXX
PUT수정/생성XOX
PATCH부분 수정XXX
DELETE삭제XOX

RESTful API 설계 예시

// Express.js 예시
const app = express();

// 리소스 중심의 URL 설계
app.get('/api/v1/users', getAllUsers);           
app.get('/api/v1/users/:id', getUserById);       
app.post('/api/v1/users', createUser);           
app.put('/api/v1/users/:id', updateUser);        
app.delete('/api/v1/users/:id', deleteUser);     

// 중첩 리소스
app.get('/api/v1/users/:userId/posts', getUserPosts);

📚 참고 링크


10. API 설계 방법과 경험

API 설계 단계별 접근법

1. 요구사항 분석

## API 요구사항 예시
- 사용자 관리 (CRUD)
- 인증/인가 기능
- 페이징 처리
- 검색 기능

2. URL 구조 설계

GET /api/v1/users                    # 사용자 목록
GET /api/v1/users/123               # 특정 사용자
GET /api/v1/users/123/posts         # 사용자의 게시글
GET /api/v1/users?page=1&limit=10   # 페이징

3. 응답 구조 표준화

// 성공 응답
{
  "success": true,
  "data": {
    "users": [...],
    "pagination": {
      "current_page": 1,
      "total_pages": 10
    }
  }
}

// 에러 응답
{
  "success": false,
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "해당 사용자를 찾을 수 없습니다."
  }
}

📚 참고 링크


11. UML (Unified Modeling Language)

UML 정의

통합 모델링 언어 - 소프트웨어 개발에서 시스템의 구조와 동작을 시각적으로 표현하는 표준 모델링 언어

UML 다이어그램 분류

1. 클래스 다이어그램

┌─────────────────┐
│      User       │
├─────────────────┤
│ - id: long      │
│ - name: String  │
│ - email: String │
├─────────────────┤
│ + getId()       │
│ + setName()     │
└─────────────────┘
        │ 1:N
        ▼
┌─────────────────┐
│      Post       │
├─────────────────┤
│ - id: long      │
│ - title: String │
│ - content: Text │
└─────────────────┘

2. 시퀀스 다이어그램

Client → Server → Database
  │        │         │
  │─login──→│         │
  │        │─query───→│
  │        │←result──│
  │←token──│         │

UML 관계 표현

관계 유형표기법의미
연관────클래스 간 참조 관계
집합◇────전체-부분 관계
합성◆────강한 소유 관계
상속△────일반화/특수화

📚 참고 링크


12. HTTP, TCP, UDP의 차이점

프로토콜 계층별 분류

프로토콜계층연결성신뢰성속도용도
HTTP응용 계층 (7층)무상태높음보통웹 통신
TCP전송 계층 (4층)연결형높음느림신뢰성 중요
UDP전송 계층 (4층)비연결형낮음빠름실시간 통신

1. HTTP (HyperText Transfer Protocol)

  • 특징: 웹에서 데이터를 주고받는 응용 계층 프로토콜
  • 동작 방식: Request-Response 구조
  • 상태: Stateless (무상태)
  • 기반: TCP 위에서 동작
  • 포트: 80 (HTTP), 443 (HTTPS)

2. TCP (Transmission Control Protocol)

  • 특징: 신뢰성 있는 연결형 프로토콜
  • 연결 설정: 3-way handshake
  • 데이터 전송: 순서 보장, 오류 검출/복구
  • 흐름 제어: 송신자와 수신자 간 데이터 전송 속도 조절
  • 사용 예시: HTTP, HTTPS, FTP, SMTP

3. UDP (User Datagram Protocol)

  • 특징: 빠르고 간단한 비연결형 프로토콜
  • 연결 설정: 없음 (바로 전송)
  • 데이터 전송: 순서 보장 없음, 오류 검출 최소화
  • 오버헤드: 매우 낮음
  • 사용 예시: DNS, 게임, 실시간 스트리밍

📚 참고 링크


13. 세션 쿠키 vs JWT

인증 방식 비교

구분세션 쿠키JWT
저장 위치서버 (세션), 클라이언트 (쿠키)클라이언트만
상태 관리StatefulStateless
확장성서버 부하 증가서버 부하 적음
보안성서버에서 제어 가능토큰 탈취 위험
크기작음 (Session ID만)큼 (Payload 포함)

세션 쿠키 방식

// 로그인 성공 시
req.session.userId = user.id;
res.cookie('sessionId', req.session.id, {
  httpOnly: true,
  secure: true,
  maxAge: 3600000 // 1시간
});

장점:

  • 서버에서 세션 제어 가능 (강제 로그아웃 등)
  • 민감한 정보를 서버에 저장
  • 세션 무효화 즉시 적용

단점:

  • 서버 메모리/DB 사용량 증가
  • 분산 서버 환경에서 세션 공유 복잡
  • 서버 상태에 의존적

JWT (JSON Web Token)

// JWT 생성
const token = jwt.sign(
  { userId: user.id, role: user.role },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

// 헤더에 포함
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

구조: Header.Payload.Signature

장점:

  • Stateless 서버 구현 가능
  • 분산 시스템에 유리
  • 서버 부하 감소
  • Cross-domain 인증 용이

단점:

  • 토큰 탈취 시 무효화 어려움
  • 토큰 크기가 상대적으로 큼
  • Payload 정보 노출 가능성

JWT Stateless의 의미

🔍 Stateless란?

서버가 클라이언트의 상태 정보를 저장하지 않는 것

// 세션 방식 (Stateful)
// 서버가 세션 정보를 메모리/DB에 저장
server.sessions = {
  "session123": { userId: 1, loginTime: "2024-12-01" }
}

// JWT 방식 (Stateless)  
// 모든 정보가 토큰 자체에 포함됨
const token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsImV4cCI6MTcwMzk5NzYwMH0.signature"
// 서버는 별도 저장소에 상태 정보를 보관하지 않음

💡 Stateless의 장점

  • 확장성: 여러 서버에서 토큰 검증 가능 (로드밸런싱 유리)
  • 독립성: 서버 재시작해도 토큰은 계속 유효
  • 분산 시스템: 마이크로서비스 간 인증 정보 공유 용이

JWT 서명 및 검증 과정

1. 대칭키 서명 (HMAC)

const jwt = require('jsonwebtoken');
const crypto = require('crypto');

// 대칭키 생성 (서버만 알고 있음)
const secretKey = 'your-256-bit-secret';

// JWT 생성 (서명)
const payload = { 
  userId: 123, 
  role: 'user',
  exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1시간
};

const token = jwt.sign(payload, secretKey, { algorithm: 'HS256' });
console.log('생성된 토큰:', token);

// JWT 검증
try {
  const decoded = jwt.verify(token, secretKey);
  console.log('검증 성공:', decoded);
  // { userId: 123, role: 'user', exp: 1703997600, iat: 1703994000 }
} catch (error) {
  console.log('검증 실패:', error.message);
}

2. 비대칭키 서명 (RSA)

// RSA 키 쌍 생성
const { generateKeyPairSync } = require('crypto');

const { publicKey, privateKey } = generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: { type: 'spki', format: 'pem' },
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});

// 개인키로 서명 (서버에서만 가능)
const token = jwt.sign(
  { userId: 123, role: 'admin' },
  privateKey,
  { algorithm: 'RS256', expiresIn: '1h' }
);

// 공개키로 검증 (어디서든 가능)
try {
  const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
  console.log('검증 성공:', decoded);
} catch (error) {
  console.log('검증 실패:', error.message);
}

3. 서버에서 JWT 검증 미들웨어

// Express.js 미들웨어 예시
const authenticateToken = (req, res, next) => {
  // Authorization 헤더에서 토큰 추출
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
  
  if (!token) {
    return res.status(401).json({ error: '토큰이 없습니다' });
  }
  
  // 토큰 검증
  jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
    if (err) {
      if (err.name === 'TokenExpiredError') {
        return res.status(401).json({ error: '토큰이 만료되었습니다' });
      } else if (err.name === 'JsonWebTokenError') {
        return res.status(401).json({ error: '유효하지 않은 토큰입니다' });
      }
      return res.status(403).json({ error: '토큰 검증 실패' });
    }
    
    // 검증 성공 시 사용자 정보를 req 객체에 저장
    req.user = decoded;
    next();
  });
};

// 보호된 라우트 사용
app.get('/protected', authenticateToken, (req, res) => {
  res.json({ 
    message: '인증된 사용자만 접근 가능',
    user: req.user 
  });
});

4. 대칭키 vs 비대칭키 비교

구분대칭키 (HMAC)비대칭키 (RSA)
키 개수1개 (공유 비밀키)2개 (공개키/개인키)
서명비밀키로 서명개인키로 서명
검증같은 비밀키로 검증공개키로 검증
성능빠름느림
보안키 노출 시 위험개인키만 안전하게 보관
사용 사례단일 서버분산 시스템, 마이크로서비스

5. JWT 구조 분석

Header.Payload.Signature

// Header (Base64 인코딩)
{
  "alg": "HS256",  // 알고리즘
  "typ": "JWT"     // 토큰 타입
}

// Payload (Base64 인코딩)
{
  "userId": 123,
  "role": "user",
  "iat": 1703994000,  // 발급 시간
  "exp": 1703997600   // 만료 시간
}

// Signature (서명)
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

JWT 보안 고려사항

  • 저장 위치: httpOnly 쿠키 또는 메모리
  • 만료 시간: 짧게 설정 (Access Token + Refresh Token)
  • 암호화: 중요한 정보는 암호화하여 저장
  • 키 관리: 비밀키/개인키 안전한 보관
  • 알고리즘 검증: verify 시 허용된 알고리즘만 사용

📚 참고 링크


14. 컴퓨터 프로그램 실행 시 메모리/CPU 동작 원리

프로그램 실행 과정

graph LR
    A[소스 코드] --> B[컴파일러]
    B --> C[실행 파일]
    C --> D[로더]
    D --> E[메모리 적재]
    E --> F[CPU 실행]

1. 메모리 구조 (4개 영역)

영역용도특징관리
코드 영역실행 코드 저장읽기 전용OS
데이터 영역전역/정적 변수프로그램 종료까지OS
힙 영역동적 할당 메모리런타임 크기 결정프로그래머
스택 영역지역 변수, 함수 호출LIFO 구조컴파일러

2. CPU 동작 원리

Fetch-Decode-Execute 사이클

1. Fetch (인출): 메모리에서 명령어를 가져옴
2. Decode (해석): 명령어를 해석하여 제어 신호 생성
3. Execute (실행): ALU에서 연산 수행
4. Write Back (저장): 결과를 레지스터/메모리에 저장

3. 프로그램 실행 단계별 과정

① 프로그램 로딩

  • 로더가 실행 파일을 메모리에 적재
  • 코드, 데이터 영역을 메모리에 복사
  • 프로세스 제어 블록(PCB) 생성

② 메모리 할당

// 스택 영역 (자동 관리)
int localVar = 10;

// 힙 영역 (수동 관리)
int* ptr = malloc(sizeof(int));

③ CPU 실행

  • 프로그램 카운터(PC)가 다음 실행할 명령어 주소 저장
  • 레지스터에 임시 데이터 저장
  • 캐시 메모리로 자주 사용하는 데이터 빠른 접근

4. 성능 최적화 요소

메모리 계층 구조

레지스터 (가장 빠름, 가장 작음)
↓
L1 캐시
↓
L2 캐시
↓
L3 캐시
↓
주 메모리 (RAM)
↓
보조 메모리 (SSD/HDD) (가장 느림, 가장 큼)

📚 참고 링크


15. 도커 컨테이너 사용 이유 (OS 측면)

가상화 방식 비교

구분기존 가상머신도커 컨테이너
가상화 수준하드웨어 수준OS 수준
게스트 OS필요불필요
리소스 사용량높음낮음
부팅 시간느림 (분 단위)빠름 (초 단위)
격리 수준완전 격리프로세스 수준 격리

1. OS 레벨 가상화의 장점

① 리소스 효율성

기존 VM:
Host OS → Hypervisor → Guest OS → App

Docker:
Host OS → Docker Engine → Container (App)
  • 오버헤드 최소화: Guest OS 불필요
  • 메모리 절약: OS 커널 공유
  • CPU 효율성: 네이티브 성능에 근접

② 빠른 시작/종료

  • 부팅 시간: 초 단위 (vs VM의 분 단위)
  • 프로세스 격리: OS 커널 공유로 빠른 실행
  • 이미지 계층화: 변경된 부분만 업데이트

2. 컨테이너 격리 기술

네임스페이스 (Namespace)

# 프로세스 격리
PID namespace: 프로세스 ID 격리
Network namespace: 네트워크 인터페이스 격리
Mount namespace: 파일 시스템 마운트 격리
User namespace: 사용자 ID 격리

컨트롤 그룹 (Cgroups)

  • CPU 제한: CPU 사용량 제어
  • 메모리 제한: 메모리 사용량 제어
  • I/O 제한: 디스크/네트워크 대역폭 제어

3. 도커의 핵심 이점

① 환경 일관성

FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

"내 컴퓨터에서는 되는데?" 문제 해결

② 배포 간소화

  • 이미지 기반: 전체 환경을 이미지로 패키징
  • 버전 관리: 이미지 태그로 버전 관리
  • 롤백 용이: 이전 이미지로 즉시 롤백

③ 마이크로서비스 아키텍처

  • 서비스 분리: 각 서비스를 독립적인 컨테이너로
  • 확장성: 필요한 서비스만 스케일 아웃
  • 장애 격리: 한 컨테이너 장애가 다른 서비스에 영향 최소화

4. 실무 활용 시나리오

개발 환경 통일

# docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
  db:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp

CI/CD 파이프라인

  1. 빌드: 코드 → 도커 이미지
  2. 테스트: 컨테이너에서 자동 테스트
  3. 배포: 프로덕션 환경에 컨테이너 배포

📚 참고 링크


16. 프로세스와 스레드 차이점

기본 개념 비교

구분프로세스스레드
정의실행 중인 프로그램프로세스 내 실행 단위
메모리 공유독립적일부 공유
생성 비용높음낮음
통신 방법IPC (복잡)메모리 공유 (간단)
안정성높음 (격리)낮음 (영향 받음)

1. 메모리 구조 차이

프로세스 메모리 구조

Process A          Process B
┌─────────────┐    ┌─────────────┐
│   Stack     │    │   Stack     │
├─────────────┤    ├─────────────┤
│    Heap     │    │    Heap     │
├─────────────┤    ├─────────────┤
│    Data     │    │    Data     │
├─────────────┤    ├─────────────┤
│    Code     │    │    Code     │
└─────────────┘    └─────────────┘
   독립적 메모리         독립적 메모리

스레드 메모리 구조

        Process
┌─────────────────────┐
│ Thread1 │ Thread2   │ ← Stack (독립)
│ Stack   │ Stack     │
├─────────────────────┤
│      Heap           │ ← 공유
├─────────────────────┤
│      Data           │ ← 공유
├─────────────────────┤
│      Code           │ ← 공유
└─────────────────────┘

2. 메모리 영역별 저장 위치

스택(Stack) 영역

  • 프로세스: 각 프로세스마다 독립적인 스택
  • 스레드: 각 스레드마다 독립적인 스택
  • 저장 내용: 지역 변수, 함수 매개변수, 리턴 주소
void function() {
    int localVar = 10;  // 각 스레드의 스택에 독립적으로 저장
    // 스레드 간 서로 다른 localVar 값 가능
}

힙(Heap) 영역

  • 프로세스: 각 프로세스마다 독립적인 힙
  • 스레드: 같은 프로세스 내 스레드들이 힙 공유
  • 저장 내용: 동적 할당된 메모리
int* ptr = malloc(sizeof(int));  // 같은 프로세스 내 모든 스레드가 접근 가능
*ptr = 20;  // 스레드 간 공유되는 데이터

3. 프로세스 vs 스레드 생성

프로세스 생성 (fork)

#include <unistd.h>

int main() {
    pid_t pid = fork();  // 새로운 프로세스 생성
    
    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process\n");
    } else {
        // 부모 프로세스
        printf("Parent Process\n");
    }
    return 0;
}

스레드 생성 (pthread)

#include <pthread.h>

void* thread_function(void* arg) {
    printf("Thread running\n");
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, NULL);  // 스레드 생성
    pthread_join(thread, NULL);  // 스레드 종료 대기
    return 0;
}

4. 통신 방법

프로세스 간 통신 (IPC)

  • 파이프: 단방향 통신
  • 소켓: 네트워크 통신
  • 공유 메모리: 빠른 데이터 교환
  • 메시지 큐: 비동기 메시지 전달

스레드 간 통신

// 전역 변수 공유
int shared_data = 0;

void* thread1(void* arg) {
    shared_data = 100;  // 공유 변수 수정
    return NULL;
}

void* thread2(void* arg) {
    printf("%d\n", shared_data);  // 공유 변수 읽기
    return NULL;
}

5. 동기화 문제와 해결

경쟁 상태 (Race Condition)

int counter = 0;

void* increment(void* arg) {
    for (int i = 0; i < 1000000; i++) {
        counter++;  // 위험! 동시 접근 시 데이터 손실
    }
    return NULL;
}

뮤텍스 (Mutex) 해결

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* safe_increment(void* arg) {
    for (int i = 0; i < 1000000; i++) {
        pthread_mutex_lock(&mutex);
        counter++;  // 안전한 접근
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

📚 참고 링크


17. 스레드의 정의와 특징

스레드 정의

Thread - 프로세스 내에서 실행되는 여러 실행 흐름의 단위로, CPU 이용의 기본 단위

스레드 vs 프로세스 비교

구분프로세스스레드
정의실행 중인 프로그램프로세스 내의 실행 단위
메모리독립적 메모리 공간프로세스 내 메모리 공유
생성 비용높음낮음
통신 방법IPC (파이프, 소켓)공유 메모리
독립성완전 독립부분 독립

스레드 메모리 구조

┌─────────────────────────────────┐
│          프로세스 메모리          │
├─────────────────────────────────┤
│         코드 영역 (공유)         │  ← 모든 스레드 공유
├─────────────────────────────────┤
│         데이터 영역 (공유)        │  ← 전역변수, 정적변수
├─────────────────────────────────┤
│          힙 영역 (공유)          │  ← 동적 할당 메모리
├─────────────────────────────────┤
│    스택 영역 1 (스레드 1 전용)    │  ← 각 스레드별 독립
├─────────────────────────────────┤
│    스택 영역 2 (스레드 2 전용)    │  ← 지역변수, 함수 호출
└─────────────────────────────────┘

멀티스레드 구현 예시

Java 스레드

// Thread 클래스 상속
class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}

// 사용 예시
public static void main(String[] args) {
    MyThread thread1 = new MyThread();
    thread1.start();
    
    // Lambda 표현식
    Thread thread2 = new Thread(() -> {
        for (int i = 0; i < 5; i++) {
            System.out.println("Lambda Thread: " + i);
        }
    });
    thread2.start();
}

스레드 장단점

장점

  • 성능 향상: 멀티코어 CPU 활용
  • 응답성: 비동기 작업 처리
  • 자원 효율성: 프로세스보다 적은 메모리 사용
  • 공유 용이성: 메모리 공간 공유

단점

  • 복잡성: 동기화 문제
  • 디버깅 어려움: 비결정적 실행
  • 교착상태: 데드락 위험
  • 컨텍스트 스위칭: 오버헤드

📚 참고 링크


18. C언어와 C++ 차이점

기본 차이점

구분CC++
패러다임절차지향객체지향 + 절차지향
개발년도1972년1985년
확장자.c.cpp, .cxx
컴파일러gccg++, cl
표준 라이브러리작음매우 큼 (STL 포함)

프로그래밍 패러다임

C - 절차지향

// C 스타일 - 함수 중심
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x, y;
} Point;

Point* createPoint(int x, int y) {
    Point* p = malloc(sizeof(Point));
    p->x = x;
    p->y = y;
    return p;
}

void printPoint(Point* p) {
    printf("Point: (%d, %d)\n", p->x, p->y);
}

int main() {
    Point* p = createPoint(10, 20);
    printPoint(p);
    free(p);
    return 0;
}

C++ - 객체지향

// C++ 스타일 - 클래스 중심
#include <iostream>

class Point {
private:
    int x, y;
    
public:
    Point(int x, int y) : x(x), y(y) {}  // 생성자
    ~Point() {}                          // 소멸자
    
    void print() {
        std::cout << "Point: (" << x << ", " << y << ")" << std::endl;
    }
    
    // 연산자 오버로딩
    Point operator+(const Point& other) {
        return Point(x + other.x, y + other.y);
    }
};

int main() {
    Point p1(10, 20);
    Point p2(5, 15);
    Point p3 = p1 + p2;  // 연산자 오버로딩 사용
    p3.print();
    return 0;
}

주요 차이점

1. 메모리 관리

// C - malloc/free
int* arr = malloc(sizeof(int) * 10);
free(arr);
// C++ - new/delete + 스마트 포인터
int* arr = new int[10];
delete[] arr;

// 스마트 포인터 (C++11)
std::unique_ptr<int[]> arr = std::make_unique<int[]>(10);
// 자동으로 메모리 해제

2. 입출력

// C - printf/scanf
printf("Hello %s\n", name);
scanf("%d", &number);
// C++ - iostream
std::cout << "Hello " << name << std::endl;
std::cin >> number;

3. 문자열 처리

// C - char 배열
char str[100];
strcpy(str, "Hello");
strcat(str, " World");
// C++ - string 클래스
std::string str = "Hello";
str += " World";

C++의 고급 기능

1. 템플릿

template<typename T>
class Vector {
private:
    T* data;
    size_t size;
    
public:
    Vector(size_t size) : size(size) {
        data = new T[size];
    }
    
    T& operator[](size_t index) {
        return data[index];
    }
};

// 사용
Vector<int> intVector(10);
Vector<double> doubleVector(5);

2. STL (Standard Template Library)

#include <vector>
#include <map>
#include <algorithm>

std::vector<int> numbers = {5, 2, 8, 1, 9};
std::sort(numbers.begin(), numbers.end());

std::map<std::string, int> ages;
ages["Alice"] = 25;
ages["Bob"] = 30;

언어 선택 기준

C를 선택하는 경우

  • 시스템 프로그래밍: 운영체제, 드라이버
  • 임베디드 시스템: 메모리 제약이 큰 환경
  • 성능 최우선: 오버헤드 최소화 필요
  • 하드웨어 제어: 직접적인 하드웨어 접근

C++을 선택하는 경우

  • 대규모 애플리케이션: 복잡한 소프트웨어 개발
  • 게임 개발: 성능 + 객체지향
  • GUI 애플리케이션: Qt, MFC 등
  • 고성능 컴퓨팅: 과학 계산, 시뮬레이션

📚 참고 링크


19. C언어와 Java 차이점

기본 특성 비교

구분CJava
패러다임절차지향객체지향
플랫폼플랫폼 의존적플랫폼 독립적 (JVM)
메모리 관리수동 (malloc/free)자동 (GC)
포인터지원미지원
컴파일네이티브 코드바이트코드
실행 속도빠름상대적으로 느림

메모리 관리 비교

C - 수동 메모리 관리

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 동적 메모리 할당
    int* arr = malloc(sizeof(int) * 10);
    
    if (arr == NULL) {
        printf("메모리 할당 실패\n");
        return 1;
    }
    
    // 메모리 사용
    for (int i = 0; i < 10; i++) {
        arr[i] = i * i;
    }
    
    // 수동으로 메모리 해제 (필수!)
    free(arr);
    arr = NULL;  // 댕글링 포인터 방지
    
    return 0;
}

Java - 자동 메모리 관리

public class MemoryExample {
    public static void main(String[] args) {
        // 객체 생성 (힙에 할당)
        int[] arr = new int[10];
        
        // 메모리 사용
        for (int i = 0; i < 10; i++) {
            arr[i] = i * i;
        }
        
        // 메모리 해제 불필요 (GC가 자동 처리)
        // arr = null; // 참조 제거 (선택사항)
    }
}

플랫폼 독립성

C - 플랫폼 의존적

// hello.c
#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

// 컴파일 및 실행
// Windows: gcc hello.c -o hello.exe && hello.exe
// Linux:   gcc hello.c -o hello && ./hello
// 각 플랫폼별로 다른 실행 파일 생성

Java - 플랫폼 독립적

// Hello.java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

// 컴파일 및 실행 (모든 플랫폼에서 동일)
// javac Hello.java  (바이트코드 생성)
// java Hello        (JVM에서 실행)

프로그래밍 스타일 비교

C - 절차지향

// 구조체와 함수 분리
typedef struct {
    int balance;
    char owner[50];
} Account;

void deposit(Account* account, int amount) {
    account->balance += amount;
}

void withdraw(Account* account, int amount) {
    if (account->balance >= amount) {
        account->balance -= amount;
    }
}

int getBalance(Account* account) {
    return account->balance;
}

Java - 객체지향

// 클래스에 데이터와 메소드 통합
public class Account {
    private int balance;
    private String owner;
    
    public Account(String owner) {
        this.owner = owner;
        this.balance = 0;
    }
    
    public void deposit(int amount) {
        balance += amount;
    }
    
    public boolean withdraw(int amount) {
        if (balance >= amount) {
            balance -= amount;
            return true;
        }
        return false;
    }
    
    public int getBalance() {
        return balance;
    }
}

에러 처리 방식

C - 반환값 체크

#include <stdio.h>

int divide(int a, int b, int* result) {
    if (b == 0) {
        return -1;  // 에러 코드 반환
    }
    *result = a / b;
    return 0;  // 성공
}

int main() {
    int result;
    if (divide(10, 0, &result) != 0) {
        printf("나누기 에러: 0으로 나눌 수 없습니다.\n");
        return 1;
    }
    printf("결과: %d\n", result);
    return 0;
}

Java - 예외 처리

public class ErrorHandling {
    public static int divide(int a, int b) throws ArithmeticException {
        if (b == 0) {
            throw new ArithmeticException("0으로 나눌 수 없습니다.");
        }
        return a / b;
    }
    
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("결과: " + result);
        } catch (ArithmeticException e) {
            System.out.println("나누기 에러: " + e.getMessage());
        }
    }
}

성능 비교

C의 장점

  • 직접적인 하드웨어 접근: 메모리, CPU 직접 제어
  • 컴파일 최적화: 네이티브 코드로 직접 실행
  • 작은 실행 파일: 런타임 환경 불필요

Java의 장점

  • JIT 컴파일: 실행 시간 최적화
  • 가비지 컬렉션: 메모리 누수 방지
  • 멀티스레딩: 내장된 동시성 지원

사용 영역

C 주요 사용 분야

  • 시스템 프로그래밍: 운영체제, 디바이스 드라이버
  • 임베디드 시스템: IoT, 마이크로컨트롤러
  • 고성능 컴퓨팅: 과학 계산, 게임 엔진
  • 하드웨어 제어: 로봇틱스, 자동차 SW

Java 주요 사용 분야

  • 엔터프라이즈 애플리케이션: 은행, 전자상거래
  • 웹 개발: Spring Framework, JSP
  • 안드로이드 앱: 모바일 애플리케이션
  • 빅데이터: Hadoop, Spark, Kafka

📚 참고 링크


20. 인터넷과 인트라넷 차이점

기본 정의

인터넷 (Internet)

전 세계적으로 연결된 컴퓨터 네트워크의 집합으로, 누구나 접근 가능한 공개 네트워크

인트라넷 (Intranet)

특정 조직 내부에서만 사용하는 사설 네트워크로, 인터넷 기술을 활용하되 접근이 제한됨

주요 차이점 비교

구분인터넷인트라넷
접근성전 세계 누구나조직 구성원만
보안 수준낮음높음
네트워크 범위전 세계조직 내부
정보 범위무제한제한적
소유권없음 (공공)조직 소유
비용사용자 부담조직 부담
속도상대적으로 느림빠름

네트워크 구조 비교

인터넷 구조

[사용자 PC] ↔ [ISP] ↔ [인터넷 백본] ↔ [웹 서버]
                ↕
         [다른 ISP들과 연결]

인트라넷 구조

[직원 PC] ↔ [스위치] ↔ [방화벽] ↔ [사내 서버]
               ↕
         [다른 부서 네트워크]

접근 제어 방식

인터넷 접근

// 누구나 접근 가능한 웹사이트
<html>
<head><title>공개 웹사이트</title></head>
<body>
    <h1>누구나 볼 수 있는 내용</h1>
    <p>인터넷에 연결된 모든 사람이 접근 가능</p>
</body>
</html>

인트라넷 접근

// 로그인이 필요한 사내 포털
const intranetAccess = {
    authentication: "Active Directory",
    authorization: "Role-based",
    network: "192.168.1.0/24",  // 사설 IP 대역
    firewall: "Only internal access"
};

// 접근 절차
if (user.isEmployee && user.isOnCorporateNetwork) {
    grantAccess();
} else {
    denyAccess();
}

IP 주소 체계

인터넷 - 공인 IP

공인 IP 주소 예시:
- 8.8.8.8 (Google DNS)
- 1.1.1.1 (Cloudflare DNS)
- 203.248.252.2 (네이버)

인트라넷 - 사설 IP

사설 IP 주소 범위:
- A 클래스: 10.0.0.0 ~ 10.255.255.255
- B 클래스: 172.16.0.0 ~ 172.31.255.255  
- C 클래스: 192.168.0.0 ~ 192.168.255.255

보안 측면

인터넷 보안 위험

보안 위협:
✗ 해킹 시도
✗ 악성 코드
✗ 피싱 사이트
✗ DDoS 공격
✗ 개인정보 유출

인트라넷 보안 장점

보안 강화:
✓ 방화벽 보호
✓ 접근 통제
✓ 암호화 통신
✓ 사용자 인증
✓ 네트워크 모니터링

실제 사용 예시

인터넷 활용

<!-- 전자상거래 사이트 -->
<!DOCTYPE html>
<html>
<head>
    <title>온라인 쇼핑몰</title>
</head>
<body>
    <header>전 세계 누구나 접근 가능</header>
    <main>
        <h1>상품 목록</h1>
        <div class="products">
            <!-- 공개 상품 정보 -->
        </div>
    </main>
</body>
</html>

인트라넷 활용

<!-- 사내 포털 시스템 -->
<!DOCTYPE html>
<html>
<head>
    <title>사내 포털</title>
</head>
<body>
    <header>직원 전용 시스템</header>
    <nav>
        <ul>
            <li>인사 관리</li>
            <li>급여 조회</li>
            <li>사내 공지</li>
            <li>프로젝트 관리</li>
        </ul>
    </nav>
    <main>
        <!-- 기밀 회사 정보 -->
    </main>
</body>
</html>

하이브리드: 엑스트라넷 (Extranet)

엑스트라넷 정의

인트라넷을 특정 외부 사용자에게 부분적으로 개방한 네트워크

인트라넷 + 제한적 외부 접근 = 엑스트라넷

예시:
- 협력업체 포털
- 고객 지원 시스템  
- 공급망 관리 시스템

현대적 발전: VPN

VPN을 통한 원격 인트라넷 접근

[재택근무 직원] ↔ [VPN 터널] ↔ [회사 인트라넷]

보안 기능:
- 암호화된 연결
- 사용자 인증
- 트래픽 터널링
- IP 주소 마스킹

클라우드 시대의 변화

하이브리드 클라우드

온프레미스 인트라넷 + 클라우드 서비스
↓
Microsoft 365, Google Workspace 등
- 인터넷을 통해 접근
- 하지만 조직별 격리된 환경
- 강력한 인증 및 권한 관리

📚 참고 링크


21. AWS VPC CIDR 개념

VPC와 CIDR 기본 개념

VPC (Virtual Private Cloud)

AWS 클라우드에서 논리적으로 격리된 가상 네트워크로, 사용자가 정의한 가상 네트워크 환경

CIDR (Classless Inter-Domain Routing)

IP 주소와 라우팅을 효율적으로 관리하기 위한 주소 할당 방법

CIDR 표기법 이해

기본 형식

IP주소/서브넷마스크비트수
예: 192.168.1.0/24

192.168.1.0: 네트워크 주소
/24: 처음 24비트가 네트워크 부분
     (나머지 8비트가 호스트 부분)

CIDR 계산 예시

10.0.0.0/16 분석:
- 네트워크 부분: 10.0 (16비트)
- 호스트 부분: 0.0 (16비트)
- 사용 가능한 IP: 2^16 = 65,536개
- 범위: 10.0.0.0 ~ 10.0.255.255

10.0.0.0/24 분석:  
- 네트워크 부분: 10.0.0 (24비트)
- 호스트 부분: 0 (8비트)
- 사용 가능한 IP: 2^8 = 256개
- 범위: 10.0.0.0 ~ 10.0.0.255

VPC CIDR 설계 원칙

1. 사설 IP 대역 사용 권장

AWS 권장 사설 IP 대역:
- 10.0.0.0/8    (10.0.0.0 ~ 10.255.255.255)
- 172.16.0.0/12 (172.16.0.0 ~ 172.31.255.255)  
- 192.168.0.0/16 (192.168.0.0 ~ 192.168.255.255)

2. VPC CIDR 크기 제한

AWS VPC CIDR 제약:
- 최소: /28 (16개 IP)
- 최대: /16 (65,536개 IP)
- 추천: /16 ~ /20 (대부분의 경우)

실제 VPC 설계 예시

소규모 환경

{
  "VPC_CIDR": "10.0.0.0/24",
  "총_IP_수": 256,
  "서브넷_설계": {
    "퍼블릭_서브넷": "10.0.0.0/26",    // 64개 IP
    "프라이빗_서브넷": "10.0.0.64/26",  // 64개 IP  
    "데이터베이스_서브넷": "10.0.0.128/26" // 64개 IP
  }
}

중규모 환경

{
  "VPC_CIDR": "10.0.0.0/16",
  "총_IP_수": 65536,
  "가용영역별_서브넷": {
    "AZ_A": {
      "퍼블릭": "10.0.1.0/24",     // 256개
      "프라이빗": "10.0.2.0/24",    // 256개
      "데이터베이스": "10.0.3.0/24" // 256개
    },
    "AZ_B": {
      "퍼블릭": "10.0.4.0/24",     // 256개
      "프라이빗": "10.0.5.0/24",    // 256개  
      "데이터베이스": "10.0.6.0/24" // 256개
    }
  }
}

서브넷 분할 전략

계층별 분할

VPC: 10.0.0.0/16

Tier 1 - 웹 계층 (Public Subnet):
├── AZ-a: 10.0.1.0/24
└── AZ-b: 10.0.2.0/24

Tier 2 - 애플리케이션 계층 (Private Subnet):  
├── AZ-a: 10.0.11.0/24
└── AZ-b: 10.0.12.0/24

Tier 3 - 데이터베이스 계층 (DB Subnet):
├── AZ-a: 10.0.21.0/24  
└── AZ-b: 10.0.22.0/24

환경별 분할

VPC: 10.0.0.0/16

개발 환경 (Dev):
├── 10.0.1.0/24 ~ 10.0.10.0/24

스테이징 환경 (Staging):  
├── 10.0.11.0/24 ~ 10.0.20.0/24

프로덕션 환경 (Production):
├── 10.0.21.0/24 ~ 10.0.50.0/24

AWS 예약 IP 주소

각 서브넷에서 예약되는 5개 IP

서브넷 CIDR: 10.0.1.0/24 (10.0.1.0 ~ 10.0.1.255)

예약된 IP:
- 10.0.1.0:   네트워크 주소
- 10.0.1.1:   VPC 라우터용 (AWS 예약)
- 10.0.1.2:   DNS 서버용 (AWS 예약)  
- 10.0.1.3:   향후 사용 (AWS 예약)
- 10.0.1.255: 브로드캐스트 주소

실제 사용 가능: 10.0.1.4 ~ 10.0.1.254 (251개)

VPC CIDR 확장

보조 CIDR 블록 추가

# AWS CLI로 보조 CIDR 추가
aws ec2 associate-vpc-cidr-block \
    --vpc-id vpc-12345678 \
    --cidr-block 10.1.0.0/16

# 결과: VPC가 두 개의 CIDR 블록 보유
# 기본: 10.0.0.0/16
# 보조: 10.1.0.0/16

멀티 VPC 설계 고려사항

VPC 피어링을 고려한 CIDR 설계

VPC-A (Production):  10.0.0.0/16
VPC-B (Development): 10.1.0.0/16  
VPC-C (Staging):     10.2.0.0/16

주의사항:
✓ CIDR 블록이 겹치면 안됨
✓ 향후 확장 가능성 고려
✓ 온프레미스와의 연결 고려

온프레미스 연결 고려

VPN/Direct Connect 연결 시

온프레미스: 192.168.0.0/16
AWS VPC:   10.0.0.0/16

라우팅 테이블:
- 온프레미스 → AWS: 10.0.0.0/16 via VPN
- AWS → 온프레미스: 192.168.0.0/16 via VPN

충돌 방지:
✗ 같은 대역 사용 금지
✓ 서로 다른 사설 IP 대역 사용

CIDR 계산 도구 활용

온라인 CIDR 계산기

입력: 10.0.0.0/20
출력:
- 네트워크: 10.0.0.0
- 마스크: 255.255.240.0
- 범위: 10.0.0.0 ~ 10.0.15.255
- 호스트 수: 4,096개
- 서브넷 분할 옵션 제공

베스트 프랙티스

1. 초기 설계 시 여유 확보

현재 필요: 100개 인스턴스
권장 CIDR: /20 (4,096개 IP) 
이유: 향후 확장성 고려

2. 일관된 명명 규칙

서브넷 명명 예시:
- public-subnet-1a (10.0.1.0/24)
- private-subnet-1a (10.0.11.0/24)  
- db-subnet-1a (10.0.21.0/24)

3. 문서화

# VPC 설계 문서
VPC_Design:
  VPC_CIDR: "10.0.0.0/16"
  Region: "ap-northeast-2"
  Availability_Zones:
    - name: "ap-northeast-2a"
      subnets:
        public: "10.0.1.0/24"
        private: "10.0.11.0/24"
        database: "10.0.21.0/24"
    - name: "ap-northeast-2c"  
      subnets:
        public: "10.0.2.0/24"
        private: "10.0.12.0/24"
        database: "10.0.22.0/24"

📚 참고 링크


22. 시간 복잡도의 정의와 표기법

시간 복잡도 정의

알고리즘이 실행되는 데 걸리는 시간을 입력 크기에 대한 함수로 표현한 것

  • 목적: 알고리즘의 효율성을 비교 분석
  • 표현: 주로 Big O 표기법 사용
  • 기준: 최악의 경우(Worst Case) 시간 복잡도

Big O 표기법 종류

표기법이름예시 알고리즘설명
O(1)상수 시간배열 인덱스 접근입력 크기와 무관하게 일정
O(log n)로그 시간이진 탐색입력이 절반씩 줄어듦
O(n)선형 시간선형 탐색입력 크기에 비례
O(n log n)선형 로그 시간합병 정렬효율적인 정렬 알고리즘
O(n²)이차 시간버블 정렬중첩 반복문
O(2ⁿ)지수 시간피보나치 재귀매우 비효율적

시간 복잡도 분석 방법

1. 기본 연산 식별

def linear_search(arr, target):
    for i in range(len(arr)):  # n번 반복
        if arr[i] == target:   # 비교 연산 (기본 연산)
            return i
    return -1

분석: 비교 연산이 최대 n번 → O(n)

2. 중첩 반복문

def bubble_sort(arr):
    n = len(arr)
    for i in range(n):         # n번 반복
        for j in range(n-1):   # n-1번 반복
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]

분석: n × (n-1) ≈ n² → O(n²)

3. 분할 정복

def binary_search(arr, target, left, right):
    if left > right:
        return -1
    
    mid = (left + right) // 2
    if arr[mid] == target:
        return mid
    elif arr[mid] > target:
        return binary_search(arr, target, left, mid-1)  # 절반으로 줄어듦
    else:
        return binary_search(arr, target, mid+1, right)

분석: 매번 절반씩 줄어듦 → O(log n)

성능 비교 (n = 1,000,000 기준)

graph LR
    A[O(1)] --> B[1번]
    C[O(log n)] --> D[20번]
    E[O(n)] --> F[100만번]
    G[O(n log n)] --> H[2000만번]
    I[O(n²)] --> J[1조번]

실제 코드 예시

O(1) - 상수 시간

def get_first_element(arr):
    return arr[0]  # 배열 크기와 무관하게 항상 1번

O(n) - 선형 시간

def find_max(arr):
    max_val = arr[0]
    for num in arr:  # n번 반복
        if num > max_val:
            max_val = num
    return max_val

O(n²) - 이차 시간

def print_pairs(arr):
    for i in arr:      # n번
        for j in arr:  # n번
            print(i, j)  # n × n = n²번

O(log n) - 로그 시간

def power(base, exp):
    if exp == 0:
        return 1
    if exp % 2 == 0:
        half = power(base, exp // 2)  # 지수가 절반으로
        return half * half
    else:
        return base * power(base, exp - 1)

공간 복잡도

알고리즘이 실행되는 데 필요한 메모리 공간을 입력 크기에 대한 함수로 표현

# O(1) 공간 복잡도
def sum_array(arr):
    total = 0  # 상수 공간
    for num in arr:
        total += num
    return total

# O(n) 공간 복잡도  
def reverse_array(arr):
    return arr[::-1]  # 새로운 배열 생성 (n만큼 공간 필요)

최적화 팁

  1. 불필요한 중첩 반복문 제거
  2. 적절한 자료구조 선택 (해시맵: O(1), 배열: O(n))
  3. 분할 정복 활용 (병합정렬, 퀵정렬)
  4. 메모이제이션 (동적 프로그래밍)

📚 참고 링크


23. CAP 이론

CAP 이론 정의

분산 데이터베이스 시스템에서 동시에 보장할 수 있는 3가지 속성 중 최대 2가지만 선택 가능하다는 이론

CAP의 3가지 속성

속성영어명의미예시
일관성 (C)Consistency모든 노드가 동시에 동일한 데이터를 봄은행 잔고가 모든 ATM에서 동일
가용성 (A)Availability시스템이 항상 응답을 반환함서버 일부 장애 시에도 서비스 이용 가능
분할 허용성 (P)Partition Tolerance네트워크 분할에도 시스템이 계속 동작노드 간 통신 장애 시에도 각 노드가 동작

가능한 조합

1. CP (일관성 + 분할 허용성)

  • 특징: 데이터 정확성 우선, 가용성 희생
  • 동작: 네트워크 분할 시 일관성 유지를 위해 일부 노드 차단
  • 예시: MongoDB, Redis, 은행 시스템
  • 사용 사례: 금융, 결제 시스템

2. AP (가용성 + 분할 허용성)

  • 특징: 서비스 지속성 우선, 일관성 희생 (최종 일관성)
  • 동작: 네트워크 분할 시에도 모든 노드에서 서비스 제공
  • 예시: Cassandra, DynamoDB, DNS
  • 사용 사례: 소셜 미디어, 콘텐츠 배포

3. CA (일관성 + 가용성) - 실제로는 불가능

  • 이론적: 네트워크 분할이 없는 환경에서만 가능
  • 현실적: 분산 시스템에서는 네트워크 분할이 불가피하므로 실현 불가
  • 예시: 단일 노드 RDBMS (MySQL, PostgreSQL)

실무 적용 예시

은행 시스템 (CP)

-- 네트워크 분할 시
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 모든 노드 동기화 확인 후 COMMIT
-- 동기화 실패 시 ROLLBACK
COMMIT;

소셜 미디어 (AP)

// 네트워크 분할 시에도 포스팅 허용
async function createPost(userId, content) {
  try {
    // 로컬 노드에 저장
    await localDB.insert({ userId, content, timestamp: now() });
    // 백그라운드에서 다른 노드에 복제 (최종 일관성)
    syncToOtherNodes({ userId, content });
    return { success: true };
  } catch (error) {
    return { success: false };
  }
}

PACELC 이론 (CAP의 확장)

  • P: 분할 발생 시 → A vs C 선택
  • E: 분할 없을 시 → L(지연시간) vs C(일관성) 선택

📚 참고 링크


24. MongoDB와 NoSQL 개념

NoSQL 정의

Not Only SQL - 관계형 데이터베이스가 아닌 다양한 형태의 데이터 저장 기술

NoSQL vs RDBMS 비교

구분NoSQLRDBMS
데이터 모델문서, 키-값, 컬럼, 그래프테이블(행, 열)
스키마유연함 (Schema-less)고정적 (Schema-strict)
확장성수평 확장 용이수직 확장 중심
ACID완전 지원 어려움완전 지원
쿼리API 호출, 단순 쿼리SQL (복잡한 쿼리 가능)
트랜잭션제한적완전 지원

NoSQL 데이터베이스 유형

1. 문서형 (Document-based)

  • 특징: JSON, BSON 형태의 문서 저장
  • 예시: MongoDB, CouchDB
  • 사용 사례: 콘텐츠 관리, 사용자 프로필

2. 키-값 (Key-Value)

  • 특징: 단순한 키-값 쌍으로 데이터 저장
  • 예시: Redis, DynamoDB
  • 사용 사례: 캐싱, 세션 저장

3. 컬럼형 (Column-family)

  • 특징: 컬럼 단위로 데이터 저장
  • 예시: Cassandra, HBase
  • 사용 사례: 시계열 데이터, 로그 분석

4. 그래프형 (Graph)

  • 특징: 노드와 엣지로 관계 표현
  • 예시: Neo4j, Amazon Neptune
  • 사용 사례: 소셜 네트워크, 추천 시스템

MongoDB 특징

1. 문서 지향 데이터베이스

// MongoDB 문서 예시
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "홍길동",
  "age": 30,
  "address": {
    "city": "서울",
    "district": "강남구"
  },
  "hobbies": ["독서", "영화감상", "프로그래밍"]
}

2. 스키마 유연성

// 다양한 구조의 문서들이 같은 컬렉션에 저장 가능
{ "name": "김철수", "age": 25 }
{ "name": "이영희", "age": 28, "email": "lee@example.com" }
{ "name": "박민수", "phone": "010-1234-5678", "married": true }

3. 수평 확장 (Sharding)

// 샤딩 설정 예시
sh.enableSharding("myDatabase")
sh.shardCollection("myDatabase.users", { "userId": 1 })

MongoDB 주요 연산

CRUD 연산

// Create (생성)
db.users.insertOne({ name: "홍길동", age: 30 })

// Read (조회)
db.users.find({ age: { $gte: 25 } })

// Update (수정)
db.users.updateOne(
  { name: "홍길동" },
  { $set: { age: 31 } }
)

// Delete (삭제)
db.users.deleteOne({ name: "홍길동" })

집계 파이프라인

db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { _id: "$customerId", total: { $sum: "$amount" } } },
  { $sort: { total: -1 } }
])

MongoDB vs MySQL 비교

구분MongoDBMySQL
데이터 모델문서형 (BSON)관계형 (테이블)
스키마동적정적
쿼리 언어MQL (MongoDB Query Language)SQL
인덱스단일, 복합, 텍스트, 지리공간B-Tree, Hash, Full-text
트랜잭션4.0+ 지원 (제한적)완전 지원
조인$lookup (제한적)다양한 JOIN 지원

NoSQL 선택 기준

NoSQL이 적합한 경우

  • 빠른 개발과 유연한 스키마가 필요
  • 대량의 데이터와 높은 트래픽 처리
  • 수평 확장이 필요한 경우
  • 복잡한 관계보다 단순한 데이터 구조

RDBMS가 적합한 경우

  • 복잡한 관계와 트랜잭션이 중요
  • 데이터 일관성이 매우 중요
  • 복잡한 쿼리와 분석이 필요
  • 기존 SQL 지식 활용

📚 참고 링크


25. LEFT JOIN 개념

JOIN의 정의

두 개 이상의 테이블을 연결하여 데이터를 조회하는 SQL 연산

LEFT JOIN 특징

  • 왼쪽 테이블의 모든 레코드를 반환
  • 오른쪽 테이블에서 일치하는 레코드를 결합
  • 일치하지 않으면 NULL 값으로 채움

기본 문법

SELECT 컬럼명
FROM 왼쪽테이블 A
LEFT JOIN 오른쪽테이블 B ON A.조인키 = B.조인키;

실습 예시

테이블 구조

-- 고객 테이블 (customers)
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    customer_name VARCHAR(50),
    city VARCHAR(50)
);

-- 주문 테이블 (orders)
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE,
    amount DECIMAL(10,2)
);

데이터 삽입

-- 고객 데이터
INSERT INTO customers VALUES 
(1, '홍길동', '서울'),
(2, '김철수', '부산'),
(3, '이영희', '대구'),
(4, '박민수', '인천');

-- 주문 데이터
INSERT INTO orders VALUES 
(101, 1, '2024-01-15', 50000),
(102, 2, '2024-01-16', 75000),
(103, 1, '2024-01-17', 30000);
-- 박민수(customer_id=4)는 주문이 없음

LEFT JOIN 실행

SELECT 
    c.customer_id,
    c.customer_name,
    c.city,
    o.order_id,
    o.order_date,
    o.amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
ORDER BY c.customer_id;

결과

customer_idcustomer_namecityorder_idorder_dateamount
1홍길동서울1012024-01-1550000
1홍길동서울1032024-01-1730000
2김철수부산1022024-01-1675000
3이영희대구NULLNULLNULL
4박민수인천NULLNULLNULL

JOIN 유형별 비교

1. INNER JOIN

-- 양쪽 테이블에 모두 존재하는 데이터만 반환
SELECT c.customer_name, o.order_id
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;
-- 결과: 홍길동(2건), 김철수(1건)만 반환

2. LEFT JOIN

-- 왼쪽 테이블 모든 데이터 + 오른쪽 테이블 일치 데이터
SELECT c.customer_name, o.order_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id;
-- 결과: 모든 고객 포함, 주문 없으면 NULL

3. RIGHT JOIN

-- 오른쪽 테이블 모든 데이터 + 왼쪽 테이블 일치 데이터
SELECT c.customer_name, o.order_id
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;
-- 결과: 모든 주문 포함, 고객 정보 없으면 NULL

4. FULL OUTER JOIN

-- 양쪽 테이블의 모든 데이터 반환
SELECT c.customer_name, o.order_id
FROM customers c
FULL OUTER JOIN orders o ON c.customer_id = o.customer_id;
-- 결과: 모든 고객과 모든 주문 포함

실무 활용 예시

1. 주문하지 않은 고객 찾기

SELECT c.customer_name
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.customer_id IS NULL;
-- 결과: 이영희, 박민수

2. 고객별 총 주문 금액

SELECT 
    c.customer_name,
    COALESCE(SUM(o.amount), 0) as total_amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name
ORDER BY total_amount DESC;

3. 다중 테이블 LEFT JOIN

SELECT 
    c.customer_name,
    o.order_id,
    p.product_name
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
LEFT JOIN order_details od ON o.order_id = od.order_id
LEFT JOIN products p ON od.product_id = p.product_id;

성능 최적화 팁

  • 인덱스 활용: JOIN 키에 인덱스 생성
  • 필요한 컬럼만 SELECT: SELECT * 지양
  • WHERE 조건 활용: 불필요한 데이터 필터링
  • JOIN 순서 고려: 작은 테이블을 먼저 JOIN

📚 참고 링크


26. 오라클 윈도우 함수

윈도우 함수 정의

행과 행 간의 관계를 정의하여 연산을 수행하는 함수 (SQL 표준 ANSI)

기본 문법

함수명() OVER (
    [PARTITION BY 컬럼]
    [ORDER BY 컬럼]
    [ROWS/RANGE 절]
)

주요 윈도우 함수 유형

1. 순위 함수 (Ranking Functions)

ROW_NUMBER()
-- 고유한 순위 부여 (동일 값도 다른 순위)
SELECT 
    employee_id,
    name,
    salary,
    ROW_NUMBER() OVER (ORDER BY salary DESC) as row_num
FROM employees;
RANK()
-- 동일 값에 같은 순위, 다음 순위는 건너뜀
SELECT 
    name,
    salary,
    RANK() OVER (ORDER BY salary DESC) as rank_num
FROM employees;
-- 결과: 1, 2, 2, 4, 5 (3번 건너뜀)
DENSE_RANK()
-- 동일 값에 같은 순위, 다음 순위는 연속
SELECT 
    name,
    salary,
    DENSE_RANK() OVER (ORDER BY salary DESC) as dense_rank_num
FROM employees;
-- 결과: 1, 2, 2, 3, 4 (연속된 순위)

2. 분석 함수 (Analytic Functions)

LAG() / LEAD()
-- 이전/다음 행의 값 가져오기
SELECT 
    name,
    salary,
    LAG(salary, 1, 0) OVER (ORDER BY hire_date) as prev_salary,
    LEAD(salary, 1, 0) OVER (ORDER BY hire_date) as next_salary
FROM employees;
FIRST_VALUE() / LAST_VALUE()
-- 윈도우 내 첫 번째/마지막 값
SELECT 
    name,
    salary,
    FIRST_VALUE(salary) OVER (
        PARTITION BY department_id 
        ORDER BY salary DESC
        ROWS UNBOUNDED PRECEDING
    ) as highest_salary_in_dept
FROM employees;

3. 집계 함수 (Aggregate Functions)

SUM() OVER
-- 누적 합계
SELECT 
    name,
    salary,
    SUM(salary) OVER (
        ORDER BY hire_date 
        ROWS UNBOUNDED PRECEDING
    ) as running_total
FROM employees;
AVG() OVER
-- 이동 평균
SELECT 
    name,
    salary,
    AVG(salary) OVER (
        ORDER BY hire_date 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) as moving_avg_3
FROM employees;

PARTITION BY vs GROUP BY

구분PARTITION BYGROUP BY
결과 행 수원본과 동일그룹 수만큼
용도분석용집계용
SELECT 절모든 컬럼 가능그룹키 + 집계함수만
-- GROUP BY (부서별 평균 급여)
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id;
-- 결과: 부서 수만큼 행

-- PARTITION BY (각 직원과 부서 평균 급여)
SELECT 
    name, 
    department_id, 
    salary,
    AVG(salary) OVER (PARTITION BY department_id) as dept_avg
FROM employees;
-- 결과: 전체 직원 수만큼 행

실무 활용 예시

1. 부서별 급여 순위

SELECT 
    department_id,
    name,
    salary,
    RANK() OVER (
        PARTITION BY department_id 
        ORDER BY salary DESC
    ) as dept_rank
FROM employees
WHERE RANK() OVER (
    PARTITION BY department_id 
    ORDER BY salary DESC
) <= 3;  -- 각 부서 상위 3명

2. 월별 매출 전년 동월 비교

SELECT 
    year_month,
    sales,
    LAG(sales, 12) OVER (ORDER BY year_month) as prev_year_sales,
    ROUND(
        (sales - LAG(sales, 12) OVER (ORDER BY year_month)) 
        / LAG(sales, 12) OVER (ORDER BY year_month) * 100, 2
    ) as growth_rate
FROM monthly_sales;

3. 백분위수 계산

SELECT 
    name,
    salary,
    NTILE(4) OVER (ORDER BY salary) as quartile,
    PERCENT_RANK() OVER (ORDER BY salary) as percentile
FROM employees;

Frame 절 (ROWS/RANGE)

ROWS 절

-- 물리적 행 기준
SELECT 
    name,
    salary,
    AVG(salary) OVER (
        ORDER BY hire_date
        ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
    ) as avg_3_rows
FROM employees;

RANGE 절

-- 논리적 값 기준
SELECT 
    name,
    salary,
    COUNT(*) OVER (
        ORDER BY salary
        RANGE BETWEEN 1000 PRECEDING AND 1000 FOLLOWING
    ) as similar_salary_count
FROM employees;

📚 참고 링크


27. 메인쿼리와 서브쿼리 실행 순서

서브쿼리 정의

다른 SQL 문 안에 포함된 SELECT 문

서브쿼리 유형별 실행 순서

1. 단순 서브쿼리 (Simple Subquery)

-- 평균 급여보다 높은 직원 조회
SELECT name, salary
FROM employees
WHERE salary > (
    SELECT AVG(salary) FROM employees  -- 1. 서브쿼리 먼저 실행
);
-- 실행 순서: 서브쿼리 → 메인쿼리

실행 과정:
1. SELECT AVG(salary) FROM employees 실행 → 결과: 5000
2. WHERE salary > 5000 조건으로 메인쿼리 실행

2. 상관 서브쿼리 (Correlated Subquery)

-- 각 부서별 평균보다 급여가 높은 직원
SELECT e1.name, e1.salary, e1.department_id
FROM employees e1
WHERE e1.salary > (
    SELECT AVG(e2.salary)
    FROM employees e2
    WHERE e2.department_id = e1.department_id  -- 외부 테이블 참조
);

실행 과정:
1. 메인쿼리의 첫 번째 행 처리
2. 해당 행의 department_id로 서브쿼리 실행
3. 서브쿼리 결과와 비교하여 조건 확인
4. 메인쿼리의 다음 행으로 반복

3. EXISTS 서브쿼리

-- 주문이 있는 고객만 조회
SELECT c.customer_name
FROM customers c
WHERE EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.customer_id = c.customer_id
);

실행 과정:
1. 메인쿼리의 각 행에 대해
2. 서브쿼리에서 일치하는 행 존재 여부 확인
3. 존재하면 TRUE, 없으면 FALSE
4. TRUE인 행만 결과에 포함

성능 최적화 관점

실행 순서에 따른 성능 차이

1. 비상관 서브쿼리 (성능 우수)
-- 서브쿼리가 한 번만 실행됨
SELECT name FROM employees
WHERE department_id IN (
    SELECT department_id 
    FROM departments 
    WHERE location = 'Seoul'
);
-- 실행 횟수: 서브쿼리 1회 + 메인쿼리 1회
2. 상관 서브쿼리 (성능 주의)
-- 메인쿼리 행 수만큼 서브쿼리 실행
SELECT name FROM employees e1
WHERE salary > (
    SELECT AVG(salary) 
    FROM employees e2 
    WHERE e2.department_id = e1.department_id
);
-- 실행 횟수: 서브쿼리 N회 (N = 메인쿼리 행 수)

서브쿼리 최적화 방법

1. JOIN으로 변환

-- 상관 서브쿼리 (느림)
SELECT e1.name
FROM employees e1
WHERE e1.salary > (
    SELECT AVG(e2.salary)
    FROM employees e2
    WHERE e2.department_id = e1.department_id
);

-- JOIN으로 최적화 (빠름)
SELECT e1.name
FROM employees e1
JOIN (
    SELECT department_id, AVG(salary) as avg_salary
    FROM employees
    GROUP BY department_id
) dept_avg ON e1.department_id = dept_avg.department_id
WHERE e1.salary > dept_avg.avg_salary;

2. EXISTS vs IN 선택

-- EXISTS (대용량 데이터에서 유리)
SELECT customer_name
FROM customers c
WHERE EXISTS (
    SELECT 1 FROM orders o 
    WHERE o.customer_id = c.customer_id
);

-- IN (소용량 데이터에서 유리)
SELECT customer_name
FROM customers
WHERE customer_id IN (
    SELECT DISTINCT customer_id FROM orders
);

실행 계획 확인

-- Oracle
EXPLAIN PLAN FOR
SELECT name FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

-- MySQL
EXPLAIN
SELECT name FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

서브쿼리 유형별 특징

유형실행 방식성능사용 시기
단순 서브쿼리서브쿼리 → 메인쿼리우수고정값 조건
상관 서브쿼리메인쿼리 행마다 서브쿼리주의행별 다른 조건
EXISTS존재 여부만 확인양호존재 여부 확인
IN값 목록과 비교양호값 목록 매칭

📚 참고 링크


28. 오라클 vs MySQL 차이점

기본 정보 비교

구분OracleMySQL
개발사Oracle CorporationOracle Corporation (오픈소스)
라이선스상용 (유료)오픈소스 (GPL) + 상용
플랫폼멀티 플랫폼멀티 플랫폼
아키텍처멀티 프로세스멀티 스레드
주요 용도대기업, 복잡한 시스템웹 애플리케이션, 스타트업

1. 문법 차이점

문자열 연결

-- Oracle
SELECT first_name || ' ' || last_name AS full_name
FROM employees;

-- MySQL  
SELECT CONCAT(first_name, ' ', last_name) AS full_name
FROM employees;

제한된 행 조회

-- Oracle (12c 이전)
SELECT * FROM (
  SELECT * FROM employees ORDER BY salary DESC
) WHERE ROWNUM <= 5;

-- Oracle (12c 이후)
SELECT * FROM employees 
ORDER BY salary DESC 
FETCH FIRST 5 ROWS ONLY;

-- MySQL
SELECT * FROM employees 
ORDER BY salary DESC 
LIMIT 5;

현재 날짜/시간

-- Oracle
SELECT SYSDATE FROM DUAL;
SELECT SYSTIMESTAMP FROM DUAL;

-- MySQL
SELECT NOW();
SELECT CURRENT_TIMESTAMP();

문자열 일부 추출

-- Oracle
SELECT SUBSTR(name, 1, 3) FROM employees;

-- MySQL
SELECT SUBSTRING(name, 1, 3) FROM employees;
-- 또는
SELECT LEFT(name, 3) FROM employees;

2. 데이터 타입 차이

용도OracleMySQL
정수NUMBER(10)INT, BIGINT
실수NUMBER(10,2)DECIMAL(10,2), FLOAT
문자열VARCHAR2(4000)VARCHAR(65535)
긴 문자열CLOBTEXT, LONGTEXT
날짜DATEDATE, DATETIME
시간TIMESTAMPTIME, TIMESTAMP
불린NUMBER(1)BOOLEAN (TINYINT)

3. 시퀀스와 자동 증가

Oracle 시퀀스

-- 시퀀스 생성
CREATE SEQUENCE emp_seq
START WITH 1
INCREMENT BY 1
NOCACHE;

-- 사용
INSERT INTO employees (id, name) 
VALUES (emp_seq.NEXTVAL, '홍길동');

-- 현재 값 조회
SELECT emp_seq.CURRVAL FROM DUAL;

MySQL 자동 증가

-- 테이블 생성 시
CREATE TABLE employees (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100)
);

-- 사용 (자동으로 증가)
INSERT INTO employees (name) VALUES ('홍길동');

-- 마지막 값 조회
SELECT LAST_INSERT_ID();

4. 스토리지 엔진

Oracle

  • 단일 스토리지 엔진: Oracle Database Engine
  • 특징: ACID 완전 준수, 복잡한 트랜잭션 지원

MySQL

  • 다중 스토리지 엔진: 용도에 따라 선택 가능
엔진특징용도
InnoDB트랜잭션 지원, 외래키일반적인 애플리케이션
MyISAM빠른 읽기, 트랜잭션 미지원로그, 통계 데이터
Memory메모리에 저장임시 데이터, 캐시

5. 성능 및 확장성

Oracle 장점

  • 복잡한 쿼리 최적화: 고급 옵티마이저
  • 대용량 데이터 처리: 수십 TB급 데이터베이스
  • 파티셔닝: 고급 파티셔닝 기능
  • RAC: 클러스터링 지원

MySQL 장점

  • 빠른 시작: 설치 및 설정 간편
  • 웹 최적화: LAMP 스택의 일부
  • 리플리케이션: 마스터-슬레이브 구조
  • 가벼운 리소스: 메모리 사용량 적음

6. 고급 기능 비교

윈도우 함수

-- Oracle (오래전부터 지원)
SELECT name, salary,
       RANK() OVER (ORDER BY salary DESC) as rank
FROM employees;

-- MySQL (8.0부터 지원)
SELECT name, salary,
       RANK() OVER (ORDER BY salary DESC) as rank
FROM employees;

재귀 쿼리 (CTE)

-- Oracle
WITH tree(id, name, parent_id, level) AS (
  SELECT id, name, parent_id, 1
  FROM categories WHERE parent_id IS NULL
  UNION ALL
  SELECT c.id, c.name, c.parent_id, t.level + 1
  FROM categories c
  JOIN tree t ON c.parent_id = t.id
)
SELECT * FROM tree;

-- MySQL (8.0부터 지원)
WITH RECURSIVE tree AS (
  SELECT id, name, parent_id, 1 as level
  FROM categories WHERE parent_id IS NULL
  UNION ALL
  SELECT c.id, c.name, c.parent_id, t.level + 1
  FROM categories c
  JOIN tree t ON c.parent_id = t.id
)
SELECT * FROM tree;

7. 비용 및 라이선스

Oracle

  • Enterprise Edition: 매우 높은 비용
  • Standard Edition: 높은 비용
  • Express Edition: 무료 (기능 제한)

MySQL

  • Community Edition: 완전 무료
  • Enterprise Edition: 유료 (기술 지원 포함)
  • 클라우드 서비스: AWS RDS, Google Cloud SQL

8. 선택 기준

Oracle을 선택하는 경우

  • 대용량 엔터프라이즈 시스템
  • 복잡한 비즈니스 로직과 트랜잭션
  • 높은 가용성과 성능이 필요
  • 충분한 예산과 전문 인력

MySQL을 선택하는 경우

  • 웹 애플리케이션 개발
  • 스타트업이나 중소기업
  • 빠른 개발과 배포 필요
  • 비용 절약이 중요

📚 참고 링크


29. 트랜잭션 ACID 개념

트랜잭션 정의

데이터베이스에서 하나의 논리적 작업 단위를 구성하는 연산들의 집합

ACID 속성

1. 원자성 (Atomicity)

트랜잭션의 모든 연산이 성공하거나 모두 실패해야 함 (All or Nothing)

BEGIN TRANSACTION;

-- 계좌 A에서 10만원 출금
UPDATE accounts 
SET balance = balance - 100000 
WHERE account_id = 'A';

-- 계좌 B에 10만원 입금
UPDATE accounts 
SET balance = balance + 100000 
WHERE account_id = 'B';

-- 둘 다 성공하면 COMMIT, 하나라도 실패하면 ROLLBACK
COMMIT;

위반 예시:

-- 출금은 성공했지만 입금이 실패한 경우
-- → 돈이 사라지는 문제 발생 (원자성 위반)

2. 일관성 (Consistency)

트랜잭션 실행 전후에 데이터베이스가 일관된 상태를 유지해야 함

-- 제약 조건 예시
ALTER TABLE accounts 
ADD CONSTRAINT chk_balance 
CHECK (balance >= 0);

-- 일관성 유지 예시
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 50000 WHERE account_id = 'A';
-- 만약 balance가 음수가 되면 제약 조건 위반으로 자동 ROLLBACK
COMMIT;

위반 예시:

-- 잔고가 음수가 되는 경우
-- 외래키 제약 조건을 위반하는 경우

3. 격리성 (Isolation)

동시에 실행되는 트랜잭션들이 서로 영향을 주지 않아야 함

격리 수준 (Isolation Level)
수준설명Dirty ReadNon-Repeatable ReadPhantom Read
READ UNCOMMITTED커밋되지 않은 데이터도 읽기OOO
READ COMMITTED커밋된 데이터만 읽기XOO
REPEATABLE READ같은 행은 항상 같은 결과XXO
SERIALIZABLE완전한 격리XXX
-- 격리 수준 설정
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 트랜잭션 1
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 'A';  -- 100,000 원
-- ... 다른 작업 수행 중

-- 트랜잭션 2 (동시 실행)
BEGIN TRANSACTION;
UPDATE accounts SET balance = 50000 WHERE account_id = 'A';
COMMIT;

-- 트랜잭션 1 계속
SELECT balance FROM accounts WHERE account_id = 'A';  -- 50,000 원 (변경됨)
COMMIT;

4. 지속성 (Durability)

커밋된 트랜잭션의 결과는 영구적으로 보존되어야 함

BEGIN TRANSACTION;
INSERT INTO orders (customer_id, amount) VALUES (1, 50000);
COMMIT;  -- 이 시점부터 시스템 장애가 발생해도 데이터는 보존됨

보장 방법:

  • WAL (Write-Ahead Logging): 데이터 변경 전에 로그 기록
  • 체크포인트: 주기적으로 메모리 데이터를 디스크에 저장
  • 백업 및 복구: 정기적인 백업과 복구 메커니즘

동시성 제어 문제

1. Dirty Read

-- 트랜잭션 A
UPDATE accounts SET balance = 50000 WHERE id = 1;
-- 아직 COMMIT 하지 않음

-- 트랜잭션 B
SELECT balance FROM accounts WHERE id = 1;  -- 50000 읽음 (문제!)
-- 트랜잭션 A가 ROLLBACK 하면 잘못된 데이터를 읽은 것

2. Non-Repeatable Read

-- 트랜잭션 A
SELECT balance FROM accounts WHERE id = 1;  -- 100000

-- 트랜잭션 B
UPDATE accounts SET balance = 50000 WHERE id = 1;
COMMIT;

-- 트랜잭션 A
SELECT balance FROM accounts WHERE id = 1;  -- 50000 (다른 값!)

3. Phantom Read

-- 트랜잭션 A
SELECT COUNT(*) FROM accounts WHERE balance > 10000;  -- 5개

-- 트랜잭션 B
INSERT INTO accounts (balance) VALUES (20000);
COMMIT;

-- 트랜잭션 A
SELECT COUNT(*) FROM accounts WHERE balance > 10000;  -- 6개 (새로운 행!)

트랜잭션 상태

graph LR
    A[Active] --> B[Partially Committed]
    B --> C[Committed]
    B --> D[Failed]
    A --> D
    D --> E[Aborted]

락(Lock) 메커니즘

공유 락 (Shared Lock)

-- 읽기 락 - 다른 트랜잭션도 읽기 가능, 쓰기 불가
SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE;

배타 락 (Exclusive Lock)

-- 쓰기 락 - 다른 트랜잭션의 읽기/쓰기 모두 불가
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

교착상태 (Deadlock)

-- 트랜잭션 A
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;  -- 1번 락
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;  -- 2번 락 대기

-- 트랜잭션 B (동시 실행)
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 2;  -- 2번 락
UPDATE accounts SET balance = balance + 1000 WHERE id = 1;  -- 1번 락 대기

-- 결과: 서로 락을 기다리는 교착상태 발생
-- 해결: DBMS가 자동으로 한 트랜잭션을 롤백

실무 트랜잭션 관리

Spring의 @Transactional

@Service
@Transactional
public class AccountService {
    
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
        // 출금
        accountRepository.withdraw(fromAccount, amount);
        
        // 입금  
        accountRepository.deposit(toAccount, amount);
        
        // 예외 발생 시 자동 롤백
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("금액은 0보다 커야 합니다");
        }
    }
}

📚 참고 링크


30. DB 모델링 툴

데이터베이스 모델링 정의

현실 세계의 데이터를 컴퓨터가 이해할 수 있도록 개념적으로 구조화하는 과정

모델링 단계

단계목적결과물특징
개념적 모델링업무 요구사항 분석ERD개체, 속성, 관계 정의
논리적 모델링시스템 설계정규화된 테이블데이터 타입, 제약조건
물리적 모델링성능 최적화실제 테이블인덱스, 파티션

주요 DB 모델링 툴

1. 상용 도구

ERwin Data Modeler
  • 개발사: Erwin Inc.
  • 특징:
    • 엔터프라이즈급 모델링 도구
    • 다양한 DBMS 지원
    • 포워드/리버스 엔지니어링
  • 가격: 고가 (수백만원~)
  • 용도: 대기업, 복잡한 시스템
PowerDesigner
  • 개발사: SAP
  • 특징:
    • 통합 모델링 도구
    • UML, ERD 모두 지원
    • 메타데이터 관리
  • 가격: 고가
  • 용도: 대기업 표준 도구
Oracle SQL Developer Data Modeler
  • 개발사: Oracle
  • 특징:
    • Oracle DB에 최적화
    • 무료 제공
    • Oracle 생태계 연동
  • 가격: 무료
  • 용도: Oracle 환경

2. 오픈소스/무료 도구

draw.io (현재 diagrams.net)
graph LR
    A[웹 기반] --> B[무료]
    B --> C[쉬운 사용]
    C --> D[실시간 공유]
  • 특징: 웹 브라우저에서 사용, 직관적인 UI
  • 장점: 무료, 클라우드 저장, 팀 협업
  • 단점: 고급 기능 부족
  • 용도: 간단한 ERD, 프로토타이핑
MySQL Workbench
-- 자동 생성되는 DDL 예시
CREATE TABLE `users` (
  `user_id` INT NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(50) NOT NULL,
  `email` VARCHAR(100) NOT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE INDEX `username_UNIQUE` (`username`),
  UNIQUE INDEX `email_UNIQUE` (`email`)
);
  • 특징: MySQL 전용 도구
  • 장점: 무료, DB 연동, SQL 편집기 내장
  • 단점: MySQL만 지원
  • 용도: MySQL 프로젝트
DBeaver
  • 특징: 다중 DBMS 지원 클라이언트
  • 장점: 무료, ERD 뷰어, 다양한 DB 지원
  • 단점: 모델링보다는 관리 도구
  • 용도: 기존 DB 분석
StarUML
  • 특징: UML 도구이지만 ERD도 지원
  • 장점: 전문적인 다이어그램
  • 단점: 학습 곡선
  • 용도: 시스템 설계 전반

3. 클라우드 기반 도구

Lucidchart
  • 특징: 웹 기반 협업 도구
  • 장점: 실시간 협업, 템플릿 풍부
  • 단점: 유료 (무료 제한적)
  • 용도: 팀 프로젝트
Creately
  • 특징: 온라인 다이어그램 도구
  • 장점: 쉬운 사용법, 모바일 지원
  • 단점: 기능 제한적
  • 용도: 빠른 스케치

실무 선택 기준

프로젝트 규모별

소규모 프로젝트
추천 도구: draw.io, MySQL Workbench
- 빠른 시작
- 비용 절약
- 단순한 구조
중규모 프로젝트
추천 도구: DBeaver + draw.io
- 기존 DB 분석 가능
- 적절한 기능
- 팀 협업 가능
대규모 프로젝트
추천 도구: ERwin, PowerDesigner
- 고급 기능 필요
- 표준화 요구
- 복잡한 관계 관리

ERD 표기법

Crow's Foot 표기법

고객 ||--o{ 주문
- ||: 하나
- o: 0개 이상  
- {: 여러 개

IE (Information Engineering) 표기법

고객 ——————< 주문
- ——: 하나
- <: 여러 개

실무 ERD 예시

전자상거래 ERD (간단 버전)

-- 고객 테이블
CREATE TABLE customers (
    customer_id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE,
    phone VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 상품 테이블  
CREATE TABLE products (
    product_id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    stock_quantity INT DEFAULT 0,
    category_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 주문 테이블
CREATE TABLE orders (
    order_id INT PRIMARY KEY AUTO_INCREMENT,
    customer_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    total_amount DECIMAL(10,2),
    status ENUM('pending', 'confirmed', 'shipped', 'delivered'),
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

-- 주문 상세 테이블
CREATE TABLE order_items (
    order_item_id INT PRIMARY KEY AUTO_INCREMENT,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(order_id),
    FOREIGN KEY (product_id) REFERENCES products(product_id)
);

모델링 베스트 프랙티스

1. 명명 규칙

-- 테이블명: 복수형, 소문자, 언더스코어
users, order_items, product_categories

-- 컬럼명: 단수형, 의미있는 이름
user_id, first_name, created_at

-- 외래키: 참조테이블명_id
customer_id, product_id

2. 정규화 고려

-- 1차 정규화: 원자값만 저장
-- 나쁜 예
CREATE TABLE users (
    id INT,
    hobbies VARCHAR(200)  -- "독서,영화,게임" (X)
);

-- 좋은 예
CREATE TABLE users (id INT, name VARCHAR(100));
CREATE TABLE user_hobbies (
    user_id INT,
    hobby VARCHAR(50),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

3. 인덱스 계획

-- 자주 검색되는 컬럼에 인덱스
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_order_date ON orders(order_date);
CREATE INDEX idx_customer_orders ON orders(customer_id);

📚 참고 링크


31. 인덱스 사용의 이점과 주의사항

인덱스 정의

테이블의 검색 속도를 향상시키기 위해 별도로 생성하는 데이터 구조

인덱스 동작 원리

B-Tree 인덱스 구조

        [50]
       /    \
   [20,30]  [70,90]
   /  |  \  /  |  \
 [10][25][35][60][80][95]

인덱스의 이점

1. 빠른 검색 성능

-- 인덱스 없이: O(n) - 전체 스캔
SELECT * FROM users WHERE email = 'user@example.com';
-- 100만 건 중 1건 찾기: 최대 100만 번 비교

-- 인덱스 있음: O(log n) - 트리 탐색  
CREATE INDEX idx_users_email ON users(email);
-- 100만 건 중 1건 찾기: 최대 20번 비교

2. 정렬 성능 향상

-- 인덱스 없이: 정렬 알고리즘 수행
SELECT * FROM products ORDER BY price;

-- 인덱스 있음: 이미 정렬된 상태로 저장됨
CREATE INDEX idx_products_price ON products(price);

3. 그룹핑 성능 향상

-- GROUP BY 절에서 인덱스 활용
SELECT category_id, COUNT(*)
FROM products
GROUP BY category_id;

-- category_id에 인덱스가 있으면 빠른 그룹핑
CREATE INDEX idx_products_category ON products(category_id);

인덱스 유형

1. 클러스터형 인덱스 (Clustered Index)

-- 테이블 데이터가 인덱스 순서로 물리적 저장
CREATE TABLE users (
    id INT PRIMARY KEY,  -- 자동으로 클러스터형 인덱스
    name VARCHAR(100)
);

2. 비클러스터형 인덱스 (Non-Clustered Index)

-- 별도의 구조로 저장, 테이블 데이터를 가리킴
CREATE INDEX idx_users_name ON users(name);

3. 복합 인덱스 (Composite Index)

-- 여러 컬럼을 조합한 인덱스
CREATE INDEX idx_orders_customer_date 
ON orders(customer_id, order_date);

-- 효과적인 쿼리들
SELECT * FROM orders WHERE customer_id = 123;  -- ✓
SELECT * FROM orders WHERE customer_id = 123 AND order_date = '2024-01-01';  -- ✓
SELECT * FROM orders WHERE order_date = '2024-01-01';  -- △ (두 번째 컬럼만 사용)

4. 유니크 인덱스 (Unique Index)

-- 중복 값 방지 + 성능 향상
CREATE UNIQUE INDEX idx_users_email ON users(email);

인덱스 주의사항

1. 저장 공간 증가

-- 테이블 크기: 1GB
-- 인덱스 추가 시: 테이블 1GB + 인덱스 200MB = 1.2GB

2. DML 성능 저하

-- INSERT 시
INSERT INTO users (name, email) VALUES ('홍길동', 'hong@email.com');
-- 1. 테이블에 데이터 삽입
-- 2. 모든 인덱스 업데이트 (추가 시간 소요)

-- UPDATE 시  
UPDATE users SET email = 'new@email.com' WHERE id = 1;
-- 1. 테이블 데이터 수정
-- 2. email 인덱스 재구성 (기존 삭제 + 새로운 추가)

-- DELETE 시
DELETE FROM users WHERE id = 1;
-- 1. 테이블에서 데이터 삭제
-- 2. 모든 인덱스에서 해당 항목 삭제

3. 인덱스 조각화 (Fragmentation)

-- 시간이 지나면서 인덱스 성능 저하
-- 정기적인 재구성 필요
ALTER INDEX idx_users_email REBUILD;  -- Oracle
OPTIMIZE TABLE users;  -- MySQL

인덱스 사용 전략

1. 선택도 (Selectivity) 고려

-- 좋은 인덱스 후보 (높은 선택도)
CREATE INDEX idx_users_email ON users(email);      -- 99% 유니크
CREATE INDEX idx_users_ssn ON users(ssn);          -- 100% 유니크

-- 나쁜 인덱스 후보 (낮은 선택도)  
CREATE INDEX idx_users_gender ON users(gender);    -- 50% (남/여)
CREATE INDEX idx_users_status ON users(status);    -- 10% (활성/비활성/대기 등)

2. 카디널리티 고려

-- 카디널리티가 높은 컬럼부터 복합 인덱스 구성
CREATE INDEX idx_orders_date_customer 
ON orders(order_date, customer_id);  -- order_date가 더 다양함

-- 잘못된 순서
CREATE INDEX idx_orders_customer_date
ON orders(customer_id, order_date);  -- customer_id 값이 적음

3. 쿼리 패턴 분석

-- 자주 사용되는 WHERE 절 분석
SELECT * FROM products 
WHERE category_id = 1 AND price BETWEEN 10000 AND 50000;

-- 적절한 인덱스 생성
CREATE INDEX idx_products_category_price 
ON products(category_id, price);

인덱스 성능 모니터링

1. 인덱스 사용률 확인

-- MySQL
SELECT 
    table_schema,
    table_name,
    index_name,
    cardinality
FROM information_schema.statistics
WHERE table_schema = 'mydb';

-- Oracle
SELECT 
    index_name,
    table_name,
    uniqueness,
    status
FROM user_indexes;

2. 실행 계획 분석

-- MySQL
EXPLAIN SELECT * FROM users WHERE email = 'test@email.com';

-- Oracle  
EXPLAIN PLAN FOR
SELECT * FROM users WHERE email = 'test@email.com';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

실무 인덱스 가이드라인

생성할 인덱스

  • Primary Key: 자동 생성
  • Foreign Key: 조인 성능 향상
  • WHERE 절 자주 사용: 검색 성능 향상
  • ORDER BY 절: 정렬 성능 향상
  • 유니크 제약: 데이터 무결성 + 성능

피해야 할 인덱스

  • 작은 테이블: 오히려 성능 저하
  • 자주 변경되는 컬럼: DML 성능 저하
  • 카디널리티가 낮은 컬럼: 효과 미미
  • 사용하지 않는 인덱스: 저장 공간 낭비

📚 참고 링크


27. 스레드의 정의와 특징

스레드 정의

Thread - 프로세스 내에서 실행되는 여러 실행 흐름의 단위로, CPU 이용의 기본 단위

스레드 vs 프로세스 비교

구분프로세스스레드
정의실행 중인 프로그램프로세스 내의 실행 단위
메모리독립적 메모리 공간프로세스 내 메모리 공유
생성 비용높음낮음
통신 방법IPC (파이프, 소켓)공유 메모리
독립성완전 독립부분 독립

스레드 메모리 구조

┌─────────────────────────────────┐
│          프로세스 메모리          │
├─────────────────────────────────┤
│         코드 영역 (공유)         │  ← 모든 스레드 공유
├─────────────────────────────────┤
│         데이터 영역 (공유)        │  ← 전역변수, 정적변수
├─────────────────────────────────┤
│          힙 영역 (공유)          │  ← 동적 할당 메모리
├─────────────────────────────────┤
│    스택 영역 1 (스레드 1 전용)    │  ← 각 스레드별 독립
├─────────────────────────────────┤
│    스택 영역 2 (스레드 2 전용)    │  ← 지역변수, 함수 호출
└─────────────────────────────────┘

멀티스레드 구현 예시

Java 스레드

// Thread 클래스 상속
class MyThread extends Thread {

|------|---|-----|
| **패러다임** | 절차지향 | 객체지향 + 절차지향 |
| **개발년도** | 1972| 1985|
| **확장자** | .c | .cpp, .cxx |
| **컴파일러** | gcc | g++, cl |
| **표준 라이브러리** | 작음 | 매우 큼 (STL 포함) |

### 프로그래밍 패러다임

#### C - 절차지향
```c
// C 스타일 - 함수 중심
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x, y;
} Point;

Point* createPoint(int x, int y) {
    Point* p = malloc(sizeof(Point));
    p->x = x;
    p->y = y;
    return p;
}

void printPoint(Point* p) {
    printf("Point: (%d, %d)\n", p->x, p->y);
}

int main() {
    Point* p = createPoint(10, 20);
    printPoint(p);
    free(p);
    return 0;
}

C++ - 객체지향

// C++ 스타일 - 클래스 중심
#include <iostream>

class Point {
private:
    int x, y;
    
public:
    Point(int x, int y) : x(x), y(y) {}  // 생성자
    ~Point() {}                          // 소멸자
    
    void print() {
        std::cout << "Point: (" << x << ", " << y << ")" << std::endl;
    }
    
    // 연산자 오버로딩
    Point operator+(const Point& other) {
        return Point(x + other.x, y + other.y);
    }
};

int main() {
    Point p1(10, 20);
    Point p2(5, 15);
    Point p3 = p1 + p2;  // 연산자 오버로딩 사용
    p3.print();
    return 0;
}

주요 차이점

1. 메모리 관리

// C - malloc/free
int* arr = malloc(sizeof(int) * 10);
free(arr);
// C++ - new/delete + 스마트 포인터
int* arr = new int[10];
delete[] arr;

// 스마트 포인터 (C++11)
std::unique_ptr<int[]> arr = std::make_unique<int[]>(10);
// 자동으로 메모리 해제

2. 입출력

// C - printf/scanf
printf("Hello %s\n", name);
scanf("%d", &number);
// C++ - iostream
std::cout << "Hello " << name << std::endl;
std::cin >> number;

3. 문자열 처리

// C - char 배열
char str[100];
strcpy(str, "Hello");
strcat(str, " World");
// C++ - string 클래스
std::string str = "Hello";
str += " World";

C++의 고급 기능

1. 템플릿

template<typename T>
class Vector {
private:
    T* data;
    size_t size;
    
public:
    Vector(size_t size) : size(size) {
        data = new T[size];
    }
    
    T& operator[](size_t index) {
        return data[index];
    }
};

// 사용
Vector<int> intVector(10);
Vector<double> doubleVector(5);

2. STL (Standard Template Library)

#include <vector>
#include <map>
#include <algorithm>

std::vector<int> numbers = {5, 2, 8, 1, 9};
std::sort(numbers.begin(), numbers.end());

std::map<std::string, int> ages;
ages["Alice"] = 25;
ages["Bob"] = 30;

언어 선택 기준

C를 선택하는 경우

  • 시스템 프로그래밍: 운영체제, 드라이버
  • 임베디드 시스템: 메모리 제약이 큰 환경
  • 성능 최우선: 오버헤드 최소화 필요
  • 하드웨어 제어: 직접적인 하드웨어 접근

C++을 선택하는 경우

  • 대규모 애플리케이션: 복잡한 소프트웨어 개발
  • 게임 개발: 성능 + 객체지향
  • GUI 애플리케이션: Qt, MFC 등
  • 고성능 컴퓨팅: 과학 계산, 시뮬레이션

📚 참고 링크


29. C언어와 Java 차이점

기본 특성 비교

구분CJava
패러다임절차지향객체지향
플랫폼플랫폼 의존적플랫폼 독립적 (JVM)
메모리 관리수동 (malloc/free)자동 (GC)
포인터지원미지원
컴파일네이티브 코드바이트코드
실행 속도빠름상대적으로 느림

메모리 관리 비교

C - 수동 메모리 관리

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 동적 메모리 할당
    int* arr = malloc(sizeof(int) * 10);
    
    if (arr == NULL) {
        printf("메모리 할당 실패\n");
        return 1;
    }
    
    // 메모리 사용
    for (int i = 0; i < 10; i++) {
        arr[i] = i * i;
    }
    
    // 수동으로 메모리 해제 (필수!)
    free(arr);
    arr = NULL;  // 댕글링 포인터 방지
    
    return 0;
}

Java - 자동 메모리 관리

public class MemoryExample {
    public static void main(String[] args) {
        // 객체 생성 (힙에 할당)
        int[] arr = new int[10];
        
        // 메모리 사용
        for (int i = 0; i < 10; i++) {
            arr[i] = i * i;
        }
        
        // 메모리 해제 불필요 (GC가 자동 처리)
        // arr = null; // 참조 제거 (선택사항)
    }
}

플랫폼 독립성

C - 플랫폼 의존적

// hello.c
#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

// 컴파일 및 실행
// Windows: gcc hello.c -o hello.exe && hello.exe
// Linux:   gcc hello.c -o hello && ./hello
// 각 플랫폼별로 다른 실행 파일 생성

Java - 플랫폼 독립적

// Hello.java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

// 컴파일 및 실행 (모든 플랫폼에서 동일)
// javac Hello.java  (바이트코드 생성)
// java Hello        (JVM에서 실행)

프로그래밍 스타일 비교

C - 절차지향

// 구조체와 함수 분리
typedef struct {
    int balance;
    char owner[50];
} Account;

void deposit(Account* account, int amount) {
    account->balance += amount;
}

void withdraw(Account* account, int amount) {
    if (account->balance >= amount) {
        account->balance -= amount;
    }
}

int getBalance(Account* account) {
    return account->balance;
}

Java - 객체지향

// 클래스에 데이터와 메소드 통합
public class Account {
    private int balance;
    private String owner;
    
    public Account(String owner) {
        this.owner = owner;
        this.balance = 0;
    }
    
    public void deposit(int amount) {
        balance += amount;
    }
    
    public boolean withdraw(int amount) {
        if (balance >= amount) {
            balance -= amount;
            return true;
        }
        return false;
    }
    
    public int getBalance() {
        return balance;
    }
}

에러 처리 방식

C - 반환값 체크

#include <stdio.h>

int divide(int a, int b, int* result) {
    if (b == 0) {
        return -1;  // 에러 코드 반환
    }
    *result = a / b;
    return 0;  // 성공
}

int main() {
    int result;
    if (divide(10, 0, &result) != 0) {
        printf("나누기 에러: 0으로 나눌 수 없습니다.\n");
        return 1;
    }
    printf("결과: %d\n", result);
    return 0;
}

Java - 예외 처리

public class ErrorHandling {
    public static int divide(int a, int b) throws ArithmeticException {
        if (b == 0) {
            throw new ArithmeticException("0으로 나눌 수 없습니다.");
        }
        return a / b;
    }
    
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("결과: " + result);
        } catch (ArithmeticException e) {
            System.out.println("나누기 에러: " + e.getMessage());
        }
    }
}

성능 비교

C의 장점

  • 직접적인 하드웨어 접근: 메모리, CPU 직접 제어
  • 컴파일 최적화: 네이티브 코드로 직접 실행
  • 작은 실행 파일: 런타임 환경 불필요

Java의 장점

  • JIT 컴파일: 실행 시간 최적화
  • 가비지 컬렉션: 메모리 누수 방지
  • 멀티스레딩: 내장된 동시성 지원

사용 영역

C 주요 사용 분야

  • 시스템 프로그래밍: 운영체제, 디바이스 드라이버
  • 임베디드 시스템: IoT, 마이크로컨트롤러
  • 고성능 컴퓨팅: 과학 계산, 게임 엔진
  • 하드웨어 제어: 로봇틱스, 자동차 SW

Java 주요 사용 분야

  • 엔터프라이즈 애플리케이션: 은행, 전자상거래
  • 웹 개발: Spring Framework, JSP
  • 안드로이드 앱: 모바일 애플리케이션
  • 빅데이터: Hadoop, Spark, Kafka

📚 참고 링크


30. 인터넷과 인트라넷 차이점

기본 정의

인터넷 (Internet)

전 세계적으로 연결된 컴퓨터 네트워크의 집합으로, 누구나 접근 가능한 공개 네트워크

인트라넷 (Intranet)

특정 조직 내부에서만 사용하는 사설 네트워크로, 인터넷 기술을 활용하되 접근이 제한됨

주요 차이점 비교

구분인터넷인트라넷
접근성전 세계 누구나조직 구성원만
보안 수준낮음높음
네트워크 범위전 세계조직 내부
정보 범위무제한제한적
소유권없음 (공공)조직 소유
비용사용자 부담조직 부담
속도상대적으로 느림빠름

네트워크 구조 비교

인터넷 구조

[사용자 PC] ↔ [ISP] ↔ [인터넷 백본] ↔ [웹 서버]
                ↕
         [다른 ISP들과 연결]

인트라넷 구조

[직원 PC] ↔ [스위치] ↔ [방화벽] ↔ [사내 서버]
               ↕
         [다른 부서 네트워크]

접근 제어 방식

인터넷 접근

// 누구나 접근 가능한 웹사이트
<html>
<head><title>공개 웹사이트</title></head>
<body>
    <h1>누구나 볼 수 있는 내용</h1>
    <p>인터넷에 연결된 모든 사람이 접근 가능</p>
</body>
</html>

인트라넷 접근

// 로그인이 필요한 사내 포털
const intranetAccess = {
    authentication: "Active Directory",
    authorization: "Role-based",
    network: "192.168.1.0/24",  // 사설 IP 대역
    firewall: "Only internal access"
};

// 접근 절차
if (user.isEmployee && user.isOnCorporateNetwork) {
    grantAccess();
} else {
    denyAccess();
}

IP 주소 체계

인터넷 - 공인 IP

공인 IP 주소 예시:
- 8.8.8.8 (Google DNS)
- 1.1.1.1 (Cloudflare DNS)
- 203.248.252.2 (네이버)

인트라넷 - 사설 IP

사설 IP 주소 범위:
- A 클래스: 10.0.0.0 ~ 10.255.255.255
- B 클래스: 172.16.0.0 ~ 172.31.255.255  
- C 클래스: 192.168.0.0 ~ 192.168.255.255

보안 측면

인터넷 보안 위험

보안 위협:
✗ 해킹 시도
✗ 악성 코드
✗ 피싱 사이트
✗ DDoS 공격
✗ 개인정보 유출

인트라넷 보안 장점

보안 강화:
✓ 방화벽 보호
✓ 접근 통제
✓ 암호화 통신
✓ 사용자 인증
✓ 네트워크 모니터링

실제 사용 예시

인터넷 활용

<!-- 전자상거래 사이트 -->
<!DOCTYPE html>
<html>
<head>
    <title>온라인 쇼핑몰</title>
</head>
<body>
    <header>전 세계 누구나 접근 가능</header>
    <main>
        <h1>상품 목록</h1>
        <div class="products">
            <!-- 공개 상품 정보 -->
        </div>
    </main>
</body>
</html>

인트라넷 활용

<!-- 사내 포털 시스템 -->
<!DOCTYPE html>
<html>
<head>
    <title>사내 포털</title>
</head>
<body>
    <header>직원 전용 시스템</header>
    <nav>
        <ul>
            <li>인사 관리</li>
            <li>급여 조회</li>
            <li>사내 공지</li>
            <li>프로젝트 관리</li>
        </ul>
    </nav>
    <main>
        <!-- 기밀 회사 정보 -->
    </main>
</body>
</html>

하이브리드: 엑스트라넷 (Extranet)

엑스트라넷 정의

인트라넷을 특정 외부 사용자에게 부분적으로 개방한 네트워크

인트라넷 + 제한적 외부 접근 = 엑스트라넷

예시:
- 협력업체 포털
- 고객 지원 시스템  
- 공급망 관리 시스템

현대적 발전: VPN

VPN을 통한 원격 인트라넷 접근

[재택근무 직원] ↔ [VPN 터널] ↔ [회사 인트라넷]

보안 기능:
- 암호화된 연결
- 사용자 인증
- 트래픽 터널링
- IP 주소 마스킹

클라우드 시대의 변화

하이브리드 클라우드

온프레미스 인트라넷 + 클라우드 서비스
↓
Microsoft 365, Google Workspace 등
- 인터넷을 통해 접근
- 하지만 조직별 격리된 환경
- 강력한 인증 및 권한 관리

📚 참고 링크


31. AWS VPC CIDR 개념

VPC와 CIDR 기본 개념

VPC (Virtual Private Cloud)

AWS 클라우드에서 논리적으로 격리된 가상 네트워크로, 사용자가 정의한 가상 네트워크 환경

CIDR (Classless Inter-Domain Routing)

IP 주소와 라우팅을 효율적으로 관리하기 위한 주소 할당 방법

CIDR 표기법 이해

기본 형식

IP주소/서브넷마스크비트수
예: 192.168.1.0/24

192.168.1.0: 네트워크 주소
/24: 처음 24비트가 네트워크 부분
     (나머지 8비트가 호스트 부분)

CIDR 계산 예시

10.0.0.0/16 분석:
- 네트워크 부분: 10.0 (16비트)
- 호스트 부분: 0.0 (16비트)
- 사용 가능한 IP: 2^16 = 65,536개
- 범위: 10.0.0.0 ~ 10.0.255.255

10.0.0.0/24 분석:  
- 네트워크 부분: 10.0.0 (24비트)
- 호스트 부분: 0 (8비트)
- 사용 가능한 IP: 2^8 = 256개
- 범위: 10.0.0.0 ~ 10.0.0.255

VPC CIDR 설계 원칙

1. 사설 IP 대역 사용 권장

AWS 권장 사설 IP 대역:
- 10.0.0.0/8    (10.0.0.0 ~ 10.255.255.255)
- 172.16.0.0/12 (172.16.0.0 ~ 172.31.255.255)  
- 192.168.0.0/16 (192.168.0.0 ~ 192.168.255.255)

2. VPC CIDR 크기 제한

AWS VPC CIDR 제약:
- 최소: /28 (16개 IP)
- 최대: /16 (65,536개 IP)
- 추천: /16 ~ /20 (대부분의 경우)

실제 VPC 설계 예시

소규모 환경

{
  "VPC_CIDR": "10.0.0.0/24",
  "총_IP_수": 256,
  "서브넷_설계": {
    "퍼블릭_서브넷": "10.0.0.0/26",    // 64개 IP
    "프라이빗_서브넷": "10.0.0.64/26",  // 64개 IP  
    "데이터베이스_서브넷": "10.0.0.128/26" // 64개 IP
  }
}

중규모 환경

{
  "VPC_CIDR": "10.0.0.0/16",
  "총_IP_수": 65536,
  "가용영역별_서브넷": {
    "AZ_A": {
      "퍼블릭": "10.0.1.0/24",     // 256개
      "프라이빗": "10.0.2.0/24",    // 256개
      "데이터베이스": "10.0.3.0/24" // 256개
    },
    "AZ_B": {
      "퍼블릭": "10.0.4.0/24",     // 256개
      "프라이빗": "10.0.5.0/24",    // 256개  
      "데이터베이스": "10.0.6.0/24" // 256개
    }
  }
}

서브넷 분할 전략

계층별 분할

VPC: 10.0.0.0/16

Tier 1 - 웹 계층 (Public Subnet):
├── AZ-a: 10.0.1.0/24
└── AZ-b: 10.0.2.0/24

Tier 2 - 애플리케이션 계층 (Private Subnet):  
├── AZ-a: 10.0.11.0/24
└── AZ-b: 10.0.12.0/24

Tier 3 - 데이터베이스 계층 (DB Subnet):
├── AZ-a: 10.0.21.0/24  
└── AZ-b: 10.0.22.0/24

환경별 분할

VPC: 10.0.0.0/16

개발 환경 (Dev):
├── 10.0.1.0/24 ~ 10.0.10.0/24

스테이징 환경 (Staging):  
├── 10.0.11.0/24 ~ 10.0.20.0/24

프로덕션 환경 (Production):
├── 10.0.21.0/24 ~ 10.0.50.0/24

AWS 예약 IP 주소

각 서브넷에서 예약되는 5개 IP

서브넷 CIDR: 10.0.1.0/24 (10.0.1.0 ~ 10.0.1.255)

예약된 IP:
- 10.0.1.0:   네트워크 주소
- 10.0.1.1:   VPC 라우터용 (AWS 예약)
- 10.0.1.2:   DNS 서버용 (AWS 예약)  
- 10.0.1.3:   향후 사용 (AWS 예약)
- 10.0.1.255: 브로드캐스트 주소

실제 사용 가능: 10.0.1.4 ~ 10.0.1.254 (251개)

VPC CIDR 확장

보조 CIDR 블록 추가

# AWS CLI로 보조 CIDR 추가
aws ec2 associate-vpc-cidr-block \
    --vpc-id vpc-12345678 \
    --cidr-block 10.1.0.0/16

# 결과: VPC가 두 개의 CIDR 블록 보유
# 기본: 10.0.0.0/16
# 보조: 10.1.0.0/16

멀티 VPC 설계 고려사항

VPC 피어링을 고려한 CIDR 설계

VPC-A (Production):  10.0.0.0/16
VPC-B (Development): 10.1.0.0/16  
VPC-C (Staging):     10.2.0.0/16

주의사항:
✓ CIDR 블록이 겹치면 안됨
✓ 향후 확장 가능성 고려
✓ 온프레미스와의 연결 고려

온프레미스 연결 고려

VPN/Direct Connect 연결 시

온프레미스: 192.168.0.0/16
AWS VPC:   10.0.0.0/16

라우팅 테이블:
- 온프레미스 → AWS: 10.0.0.0/16 via VPN
- AWS → 온프레미스: 192.168.0.0/16 via VPN

충돌 방지:
✗ 같은 대역 사용 금지
✓ 서로 다른 사설 IP 대역 사용

CIDR 계산 도구 활용

온라인 CIDR 계산기

입력: 10.0.0.0/20
출력:
- 네트워크: 10.0.0.0
- 마스크: 255.255.240.0
- 범위: 10.0.0.0 ~ 10.0.15.255
- 호스트 수: 4,096개
- 서브넷 분할 옵션 제공

베스트 프랙티스

1. 초기 설계 시 여유 확보

현재 필요: 100개 인스턴스
권장 CIDR: /20 (4,096개 IP) 
이유: 향후 확장성 고려

2. 일관된 명명 규칙

서브넷 명명 예시:
- public-subnet-1a (10.0.1.0/24)
- private-subnet-1a (10.0.11.0/24)  
- db-subnet-1a (10.0.21.0/24)

3. 문서화

# VPC 설계 문서
VPC_Design:
  VPC_CIDR: "10.0.0.0/16"
  Region: "ap-northeast-2"
  Availability_Zones:
    - name: "ap-northeast-2a"
      subnets:
        public: "10.0.1.0/24"
        private: "10.0.11.0/24"
        database: "10.0.21.0/24"
    - name: "ap-northeast-2c"  
      subnets:
        public: "10.0.2.0/24"
        private: "10.0.12.0/24"
        database: "10.0.22.0/24"

📚 참고 링크


💡 면접 팁

답변 구조 (30초~1분)

  1. 핵심 개념 정의 (10초)
  2. 주요 특징/차이점 (30초)
  3. 실무 활용 예시 (10-20초)

기술별 핵심 포인트

웹 기술

  • SPA vs MPA: 사용자 경험과 SEO 트레이드오프
  • CSS Grid: 2차원 레이아웃의 강력함
  • JWT: Stateless 인증의 장점과 주의사항

시스템/인프라

  • 프로세스 vs 스레드: 메모리 공유 방식의 차이
  • 도커: OS 가상화 vs 하드웨어 가상화
  • 언어 비교: 용도에 따른 적절한 선택

데이터베이스

  • CAP 이론: 분산 시스템의 기본 원리
  • NoSQL: 확장성과 유연성의 장점
  • 인덱스: 성능 향상과 저장공간 트레이드오프

추가 학습 방향

  • 최신 트렌드 파악 (2024년 기준)
  • 실제 프로젝트 경험과 연결하여 설명
  • 장단점을 균형 있게 제시

최종 업데이트: 2024년 12월

profile
hi im gggongbo

0개의 댓글