단일 서버

11st에 접속할때 서버에서 어떤일이 일어나는지 생각해보자.

  1. www.11st.com를 주소창에 입력
  2. 브라우저의 DNS 캐시 확인 
    브라우저 캐시에 IP 주소가 없으면 운영 체제의 DNS 캐시 확인
  3. 운영 체제의 DNS 캐시에도 IP 주소가 없으면 루트 DNS 서버로의 쿼리 시작
  4. 루트 DNS 서버는 com 최상위 도메인(TLD) 서버의 주소를 반환
  5. DNS 클라이언트는 com TLD 서버에 www.11st.com의 IP 주소를 요청
  6. com TLD 서버는 11st.com 도메인의 권한 있는 네임 서버의 주소를 반환
  7. DNS 클라이언트는 11st.com 도메인의 권한 있는 네임 서버에 www.11st.com의 IP 주소를 요청합니다.
  8. 권한 있는 네임 서버는 www.11st.com의 IP 주소를 반환
  9. 브라우저는 반환된 IP 주소로 TCP 연결을 설정합니다. 이를 위해 3-way 핸드셰이크가 사용, TLS/SSL 연결
    - SSL → TLS - 데이터 조작 방지
  10. HTTP 요청
  11. 요청을 받은 웹 서버는 요청을 처리
    브라우저는 수신한 HTML을 파싱하여 DOM(Document Object Model) 트리를 구축
  12. 브라우저의 내용 렌더링
  13. 쿠키 및 세션 관리
    서버가 응답 시 쿠키를 설정하면, 브라우저는 해당 쿠키를 저장하고 이후 같은 도메인에 요청할 때마다 쿠키를 전송

 

데이터베이스

트래픽 처리가 늘게 되면 서버(웹 계층)와 데이터베이스 서버(데이터 계층)을 분리하여 확장을 고민해볼 수 있는데

사용목적에 따라 관계형 데이터베이스, 비관계형 데이터베이스를 고민해볼 수 있다. 

 

관계형 데이터베이스

  • RDBMS(Relational Database Management System)
    • 테이블은 행과 열로 이루어져있다. 
    • 스키마 기반입니다. 데이터 무결성 및 일관성을 보장
    • ACID 특성

비-관계형 데이터베이스

  • NoSQL(Not Only SQL)
  • CouchDB, Neo4j, Cassandra, HBase, Amazon DynamoDB 등이 있다.
    • 키-값 저장소(key-value store)
      • 높은 성능과 확장 가능성을 제공하지만 복잡한 쿼리는 지원하지 않는다.
      • ex) Redis, Amazon DynamoDB, Memcached 
    • 그래프 저장소(graph store)
      • 노드(객체), 엣지(관계) 형태를 띄며 네트워크 분석에 특히 유용하다.
      • ex) Titan
    • 칼럼 저장소(column store)
      • 테이블 행 대신 열 단위로 저장 
      • 대규모 데이터 셋의 집계 쿼리
      • ex) Apache Cassandra, HBase
    • 문서 저장소(document sotre)
      • 유연한 스키마, 쉬운 확장성, 복잡한 쿼리 수행
      • JSON, BSON 문서 형식으로 데이터를 저장
  • 일반적으로 조인 연산이 불가능.

비-관계형 데이터베이스는 다음과 같은 상황에서 고려하기 좋다.

  • 게임, 실시간 분석 시스템, 소셜 미디어 피드 등에서 매우 짧은 응답 시간이 필요
    • low-latency이 필요.
  • 데이터가 비정형데이터인 경우
    • 예를 들어 로그 데이터, 소셜 미디어 게시물, 문서 저장소 등에서 비-관계형 데이터베이스가 유리
  • 데이터(JSON, YAML, XML)를 직렬화 또는 역직렬화 
    • 복잡한 쿼리나 관계가 필요 없는 경우 NoSQL 데이터베이스가 적합
  • 대량의 데이터 양의 데이터를 저장할 필요가 있다.
    • 애플리케이션, 사물 인터넷(IoT) 데이터, 로그 데이터 저장소 등에서 NoSQL 데이터베이스는 수평적 확장을 통해 대량의 데이터를 효율적으로 처리

NoSQL이 빠른 이유는 키-값인 경우 데이터를 읽는데에 최적화된 자료구조를 사용하기 때문이다. HashMap이나 B+ Tree 구조가 있다. 
 

수평적 규모 확장 vs 수직적 규모 확장

스케일 업(scale up)이라고 불리는 수직적 확장, 스케일 아웃(scale out)이라고 불리는 수평적 확장이 있다.

스케일 업

스케일 업은 서버의 하드웨어 리소스를 추가하거나 업그레이드하여 성능을 향상시키는 방식

  • 장점
    • 하드웨어를 업그레이드하는 것만으로 성능 향상
    • 단일 서버에 모든 자원을 집중하기 때문에 관리와 모니터링이 비교적 간단
    • 기존 애플리케이션을 수정하지 않고 그대로 사용
  • 단점
    • CPU나 메모리를 무한대로 늘릴 순 없습니다.
    • 장애에 대한 자동복구(failover) 방안이나 다중화(redundancy) 방안을 제시하지 않는다.
    • 서버 장애 발생시 웹,앱 등 서비스가 완전히 중단된다.

