초등학생도 이해하는 IT 인프라 2 - IT 기본 이론과 핵심 기술
IT 기본 이론, IT 핵심 기술
목차
지난 포스팅에서 수많은 사용자들에게 IT 서비스를 안정적으로 제공하기 위한 IT 인프라 기본 구조인 아키텍처, 그리고 아키텍처를 이루는 물리적인 구성(데이터센터, 서버)를 알아보았고, 3계층 아키텍처 물리적인 구성 위에서의 데이터 흐름을 살펴보면서 실제로 어떻게 IT 서비스가 제공되는지 내부 논리적 동작(프로세스, 스레드, 커널)에 대해서 간단하게 알아보았습니다.
이번에는 3계층 데이터 흐름의 물리적/논리적 동작 안에 숨어있는 IT 기본 이론(CS 지식)과, 이론을 응용한 핵심 기술에는 무엇이 있는지, 어떤 시스템에서 효과적으로 사용하고 있는지, 각 기술의 장단점은 무엇인지 알아봅시다. 추후에 시스템을 구축하게 될 때 어떤 기술을 도입할지 고려할 수 있는 역량을 갖추게 될 것입니다.
각 이론과 기술을 살펴볼 때 3계층 아키텍처의 그림을 같이 띄워두고, 어떤 부분에서 해당 기술이 사용되고 있는지 생각해보며, 살펴보기를 바랍니다.
1. 직렬 / 병렬
인기가 매우 많은 햄버거 패스트푸드점의 계산대를 상상해봅시다. 계산대가 1개만 있다면, 줄 서있는 사람들은 한번에 한명씩 주문을 접수할 수 있을 것입니다. 긴 대기시간에 대한 고객들의 VoC가 쌓여서, 더 빠르게 주문을 처리할 수 있는 패스트푸드점 10년 경력의 직원을 뽑았습니다. 분명히 1개의 계산대에서 주문을 받는 속도는 3배 빨라졌지만, 1년 경력의 직원에 비해서 5배의 임금을 지불해야한다고 합니다. 그래서 햄버거 가게 사장은 어떻게 하면 더 빠른 속도로 손님들의 주문을 처리할지 고민했고, 그 결과 계산대를 3대로 늘리고, 1년 경력의 직원을 3명 채용하였습니다. 결과적으로 10년 경력의 직원을 채용하는 것에 비해서 더 비용효율적입니다.
이 예시에서 직원은 CPU의 코어, 그리고 경력(능률)은 CPU의 클럭 수에 해당합니다. “햄버거 주문받기”와 같이 서로 영향을 주지않고, 병렬적으로 처리할 수 있는 프로세스는 개발자들이 프로그래밍을 통해서 여러 개의 스레드로 나누고, 여러 개의 코어에 스레드를 하나씩 나누어 할당함으로써, 병렬적으로 처리하여 “처리량”을 늘릴 수 있고, 결과적으로 더 빠르게 작업을 처리할 수 있게 됩니다. 물론, 클럭 수를 높이는 방법도 가능하지만, 햄버거 가게 예시와 같이 클럭 수는 투자 비용과 비례하여 처리속도가 상승하지 않았습니다. 뿐만아니라, 클럭 수가 높아짐에 따라 CPU의 발열이 심해지는 하드웨어적인 장벽이 있었습니다.
요약하자면, “병렬”은 하나의 작업을 나누어 동시에 여러 곳에서 처리하여 단위시간당 처리량을 늘리는 방법 이고, “직렬”은 하나의 작업을 한번에 하나씩 빠르게 처리하는 방법입니다. 병렬 처리는 원하는 만큼 작업을 나누어, 성능이 무제한으로 늘어날 수 있는 것처럼 보이지만, 두 가지의 한계점이 있습니다.
- 하나의 작업을 여러 개의 작업으로 나누고, 그 결과를 다시 합치는 것에 모두 오버헤드가 발생합니다.
- 일정한 순서에 따라 순차적으로 처리되어야하는 작업이 있듯이, 모든 작업을 병렬로 나눌 수는 없습니다.
- CPU 하나의 코어는 한번에 하나의 스레드만 처리할 수 있습니다. CPU의 코어가 하나밖에 없다면 작업을 병렬로 나누어 처리해도 어떠한 이점도 얻을 수 없습니다.
따라서 처리해야하는 작업에 따라 병렬로 처리할 수 있는지 여부를 판단하고, 병렬로 작업을 나누고 다시 합칠때의 오버헤드에 비해서 얻는 이점이 많을지 충분히 고려해야합니다.
1-1. 예시 - 웹 서버, AP 서버
웹 서버와 AP서버는 수많은 사용자들의 요청을 빠르게 처리해야합니다. 이를 위해서 웹 서버의 Apache HTTP Server, AP서버의 JVM 모두 병렬처리를 위한 멀티프로세싱, 멀티스레딩을 지원합니다. 또한, 보통 클라이언트의 요청간의 연관관계가 크게 없기 때문에 웹 서버, AP서버에서 처리하는 작업은 병렬적으로 처리해도 큰 문제가 없으므로 큰 오버헤드 없이, 성능 향상을 기대할 수 있습니다.
1-2. 예시 - DB 서버
DB서버 또한 AP서버에서 수많은 SQL쿼리 요청을 받게되고, 디스크에 데이터를 읽고 쓰는 작업을 반복합니다. 마찬가지로, AP서버의 요청에 비례해서 서버 프로세스를 여러 개 생성하고 병렬로 처리하고, 접근속도를 줄이기 위해 캐시에 쓰여진 데이터는 여러 개의 DBWR 프로세스를 통해 병렬적으로 디스크에 기록됩니다.
1.3 정리
직렬 | 병렬 | |
---|---|---|
장점 | 병렬에 비해서 프로그래밍이 쉽고, 단순하다. | 서버의 리소스(CPU, 메모리 등)를 충분히 활용할 수 있다. |
단점 | 서버의 리소스를 충분히 활용하는 것에 한계가 있다. | 작업을 분기하고 종합하기 위한 오버헤드가 발생하고, 공유하고있는 자원에 동시에 접근할 때의 배타적 제어도 고려해야하므로 프로그래밍이 매우 복잡하다. |
검색해볼만한 키워드
- Concurrent와 Parallel의 차이
- 오버헤드
- 병목현상
- Oracle DBWR 프로세스, 서버 프로세스
2. 동기/비동기
병렬처리 이외에도, 처리 성능을 끌어올려 시스템 리소스를 최대한 효율적으로 사용하기 위한 또다른 방법은 “비동기”입니다.
이번에도 햄버거 가게를 예로 들어보겠습니다. “동기”는 계산대의 직원이 주문을 받고, 메뉴를 만들어달라고 요청한 후 메뉴가 완성될 때까지 아무것도 하지않고 기다리는 것, “비동기”는 계산대의 직원이 주문을 받고, 다른 주문을 받거나 감자튀김을 만드는 등 다른 작업을 하는 것을 말합니다. 동기/비동기에 대해서 더 자세히 알아보겠습니다.
“동기”는 작업을 요청한 후 끝날때까지 잠자코 기다리는 것을 말합니다. 작업이 끝날 때까지 기다리므로 작업이 완료된 시점을 정확히 알 수 있지만, 작업이 끝날 때까지 대기해야하므로 시스템 리소스를 효율적으로 활용할 수 없습니다. 반면, “비동기”는 작업을 요청한 후 다른 작업을 처리하는 것을 말합니다. 작업이 끝날 때까지 기다리지않으므로 작업이 완료됐는지 정확하게 알 수 없지만, 작업이 처리되는 동안 시스템 리소스를 효율적으로 활용할 수 있습니다.
2-1. 예시 - Ajax
유튜브에서 검색창에 키워드를 입력할 때, 실시간으로 키워드와 가장 관련있는 검색어의 리스트를 보여주곤 합니다. 이러한 기능에는 Ajax라는 비동기 기술이 숨어있습니다. 실제로 우리가 검색창에 키워드를 입력할 때마다 병렬적으로 입력한 키워드와 가장 유사하고, 검색수가 많은 키워드 후보들을 필터링해서 가져오도록 검색엔진서버에 비동기로 요청합니다. 비동기로 완료된 작업은, 화면에서 해당 부분만 바뀌게 됩니다. 만약 이러한 일련의 과정이 동기로 처리됐다면, 키워드를 한 글자 입력할 때마다 그 결과값이 화면에 반영될 때까지 기다려야할 것 입니다.
2-2. 예시 - DBMS의 비동기 I/O
Oracle, Postgres와 같은 DBMS는 메모리 상에 있는 수많은 데이터를 디스크에 기록해야 합니다. DBMS는 보통 수많은 I/O를 빠르게 처리하기 위해서 병렬 또는 비동기 방식을 활용합니다. 병렬로 처리할 경우에는 여러 DBMS 프로세스를 이용해서 동기로 I/O 처리를 요청하고 기다립니다. 반면, 비동기로 처리할 경우에는 DBMS 프로세스가 I/O 처리 완료 여부와 상관없이 계속해서 I/O 처리를 요청합니다. (DBMS의 비동기 I/O처리는 DBMS 종류와 OS 종류마다 다른 시스템 콜을 이용하므로, 자세한 작동방식에는 차이가 있을 수 있습니다.)
2-3. 정리
위의 예시처럼 비동기를 이용하면 병렬적으로 작업을 처리함으로써 디스크 I/O의 상한선까지는 서버의 리소스를 효율적으로 사용할 수 있습니다. 하지만 동기 처리와 다르게 요청한 작업이 완료됐는지 확인하지않으므로, 작업 완료 여부를 알아야할 경우 “이벤트 주도 방식” 등 다른 방법을 이용해야하고, 앞에서 요청한 처리가 끝나지않아도 다음 처리를 진행해도 문제 없을지 등 고민해야하는 복잡성이 생깁니다.
동기 | 비동기 | |
---|---|---|
장점 | 요청한 작업이 완료되었는지 쉽게 확인할 수 있어 단순하고, 구현이 쉽다. | 병렬 처리를 통해서 서버의 리소스를 충분히 활용할 수 있다. |
단점 | 서버의 리소스를 충분히 활용하는 것에 한계가 있다. | 요청한 작업이 완료되었는지 여부를 따로 확인해야하는 등 프로그래밍이 상대적으로 복잡하다. |
검색해볼만한 키워드
- Javascript 비동기처리(callback, promise, async)
- NodeJS의 비동기 처리 원리
- 이벤트 주도 방식(Event Driven Architecture)
- 트랜잭션 동기/비동기
3. 큐
“큐(Queue)”란 대기 행렬을 말합니다. 자료구조와 알고리즘을 공부할 때 쉽게 접할 수 있는 구조입니다. 햄버거 가게의 대기열과 같이, 먼저 대기한 사람이 (First In) 먼저 나가는 구조(First Out)라고해서, FIFO(선입선출)라고도 합니다. 큐는 컴퓨터 거의 모든 곳에서 사용되고 있는 구조입니다. 예를 들면, CPU 할당을 기다리는 프로세스 행렬(Ready Queue)나 I/O를 대기하고있는 작업(프린트, 네트워크 통신, 디스크 Read/Write) 대기열이 있겠습니다. 주로 여러 처리를 순차적으로 처리해야할 때 사용하게 됩니다.
3-1. 예시 - 프로세스 Run Queue(Ready Queue) / Waiting Queue
이전 포스팅에서 커널의 핵심 역할 중 하나는 프로세스 관리(프로세스 스케줄링)이라고 했습니다. 서버에서 처리해야하는 수많은 작업(프로세스, 스레드)에 대해서 우선순위를 정하는 스케줄링 방식은 OS마다 차이가 있으며, 멀티코어 서버의 경우, 어떤 프로세스가 어떤 코어를, 어떤 순서로 할당 받을지를 결정하게 됩니다. CPU 할당을 대기하는 프로세스들은 레디큐(Ready Queue)라는 대기행렬에서 대기하며, I/O 작업(네트워크, 디스크 등)을 요청한 프로세스들은 대기큐(Waiting Queue)에서 대기합니다. Linux 환경에서는 vmstat이라는 명령어를 통해서 해당 행렬에서 대기하고있는 프로세스 수를 알 수 있습니다.
위의 이미지는 실제 RHEL 환경의 WEB 서버에서 vmstat 명령어를 입력했을 때 출력되는 화면입니다. CPU 코어 수에 비해 Ready Queue에서 대기하고있는 프로세스가 많은 경우, I/O 처리를 기다리고 있는 프로세스가 많은 경우 등 vmstat 명령어를 통해 병목 지점을 진단할 수 있을 것입니다.
Linux 환경에서는 대기하고있는 프로세스의 수 뿐만아니라, 실제로 CPU 코어를 할당받은 프로세스도 Ready Queue에 포함하여 카운트 한다는 점을 유의하시기를 바랍니다.
검색해볼만한 키워드
- 프로세스 스케줄링와 프로세스 상태
- 리눅스의 CFS 스케줄링
- vmstat 명령어
- Context Switching
3-2. 정리
앞에서 말씀드렸던 것처럼, 큐는 먼저 입력된 작업에 대해서, 먼저 처리하게 됩니다. 따라서, 여러 작업에 대해서 순서대로 처리하고싶은 경우에 주로 사용합니다. 하지만, 여러 작업이 비동기/병렬로 빠르게 큐에 쌓이게 될 경우, 직렬로 처리되는 큐가 병목지점이 될 수 있다는 점을 인지해야하며, 한정된 메모리 자원을 사용하는 자료구조이기때문에 요청받은 작업의 수가 큐의 길이를 넘게 될 경우에 대해서도 고려해야합니다.
순차처리 이외에도, 아키텍처를 설계할 때 큐를 활용하면 시스템간의 결합도(Coupling)를 줄일 수 있습니다. 자동차 공장을 상상해보면, 타이어를 자동차에 결합해야하는 사람들은 타이어와 결합하고 컨베이어 벨트(큐)를 통해서 다음 사람들에게 작업을 넘기게 됩니다. 이처럼 큐를 활용하면 작업을 요청하는 여러 프로세스들은 큐(컨베이어 벨트)에 단순히 요청을 밀어넣고, 완료 여부에 대해서는 크게 신경쓰지않아도 됩니다. 이후, 큐(컨베이어 벨트)를 거쳐 나온 작업들은 그 작업들을 처리하는 프로세스(작업자)들이 각각 가져가서 처리하게 됩니다. 이처럼, 시스템 간의 결합도를 낮춰 장애 전파를 막을 수 있습니다. 이를 활용한 메세징 큐 기술에는 RabbitMQ, Kafka, AWS SQS 등이 있습니다.
4. 배타적제어
배타적 제어(Mutual Exclusion)란 여러 프로세스가 공유하는 자원에 대해서, 한번에 하나의 프로세스만 접근할 수 있도록 하는 것입니다.
은행 입출금 서비스를 예로 들어봅시다. A계좌에는 지금 2만원이 있고, B계좌에서 A계좌로 3만원을, C계좌에서 A계좌로 4만원을 우연히 정확히 같은 시각에 송금하는 상황을 가정해보겠습니다. 만약 배타적 제어를 제대로 고려하지않았다면 B, C 계좌에서 기억하고있는 A계좌 잔액에 각 송금액을 더하게 되고 2+3 만원 또는 2+4만원 중의 하나의 결과만 반영되게 될 것 입니다. 이처럼, 동시에 하나의 자원에 접근을 허용하게 되면 데이터 정합성에 문제가 생길 수 있습니다. 이를 해결하기 위해서, 하나의 송금 트랜잭션이 진행될 때 해당 데이터는 다른 프로세스가 접근할 수 없도록 잠그고, 트랜잭션이 완료되면 그 잠금을 해제하게 됩니다.
실제로, 병렬로 작업을 처리하게 될때 반드시 배타적 제어를 고려해야하고, 이는 이미 OS, DBMS, 프로그래밍 언어(Java, Golang 등) 에서 병렬처리를 위해서 다양한 방법(스핀락, synchronized, row lock, mutex)을 적용합니다. 다만, 동시에 같은 자원(CPU, 메모리, 디스크 등)을 사용하는 것은 한번에 하나의 작업만 가능하도록 제어하는 부분이기때문에, 병렬처리 중 성능을 낮추게되는 병목 지점이 될 수 있습니다.
4-1. 예시 - DBMS 배타적제어
DBMS에서는 어떤 프로세스가 데이터를 변경하고 있을 때, 동시에 다른 프로세스가 데이터를 읽거나 변경하는 것을 배타적으로 제어합니다. DBMS 별로 다르겠지만, 데이터 행 단위로 잠그거나 테이블 단위로 잠그는 등 배타적 제어 범위(Lock Level)에 대해 설정할 수 있으며, 대기하고 있는 DB 프로세스들은 내부적으로 Lock이 풀렸는지 체크하는 동작을 반복하며 Lock을 확보할 수 있도록 대기합니다. 이를 스핀 락(Spin-lcok) 이라고 합니다.
4-2. 예시 - OS 배타적 제어
OS에서도 동일하게, 여러 CPU 코어에서 동작하고 있는 프로세스(스레드)가 동시에 커널을 사용하려고 할때 빅 커널락(Big Kernel Lock)을 통해서 한번에 하나의 프로세스만 커널에 접근할 수 있도록 배타적 제어를 구현합니다. 따라서 CPU가 멀티 코어를 통해서 병렬처리를 하더라도 배타적 제어가 구현된 부분에서는 직렬로 처리되도록 합니다.
4-3. 정리
배타적 제어 O | 배타적 제어 X | |
---|---|---|
장점 | 공유 자원에 대해서 데이터 일관성을 유지할 수 있다. | 데이터 일관성을 보장할 수 없다. |
단점 | 구현이 복잡하고, 병렬 처리에 대해서 병목 지점이 될 수 있다. | 구현이 단순하며, 직렬처리 구간이 없어 병렬로 빠르게 작업을 처리할 수 있다. |
검색해볼만한 키워드
- Mutual Exclusion
- Critical Section
- 세마포어(Semaphore)
- Mutex
- Dead Lock
- 식사하는 철학자 문제
- Test and Set
- Compare And Swap(CAS)
5. 상태저장/상태비저장
“상태저장”, “상태비저장”에서의 상태는 어떤 대상에 대한 정보, 이력, 기록을 말합니다. 상태를 갖는 대상은 하나의 요청이 될 수도 있고, 하나의 프로세스가 될 수도 있습니다. 어떤 대상에 대한 정보와 기록이 남아있다면, 그 기록에 따라서 적절한 처리를 할 수 있을 것입니다.
예를 들어 병원 진료 기록이 “상태 저장”에 해당합니다. 병원에서 환자의 의료 기록이 관리되며, 어떤 질환이 있었고, 어떤 약의 처방을 피해야하는지 기존의 기록을 살펴보면 그때 그때 환자에게 맞는 적절한 처리를 할 수 있습니다. 하지만 “상태 비저장”이라면 병원에 방문할 때마다 자신의 과거 진료이력을 직접 준비 해야할 것 입니다.
이처럼, “상태저장”은 “상태를 저장하며, 특정 동작에 의해서 상태가 전이되는 것”을 말합니다. 매 과정마다 상태를 체크하고 그에 따른 적절한 분기가 필요하므로 “상태비저장”에 비해 복잡합니다. 뿐만아니라, 상태를 저장하는 테이블을 활용한다면 그에 따라 동일한 기능을 하는 서버에도 테이블을 동기화해야하는 등 서버를 자유롭게 확장하는 데 제약이 생기게 됩니다. “상태비저장”은 상태를 저장하지않으므로 시스템이 복잡하지않고, 시스템을 자유롭게 확장할 수 있습니다.
5-1. 예시 - 프로세스 상태저장
앞의 큐에서 말했던 것처럼 여러 프로세스는 CPU의 코어를 할당받기 위해서 Ready Queue에서 대기하고, I/O 요청을 보낸 후에는 Waiting Queue에서 대기하는 상태를 가집니다. 조금 더 자세히 알아보겠습니다.
위의 이미지처럼, 프로세스는 생성(Created), 준비(Ready), 대기(Waiting), 실행(Runnning), 종료(Terminated) 상태를 가집니다. 각 상태의 의미 다음과 같습니다.
- 생성(Created, New) = 명령이나, 애플리케이션을 실행했을 때 커널에 의해 프로세스 생성
- 준비(Ready) = 프로세스 생성 후, 레디 큐(Ready Queue)에서 CPU 할당을 기다리는 상태
- 실행(Running) = Ready Queue에서 커널의 프로세스 스케쥴링에 의해 선택된 프로세스가 CPU 코어를 할당(Dispatch)받고, 작업을 처리하고있는 상태
- 대기(Waiting) = CPU를 할당받은 프로세스가 I/O 작업을 요청한 후 Waiting Queue에서 대기하는 상태
- 종료(Terminated) = 프로세스가 종료된 상태
이처럼 프로세스는 각 단계별로 상태를 갖고, 특정 동작 후에는 상태를 전이하는 복잡한 시스템을 갖고있지만, 프로세스의 상태를 저장함으로써 여러 프로세스를 빠른 속도로 번갈아가며 실행 할 수 있는 “멀티 프로세싱”이 가능해집니다.
5-2. 예시 - HTTP 상태비저장
대표적인 “상태비저장” 처리는 HTTP 요청입니다. HTTP 요청은 기본적으로 상태를 저장하지않습니다. 따라서 복잡한 처리가 필요할 경우 매 HTTP 요청마다 헤더에 추가적인 정보를 심어서 전달해주어야 합니다. 아래 그림처럼 HTTP 헤더에 “어떤 브라우저를 통해서 요청했는지”, “어떤 종류의 데이터를 요청한 것인지” 등등 정보를 심어 보내야합니다.
그러나 회원/비회원에게 보여주는 화면을 구분하고 싶은 경우에는, 페이지를 이동할때마다 필요한 정보(사용자의 아이디, 패스워드)를 요청해야합니다. 이것이 “상태비저장”의 단점입니다. 기본적으로 HTTP는 상태비저장 방식이지만 쿠키, 세션 기술을 활용하면 사용자의 상태를 저장할 수 있습니다. 사용자가 로그인을 성공하면 어떠한 랜덤한 문자열인 쿠키값(토큰값)을 전달하고, 사용자는 이 쿠키값(토큰값)을 저장해두고, 이후에는 이 토큰을 헤더에 넣어 요청하게 됩니다. 서버 측에서는 이러한 쿠키 정보와 매핑할 수 있는 사용자 상태를 저장해두고 이후 요청이 올 때마다 쿠키 정보를 바탕으로 해당 사용자의 상태를 조회할 수 있게 됩니다.
검색해볼만한 키워드
- RESTful API
- 쿠키, 세션
5-4. 정리
상태 저장 | 상태 비저장 | |
---|---|---|
장점 | 상태 정보를 바탕으로 복잡한 처리가 가능하다. | 상태 정보를 고려할 필요 없어 단순하므로 성능이 상대적으로 좋고, 확장성이 좋다. |
단점 | 상태 정보를 고려해야하므로 확장성이 좋지않다. | 복잡한 처리가 불가능하고, 상태를 저장하기 위해서 별도의 기술을 고려해야한다. |
6. 가변길이/고정길이
컴퓨터는 기본적으로 데이터의 길이를 가변길이/고정길이로 다룹니다. 이렇게만 설명해서는 잘 와닿지 않는 것 같습니다. 이번에는 책꽂이를 예시로 설명해보겠습니다.
두 개의 책꽂이가 있습니다. “고정길이”는 일반적인 도서관의 책꽂이를 생각하면 됩니다. 각 칸의 카테고리와 크기가 고정으로 정해져있으며, 카테고리에 해당하지않는 경우에 해당 칸에 책을 꽂을 수 없습니다. 때문에, 각 칸마다 빈자리가 많아 공간효율성이 좋지는 않지만, 각 칸마다 용도가 정해져있으므로 원하는 카테고리의 원하는 책을 빠르게 찾거나 제자리로 되돌려 놓을수 있습니다. 반면, “가변길이”는 도서관 반납함의 책꽂이를 떠올릴 수 있습니다. 반납 책꽂이의 칸은 책의 카테고리와 상관없이 빈자리에 꽂으면 됩니다. 따라서, 빈공간 없이 공간을 효율적으로 활용할 수 있지만, 원하는 책을 찾기에는 매우 어려울 것 입니다. 이 경우, 매번 정리하기에도 매우 복잡한 과정이 필요할 것 입니다.
실제 컴퓨터에서 어떻게 사용되는지 예시를 들어보겠습니다.
6-1. 고정길이 예시 - 배열
프로그래밍 언어에서도 알 수 있듯 기본적으로 배열은 고정길이입니다. 위의 도서관 책꽂이 예시와 같이, 처음 생성할 때 길이가 고정돼있으며, 각 칸의 크기도 고정돼있습니다. 배열은 기본적으로 인덱스를 활용해서 원하는 정보를 효율적으로 찾을 수 있을 뿐만아니라, 일정한 패턴으로 데이터를 조회/수정 하기에도 용이합니다. 컴퓨터는 내부적으로 배열과 같은 고정길이의 특징을 활용해서 파일시스템을 구현하여 고정길이의 이점을 가져갑니다. 이때, 하드디스크의 섹터의 크기(512바이트)를 고려하여 고정길이(I/O 크기, 블록)에 대해 고려하는 데, 이 내용은 아래에서 더 자세히 다루겠습니다.
6-2. 가변길이 예시 - 네트워크 패킷
애플리케이션에서 네트워크를 경유해서 다른 서버로 데이터를 전달하기 위해서는 데이터를 여러 조각(패킷)으로 분할합니다. 일반적으로 네트워크에서 보낼 수 있는 패킷의 최대 크기를 MTU(Maximum Transfer Unit)라고 하고, 1500바이트의 크기를 갖습니다. MTU과 IP 헤더, TCP 헤더를 고려해서 애플리케이션에서 내려올 수 있는 데이터 세그먼트의 최대 크기(Maximum Segment Size)는 1460바이트 입니다. (아직은 익숙하지않겠지만, 네트워크에 대한 더 자세한 내용은 다른 포스팅에서 다루겠습니다.) 따라서, 애플리케이션에서 3200바이트의 데이터를 다른 서버로 전송해야할때, 1460 + 1460 + 80 바이트의 총 3조각의 패킷으로 나누어야 합니다. 이렇게 패킷으로 나눈 후에, 어떠한 정보를 담은 헤더와 트레일러를 붙이게되면 실제로 네트워크를 흐를 수 있는 이더넷 프레임이 됩니다.
위의 책꽂이 예시에서 가변길이의 단점은 데이터를 다시 조회하거나, 정리하기 어렵다는 점입니다. 하지만 패킷 자체는 다른 서버로 전달된 후 버려지는 일회용 데이터이므로 다시 조회하거나, 정리할 필요가 없고, 가변길이를 사용함으로써 네트워크 공간을 효율적으로 활용할 수 있게 됩니다.
6-3. 정리
고정 길이 | 가변 길이 | |
---|---|---|
장점 | 데이터 조회 성능이 뛰어나다. | 공간을 효율적으로 활용할 수 있다. |
단점 | 공간을 효율적으로 활용할 수 없다. | 데이터 조회 성능이 떨어진다. |
7. 자료구조(배열, 연결리스트, 해시, 트리)와 알고리즘
기본적으로 자료구조와 알고리즘은 컴퓨터공학 전공과목 중 필수과목이기도하고, 운영체제부터 게임까지 다양한 시스템을 구현할 때 많이 응용되는 지식입니다. 시스템 목적에 따라서 중요한 성능(조회, 생성, 삭제 등)이 다릅니다. 시스템에서 집중하고자하는 성능에 따라 적절한 알고리즘이 있고, 그러한 알고리즘을 구현하기 위해서 데이터를 미리 적절한 자료구조로 정리하여 저장해두는 것이 반드시 선행돼야합니다. 책상을 미리 계획적으로 정리해두면 내가 원하는 필기구와 노트를 빠르게 찾아서 사용할 수 있는 것을 떠올리면 될 것 같습니다. 자료구조를 선택할 때 유의할 점은, 데이터가 저장되는 하드웨어에 따라서도 적절한 자료구조가 다를 수 있다는 것입니다. 예를 들어, 트리라는 자료구조는 하드디스크에서는 B-Tree, 메모리에서는 T-Tree가 유용하게 사용됩니다.
이처럼, “자료구조”는 데이터를 저장하는 방식을 말하며, “알고리즘”은 자료구조에서 데이터를 다루는 방식을 말합니다. 이번에는 가장 많이 응용되는 동시에, 가장 기본적인 선형 자료구조, 배열과 연결리스트에 대해서 간단하게 다루겠습니다. 다른 다양한 자료구조와 알고리즘에 대해서는 별도의 알고리즘 문제풀이와 포스팅으로 자세히 다루겠습니다.
7-1. 배열과 연결리스트
배열과 연결리스트는 데이터를 순차적으로 처리하는 “선형 자료구조” 라는 공통점이 있습니다. 반면, 구현되는 방식의 차이가 있어 데이터 조회/추가/삭제 성능에 차이가 있습니다. “배열”의 경우 같은 타입의 데이터를 일렬로 나열한 구조이며, 실제로 저장할 데이터 타입과 배열의 크기를 고려하여 메모리 상에서 연속된 공간을 할당하게 됩니다. 따라서, 원하는 데이터에 대해서 순서정보(인덱스)를 알고있다면 상수시간O(1)
만에 데이터를 조회할 수 있으므로 조회 성능은 좋습니다. 하지만 데이터가 중간에 추가되거나 삭제하려면 그 이후 데이터를 전부 밀거나, 당겨와야하므로O(n)
추가/삭제 성능은 떨어집니다.
반면, “연결리스트”의 경우 다음 데이터에 대한 주소값(메모리 주소, 포인터)을 저장하는 방식으로 연결되어 있습니다. 따라서, 원하는 데이터를 조회하기 위해서는 주소정보를 따라서 첫 노드부터 다음 주소를 확인하며 순서대로 하나하나 확인해야하므로 조회 성능은 떨어집니다. 하지만 데이터가 중간에 추가되거나 삭제하는 경우, 앞에 있는 노드가 원래 가리키던 주소값을 변경하기만 하면되므로 상수시간O(1)
만에 데이터를 조회할 수 있습니다.
7-2. 예시 - 해시 테이블
아래 이미지는 “해시테이블”이라는 자료 구조입니다. “배열”과 “연결리스트”의 장점만을 섞은 자료구조입니다. 초록색의 박스들은 “배열”이며, 빨간색의 박스들은 “연결리스트”입니다. 실제로 배열의 특성을 이용하여 빠른 조회 성능, 연결리스트의 특성을 이용하여 빠른 추가, 삭제 성능을 자랑하므로 DB 캐싱 등 엄청나게 많은 시스템을 구현하는데 유용하게 사용되는 자료구조이며, 프로그래밍 언어 Java에서 “HashMap”, Go에서는 “Map”을 통해 해시테이블을 사용할 수 있습니다.
7-2. 정리
배열 | 연결리스트 | |
---|---|---|
장점 | 데이터 조회 성능이 뛰어나다. | 데이터 추가, 삭제 성능이 뛰어나다. |
단점 | 데이터 추가, 삭제 성능이 떨어진다. | 데이터 조회 성능이 떨어진다. |
검색해볼만한 키워드
- 자료구조와 알고리즘
- 시간복잡도와 공간복잡도(Time Complexity, Space Complexity)
- Java Hashmap의 내부 구현
- DB 풀스캔(Full scan)과 인덱스 스캔(Index scan)
- DB 인덱스와 트리(B-tree) 자료구조
- DB 해시 인덱스
8. 캐시
“캐시”는 사용빈도가 높은 데이터를 가깝고, 고속으로 접근할 수 있는 위치에 두는 것을 말합니다. 자주 보거나, 읽고있는 책은 책상에 두고, 그렇지않은 책은 책방의 책꽂이에 꽂아두는 것을 떠올리면 더 이해하기 쉬울 것 같습니다. 모든 책을 책상에 두면 좋겠지만, 책상이라는 공간의 크기는 한정돼있습니다. 이전 포스팅의 메모리 계층구조에서도 언급했지만, 캐시 기술은 CPU의 캐시메모리 뿐만아니라, 데이터베이스 캐시, 스토리지 캐시메모리 등 광범위하게 사용되고 있습니다.
8-1. 예시 - 브라우저 캐싱과 CDN(Content Delivery Network)
구글 크롬과 같은 웹브라우저는 접속했던 페이지에 대한 정보를 캐싱합니다. 일반적으로 처음 접속하는 웹페이지에 대해서는 도메인 이름을 해석(DNS Resolution)하고, 실제 서버의 IP를 알아내서 네트워크 통신으로 화면 컨텐츠를 요청하게 됩니다. 하지만 다시 웹브라우저를 통해서 해당 웹페이지에 접근하려고 할때, 크게 총 세가지의 캐시 기술이 사용됩니다.
- 웹 브라우저 캐시
- DNS 캐시
- CDN
구글 크롬 브라우저를 통해서 넷플릭스 웹페이지에 재접속하는 상황을 가정해봅시다.
- 웹 브라우저 캐시 = 웹 브라우저는 웹 페이지에 대한 콘텐츠를 로컬 서버에 캐시해둡니다. 웹 서버는 요청을 보내기전에 캐시된 정보를 먼저 확인함으로써 해당 웹서버로 직접 접근하는 것을 줄이므로, 웹 서버는 부하를 줄일 수 있고, 사용자는 원거리에 있는 서버와 네트워크 통신하는데 걸리는 시간을 단축함으로써 더 빠르게 컨텐츠를 확인할 수 있게 됩니다.
- DNS 캐시 = 도메인 해석(DNS Resolution)정보가 로컬 서버에 캐시돼있는지 먼저 확인하고, 캐시돼있다면 DNS 서버에 다시 질의할 필요 없이 갖고있는 IP 정보를 재사용하여 웹서버에 요청을 보내게 됩니다.
- CDN 캐시 = 해외의 멀리있는 서버와 네트워크 통신을 하기 위해서는 글로벌한 백본 네트워크를 통과해야하므로, 비용(망 사용료)과 응답시간에 문제가 발생합니다. 따라서, 넷플릭스와 같은 서비스는 전 세계에 골고루 여러 개의 서버를 두고 각 서버에 영상 데이터의 복사본을 저장해둡니다. 사용자는 오리지널 서버에 접근할 필요 없이, 여러 서버에 분산돼있는 데이터에 대한 정보를 종합하여 빠르게 비디오 컨텐츠를 제공받을 수 있습니다. 뿐만아니라, 전 세계의 여러 서버들로 네트워크 요청과 부하를 분산할 수 있으므로 서비스의 안정적인 제공이 가능하게 됩니다.
실제로 아래 이미지처럼, Netflix는 세계 전역에 자체 CDN 서버를 두어 시청 경험(레이턴시)와 비용적인 측면을 모두 개선하려고 노력하고 있습니다.
8-2. 정리
캐시 기술의 장단점은 앞에서 언급했던 것처럼 아래와 같습니다.
캐시 | |
---|---|
장점 | 데이터를 고속으로 액세스할 수 있으며, 원본을 갖고있는 서버에 대한 접근 부하를 줄일 수 있다. |
단점 | 원본 데이터가 변경될 경우, 변경 사항을 원본 데이터에 반영해야하는 등 복잡함이 있다. |
따라서, 캐시 기술은 데이터가 변경되는 빈도가 적고, 조회가 많은 시스템(Youtube, Netflix)에 유용하게 사용할 수 있습니다. 조회 빈도가 많은 시스템의 경우 캐시된 데이터가 손실되더라도, 원본의 데이터를 다시 배치하면 되므로 크게 문제가 발생하지 않습니다. 반면에 갱신 빈도가 많은 시스템의 경우, 갱신된 데이터를 원본 서버에 반영해야하고, 캐시 서버에만 갱신된 데이터가 원본 서버에 반영되지않는 경우 데이터 일관성에 문제가 발생할 수 있는 점을 고려해야합니다.
검색해볼만한 키워드
- CDN(Content Delivery Network)
9. 인터럽트와 폴링
9-1. 인터럽트
“인터럽트”란, 단어 뜻 그대로 진행 중인 일을 중단하고 급한 일을 끝낸 후, 다시 돌아와서 작업을 계속하는 것을 말합니다.
일상생활 속에서도 공부를 하다가 급한 전화가 오면, 전화를 받은 후에 다시 공부를 이어나갑니다. 이와 비슷하게 CPU에서 애플리케이션 프로세스(스레드)을 처리하다가, NIC에 이더넷 프레임이 도착하거나, 키보드로 어떤 값을 입력하는 등 급하게 처리해야하는 이벤트가 발생하면 CPU는 처리하던 프로세스의 정보를 잠시 메모리에 저장해두고 급한 이벤트를 먼저 처리하게 됩니다. 우리가 다른 애플리케이션을 실행하고있더라도 키보드로 값을 입력하면 바로바로 그 결과값이 화면에 출력되는 것도 인터럽트에 의한 현상입니다.
인터럽트는 기본적으로 하드웨어에 의해 발생하는 하드웨어 인터럽트와 소프트웨어에 의해 발생하는 소프트웨어 인터럽트로 나눌 수 있습니다. 하드웨어 인터럽트에는 키보드 입력, 이더넷 프레임 수신, 디스크 쓰기 완료, 타임슬라이스 등의 인터럽트가 있으며, 소프트웨어 인터럽트에는 코딩한 프로그램을 실행시킬 때 흔히 발생하는 Error, Exception을 일컫는 트랩(Trap) 이있습니다. 기본적으로 두 종류의 인터럽트가 처리되는 과정은 유사합니다.
9-2. 폴링
인터럽트의 경우 평소에 신경쓰지않다가 어떠한 이벤트가 발생했을 때, 이벤트 종류에 맞게 적절한 처리를 수행했습니다. 반면, “폴링”은 정기적으로 상태를 확인하는 등의 작업을 반복 수행하는 것을 말합니다. 우체국 집배원이 일정한 시간마다 우체통을 확인하는 것을 생각하면 됩니다. 우체통에 편지가 있는지, 없는지는 중요하지않고 주기적으로 상태를 확인 하면 됩니다.
인터럽트와 폴링은 정확히 정반대의 특징을 갖기 때문에 인터럽트와의 차이점을 바탕으로 폴링을 이해하면 더 쉽습니다. “인터럽트”는 평소에는 상태를 체크하지않고, 이벤트가 발생하면 CPU가 적절한 처리를 하는 것입니다. 반면 “폴링” 기술은 일정한 시간 간격으로 계속해서 단방향의 질의를 보내기 때문에 루프를 통해 CPU가 지속적으로 상태를 체크해야합니다.
디스크 I/O가 완료됐는지, NIC에 이더넷 프레임이 도착했는지, 키보드에 어떤 값이 입력됐는지. 즉 언제 발생할지 모르는 I/O 작업에 대해서 폴링으로 짧은 시간 간격으로 계속해서 확인한다면 CPU 리소스가 낭비되는 상황이 발생하게 됩니다. 반대로 폴링 간격을 길게하면 이벤트가 발생하더라도 다음의 폴링이 돌아올때까지 인지하지 못하므로, 키보드를 입력하더라도 뒤늦게 화면에서 출력될 것 입니다. 따라서 CPU에 비해서 훨씬 느리고 언제 일어날지 모르는, I/O 관련된 작업에 대해서는 이벤트 주도 방식(Event Driven)의 인터럽트로 처리하는 것이 적절하다는 것입니다. 즉, 작동 방식에 따라 폴링/인터럽트를 적절하게 선택하는 것이 중요합니다. 예시를 통해 폴링과 인터럽트가 어떤 시스템에서 사용되는지 자세히 알아봅시다.
9-3. 인터럽트 예시 - 이더넷 프레임 수신
“브라우저를 통해 어떤 웹사이트에 접근하는 동작”을 예로 들어, 인터럽트 처리 과정을 알아봅시다.
- 화면에 대한 컨텐츠를 웹 서버로 요청하게됩니다.
- 요청에 대한 응답이 이더넷 프레임이라는 형태로 NIC 카드에 도착하게 됩니다.
- 이때, I/O 컨트롤러에 의해서 CPU에 인터럽트 이벤트가 발생하게 됩니다.
- 기존에 실행되고있던 프로세스의 정보를 메모리에 저장합니다.
- 인터럽트 컨트롤러(Interrupt Controller)라는 OS 내부적인 메뉴얼을 참고하여, 발생한 이벤트에 맞는 적절한 인터럽트 처리과정을 거칩니다.
- 이더넷 프레임 도착 이벤트를 처리하기 위해 CPU를 할당하여 선택한 인터럽트 처리과정을 실행합니다.
- 인터럽트 처리 작업을 마치면, 메모리에 저장돼있던 프로세스 정보를 바탕으로 다시 돌아와서 작업을 계속합니다.
9-4. 폴링 예시 - 로드밸런서 헬스 체크
“로드밸런서”란 수평 분산 아키텍처에서 같은 역할을 하는 여러 서버들에게 적절하게 부하를 나누어주는 네트워크 기술입니다. 안정적인 서비스 운영에 도움을 주어 많은 IT서비스에서 유용하게 사용하고 있습니다. 로드밸런서가 부하를 분산할 때 어떤 서버가 다운됐다면 부하를 나눠줄 때 해당 서버를 반드시 제외해야합니다. 제외하지못하면 적절한 처리와 응답을 하지 못할테니까요.
부하를 분산하고, 서비스를 지속하기 위해서는 서버의 상태를 계속해서 점검해야합니다. 물론 인터럽트 방식으로 서버의 상태를 알려주는 이벤트를 서버가 직접 중앙관리서버로 전송하는 식으로 작동할 수 있지만, Down된 서버는 자신이 죽었다는 이벤트를 더 이상 전송할 수 없게 됩니다. 따라서, 중앙모니터링 서버가 서버의 생존 여부에 대해서 일정한 간격으로 상태를 질의(“헬스 체크”)하는 식으로 동작합니다.
9-5. 정리
인터럽트 | 폴링 | |
---|---|---|
장점 | 서버 자원을 효율적으로 활용할 수 있다. | 일정한 간격으로 작업을 처리한다. 단순 루프이므로, 구현이 쉽다. |
단점 | 이벤트 주도 방식의 구현이 상대적으로 더 복잡하다. | 서버 리소스를 낭비하지않기 위해서, 시스템에 따라 적절한 시간 간격을 설정해야한다. |
검색해볼만한 키워드
- 시분할, 타이머 인터럽트(Timer Interrupt)
- 컨텍스트 스위칭과 멀티프로세싱
- NTP 서버
- AWS NLB, ALB 차이점
10. I/O 크기
데이터를 입출력 할때 한번에 입출력(I/O)할 수 있는 데이터 크기의 단위를 “I/O 크기”라고 합니다.
사과 100개를 박스에 담아서 사과를 옮기는 상황을 생각해봤을 때, 사과 박스가 너무 작으면 목적지와 출발지를 여러번 왔다갔다 해야합니다. 반면, 사과 박스가 너무 커도 사과를 다 담는데 시간이 더 오래걸리고, 직접 손으로 들 수 없어 차에 실어서 옮겨야합니다. 이 예시처럼, “I/O 크기”는 시스템의 특성과 데이터의 크기를 충분히 고려해서 적절한 크기로 단위를 설정해야 효율적으로 I/O 처리가 가능합니다.
일반적으로 DB의 데이터는 OS 커널을 통해 하드디스크에 쓰고, 읽습니다. 이러한 일련의 과정속에서도 “I/O 크기”를 적절한 크기로 설정함으로써 시스템 특성에 맞게 튜닝하여 성능을 개선할 수 있습니다. 아래 예시로 조금 더 자세히 알아보겠습니다.
10-1. 예시 - 오라클 DB ↔ 하드디스크
설명하기에 앞서, 오라클 DB에서 하드디스크와 입출력하는 과정은 총 3 계층으로 나눠서 이해하면 더 쉽고 명확하게 이해할 수 있을 것 같습니다.
- 소프트웨어 = Oracle DB 계층
- I/O 크기의 단위를 블록(block)이라고 합니다.
- 오라클 DB에서 디폴트(default)로 사용되는 블록의 크기는 8KB입니다. 즉, 파일(OS)에서 DB로 데이터를 8KB 단위로 읽고 쓴다는 것입니다.
- OS = 파일시스템 계층
- I/O 크기의 단위를 블록(block)이라고 합니다.
- 파일시스템 계층에서의 블록의 크기는 4KB입니다. 즉, 디스크에서 파일(OS)로 데이터를 4KB 단위로 읽고 쓴다는 것입니다.
- 하드웨어(HDD) = 하드디스크 계층
- I/O 크기의 단위를 섹터(sector)이라고 합니다.
- 디스크에서 데이터를 읽고 쓰는 단위는 섹터(sector)라고 하며, 크기는 512 바이트입니다. 하드웨어인 디스크의 사양이므로 이 값은 변경할 수 없습니다.
정리하자면, DB에서 하나의 블록(8KB)을 읽고, 쓰게되면 파일시스템에서 두 개의 블록(8KB = 4KB x 2)을 읽고 써야하며, 이때 하드웨어 디스크에서는 16개의 섹터(8KB = 4KB x 2 = 512바이트 x 16 )을 읽고 써야합니다.
디스크의 I/O 크기(섹터의 크기)는 하드웨어 사양이므로 변경할 수 없지만, DB의 블록 크기 및 파일시스템 블록의 크기는 설정값을 변경하면 바꿀 수 있는 값입니다. 하지만 처음에 언급했던 것처럼 블록의 크기를 튜닝할 때는 시스템의 특성과, 데이터 이동의 효율성 등을 검토해야합니다.
블록의 크기를 늘리면 한 번에 처리할 수 있는 데이터의 양이 많아지므로 처리량은 늘어나겠지만, 데이터를 이동시키는 데 더 많은 시간이 걸리므로, 지연시간은 증가합니다. 블록 크기를 줄이는 것은 반대로, 처리량은 줄지만 지연시간은 감소합니다.
위의 그림처럼 충분히 고려하지않고 파일시스템의 I/O 크기를 임의로 4KB → 7KB로 변경하게 되면, DB에서 8KB의 데이터를 읽기위해서 파일시스템은 2블록(14KB)을 읽어야하고, 디스크의 섹터는 28개를 읽고 써야합니다. 이렇게되면, 파일시스템에서 읽은 6KB를 사용하지않고, 디스크에서 읽은 섹터 12개를 사용하지 않게되므로 I/O가 비효율적이게 됩니다.
10-2. 예시 - 네트워크 MTU & MSS
전의 포스팅의 “커널의 핵심 역할 - 네트워크 스택”에서도 언급했지만, 애플리케이션에서 네트워크로 데이터를 전송할 때는 커널의 도움을 받아, OS에 소켓이라는 것을 생성합니다. 소켓에는 소켓 버퍼라는 데이터를 담을 수 있는 박스가 있습니다. 소켓 버퍼는 송신버퍼와 수신버퍼로 이루어져 있습니다. 데이터를 송신할 때는 송신버퍼에 데이터를 채워넣고, 데이터를 수신할 때는 수신버퍼에 데이터를 넣습니다.
어떤 애플리케이션에서 네트워크를 경유하여 다른 서버로 데이터를 보내는 상황을 생각해보겠습니다.
- 애플리케이션에서 대상 서버의 IP와 포트를 지정하면, 시스템 콜을 통해서 소켓을 생성하고, 소켓 송신 버퍼에 데이터 저장한다.
- 송신 버퍼가 가득차면 데이터를 TCP 세그먼트라는 데이터 조각으로 잘게 쪼갠다.
- 네트워크에는 MSS(Maximum Segment Size)라는 세그먼트 최대 크기가 정해져있어, 이를 고려해서 데이터를 쪼갠다.
- MSS 값은 일반적으로 1460바이트이며, IP 패킷이 가질 수 있는 최대 크기인 MTU(Maximum Transfer Unit)에서 TCP헤더 20바이트, IP헤더 20바이트를 제외한 크기이다.
- 각 네트워크 계층에서 분할된 세그먼트에 TCP 헤더, IP 헤더, MAC 헤더를 붙여 이더넷 프레임을 만들고, 네트워크를 경유하도록 전송한다.
네트워크 통신에서도 MSS, MTU라는 I/O 크기에 대한 규칙이 정해져있습니다. 이 규칙은 외부 네트워크와 통신할 때 거치는 라우터에서 설정된 MTU 값에 영향을 받을 수 있으므로 일반적으로 규칙에 맞는 크기로 설정해야합니다. 하지만, Oracle DB의 RAC 같은 시스템은 내부 네트워크를 통해서 높은 처리량과 지연시간이 필요하므로 MTU 값을 9000 바이트 정도로 튜닝하는 점보프레임(Jumbo Frame)이라는 기술을 사용하기도 합니다.
10-3. 정리
I/O 크기는 데이터를 한번에 읽고 쓰는 크기(단위)를 말합니다. I/O 크기 값은 시스템마다 다르고, 시스템 성능 튜닝시 I/O 크기 값 변경을 고려할 수 있습니다. 단, 해당 시스템이 처리량이 중요한 시스템인지, 지연시간(레이턴시)가 중요한 시스템인지 등 시스템의 특성을 충분히 고려해서 변경해야합니다.
검색해볼만한 키워드
- MTU와 MSS
- 점보 프레임
11. 저널링
“저널”이란, 데이터의 변경 이력을 말합니다. “저널링”은 데이터 그 자체가 아닌, 데이터의 변경이력을 기록해두는 것을 말합니다. 저널링은 데이터베이스 등 데이터가 중요한 시스템에서 데이터 안정성을 확보하는데 사용합니다. 저널은 디스크에 저장하기 전에는 메모리 위에 존재하므로 서버 장애시 손실될 수 있습니다. 이를 방지하기위해서 저널을 디스크에 기록하는 시간 간격을 조절하거나, 메모리를 이중화하여 저널 손실을 방지하기도 합니다.
저널링을 이용하면 시스템의 데이터 안정성을 확보할 수 있다고 했습니다. 저장된 저널을 이용하면 장애가 발생했을 때 체크포인트와 데이터 커밋(트랜잭션 종료)시점을 기준으로 변경이력을 그대로 거슬러올라가면서 데이터를 전 상태로 복구(Roll Back)하거나, 변경이력을 그대로 적용(Roll Forward)하여 데이터 안정성을 확보할 수 있습니다.
- 롤백(Roll Back)= 로그파일을 이용해서 트랜잭션 커밋 이전 상태로 데이터를 복구
- 롤 포워드(Roll Forward) = 로그파일을 이용해서 커밋 상태로 데이터 복구
- 체크포인트 = 데이터가 디스크에 기록돼있는 것을 보증하는 지점 (데이터 안정성 보장 시점)
11-1. 예시 - 리눅스 ext3 파일시스템
리눅스에서 ext3라는 파일시스템을 이용하면, 파일에 대한 변경이력을 기록 해둘 수 있습니다. 요구하는 데이터의 중요도와 안정성에 따라서 저널 기록 주기를 변경할 수 있습니다.
11-2. 예시 - Oracle DB 저널링
오라클 DB는 REDO 로그를 남김으로써 저널링을 구현합니다.
11-3. 정리
저널링을 이용하면 데이터를 그 자체를 복제하는 것이 아니라, 데이터 변경 이력을 저장하므로 적은 리소스를 이용해 데이터 안정성을 확보할 수 있습니다. 또한, 데이터 저장시 장애가 발생하여도 롤백과 롤포워딩을 통해서 데이터의 안정성을 확보할 수 있으므로 데이터 변경이 잦은 시스템에서 매우 유용하게 사용됩니다.
저널링 | |
---|---|
장점 | 리소스를 효율적으로 활용해서 데이터 안정성을 확보할 수 있다. 데이터 갱신이 잦은 시스템에서 유용하다. |
단점 | 저널이 아직 메모리상에 있을 때 안정성을 확보해야므로 시스템이 복잡해진다. 실제 데이터 뿐만아니라 변경이력을 디스크에 저장해야하므로 오버헤드가 발생한다. |
검색해볼만한 키워드
- ext3 파일시스템
- Oracle DB 저널링
- 섀도우 페이징(shadow paging)
12. 복제
“복제”는 저널링과 다르게, 데이터 그 자체를 그대로 복제하여 복사본을 두는 것을 말합니다. 복사본을 두면 두 가지의 장점을 얻을 수 있습니다.
- 스케일 아웃(Scale Out)과 부하 분산 : 데이터 복제본을 같은 역할을 하는 다른 서버에 두고, 로드밸런서를 이용하여 부하 분산 처리
- 데이터 백업 : 데이터 백업본을 복제해두고, 장애 시 이를 이용하여 빠르게 데이터 복구
12-1. 예시 - 스토리지 백업(데이터 복제)
스토리지 데이터 복제는 DR(재해복구) 시스템에서 유용하게 활용됩니다. 운영시스템이 존재하는 데이터센터에 재해가 발생했을 때를 고려하여, 운영시스템이 이용하던 데이터는 반드시 실시간으로 다른 데이터센터로 복제해두어야 합니다. 스토리지의 데이터 복제는 갱신된 파일만 복제하거나, 갱신된 데이터 블록의 변경분에 대해서만 복제하는 등 목적에 따라 네트워크 리소스를 많이 사용하지않고도 데이터를 동기화 시킬 수 있습니다. , 네트워크 리소스를 효율적으로 사용함과 동시에 데이터센터 재해상황이 발생하여도 DR센터의 데이터 복제본을 이용하여 빠르게 서비스를 시작하여 장애를 복구할 수 있게 됩니다.
12-2. 예시 - MySQL 데이터 복제
MySQL은 위의 예시와 다르게, “데이터 변경 SQL에 대한 로그를 전송”하여 데이터를 복제합니다. 마스터DB에서만 데이터 추가/갱신 작업을 수행하고, 데이터를 변경시키는 SQL로그를 다른 DB노드로 전송시킴으로써 복제 데이터 전송량을 줄일 수 있으며, 데이터를 복제한 워커DB에서는 데이터 추가/갱신/삭제 작업은 불가능하나, 동일한 데이터를 갖고있으므로 데이터 조회 부하를 분산하여 처리할 수 있습니다.
12-3. 정리
복제 | |
---|---|
장점 | 데이터 그 자체를 복사하여 데이터 안정성을 확보한다. 복제 데이터를 활용하여 조회 부하를 분산하거나, 장애 시 빠르게 서비스를 복구할 수 있다. |
단점 | 데이터 갱신이 많은 경우, 변경분을 반영해야하므로 복제로 인한 오버헤드가 높아진다. 갱신 작업은 분산하여 처리하기 어렵다. 데이터 복제로 인해 시스템 복잡성이 증가하여 운영이 어려워진다. |
13. 압축
“압축”은 불필요한 데이터를 제거하여 데이터의 크기를 줄이는 것을 말합니다. 데이터를 압축함으로써 데이터의 크기가 감소하므로 저장 공간을 확보하여 효율적으로 사용할 수 있고, 더 빠르게 데이터를 전송할 수 있습니다. 압축은 데이터 크기를 줄이는 대신에, 압축된 파일을 읽고 쓸때마다 데이터를 압축해제하거나, 압축하는 데 오버헤드가 발생합니다. 따라서, 자주 변경되거나, 자주 조회되지 않는 데이터에 적용하기에 유용한 기술입니다.
데이터를 압축하는 방법에는 크게 두 가지가 있습니다.
- 가역 압축
- 파일을 읽어 중복되는 패턴을 파악하고, 축약된 정보로 변경하는 것을 말한다.
- 압축한 정보를 다시 원상 복구할 수 있다.
- 예시) 허프만 알고리즘(Huffman Algorithm), zip 파일 압축
- 비가역 압축
- 필요없는 부분을 제거하여 데이터 크기를 줄이는 것을 말한다.
- 압축한 정보를 원래 상태로 복구할 수 없다.
- 예시) 사람이 듣지못하는 주파수의 음향 데이터 제거, 사람이 인지하지 못하는 영상 프레임 데이터 제거(영상 인코딩)
13-1. 정리
압축 | |
---|---|
장점 | 데이터의 불필요한 부분을 제거하여 데이터 크기를 줄인다. 데이터 저장 공간을 효율적으로 활용하고, 데이터 전송 오버헤드를 감소시킨다. |
단점 | 데이터 압축과 해제에 리소스를 사용하므로, 데이터를 자주 갱신하거나 조회할 때 추가적인 오버헤드가 발생하므로 성능 저하가 생긴다. |
검색해볼만한 키워드
- 허프만 알고리즘
14. 오류 검출
3계층 데이터 흐름에서도 알 수 있지만, IT 시스템에서는 수많은 데이터 교환이 발생합니다. 데이터는 결국에 메모리에 전자적으로 저장되고, 네트워크를 통해 전기적으로 전송되므로, 아주 적은 확률로 전자기파의 영향을 받아 데이터의 변형 및 손실이 발생할 수도 있습니다. 데이터는 일반적으로 이진 데이터로 이루어져있는데, 데이터에서 하나의 비트가 변경되는 작은 변화가 엄청난 영향을 끼치게 될 수 있습니다. 때문에 데이터 오류가 발생할 확률이 가장 높은 네트워크 통신 기술과 메모리에서 오류를 검출하고, 보정하기 위한 기술들을 적용하고 있습니다.
14-1. 예시 - 패리티비트
“패리티 비트”란, 네트워크에서 데이터를 전송할 때 데이터의 변형에 대해서 검사할 수 있는 추가적인 비트를 덧붙이는 기술을 말합니다. 패리티비트를 이용하면 전송할 데이터의 마지막에 비트를 추가하여 데이터 파손 여부를 검사할 수 있습니다. 하나의 패리티 비트를 사용하는 경우를 예로 들면, 데이터를 이진수로 변경했을 때 패리티비트를 포함한 1비트의 총 개수를 홀수가 되도록 패리티 비트를 설정합니다. 데이터를 수신하는 곳에서 1비트의 개수를 체크했을 때 짝수라면 데이터 전달 과정에서 오류가 생겼다고 판단하고, 데이터 재송신을 요청합니다.
14-2. 정리
오류 검출이란 정보의 전달 과정에서 오류가 생겼는지 검출하는 기술입니다. 일반적으로 데이터 파손 여부를 검출하고 데이터를 다시 전송하여 해결하지만, ECC 메모리와 같이 검출과 동시에 파손된 데이터를 복구하는 경우도 있습니다.
검색해볼만한 키워드
- 네트워크에서의 오류 검출 = CRC, 체크섬
- ECC 메모리
15. 요약
저번 포스팅에서는 IT 인프라의 물리적 구성(서버 물리적 구조)과 논리적 구성(커널, 프로세스, 스레드) 그리고 3계층 데이터 흐름에 대해 알아보았습니다.
이번 포스팅에서는 3계층에서 안정적이고 효율적인 웹 서비스를 제공하기 위해서 어떤 이론과 기술이 사용되며, 각각의 이론과 기술이 3계층 시스템의 어디서 적용되고 있는지, 각각의 장단점은 무엇인지 간단하게 살펴보았습니다. 실제로, 위에서 소개한 이론과 기술들은 대부분의 IT 솔루션의 이론/기술적인 기반이 되고있습니다. 이후에 어떤 서비스에 대한 SAM(Software Asset Management), 혹은 인프라 담당자가 됐다면, 이러한 지식과 기술의 장단점을 기반으로 검토해야하는 솔루션이 담당 시스템에 적합한지, 솔루션을 도입하기 위해서는 어떤 하드웨어 인프라(네트워크 장비) 등이 필요한지 검토할 수 있을 것입니다.
이번에는 각각의 주제에 대해 넓고, 얕게 알아보았지만, 이후의 포스팅에서 각각의 이론과 기술을 메인으로 더 깊고 자세하게 알아보려고 합니다. 예를 들면, Docker를 자세히 알아볼때 리눅스 커널의 이해(namespace, cgroup)을 바탕으로 가용성 실험, 레이턴시에 대한 실험(도커 엔진 위에서 컨테이너가 응답할 때와 일반 프로세스로 응답할 때)을 통해서 각 기술의 장단점과 트레이드 오프를 자세히 탐구하려고 합니다.
다음 포스팅은 IT 인프라의 기본 뼈대가 되는 네트워크의 인프라 구성부터 TCP 통신까지, 3계층 데이터 흐름을 네트워크적인 관점에서 자세히 살펴보겠습니다.
지금까지 긴 글을 읽어주셔서 감사합니다.
Reference
- 그림으로 공부하는 IT 인프라 구조
- CISCO
- NETAPP