컴퓨터 공학 핵심 개념 지도: CPU에서 분산 시스템까지
컴퓨터 공학을 처음 접하면 자료구조, 운영체제, 네트워크, 데이터베이스가 서로 다른 과목처럼 보입니다. 실제 시스템에서는 이 개념들이 한 요청 안에서 동시에 움직입니다. 사용자가 버튼을 누르면 프로그램의 명령어가 CPU에서 실행되고, 운영체제가 메모리와 소켓을 관리하며, 네트워크 패킷이 서버로 이동하고, 데이터베이스 트랜잭션이 상태를 바꿉니다.
이 문서는 컴퓨터 공학의 중요한 개념을 한곳에서 찾기 위한 지도입니다. 각 항목은 한두 문장으로 범위를 잡고, 자세한 설명이 필요한 주제는 별도의 심화 글로 연결합니다. 처음부터 끝까지 외울 필요는 없습니다. 낯선 용어가 나왔을 때 어느 영역에 속하고 무엇과 연결되는지 확인하는 기준점으로 사용하는 편이 좋습니다.
소스 코드
-> 컴파일러와 런타임
-> 프로세스와 가상 메모리
-> CPU와 메모리 계층
-> 소켓과 네트워크
-> 서버와 분산 시스템
-> 데이터베이스와 저장장치정보와 계산의 기초
비트와 바이트: 비트는 0과 1 중 하나를 표현하는 최소 단위이며, 바이트는 일반적으로 8비트를 묶은 단위입니다. 정수, 문자, 이미지와 프로그램도 결국 비트열로 저장되고 전송됩니다.
2진수와 16진수: 컴퓨터는 2진수로 값을 표현합니다. 16진수는 4비트를 한 자리로 줄여 주소, 색상, 기계어와 해시를 사람이 읽기 쉽게 표시합니다.
인코딩: 같은 비트열을 어떤 의미로 해석할지 정한 규칙입니다. UTF-8은 문자를 바이트로 바꾸는 인코딩이며, Base64는 바이너리 데이터를 제한된 문자 집합으로 표현하는 방식입니다.
불 대수: 참과 거짓, AND, OR, NOT 같은 연산을 다루는 수학 체계입니다. 조건문뿐 아니라 디지털 회로와 검색 조건의 기초가 됩니다.
상태: 시스템이 현재 기억하고 있는 값의 집합입니다. 같은 입력도 이전 상태에 따라 다른 결과를 만들 수 있으므로 상태의 저장 위치와 변경 규칙이 설계의 중심이 됩니다.
상태 머신: 가능한 상태와 상태 사이의 전이 조건으로 동작을 표현합니다. 네트워크 연결, 주문 처리, UI 흐름처럼 단계가 분명한 로직을 설명하는 데 유용합니다.
알고리즘: 입력을 원하는 출력으로 바꾸는 유한한 절차입니다. 정답을 내는 것뿐 아니라 입력이 커졌을 때 시간과 메모리를 얼마나 사용하는지도 중요합니다.
추상화: 복잡한 내부 구현을 숨기고 필요한 계약만 드러내는 방법입니다. 함수, 파일, 프로세스, 소켓과 데이터베이스 모두 서로 다른 수준의 추상화입니다.
계산 가능성: 어떤 문제를 알고리즘으로 풀 수 있는지 묻는 영역입니다. 튜링 머신은 계산을 설명하는 이론적 모델이며, 모든 문제가 프로그램으로 해결되는 것은 아니라는 경계를 보여줍니다.
결정 불가능성: 유한한 시간 안에 항상 정답을 내는 알고리즘이 존재하지 않는 문제도 있습니다. 정지 문제는 임의의 프로그램이 종료될지 일반적으로 판정할 수 없다는 대표적인 예입니다.
자료구조와 알고리즘
자료구조: 데이터를 저장하고 접근하는 방식을 정한 구조입니다. 같은 데이터라도 읽기, 삽입, 삭제 중 무엇을 자주 하는지에 따라 적합한 구조가 달라집니다.
배열: 같은 종류의 값을 연속된 메모리에 배치합니다. 인덱스로 빠르게 접근할 수 있지만 중간 삽입과 삭제에는 많은 값을 이동해야 할 수 있습니다.
연결 리스트: 각 원소가 다음 원소의 위치를 가리킵니다. 연결 위치를 알고 있다면 삽입과 삭제가 단순하지만, 임의 위치 접근에는 앞에서부터 순회가 필요합니다.
스택: 마지막에 넣은 값을 먼저 꺼내는 LIFO 구조입니다. 함수 호출, 실행 취소, 괄호 검사와 깊이 우선 탐색에 사용됩니다.
큐: 먼저 넣은 값을 먼저 꺼내는 FIFO 구조입니다. 작업 대기열, 이벤트 처리와 너비 우선 탐색의 기본 구조입니다.
해시 테이블: 키를 해시 함수로 변환해 저장 위치를 찾습니다. 평균적으로 빠른 조회가 가능하지만 충돌 처리와 테이블 크기 조정이 필요합니다.
트리: 부모와 자식 관계를 가진 계층 구조입니다. 파일 경로, 문서 구조, 검색 인덱스와 구문 트리를 표현하는 데 사용됩니다.
힙과 우선순위 큐: 가장 작거나 큰 값을 빠르게 꺼내도록 구성한 트리 기반 구조입니다. 스케줄링, 최단 경로와 상위 N개 선택에 자주 사용됩니다.
그래프: 정점과 간선으로 관계를 표현합니다. 도로망, 의존성, 소셜 관계, 네트워크 토폴로지는 모두 그래프로 모델링할 수 있습니다.
탐색: 원하는 값을 찾거나 가능한 상태를 방문하는 과정입니다. 이진 탐색은 정렬된 데이터에서 범위를 절반씩 줄이고, BFS와 DFS는 그래프를 서로 다른 순서로 탐색합니다.
정렬: 데이터를 비교 가능한 순서로 재배치합니다. 시간 복잡도뿐 아니라 같은 값의 기존 순서를 보존하는 안정성과 추가 메모리 사용량도 선택 기준입니다.
재귀: 함수가 더 작은 문제를 풀기 위해 자신을 다시 호출하는 방식입니다. 종료 조건이 필요하며, 호출 깊이가 커지면 스택 한도를 넘을 수 있습니다.
분할 정복: 문제를 독립적인 작은 문제로 나누고 결과를 합칩니다. 병합 정렬과 이진 탐색이 대표적입니다.
탐욕법: 매 단계에서 현재 가장 좋아 보이는 선택을 합니다. 빠르고 단순하지만 지역 최적 선택이 전체 최적해를 보장하는지 증명이 필요합니다.
동적 계획법: 반복되는 부분 문제의 결과를 저장해 다시 계산하지 않습니다. 문제를 상태와 점화식으로 표현할 수 있을 때 효과적입니다.
시간 복잡도: 입력 크기가 커질 때 실행 시간이 증가하는 비율을 표현합니다. Big O 표기법은 상수보다 증가 차수에 집중해 알고리즘을 비교합니다.
공간 복잡도: 알고리즘이 추가로 사용하는 메모리가 입력 크기에 따라 어떻게 늘어나는지 나타냅니다. 더 빠른 계산을 위해 메모리를 더 사용하는 시간과 공간의 교환이 자주 발생합니다.
상각 분석: 가끔 비싼 연산이 생겨도 여러 연산에 비용을 나누면 평균적으로 얼마나 드는지 분석합니다. 동적 배열의 크기 확장이 대표적인 사례입니다.
컴퓨터 구조
트랜지스터와 논리 게이트: 트랜지스터는 전기 신호를 제어하는 소자이며, 이를 조합해 AND, OR, NOT 같은 논리 게이트를 만듭니다. 소프트웨어의 조건과 산술 연산은 결국 이런 회로에서 실행됩니다.
조합 회로와 순차 회로: 조합 회로의 출력은 현재 입력으로 결정됩니다. 순차 회로는 이전 상태를 기억하므로 레지스터와 카운터 같은 저장 요소를 만들 수 있습니다.
클록: 디지털 회로가 상태를 갱신하는 기준 신호입니다. 클록 주파수가 높다고 프로그램이 항상 같은 비율로 빨라지는 것은 아니며, 명령어 효율과 메모리 지연도 함께 봐야 합니다.
명령어 집합 구조: ISA는 CPU가 이해하는 명령어, 레지스터와 메모리 접근 규칙의 계약입니다. 운영체제와 컴파일러는 특정 ISA를 대상으로 기계어를 만듭니다.
CPU: 명령어를 가져오고 해석하고 실행하는 장치입니다. 산술논리장치, 제어 장치, 레지스터와 캐시가 함께 동작합니다.
레지스터: CPU 내부의 매우 빠르고 작은 저장 공간입니다. 현재 계산 값, 명령어 위치와 스택 위치처럼 즉시 필요한 값을 보관합니다.
명령어 사이클: CPU는 명령어를 가져오고, 해석하고, 피연산자를 읽고, 실행하고, 결과를 기록합니다. 현대 CPU는 이 단계를 겹쳐 처리합니다.
파이프라이닝: 여러 명령어의 서로 다른 단계를 동시에 진행해 처리량을 높입니다. 앞선 명령어의 결과가 필요한 데이터 위험과 분기 결과를 모르는 제어 위험을 처리해야 합니다.
분기 예측과 비순차 실행: CPU는 조건문의 결과를 미리 예측하고 실행 가능한 명령어를 순서와 다르게 처리합니다. 예측이 틀리면 수행한 작업을 버려야 하며, 이런 추측 실행은 보안 경계에도 영향을 줍니다.
메모리 계층: 레지스터, CPU 캐시, RAM, SSD는 속도와 용량, 가격이 서로 다릅니다. 자주 쓰는 데이터를 빠른 계층 가까이에 두는 것이 전체 성능에 큰 영향을 줍니다.
캐시와 지역성: 캐시는 느린 저장소의 데이터를 더 빠른 공간에 복사합니다. 최근 접근한 값과 그 주변 값을 다시 사용할 가능성이 높다는 시간 및 공간 지역성을 이용합니다.
RAM과 영구 저장장치: RAM은 빠르지만 전원이 꺼지면 내용이 사라지는 주기억장치입니다. SSD와 HDD는 더 느리지만 데이터를 지속적으로 보관합니다.
버스와 I/O: CPU, 메모리와 주변 장치는 데이터와 제어 신호를 주고받습니다. 저장장치와 네트워크 장치의 속도 차이는 버퍼와 비동기 I/O가 필요한 이유입니다.
인터럽트: 장치나 타이머가 CPU에 즉시 처리할 사건을 알리는 신호입니다. CPU가 장치 상태를 계속 확인하지 않아도 입력 완료와 시간 경과에 반응할 수 있습니다.
DMA: 장치가 CPU를 매번 거치지 않고 메모리와 직접 데이터를 전송하게 합니다. 대용량 디스크와 네트워크 I/O에서 CPU 부담을 줄입니다.
엔디언: 여러 바이트로 된 값을 메모리에 어떤 순서로 놓을지 정한 규칙입니다. 서로 다른 시스템이나 네트워크 형식 사이에서 바이너리 데이터를 교환할 때 확인해야 합니다.
운영체제와 동시성
커널과 사용자 모드: 커널은 하드웨어와 시스템 자원을 관리하는 특권 코드입니다. 일반 프로그램은 제한된 사용자 모드에서 실행돼 다른 프로세스와 운영체제를 직접 훼손하지 못합니다.
시스템 콜: 사용자 프로그램이 파일, 네트워크, 메모리 같은 커널 기능을 요청하는 공식 경계입니다. 함수 호출처럼 보이지만 실행 권한과 문맥이 전환됩니다.
프로세스: 실행 중인 프로그램과 그 주소 공간, 자원, 권한을 묶은 단위입니다. 서로 다른 프로세스는 기본적으로 메모리가 격리됩니다.
스레드: 한 프로세스 안에서 실행 흐름을 나누는 단위입니다. 같은 메모리를 공유하므로 통신은 빠르지만 데이터 경쟁을 막아야 합니다.
컨텍스트 스위치: CPU가 한 실행 흐름을 멈추고 레지스터 상태를 저장한 뒤 다른 흐름을 실행하는 과정입니다. 동시성을 제공하지만 전환 자체와 캐시 손실에 비용이 듭니다.
스케줄링: 실행 가능한 프로세스와 스레드 중 다음에 CPU를 사용할 대상을 고릅니다. 처리량, 응답 시간, 공정성과 우선순위가 서로 충돌할 수 있습니다.
동시성과 병렬성: 동시성은 여러 작업이 진행 중인 구조이고, 병렬성은 실제로 같은 시점에 여러 연산이 실행되는 상태입니다. 단일 코어에서도 작업을 번갈아 실행해 동시성을 만들 수 있습니다.
경쟁 상태와 원자성: 실행 순서에 따라 결과가 달라지는 문제가 경쟁 상태입니다. 원자적 연산은 다른 작업이 중간 상태를 관찰하지 못하도록 하나의 단위처럼 처리됩니다.
뮤텍스, 세마포어와 조건 변수: 뮤텍스는 공유 자원에 한 실행 흐름만 들어가게 합니다. 세마포어는 허용 가능한 동시 접근 수를 관리하고, 조건 변수는 특정 상태가 될 때까지 기다리게 합니다.
교착 상태: 여러 작업이 서로가 가진 자원을 기다리며 영원히 진행하지 못하는 상태입니다. 잠금 순서를 고정하거나 점유 범위를 줄이고 타임아웃을 두는 방식으로 위험을 낮춥니다.
가상 메모리: 각 프로세스에 자신만의 연속된 주소 공간이 있는 것처럼 보이게 하는 추상화입니다. 주소 변환을 통해 격리, 공유와 실제 메모리보다 큰 논리 공간을 제공합니다.
페이지, TLB와 페이지 폴트: 가상 메모리는 고정 크기 페이지 단위로 관리됩니다. TLB는 최근 주소 변환을 캐시하며, 필요한 페이지가 메모리에 없으면 페이지 폴트가 발생해 운영체제가 처리합니다.
메모리 매핑: 파일이나 장치를 프로세스 주소 공간에 연결합니다. 파일 읽기와 메모리 접근을 같은 방식으로 다룰 수 있고 여러 프로세스가 페이지를 공유할 수도 있습니다.
파일 시스템: 파일 이름과 디렉터리를 저장장치의 데이터 블록에 연결합니다. 권한, 메타데이터, 캐시, 일관성과 장애 복구도 함께 관리합니다.
파일 디스크립터: 프로세스가 열린 파일, 소켓과 파이프를 가리키는 작은 정수 핸들입니다. 유닉스 계열 운영체제에서는 다양한 I/O 자원을 비슷한 인터페이스로 다룹니다.
블로킹과 논블로킹 I/O: 블로킹 호출은 작업이 끝날 때까지 실행 흐름을 기다리게 합니다. 논블로킹 및 비동기 I/O는 기다리는 동안 다른 작업을 처리하도록 구성할 수 있습니다.
프로그래밍 언어, 컴파일러와 런타임
문법과 의미론: 문법은 어떤 코드가 유효한 형태인지 정하고, 의미론은 그 코드가 무엇을 뜻하는지 정합니다. 문법이 맞아도 의도한 동작을 보장하지는 않습니다.
컴파일러와 인터프리터: 컴파일러는 소스 코드를 다른 표현이나 기계어로 미리 변환합니다. 인터프리터는 프로그램을 읽으며 실행하지만, 실제 언어 구현은 두 방식을 함께 쓰기도 합니다.
렉서, 파서와 AST: 렉서는 문자열을 토큰으로 나누고 파서는 문법에 맞춰 구조를 만듭니다. AST는 소스 코드의 의미 있는 계층을 표현해 분석과 변환의 기반이 됩니다.
중간 표현과 코드 생성: 컴파일러는 소스 언어와 기계어 사이에 IR을 두고 최적화합니다. 같은 IR에서 여러 CPU나 실행 환경을 위한 코드를 만들 수 있습니다.
AOT와 JIT: AOT는 실행 전에 코드를 기계어로 만듭니다. JIT는 실행 중 실제 사용 패턴을 관찰해 자주 쓰는 경로를 최적화할 수 있습니다.
타입 시스템: 값과 연산이 어떤 종류인지 규칙으로 표현합니다. 잘못된 조합을 실행 전이나 실행 중에 막고, 프로그램의 계약을 문서화합니다.
정적 타입과 동적 타입: 정적 타입 검사는 주로 실행 전에 이뤄지고, 동적 타입 검사는 실행 중 값에 적용됩니다. 언어마다 추론, 점진적 타입과 런타임 검사 비율이 다릅니다.
제네릭과 다형성: 구체적인 타입 하나에 묶이지 않고 여러 타입에 재사용할 수 있는 코드를 만듭니다. 상속, 인터페이스와 매개변수화 타입은 서로 다른 형태의 다형성을 제공합니다.
스코프와 수명: 스코프는 이름을 참조할 수 있는 코드 범위이며, 수명은 값이나 자원이 유효한 시간입니다. 두 개념을 혼동하면 해제된 자원 접근과 예상하지 못한 값 가림이 생깁니다.
스택과 힙: 호출 스택은 함수 실행 정보와 지역 값을 순서대로 관리합니다. 힙은 크기와 수명이 호출 구조에 맞지 않는 데이터를 동적으로 저장합니다.
포인터와 참조: 다른 값이 저장된 메모리 위치를 가리키는 개념입니다. 복사 비용을 줄이고 자료구조를 연결할 수 있지만 잘못된 수명과 경계 접근은 오류와 취약점으로 이어집니다.
소유권과 빌림: 자원의 소유자와 참조가 유효한 범위를 타입 규칙으로 표현하는 방식입니다. 일부 언어는 컴파일 시점에 메모리 안전성과 동시 접근 규칙을 검사합니다.
가비지 컬렉션: 더 이상 도달할 수 없는 객체를 런타임이 찾아 메모리를 회수합니다. 개발 부담을 줄이는 대신 추적 비용, 일시 정지와 메모리 사용량을 관리해야 합니다.
클로저: 함수와 함수가 만들어진 주변 환경을 함께 보관합니다. 콜백과 함수형 패턴에 유용하지만 캡처한 값의 수명을 늘릴 수 있습니다.
예외와 오류 값: 실패를 호출자에게 전달하는 두 가지 대표 방식입니다. 어느 방식을 쓰든 복구 가능한 오류, 프로그래밍 오류와 프로세스를 끝내야 하는 상태를 구분해야 합니다.
ABI와 FFI: ABI는 함수 호출, 레지스터 사용, 바이너리 배치 같은 저수준 계약입니다. FFI는 서로 다른 언어와 런타임의 코드가 이 경계를 통해 호출되게 합니다.
네트워크
계층과 프로토콜: 네트워크는 링크, 인터넷, 전송, 애플리케이션 계층처럼 책임을 나눕니다. 각 계층은 아래 구현을 감추고 위 계층에 일정한 서비스를 제공합니다.
프레임과 패킷: 프레임은 같은 링크 구간에서 전달되는 단위이고, IP 패킷은 여러 네트워크를 지나 목적지까지 라우팅되는 단위입니다. 계층을 통과할 때 헤더가 추가되거나 제거됩니다.
MAC 주소와 이더넷: MAC 주소는 로컬 네트워크 인터페이스를 식별하는 데 사용됩니다. 이더넷 스위치는 프레임의 목적지 MAC 주소를 보고 같은 네트워크 안에서 전달합니다.
IP 주소와 서브넷: IP 주소는 네트워크에서 호스트의 논리적 위치를 나타냅니다. 서브넷 마스크 또는 prefix는 주소에서 네트워크 부분과 호스트 부분을 구분합니다.
라우팅: 라우터가 패킷의 목적지 주소를 보고 다음 이동 경로를 선택하는 과정입니다. 한 번의 통신도 여러 독립 네트워크와 라우터를 거칠 수 있습니다.
NAT: 사설 주소와 공인 주소 사이를 변환합니다. 여러 장치가 하나의 공인 주소를 공유할 수 있지만 외부에서 내부 연결을 시작하는 구조를 복잡하게 만듭니다.
TCP: 순서가 보장된 신뢰성 있는 바이트 스트림을 제공합니다. 손실 감지, 재전송, 흐름 제어와 혼잡 제어를 수행하는 대신 연결 설정과 상태 관리가 필요합니다.
UDP: 연결 상태와 재전송을 기본 제공하지 않는 데이터그램 전송 방식입니다. 지연을 직접 통제하거나 애플리케이션이 자체 신뢰성 규칙을 구현할 때 사용됩니다.
포트와 소켓: 포트는 한 호스트 안에서 통신 대상을 구분하는 번호입니다. 소켓은 IP 주소, 포트와 전송 프로토콜을 통해 프로그램이 네트워크를 사용하는 운영체제 인터페이스입니다.
DNS: 사람이 읽는 도메인 이름을 IP 주소와 다른 레코드로 해석하는 분산 시스템입니다. 계층적인 위임과 캐시를 사용하므로 변경이 모든 위치에 즉시 반영되지는 않습니다.
HTTP: 요청과 응답으로 웹 리소스를 교환하는 애플리케이션 프로토콜입니다. 메서드, 상태 코드, 헤더, 캐시 규칙과 콘텐츠 형식을 공통 계약으로 정의합니다.
TLS: 통신 상대를 인증하고 전송 내용을 암호화하며 변조를 탐지합니다. 인증서와 공개키 기반 구조를 이용해 서버의 신원을 검증합니다.
지연 시간과 대역폭: 지연 시간은 데이터가 도착하기까지 걸리는 시간이고, 대역폭은 단위 시간에 보낼 수 있는 양입니다. 작은 요청이 많은 서비스와 대용량 전송은 서로 다른 최적화가 필요합니다.
흐름 제어와 혼잡 제어: 흐름 제어는 수신자가 처리할 수 있는 속도에 맞춥니다. 혼잡 제어는 네트워크 전체가 감당할 수 있는 범위로 송신량을 조절합니다.
연결 재사용과 풀링: TCP와 TLS 연결을 매 요청마다 새로 만들지 않고 재사용합니다. 연결 설정 지연을 줄이지만 최대 연결 수, 유휴 시간과 실패한 연결 교체를 관리해야 합니다.
프록시와 로드 밸런서: 프록시는 클라이언트와 서버 사이에서 요청을 대신 전달합니다. 로드 밸런서는 여러 서버 중 대상을 선택하고 건강 상태와 연결 수를 관리합니다.
CDN: 사용자와 가까운 위치에 콘텐츠를 캐시해 지연과 오리진 부하를 줄입니다. 캐시 키, 만료, 무효화와 개인화된 응답의 분리가 중요합니다.
데이터베이스와 저장 구조
관계형 모델: 데이터를 행과 열로 구성된 관계로 표현하고 키를 통해 연결합니다. 구현의 물리적 저장 방식과 논리적인 데이터 질의를 분리합니다.
스키마와 제약 조건: 스키마는 데이터의 구조와 타입을 정의합니다. NOT NULL, UNIQUE, CHECK와 외래 키는 잘못된 상태가 저장되는 것을 데이터베이스 경계에서 막습니다.
기본 키와 외래 키: 기본 키는 행을 고유하게 식별하고 외래 키는 다른 테이블의 행을 참조합니다. 참조 무결성을 통해 관계가 끊어진 데이터를 방지합니다.
정규화와 비정규화: 정규화는 중복과 갱신 이상을 줄이도록 데이터를 분리합니다. 비정규화는 읽기 성능이나 단순한 조회를 위해 일부 중복을 의도적으로 허용합니다.
SQL과 질의 계획: SQL은 원하는 결과를 선언하고 데이터베이스가 실행 방법을 선택하게 합니다. 같은 SQL도 통계, 인덱스와 데이터 분포에 따라 다른 계획으로 실행됩니다.
인덱스: 전체 데이터를 읽지 않고 원하는 행의 위치를 찾기 위한 별도 자료구조입니다. 조회는 빨라지지만 쓰기 비용과 저장 공간이 늘어납니다.
B-Tree: 정렬된 키를 균형 잡힌 다진 트리에 저장합니다. 디스크 접근 횟수를 줄이면서 동등 조건과 범위 검색을 모두 지원해 관계형 데이터베이스의 대표 인덱스로 사용됩니다.
해시 인덱스: 키의 해시 값으로 위치를 찾습니다. 동등 비교에는 적합하지만 정렬과 범위 검색에는 일반적으로 맞지 않습니다.
LSM Tree: 쓰기를 메모리와 순차 파일에 모은 뒤 백그라운드에서 병합합니다. 높은 쓰기 처리량을 얻는 대신 읽기 경로와 compaction 비용을 관리해야 합니다.
트랜잭션과 ACID: 트랜잭션은 여러 읽기와 쓰기를 하나의 논리 작업으로 묶습니다. 원자성, 일관성, 격리성, 지속성은 실패와 동시 실행 속에서도 데이터 규칙을 지키기 위한 성질입니다.
격리 수준과 이상 현상: 격리 수준은 동시에 실행되는 트랜잭션이 서로의 변경을 어느 정도 볼 수 있는지 정합니다. Dirty Read, Non-repeatable Read와 Write Skew 같은 이상 현상을 어디까지 허용할지 선택합니다.
MVCC: 데이터의 여러 버전을 유지해 읽기와 쓰기의 충돌을 줄입니다. 독자는 일관된 시점의 스냅샷을 보고, 오래된 버전은 나중에 정리합니다.
잠금: 동시에 변경하면 안 되는 데이터에 접근 권한을 부여합니다. 행, 페이지, 테이블처럼 잠금 범위가 커질수록 관리 비용은 줄 수 있지만 동시성도 낮아집니다.
WAL: 실제 데이터 페이지보다 변경 로그를 먼저 기록합니다. 장애 후 로그를 재생해 완료된 변경을 복구하고, 복제 서버로 변경 순서를 전달하는 데도 사용됩니다.
복제: 같은 데이터를 여러 노드에 유지합니다. 읽기 확장과 장애 대응에 유용하지만 복제 지연, 쓰기 순서와 장애 전환 중 일관성을 다뤄야 합니다.
파티셔닝과 샤딩: 큰 데이터를 여러 구획으로 나눕니다. 한 데이터베이스 안의 파티셔닝과 여러 서버에 분산하는 샤딩은 비슷해 보이지만 운영 복잡도가 크게 다릅니다.
백업과 복구: 복제는 실수로 삭제된 데이터를 그대로 복제할 수 있으므로 백업을 대신하지 않습니다. 복구 시점과 허용 가능한 데이터 손실량을 기준으로 백업 주기와 검증 절차를 정합니다.
분산 시스템
분산 시스템: 네트워크로 연결된 여러 컴퓨터가 하나의 서비스를 제공합니다. 각 노드는 독립적으로 실패할 수 있고 통신 지연이 일정하지 않다는 점이 단일 프로세스와 가장 큰 차이입니다.
부분 장애: 시스템 전체가 멈추지 않고 일부 노드나 연결만 실패할 수 있습니다. 응답이 늦는 것과 실패한 것을 즉시 구분할 수 없으므로 타임아웃과 불확실성을 설계에 포함해야 합니다.
처리량과 지연 시간: 처리량은 단위 시간에 완료하는 작업 수이고 지연 시간은 한 작업이 끝나는 데 걸리는 시간입니다. 배치와 병렬화는 처리량을 높이면서 개별 요청 지연을 늘릴 수 있습니다.
시간과 순서: 서로 다른 컴퓨터의 물리 시계는 완전히 일치하지 않습니다. 논리 시계, 버전 벡터와 순서 번호는 사건의 선후 관계를 표현하는 데 사용됩니다.
일관성: 여러 복제본을 읽었을 때 어떤 값을 볼 수 있는지에 관한 계약입니다. 강한 일관성, 세션 일관성과 최종 일관성은 서로 다른 사용자 경험과 비용을 만듭니다.
가용성: 요청을 받았을 때 유효한 응답을 제공할 수 있는 성질입니다. 단순히 프로세스가 실행 중인 것뿐 아니라 의존 서비스와 데이터 접근이 가능한지도 포함합니다.
CAP 정리: 네트워크 분할이 발생한 동안 모든 요청에 응답하는 가용성과 모든 노드가 같은 최신 값을 보장하는 일관성을 동시에 완전히 만족할 수 없다는 경계입니다. 평상시의 성능 선택을 세 글자로 단순화하는 규칙은 아닙니다.
최종 일관성: 새 쓰기가 멈추면 복제본들이 결국 같은 값에 도달하는 모델입니다. 그 사이 오래된 읽기와 충돌이 가능하므로 사용자에게 허용되는 임시 차이를 정의해야 합니다.
쿼럼: 여러 복제본 중 일정 수 이상의 응답을 받아 읽기와 쓰기를 확정합니다. 복제 수와 읽기 및 쓰기 쿼럼의 관계로 일관성과 가용성의 균형을 조절합니다.
합의: 여러 노드가 장애와 메시지 지연 속에서도 하나의 값이나 로그 순서에 동의하는 문제입니다. Raft와 Paxos 같은 알고리즘이 대표적입니다.
리더 선출: 여러 노드 중 쓰기 순서나 조정을 담당할 하나를 선택합니다. 리더 장애 감지, 임기와 이전 리더의 뒤늦은 요청을 막는 규칙이 필요합니다.
멱등성: 같은 요청을 여러 번 수행해도 최종 효과가 한 번 수행한 것과 같도록 만드는 성질입니다. 네트워크 재시도에서 중복 결제와 중복 생성을 막는 핵심입니다.
재시도, 백오프와 지터: 일시적 실패에는 재시도가 도움이 되지만 모든 클라이언트가 동시에 다시 요청하면 장애가 커질 수 있습니다. 대기 시간을 점점 늘리고 무작위 지터를 더해 요청이 한 시점에 몰리는 것을 줄입니다.
서킷 브레이커: 실패 중인 의존 서비스에 요청을 계속 보내지 않고 일정 시간 빠르게 실패시킵니다. 의존 서비스가 회복할 여유를 만들고 대기 중인 요청이 무한히 쌓이는 것을 막습니다.
메시지 큐와 Pub/Sub: 생산자와 소비자의 실행 시점을 분리하고 작업을 버퍼링합니다. 전달 보장, 순서, 중복, 재처리와 실패 메시지 보관 정책을 함께 설계해야 합니다.
백프레셔: 소비자가 처리할 수 있는 속도보다 데이터가 빠르게 들어올 때 생산 속도를 제한하거나 버퍼를 관리합니다. 없으면 지연과 메모리 사용량이 계속 늘다가 전체 서비스가 무너질 수 있습니다.
분산 트랜잭션과 Saga: 여러 서비스의 변경을 하나의 작업처럼 다루는 문제입니다. 강한 원자성을 제공하는 프로토콜 대신 각 단계의 완료와 보상 작업을 명시하는 Saga를 선택하기도 합니다.
캐시 무효화: 원본 데이터가 바뀌었을 때 복사된 값을 언제 폐기할지 결정합니다. TTL, 버전, 이벤트 기반 무효화 중 어느 방식을 쓰든 잠시 오래된 값이 보일 가능성을 정의해야 합니다.
보안
위협 모델: 보호할 자산, 공격자 능력, 신뢰 경계와 예상 공격 경로를 먼저 정의합니다. 모든 위험을 막는다는 목표보다 실제 시스템에서 우선할 위험을 구체화합니다.
기밀성, 무결성과 가용성: 기밀성은 허가되지 않은 열람을 막고, 무결성은 변조를 막으며, 가용성은 필요할 때 시스템을 사용할 수 있게 합니다. 한 보안 대책이 세 속성에 서로 다른 영향을 줄 수 있습니다.
해시 함수: 임의 길이 입력을 고정 길이 값으로 바꿉니다. 데이터 무결성 확인과 키 기반 조회에 사용되지만 암호화처럼 원문을 복원하기 위한 기능은 아닙니다.
솔트와 비밀번호 파생 함수: 비밀번호마다 무작위 솔트를 더하고 계산 비용이 큰 전용 함수로 저장 값을 만듭니다. 같은 비밀번호의 해시가 같아지는 것을 막고 대량 추측 비용을 높입니다.
대칭키 암호화: 같은 비밀 키로 암호화와 복호화를 수행합니다. 대용량 데이터에 효율적이지만 통신 당사자가 키를 안전하게 공유해야 합니다.
비대칭키 암호화: 공개키와 개인키 한 쌍을 사용합니다. 키 교환, 전자서명과 상대방 인증에 활용되며 일반적으로 대칭키 연산보다 비용이 큽니다.
전자서명: 개인키로 만든 서명을 공개키로 검증합니다. 메시지가 특정 키 소유자에게서 왔고 전송 중 바뀌지 않았음을 확인합니다.
키 교환: 두 당사자가 도청 가능한 네트워크에서 공통 비밀을 만드는 과정입니다. TLS는 키 교환으로 세션 키를 만든 뒤 실제 데이터에는 대칭키 암호화를 사용합니다.
인증서와 PKI: 인증서는 공개키와 도메인 같은 신원 정보를 연결하고 인증 기관이 서명합니다. 클라이언트는 신뢰 체인과 유효 기간, 이름을 검증합니다.
인증과 인가: 인증은 사용자가 누구인지 확인하고, 인가는 그 주체가 어떤 행동을 할 수 있는지 결정합니다. 로그인 성공이 모든 자원 접근 권한을 의미하지는 않습니다.
세션과 토큰: 세션은 서버가 로그인 상태를 저장하고 식별자를 클라이언트에 전달하는 방식입니다. 토큰은 일부 상태와 권한 정보를 서명된 값에 담을 수 있지만 만료와 폐기 전략이 필요합니다.
최소 권한: 사용자와 서비스에 작업에 필요한 권한만 부여합니다. 자격 증명이 유출되거나 코드가 침해됐을 때 피해 범위를 줄입니다.
입력 검증과 인젝션: 외부 입력을 코드, 쿼리와 명령으로 해석하면 공격자가 실행 흐름을 바꿀 수 있습니다. 파라미터 바인딩과 허용 목록, 출력 인코딩으로 데이터와 명령의 경계를 지킵니다.
XSS와 CSRF: XSS는 신뢰하지 않은 스크립트가 브라우저에서 실행되는 문제입니다. CSRF는 로그인된 사용자의 권한으로 의도하지 않은 요청을 보내게 하는 문제이며 방어 방식이 서로 다릅니다.
샌드박스와 격리: 신뢰하지 않은 코드를 제한된 권한과 자원 안에서 실행합니다. 프로세스, 컨테이너와 가상 머신은 격리 강도와 운영 비용이 다릅니다.
비밀 관리와 감사 로그: API 키와 암호화 키는 코드와 일반 로그에서 분리하고 접근과 회전을 통제해야 합니다. 감사 로그는 누가 언제 어떤 권한으로 상태를 바꿨는지 추적합니다.
소프트웨어 공학과 운영
인터페이스와 계약: 구현이 제공해야 하는 입력, 출력과 오류 규칙을 정의합니다. 호출자는 내부 구현이 바뀌어도 계약이 유지되는 한 같은 방식으로 사용할 수 있습니다.
모듈화: 함께 바뀌는 코드를 한 경계에 모으고 다른 부분과의 연결을 제한합니다. 변경 영향 범위와 이해해야 하는 문맥을 줄입니다.
응집도와 결합도: 응집도는 한 모듈의 책임이 얼마나 밀접한지 나타내고, 결합도는 모듈들이 서로 얼마나 의존하는지 나타냅니다. 높은 응집도와 필요한 만큼의 낮은 결합도가 변경에 유리합니다.
불변식과 사전 조건: 불변식은 시스템이 항상 지켜야 하는 조건이고, 사전 조건은 연산 전에 만족해야 하는 조건입니다. 정상 흐름보다 허용되지 않는 상태를 먼저 정의하는 데 도움이 됩니다.
API 버전 관리: 이미 사용하는 클라이언트를 깨뜨리지 않고 계약을 바꾸는 방법입니다. 호환 가능한 확장, 폐기 기간과 명시적인 새 버전을 구분해야 합니다.
단위 테스트: 작은 함수나 모듈의 동작을 빠르게 검증합니다. 실패 위치를 좁히기 쉽지만 실제 데이터베이스와 네트워크 경계의 문제까지 보장하지는 않습니다.
통합 테스트와 E2E 테스트: 통합 테스트는 여러 구성 요소의 연결을 확인하고, E2E 테스트는 사용자 흐름 전체를 검증합니다. 범위가 넓을수록 실제성은 높지만 실행 시간과 실패 원인 분석 비용도 커집니다.
속성 기반 테스트: 특정 예시만 나열하는 대신 항상 성립해야 하는 속성을 정의하고 다양한 입력을 생성합니다. 파서, 직렬화와 자료구조의 경계 조건을 찾는 데 효과적입니다.
버전 관리: 코드와 설정의 변경 이력을 기록하고 여러 작업 흐름을 합칩니다. 커밋은 단순 백업보다 변경 이유와 검토 단위를 남기는 역할이 큽니다.
빌드와 재현 가능성: 같은 소스와 의존성에서 같은 산출물을 만들 수 있어야 합니다. 버전 고정, 격리된 빌드 환경과 산출물 검증이 공급망 안전과 장애 분석에 중요합니다.
CI와 CD: CI는 변경마다 빌드와 테스트를 자동화하고, CD는 검증된 산출물을 배포 가능한 상태 또는 실제 환경까지 전달합니다. 자동화 범위와 승인 경계는 서비스 위험도에 맞춰야 합니다.
관측 가능성: 외부 출력만으로 시스템 내부 상태를 추론할 수 있는 정도입니다. 로그, 메트릭과 트레이스를 연결하면 한 요청의 흐름과 전체 서비스의 변화를 함께 볼 수 있습니다.
로그, 메트릭과 트레이스: 로그는 개별 사건을 기록하고, 메트릭은 시간에 따른 수치를 집계하며, 트레이스는 여러 서비스에 걸친 요청 경로를 연결합니다. 셋은 서로 대체하지 않고 다른 질문에 답합니다.
SLI, SLO와 오류 예산: SLI는 가용성과 지연 같은 실제 측정값이고, SLO는 목표 수준입니다. 오류 예산은 목표를 벗어나지 않는 범위에서 허용되는 실패량을 나타냅니다.
장애 허용과 점진적 성능 저하: 일부 의존성이 실패해도 핵심 기능을 유지하도록 설계합니다. 전체 실패 대신 캐시된 값, 제한된 기능과 읽기 전용 모드로 전환할 수 있습니다.
배포 전략: Rolling, Blue-Green과 Canary 배포는 새 버전의 노출 범위와 복구 방식을 다르게 관리합니다. 데이터베이스 스키마처럼 이전 버전과 공유되는 상태도 함께 고려해야 합니다.
프로파일링과 병목: 추측이 아니라 측정으로 CPU, 메모리, I/O와 잠금 대기 중 어디에 시간이 쓰이는지 찾습니다. 한 부분을 빠르게 만든 결과 병목이 다른 계층으로 이동할 수 있습니다.
용량 계획: 현재 평균 사용량만이 아니라 피크, 성장률, 실패 시 여유 용량을 기준으로 자원을 준비합니다. 처리량 제한과 큐 길이, 저장 공간 증가를 함께 봅니다.
기술 부채와 리팩터링: 빠른 선택이 미래 변경 비용을 키울 수 있습니다. 리팩터링은 외부 동작을 유지하면서 내부 구조를 개선하며, 테스트와 작은 변경 단위가 안전망이 됩니다.
데이터와 인공지능
데이터셋, 특성과 레이블: 데이터셋은 학습과 평가에 사용하는 사례의 집합입니다. 특성은 모델 입력이고 레이블은 예측하려는 정답 또는 목표 값입니다.
지도, 비지도와 강화 학습: 지도 학습은 정답이 있는 사례에서 관계를 배우고, 비지도 학습은 구조와 패턴을 찾습니다. 강화 학습은 행동의 장기 보상을 기준으로 정책을 학습합니다.
모델과 파라미터: 모델은 입력을 출력으로 바꾸는 함수이고 파라미터는 데이터에서 학습되는 내부 값입니다. 모델 구조와 파라미터 수만으로 실제 품질이 결정되지는 않습니다.
손실 함수와 최적화: 손실 함수는 예측과 목표의 차이를 수치로 표현합니다. 최적화는 이 값을 줄이는 파라미터를 찾는 과정입니다.
경사 하강법과 역전파: 경사 하강법은 손실이 줄어드는 방향으로 파라미터를 조금씩 갱신합니다. 역전파는 신경망 각 파라미터가 손실에 미친 영향을 효율적으로 계산합니다.
과적합과 일반화: 과적합은 학습 데이터에는 잘 맞지만 새로운 데이터에서 성능이 떨어지는 상태입니다. 일반화는 보지 못한 데이터에서도 학습한 패턴이 유효한 정도입니다.
학습, 검증과 테스트 분할: 학습 데이터로 파라미터를 만들고 검증 데이터로 설정을 선택하며 테스트 데이터로 최종 성능을 확인합니다. 같은 데이터를 반복해 선택과 평가에 쓰면 결과가 낙관적으로 치우칩니다.
추론: 학습된 모델에 새 입력을 넣어 출력을 얻는 과정입니다. 지연 시간, 처리량, 메모리, 배치 크기와 정밀도가 운영 비용에 영향을 줍니다.
임베딩: 문자, 이미지와 다른 대상을 의미 관계가 반영된 벡터로 표현합니다. 검색과 군집화에 유용하지만 거리 값이 모든 업무 의미를 자동으로 보장하지는 않습니다.
어텐션과 Transformer: 어텐션은 입력 요소들이 서로 어떤 관련이 있는지 가중치를 계산합니다. Transformer는 이를 중심으로 병렬 학습과 긴 문맥 처리를 가능하게 한 신경망 구조입니다.
생성 모델: 학습한 데이터 분포를 바탕으로 새로운 텍스트, 이미지와 음성을 만듭니다. 자연스러운 출력과 사실성은 다른 속성이므로 별도의 검증이 필요합니다.
RAG: 검색으로 찾은 외부 자료를 모델 입력에 추가해 답변 근거를 보강합니다. 검색 품질, 문맥 구성과 출처 검증이 모델 선택만큼 중요합니다.
평가: 정확도 하나로 모든 모델을 비교할 수 없습니다. 업무별 성공 조건, 실패 비용, 데이터 편향과 운영 지연을 함께 측정해야 합니다.
개념들은 한 요청 안에서 만납니다
웹 API가 데이터베이스에서 값을 읽어 JSON으로 돌려주는 짧은 흐름에도 많은 개념이 연결됩니다.
1. DNS가 도메인을 IP 주소로 해석합니다.
2. TCP 연결과 TLS 세션이 만들어집니다.
3. HTTP 요청이 소켓을 통해 서버 프로세스에 도착합니다.
4. 운영체제 스케줄러가 요청 처리 스레드를 실행합니다.
5. CPU가 명령어를 실행하고 캐시와 가상 메모리가 데이터를 공급합니다.
6. 데이터베이스가 인덱스와 질의 계획으로 행을 찾습니다.
7. 트랜잭션과 MVCC가 동시에 실행되는 요청의 일관성을 관리합니다.
8. 응답이 인코딩돼 네트워크 계층을 거쳐 클라이언트로 돌아갑니다.
9. 로그, 메트릭과 트레이스가 이 경로의 지연과 실패를 기록합니다.각 개념을 따로 공부하는 이유는 분리된 시스템을 만들기 위해서가 아닙니다. 문제가 발생했을 때 어느 계층의 계약이 깨졌는지 좁혀 가기 위해서입니다. 요청이 느릴 때 알고리즘, 잠금, 디스크, DNS와 네트워크 중 어디를 먼저 측정할지 판단하려면 전체 지도가 필요합니다.
처음 공부한다면 이 순서가 좋습니다
- 비트, 인코딩, 자료구조와 시간 복잡도로 데이터 표현과 계산 비용을 익힙니다.
- CPU, 메모리 계층, 프로세스와 가상 메모리로 프로그램이 실행되는 위치를 이해합니다.
- 스택, 힙, 타입 시스템과 컴파일 과정을 연결해 코드가 실행 형태로 바뀌는 과정을 봅니다.
- IP, TCP, 소켓, DNS와 HTTP로 컴퓨터 사이의 통신 경로를 따라갑니다.
- 인덱스, 트랜잭션, MVCC와 WAL로 상태가 안전하게 저장되는 방법을 익힙니다.
- 부분 장애, 일관성, 멱등성, 재시도와 백프레셔로 여러 서버가 함께 실패하는 방식을 다룹니다.
- 위협 모델, 인증, 인가와 암호화를 각 계층의 신뢰 경계에 적용합니다.
이 순서는 선수 과목의 절대적인 규칙은 아닙니다. 작은 프로그램과 서버를 직접 만들면서 필요한 개념을 앞뒤로 오가는 편이 오래 기억됩니다.
이 문서는 시리즈의 허브입니다
이후의 심화 글은 각 문서만 읽어도 이해되도록 작성하고 cs-core-concepts 태그로 연결합니다. 새 글이 발행되면 이 허브의 관련 항목에도 직접 링크를 추가합니다. 번호 순서대로 읽어야 하는 연재물이 아니라, 관심 있는 지점에서 들어와 전체 지도로 돌아올 수 있는 구조입니다.
먼저 확장하기 좋은 주제는 다음과 같습니다.
- 프로그램 실행 과정: 소스 코드에서 CPU 명령어까지
- 메모리 계층: 레지스터, 캐시, RAM, 가상 메모리
- 프로세스와 스레드: 동시성 오류가 생기는 지점
- 소켓과 TCP: HTTP 요청이 서버에 도착하기까지
- 데이터베이스 트랜잭션: ACID, MVCC, 격리 수준
- 분산 시스템 실패 처리: 타임아웃, 재시도, 멱등성
- 인증과 인가: 세션, 토큰, 권한 모델의 차이
- 컴파일러와 런타임: AST, IR, JIT, 가비지 컬렉션
컴퓨터 공학의 개념은 계속 늘어나지만 중심 질문은 크게 달라지지 않습니다. 데이터는 어떻게 표현되는지, 계산은 어디에서 실행되는지, 상태는 어떻게 안전하게 바뀌는지, 서로 다른 컴퓨터는 어떻게 통신하는지, 일부가 실패해도 전체를 어떻게 유지하는지를 묻습니다. 이 다섯 질문을 기준으로 두면 새로운 기술도 기존 개념 위에 놓고 이해할 수 있습니다.
함께 읽기
- 웹 플랫폼 핵심 개념 지도: URL에서 렌더링과 보안까지웹 개발을 프레임워크 이름으로만 배우면 기술이 바뀔 때마다 지식도 함께 낡아 보입니다. 하지만 브라우저가 주소를 해석하고, 서버와 통신하고, 문서를 파싱하고, 픽셀을 그리는 기본 과정은 훨씬 천천히 바뀝니다. React, Vue, Svelte와 Next.js도 이 과정 위에서 서로 다른 개발 방식을 제공합니다.
- 클라우드와 DevOps 핵심 개념 지도: 인프라에서 배포와 관측성까지클라우드와 DevOps를 제품 목록으로 익히면 비슷한 기능을 가리키는 이름이 계속 늘어납니다. 가상 머신, 컨테이너, 서버리스, CI/CD와 Kubernetes는 같은 층의 대안이 아닙니다. 어떤 것은 실행 환경이고, 어떤 것은 배포 흐름이며, 어떤 것은 원하는 상태를 유지하는 제어 시스템입니다.
- LLM 게이트웨이 직접 구현: 스트리밍부터 사용량 기록까지이 글에서 직접 구현할 LLM 서버는 모델 가중치를 GPU에 올리는 추론 서버가 아닙니다. 여러 외부 또는 내부 모델 엔드포인트 앞에서 인증, 모델 선택, 스트리밍, 장애 처리, 사용량 기록을 담당하는 애플리케이션 계층의 LLM Gateway입니다. 모델 추론 자체는 vLLM 같은 별도 엔진이나 상용 API가 담당한다고…
- LiteLLM의 역사: Python SDK에서 AI Gateway까지LiteLLM을 단순한 멀티 모델 호출 라이브러리로만 이해하면 현재 모습의 절반만 보게 됩니다. 출발점은 Python 애플리케이션 안에서 여러 AI 모델 제공자를 같은 방식으로 호출하는 일이었지만, 지금은 조직의 모델 접근을 한곳에서 통제하는 AI Gateway까지 범위가 넓어졌습니다. 이 변화는 이름만 커진 것이 아니…
- Vercel의 역사: ZEIT와 Now에서 Fluid compute까지Vercel은 흔히 "Next.js를 배포하는 곳"으로 알려져 있습니다. 현재의 결합을 보면 자연스러운 설명이지만, 제품의 출발점은 프레임워크 호스팅보다 단순했습니다. 명령어 하나로 애플리케이션을 인터넷에 올리고, 배포마다 고유한 주소를 부여하는 것이 첫 문제였습니다.