단점이 너무 치명적이라 대규모 시스템에서는 스케일 아웃방식을 사용하는것이 좋다.

스케일 아웃 (Scale Out)

스케일 아웃은 서버를 증설하여 여러 대의 서버로 부하를 분산시켜 성능을 향상시키는 방식입니다.

확장성: 수평적 확장은 거의 무한대로 확장할 수 있습니다. 트래픽 증가에 따라 서버를 추가하면 됩니다.

고가용성: 여러 서버에 부하를 분산시켜 하나의 서버에 장애가 발생해도 서비스가 중단되지 않습니다.

비용 효율성: 상대적으로 저렴한 하드웨어를 여러 대 사용하여 확장할 수 있어 비용 효율적입니다.

서버 장애가 발생시에는 사용자가 웹 사이트에 접속할 수 없고, 서버 장애가 발생하는 원인 중에는 과도한 트래픽양이 있다.

이를 해결하기 위해서 부하 분산기 또는 로드밸런스(load balancer)를 도입하는게 최선이다.

로드 밸런서

로드 밸런서는 여러 서버 간에 네트워크 트래픽을 고르게 분산시키는 역할을 합니다. 로드 밸런서를 통해 웹 서버의 부하를 효율적으로 관리할 수 있으며, 서비스 가용성과 성능을 향상시킬 수 있습니다.

로드 밸런서의 기능

  1. 트래픽 분산: 클라이언트 요청을 여러 서버에 분산하여 각 서버의 부하를 균등하게 유지합니다.
  2. 고가용성: 한 서버에 장애가 발생하면 로드 밸런서는 자동으로 다른 서버로 트래픽을 리디렉션하여 서비스 중단을 방지합니다.
  3. 확장성: 트래픽 증가 시 서버를 추가하여 부하를 분산시킬 수 있으며, 로드 밸런서를 통해 트래픽을 새로운 서버로 자동 분배합니다.

로드 밸런서의 알고리즘

  1. 라운드 로빈 (Round Robin): 순차적으로 각 서버에 트래픽을 분배합니다.
  2. 최소 연결 (Least Connections): 현재 가장 적은 연결 수를 가진 서버에 트래픽을 분배합니다.
  3. IP 해시 (IP Hash): 클라이언트의 IP 주소를 해시하여 특정 서버에 트래픽을 분배합니다.

로드 밸런서의 장점

  • 복구 능력: 서버 장애 발생 시 다른 서버로 트래픽을 자동으로 전환하여 서비스 연속성을 유지합니다.
  • 성능 향상: 트래픽을 여러 서버에 분산시켜 각 서버의 성능을 최적화하고, 높은 트래픽을 처리할 수 있습니다.
  • 확장 용이성: 서버 추가를 통해 트래픽 증가에 쉽게 대응할 수 있습니다.

 

데이터베이스 다중화 (Database Replication)

데이터베이스 다중화는 데이터베이스 시스템의 성능, 안정성, 가용성을 높이기 위한 중요한 기법입니다. 주로 주-부(Master-Slave) 관계를 설정하여 주 데이터베이스 서버에서 데이터를 작성하고, 부 데이터베이스 서버에서 데이터를 읽는 방식으로 구현됩니다.

주-부(Master-Slave) 구조

구조 설명

  • 주(Master) 서버: 데이터 원본을 저장하고 모든 쓰기 연산(INSERT, UPDATE, DELETE)을 처리합니다. 주 서버는 데이터의 일관성을 유지하고, 부 서버로 데이터를 복제합니다.
  • 부(Slave) 서버: 주 서버로부터 복제된 데이터 사본을 저장합니다. 부 서버는 읽기 연산(SELECT)만 지원하며, 여러 대의 부 서버를 운영하여 읽기 성능을 향상시킬 수 있습니다.

 

 

캐시(Cache)

캐시는 응답시간(latency)을 개선하고 시스템 성능을 최적화하는 데 중요한 역할을 합니다. 캐시는 자주 참조되는 데이터나 값비싼 연산 결과를 메모리에 저장하여 빠른 액세스를 제공합니다. 이는 데이터베이스에 대한 반복적인 요청을 줄이고, 시스템의 전반적인 성능을 향상시킵니다.

캐시의 역할

  1. 응답 시간 개선:
    • 캐시는 데이터베이스보다 빠른 메모리에 데이터를 저장하여, 데이터 요청 시 빠른 응답을 제공합니다.
    • 새로고침이나 반복적인 데이터 요청 시, 데이터베이스에 직접 접근하지 않고 캐시에서 데이터를 제공하여 성능을 최적화합니다.

  2. 부하 감소:
    • 데이터베이스에 대한 요청 수를 줄여 데이터베이스의 부하를 감소시킵니다.
    • 이는 데이터베이스 서버의 성능을 유지하고, 더 많은 동시 사용자 요청을 처리할 수 있게 합니다.

캐시 계층(Cache Tier)

캐시 계층은 데이터베이스와 웹 서버 사이에 위치하여 자주 참조되는 데이터를 임시로 저장합니다. 캐시 계층은 독립적으로 확장 가능하며, 데이터베이스의 부하를 줄이고 시스템 성능을 최적화하는 데 중요한 역할을 합니다.

읽기 주도형 캐시 전략(Read-Through Caching Strategy)

읽기 주도형 캐시 전략은 데이터가 요청될 때 캐시에서 먼저 조회하고, 캐시에 데이터가 없으면 데이터베이스에서 데이터를 가져와 캐시에 저장하는 방식입니다.

 

  1. 데이터 요청:
    • 사용자가 웹 서버에 데이터를 요청합니다.

  2. 캐시 조회:
    • 웹 서버는 먼저 캐시를 조회하여 요청된 데이터가 있는지 확인합니다.
    • 캐시에 데이터가 있으면, 캐시에서 데이터를 가져와 사용자에게 반환합니다.

  3. 데이터베이스 조회:
    • 캐시에 데이터가 없으면, 데이터베이스에서 데이터를 조회하고, 해당 데이터를 캐시에 저장한 후 사용자에게 반환합니다.

캐시 사용 시 주의점

  1. 데이터 갱신 빈도:
    • 갱신이 자주 일어나지 않고 참조가 빈번한 데이터에 캐시를 사용하면 효율적입니다.
    • 예: 사용자 프로필 정보, 자주 변경되지 않는 설정 값 등.

  2. RAM 사용:
    • 캐시는 일반적으로 RAM에서 동작하므로, RAM 크기를 적절히 설정하여 성능을 최적화해야 합니다.
    • 캐시는 휘발성이므로 영속적으로 보관할 데이터는 데이터베이스에 저장하는 것이 바람직합니다.

  3. 만료 정책:
    • 캐시 데이터의 만료(expire) 정책을 설정하여 적절한 시점에 캐시를 갱신해야 합니다.
    • 만료시간을 너무 짧게 설정하면 캐시 히트율이 낮아지고, 너무 길게 설정하면 데이터의 최신성을 보장할 수 없습니다.

  4. 데이터 일관성:
    • 데이터베이스와 캐시 간의 일관성을 유지하는 방법을 고민해야 합니다.
    • 데이터 갱신 시 캐시를 무효화하거나 업데이트하는 전략이 필요합니다

  5. 장애 대처:
    • 캐시 서버가 단일 장애 지점(Single Point of Failure, SPOF)이 되지 않도록 여러 지역에 분산하여 배치합니다.
    • 장애 발생 시 대체 서버를 통해 서비스를 지속할 수 있도록 설정합니다.

캐시 메모리 설정 및 데이터 방출 정책

  1. 캐시 메모리 크기:
    • 캐시 메모리가 작다면 자주 갱신되어 성능이 저하될 수 있습니다.
    • 캐시 메모리를 적절히 크게 설정하여 데이터가 자주 갱신되지 않도록 합니다.

  2. 데이터 방출 정책:
    • 캐시가 꽉 찼을 때 어떤 데이터를 방출할지 결정하는 정책을 설정해야 합니다.
    • 일반적인 방출 정책은 LRU(Least Recently Used), LFU(Least Frequently Used), FIFO(First In First Out) 등이 있습니다.

캐시의 종류

  1. API 캐시:
    • 변경되지 않거나 자주 변경되지 않는 데이터를 캐싱합니다.
    • 예: 날씨 정보, 뉴스 기사, 사용자 프로필 데이터 등.
    • 메모리나 별도의 캐시 서버(예: Redis, Memcached)에 저장될 수 있습니다.

  2. 데이터베이스 캐시:
    • 데이터베이스에서 조회된 데이터를 캐시에 저장합니다.
    • 예: 상품 데이터, 사용자 정보 등.
    • 캐시된 데이터를 제공하여 데이터베이스 쿼리를 줄입니다.

  3. HTTP 캐시:
    • HTTP 프로토콜을 통해 콘텐츠의 버전을 식별하여 캐싱합니다.
    • 예: ETag(Entity Tag)를 사용하여 웹 콘텐츠의 버전을 식별하고, 변경되지 않은 경우 304 Not Modified 상태 코드를 반환합니다.

  4. 로컬 캐시:
    • 단일 클라이언트나 서버 인스턴스 내에 위치한 캐시로, 해당 인스턴스에서만 접근 가능합니다.

  5. 글로벌 캐시:
    • 여러 클라이언트나 서버 인스턴스가 네트워크를 통해 공유하고 접근할 수 있는 중앙 집중식 캐시입니다.
    • 예: Redis, Memcached 등을 사용하여 구현합니다.

// memcached라는 캐시 시스템 C언어를 사용
#define SECONDS 1
cache.set("cache", "hi cache", 3600 * SECONDS);
cache.get("cache");