데이터실무

DA, SQL, DB보안 등 실무자를 위한 위한 DB기술 바이블!

레디스 성능 개선

데이터 저장
인메모리 데이터 저장
레디스 성능 개선
작성자
admin
작성일
2021-02-15 13:52
조회
4151

레디스 성능 개선 설계 개요

테크놀로지 아키텍처 영역 중 서버 성능 향상을 위한 기법으로는 스케일업(Scale-Up)과 스케일아웃(Scale-Out)이 있다. 이에 대해 좀 더 구체적으로 살펴보면 다음 표와 같다.

[표 Ⅱ-3-6] 스케일업과 스케일아웃 개요


서버 성능향상 기법 설명
스케일업
  • 동일 서버 하드웨어에 컴퓨팅 자원(CPU, 메모리, 디스크, 네트워크 I/O)을 추가해 성능향상
  • 네트워크 및 버스 I/O가 성능의 병목 지점이 되므로 단일 서버 내 컴퓨팅 자원 추가로 인한 선형적 성능 개선 효과를 얻을 수 없음
  • 서버 대수 동일
스케일아웃
  • 동일 사양의 규격화한 서버 하드웨어의 개수를 늘림으로써 성능 향상
  • 서버 개수 증설로 선형적 성능 개선 가능
  • 여러 노드로 구성된 서버 클러스터를 관리하기 위한 메커니즘 필요
  • 서버 대수 증가

레디스는 스케일아웃 형태의 서버 성능 향상을 위해 읽기 성능 확장을 위한 복제(Replication)와 쓰기 성능 향상을 위한 샤딩(Sharding) 기법을 지원한다. 관련 주요 용어는 다음과 같다.

[표 Ⅱ-3-7] 레디스 성능 확장 주요 용어


용어 설명
Replication 동일 데이터를 다수의 레디스 서버에 중복 분산 저장함으로써, 클라이언트에게 레디스 서버 보유 데이터에 대한 구성 내역 및 위치 투명성을 제공

[구성특성]
  • 마스터/슬레이브 형태로 구성된다. 마스터는 쓰기 전용(Write Only), 슬레이브는 읽기 전용(Read Only)으로 활용
  • 특정 슬레이브 노드는 하나의 마스터만 가질 수 있음
  • 특정 슬레이브 노드는 다른 노드의 마스터 역할을 할 수 있음
[구성유형]
  • 싱글 (Replication) 복제
  • 다중(Multiple) 복제
  • 계층적(Hierarchical) 복제
샤딩 단일 데이터 세트를 특정 조건에 따라 하나 이상의 레디스 서버에 분할 분산 저장해 쓰기 성능 확장

[구성유형]
  • Vertical Sharding
  • Range Sharding
  • Hash Based Sharding
※Shard
  • 분할된 데이터를 저장하는 단일 논리 노드
  • 단일 논리 샤드는 물리적으로는 하나 이상의 레디스 노드에 복제될 수 있음

읽기 성능 향상을 위한 레디스 복제

레디스는 복제(Replication)를 위해 마스터/슬레이브 구조를 사용한다. 이때 마스터 노드는 쓰기 전용으로 활용하며, 슬레이브 노드는 읽기 전용으로 활용하는 읽기와 쓰기의 명시적인 분리 구조를 가진다. 이러한 특성은 레디스 서버 인스턴스의 확장 시 유연성을 제공하는 장점이 있으나, 클라이언트 애플리케이션이 마스터 노드에는 쓰기, 슬레이브 노드에는 읽기를 구분해 요청하기 위해서는 마스터 노드와 슬레이브 노드에 대한 정보를 유지ㆍ관리해야 할 필요가 있어 결과적으로 클라이언트 애플리케이션의 복잡도가 증가하는 제한점이 있다.
마스터 노드는 하나 이상의 슬레이브 노드들에게 데이터 원본을 제공해 주는 역할을 하며, 슬레이브 노드는 마스터 노드에 최초 접속 시 전체 데이터를 수신해 동기화한 뒤 이후에는 변경 데이터만을 수신해 지속적으로 데이터 동기화를 유지한다. 마스터 노드의 위치 정보를 슬레이브 노드가 보유하는 특성을 가지며, 슬레이브 노드 추가 시 마스터 노드의 설정 변경이나 재시작이 필요하지 않은 실시간 동적 확장성(Run-Time Dynamic Scalability)을 제공한다. 동적 확장성은 용량ㆍ성능 확장 시 서비스 구성 요소의 재기동 등으로 인해 서비스가 중단되는 일이 없는 확장성을 지원한다.


싱글 복제

레디스 데이터 복제 과정을 슬레이브 노드의 함수 호출 관계로 요약하면 다음과 같다.

[표 Ⅱ-3-8] 레디스 복제 개요


번호 호출 함수 설명
1 Main( )
  • 서버기동시작
  • 설정파일로딩
2 initServer( )
  • 서버/샤드 구조체 생성
  • Event Loop 구성
  • 레디스 데이터베이스 구성
  • AOF 파일 오픈
  • TCP 소켓 구성
3 serverCron( )
  • 데이터베이스 크기 식별
  • 연결 클라이언트 식별
  • 해시 테이블 크기 재조정
  • 비활성 클라이언트 세션 단절
  • 백그라운드 저장 작업 초기화
  • LRU(Least Recently Used) 정보 계산
  • 폐기된 Key 정리
4 replicationCron( ) connectWithMaster 함수 호출
5 connectWithMaster( ) 마스터 노드와 연결
6 sysnWithMaster( ) 마스터 노드 전송 *rdb 파일 로딩
7 readSynkBulkPayload( ) 마스터 노드 변경 데이터 동기화
8 emptyDb( ) 마스터 노드와의 연결이 끊어진 경우, 마스터 노드와의 데이터 동기화를 유지하기 위해 자신의 DB를 초기화 (데이터 모두 삭제)

다음의 레디스 싱글 복제(Single Replication) 예는 단일 Ubuntu 운영체제에서 구성했다. 먼저 마스터 노드와 슬레이브 노드 기동을 위한 설정 파일을 아래와 같이 생성한다. 마스터 노드의 포트 번호는 6400, 슬레이브 노드의 포트 번호는 6501로 지정했다. 슬레이브 노드의 설정 파일에는 마스터 노드의 위치를 ‘slaveof’라는 키워드와 함께 명기한다.

[master.conf] port 6400 dbfilename 6400.rdbx [slave.conf] port 6501 dbfilename 6501.rdb slaveof 192.168.118.131 6400 slave-read-only yes

다음 명령어로 마스터 노드를 백그라운드 수행 방식으로 기동한다.

[마스터 노드 기동] taogone@ubuntu:~/redis-2.8.14/src$ ./redis-server ./master.conf >> master.log & [1] 9473

기동 완료된 마스터 노드의 상태를 확인하면 다음과 같다. 아직 슬레이브 노드를 기동하기 전이므로 현재 연결된 슬레이브 노드의 개수가 0임을 확인할 수 있다.

[마스터 노드 상태 확인 #1] 127.0.0.1:6400> info Replication # Replication role:master connected_slaves:0 master_repl_offset:0 repl_blacklog_active:0 repl_backlog_size: 1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen: 0

다음의 명령어로 슬레이브 노드를 백그라운드 수행 방식으로 기동한다.

[슬레이브 노드 기동] taogone@ubuntu:~/redis-2.8.14/src$ ./redis-server ./slave.conf >> slave.log & [2] 9495

슬레이브 노드의 기동이 완료된 후 마스터 노드의 상태를 확인하면 연결된 슬레이브 노드 개수가 1로 바뀌었음을 알 수 있다.

[마스터 노드 상태 확인 #2] #Replication role:master connected_slaves: 1 slave0:ip=192.168.118.131, port=6501, state=online, offset=57, lag=0 master_repl_offset: 57 repl_backlog_active: 1 repl_backlog_size: 1048576 repl_backlog_first_byte_offset: 2 repl_backlog_histlen: 56

마지막으로 슬레이브 노드의 상태를 확인하면, 마스터 노드 위치 정보를 식별하고 있음을 확인할 수 있다.

taogone@ubuntu: ~/redis-2.8.14/src$ redis-cli -p 6501 127.0.0.1:6501> info Replication # Replication role: slave master_host:192.168.118.131 master_port: 6400 master_link_status: up master_last_io_seconds_ago:10 master_sync_in_progress: 0 slave_repl_offset: 113 slave_priroity: 100 slave_read_only: 1 connected_slaves: 0 repl_backlog_active: 0 repl_backlog_first_byte_offset: 0 repl_backlog_histlen: 0

마스터 노드와 슬레이브 노드 간 최초 연결 시, 슬레이브 노드는 마스터 노드의 모든 데이터를 일괄 복제한다. 이후 슬레이브 노드는 마스터 노드에 대한 지속적인 자체 검사(Health Check)를 수행하며, 변경된 데이터를 지속적으로 전달 받는다. 클라이언트 애플리케이션은 마스터 노드에게 쓰기 요청을 전달하고, 슬레이브 노드에게는 읽기 요청을 전달한다.

[그림 Ⅱ-3-3] 레디스 싱글 복제(1)

[그림 Ⅱ-3-3] 레디스 싱글 복제(1)

마스터/슬레이브 노드 구성 시 아래와 같이 슬레이브 노드 또한 다른 노드의 마스터 역할을 할 수 있다.

[그림 Ⅱ-3-4] 레디스 싱글 복제(2)

[그림 Ⅱ-3-4] 레디스 싱글 복제(2)


다중 복제

싱글 복제로 쓰기와 읽기를 분리하였으나, 쓰기 보다는 읽기 요청의 비율이 높아 읽기 요청에 대한 대응 용량을 증설해 성능을 확보하기 위해 다중 복제(Multiple Replication)를 고려해야 한다. 단일 마스터 노드는 여러 개의 슬레이브 노드들을 가질 수 있으며, 신규 슬레이브 노드 추가 방법은 싱글 복제에서의 슬레이브 노드 방식 방식과 동일하다. 마스터 노드의 위치 정보를 신규 슬레이브가 가지므로 슬레이브 노드 추가 시 마스터 노드의 재설정 또는 재기동은 불필요하다.
이때 주의할 점은 단일 마스터 노드에 너무 많은 슬레이브 노드들을 할당하였을 경우, 해당 마스터 노드의 컴퓨팅 자원(CPU, 메모리, 디스크, 네트워크 I/O)에 성능 병목 지점이 된다. 즉 마스터 노드의 모든 컴퓨팅 자원이 슬레이브 노드들의 데이터 복제에 소모되므로, 전체적인 서비스 성능 저하를 불러올 수 있다. 이러한 제약을 극복하기 위해 다음에 이어지는 계층적 복제(Hierarchical Replication)를 활용할 수가 있다.

[그림 Ⅱ-3-5] 레디스 다중 복제

[그림 Ⅱ-3-5] 레디스 다중 복제


계층적 복제

다음 그림과 같이 1 수준 슬레이브 노드가 2 수준 슬레이브 노드들에게의 데이터 복제를 수행함으로써 전체 적인 서비스 성능 향상을 도모할 수 있다. 추가적인 읽기 요청에 대한 대응 용량 확보를 위해서는 2 수준 아래에 새로운 슬레이브 계층 수준을 구성할 수 있다.

[그림 Ⅱ-3-6] 레디스 계층적 복제

[그림 Ⅱ-3-6] 레디스 계층적 복제


마스터 HA 복제(Sentinel)

지금까지 언급된 레디스 복제에서 볼 수 있듯이 추가적인 구성이 없는 복제에서는 단일 마스터 노드와 다수의 슬레이브 노드들로 구성된다. 이 상태에서는 만약 마스터 노드에 장애가 발생하는 경우 전체 서비스의 중단을 피할 수 없다. 따라서 실제 서비스에 레디스를 활용하기 위해서는 마스터 노드에 대한 페일오버/페일백 구성을 통한 고가용성(HA: High Availability) 확보가 필수적이다. 이러한 서버 페일오버/페일백 구성을 소프트웨어 방식(데몬)으로 구현하는 것을 일반적으로 운영체계 수준의 ‘서버클러스터링’이라는 용어로 지칭한다. 서버 클러스터 구성 시 일반적인 요구사항은 다음과 같다.


  • 마스터 노드의 장애를 정확히 식별
  • 마스터 노드에 장애 발생 시 슬레이브 노드들 중 하나를 마스터 노드로 승격 시킴
  • 교체된 마스터 노드에 대한 정보를 다른 슬레이브 노드들에게 전파

레디스에서는 위 요구사항들에 대응하기 위해 Sentinel이라는 데몬을 제공한다. 이때 교체된 마스터 노드들에 접속되어 있는 클라이언트들에 대한 정보는 별도로 관리하지 않으며, 마스터 노드 교체 사실을 인지할 필요가 있는 클라이언트 노드들은 사전에 Redis Pub/Sub으로 Sentinel에 등록해 두어야 한다.

Redis Sentinel 데몬에 의한 마스터 노드 교체(Fail-Over) 시나리오는 다음과 같다.


  • Sentinel 데몬 구성
  • 클라이언트의 Sentinel 데몬 Subscription 등록
  • 마스터 노드에 장애 발생
  • Sentinel 데몬이 슬레이브 노드들 중 마스터노드 선택
  • 신규 마스터 노드를 바라보도록 슬레이브 노드 설정 변경
  • 클라이언트에게 마스터 데몬 교체 사실 통보

아래 그림은 정상 운영중인 마스터/슬레이브 노드 상태다.

[그림 Ⅱ-3-7] Redis Sentinel(Normal Operation)

[그림 Ⅱ-3-7] Redis Sentinel(Normal Operation)

아래는 마스터 노드에 장애 발생 시 마스터 노드 교체 후의 운영 상태다.

[그림 Ⅱ-3-8] Redis Sentinel(Fail Over)

[그림 Ⅱ-3-8] Redis Sentinel(Fail Over)

[표 Ⅱ-3-9] Redis Sentinel 서비스


Sentinel 서비스 설명
Monitoring
  • 레디스 인스턴스(마스터/슬레이브)의 정상 동작 여부 상시 모니터링
Notification
  • API를 통해 타 프로그램 또는 시스템 관리자에게 이상 현상 발생 내역을 통보
Automatic Fail-Over
  • 마스터 노드에 장애 발생 인지 시, 페일오버 절차를 통해 슬레이브 노드들 중 신규 마스터 노드 선정
  • 신규마스터 노드 정보를 슬레이브 노드들에 전달
  • 신규 마스터 노드 정보를 클라이언트들에 전달
Configuration Provider
  • 클라이언트가 질의한 특정 서비스의 현재 마스터 노드 정보를 전달
  • 향후 마스터 노드 변경 시 해당 사실을 클라이언트에게 통보

쓰기 성능 향상을 위한 레디스 샤딩

레디스 샤딩(Sharding)을 활용한 데이터 세트 분할 분산 저장의 장점은 다음과 같다.


레디스에 저장ㆍ활용하는 데이터 세트의 크기 확대

Replication을 활용한 동일 데이터 세트 중복 분산 저장 시에는, 저장할 수 있는 데이터 세트의 크기가 마스터 노드의 물리 메모리 용량을 초과할 수 없으며 그 이유는 다음과 같다.
마스터 노드는 슬레이브 노드에 데이터를 복제하기 위해 fork 함수를 통해 Child 프로세스를 생성하는데, 이 때 Child 프로세스는 Parent 프로세스와 메모리 영역을 공유하지만, fork 이후 데이터 변경이 발생하는 메모리 페이지는 지연 기록 메커니즘(COW: Copy On Write)에 의해 Child 프로세스의 고유 메모리 영역으로 복사된다.
만약, 4GB 물리 메모리 보유 서버를 마스터 노드로 활용 시 데이터 세트 크기가 4GB라면, 슬레이브 노드 데이터 복제를 위한 Child 프로세스 생성 이후 변경 데이터 저장을 위한 물리 메모리가 부족하게 되어 하드디스크의 가상 메모리(Swap Space)를 사용하게 된다. 물리 메모리와 Swap Space 간 메모리 페이지의 Page-In/Out이 발생하면, 시스템 성능이 급격이 떨어진다.
또한 복제(Replication)는 기본적으로 동일 데이터 세트를 중복 저장하는 것이므로, 특정 크기 데이터세트를 저장하기 위한 물리 메모리 공간이 마스터/슬레이브 노드의 개수만큼 증가하는 구조이다(예: 마스터 1 개 + 슬레이브 3개로 구성된 레디스 복제 구성에서는 2GB 데이터 세트를 저장하기 위해 모두 8GB의 물리 메모리 자원이 필요하다. 2 BG × 4= 8 GB)


쓰기 요청에 대한 성능 개선

쓰기 요청이 구성 분할된 샤드로 분할 전달ㆍ처리됨에 따른 쓰기 요청에 대한 작업량 분할 (Workload Balancing)이 이뤄져 결과적으로 쓰기 성능이 개선된다. 레디스 샤딩은 서버 클러스터 수준에서 데이터를 분할 저장하며 클라이언트에게는 구성 내역에 대한 투명성을 제공하는 서버측 샤딩이 아니라, 클라이언트에서 각 분할된 데이터의 위치를 알고 있어야 하는 클라이언트측 샤딩이라는 특성이 있다. 즉 샤딩으로 인해 클라이언트 애플리케이션의 복잡도가 증가하게 된다. 레디스 샤딩의 유형 및 특징을 살펴보면 다음과 같다.

[표 Ⅱ-3-10] 레디스 샤딩 유형과 특징


샤딩 유형 설명
수직 샤딩
(Vertical Sharding)
데이터 성격을 기준으로 논리적으로 분할(예: RDB의 테이블단위분할)

[고려사항]
  • 수직 샤딩에 의해 분리된 특정 샤드에 대한 처리 요청의 급격한 증가로 인한 서비스 구성 변경 또는 데이터 이동 시 서비스 중단 발생
  • 데이터 위치 정보 관리를 위해 클라이언트 애플리케이션의 복잡도가 증가하며, 이후 샤딩 구성 변경 시 클라이언트 애플리케이션에의 변경 영향도가 큼
영역 샤딩
(Range Sharding)
Key Value에 따라 데이터가 저장될 노드(Shard)를 결정
(예: Key Value 00001 ~ 10000 까지는 Shard 1번에 저장, Key Value 10001 ~ 20000 까지는 Shard 2번에 저장, Key Value 20001 ~ 30000 까지는 Shard 3번에 저장)[고려사항]
  • 수직 샤딩과 동일
해시 기반 샤딩
(Hash based Sharding)
Key의 해시 값에 따라 데이터가 저장될 노드(Shard)를 결정
  • 해수 함수로는 MD5, SHA1 등 다양한 함수를 사용할 수 있다.
  • 사용 가능한 해쉬 함수는 사용하는 클라이언트 라이브러리에 따라 상이할 수 있다.
각 노드(Shard)는 독립된 마스터 노드로 동작한다.

아래 그림의 사례와 같이 복제와 샤딩을 혼합 구성해 읽기/쓰기 성능을 한 번에 개선할 수 있다. 아래의 사례에서 전체 레디스 클러스터는 2개의 샤드로 구성돼 있으며, 각 샤드는 복제(Replication)를 활용해 마스터 노드와 슬레이브 노드를 가진다. 단일 샤드 내 저장된 데이터 세트는 동일하다(아래 사례에서 1번 샤드는 데이터 1ㆍ2ㆍ3ㆍ4ㆍ5를 저장하고 있고, 2번 샤드는 데이터 6ㆍ7ㆍ8ㆍ9ㆍ10을 저장하고 있다). 이미 언급한 바와 같이 샤드의 식별 정보는 레디스 서버 영역에서는 관리하지 않는다. 샤드 식별 정보는 클라이언트 애플리케이션에서 식별 관리해야 한다.

[그림 Ⅱ-3-9] 레디스복제와 샤딩 혼합 구성

[그림 Ⅱ-3-9] 레디스복제와 샤딩 혼합 구성


데이터 영속성

레디스는 기본적으로 메모리에 데이터를 저장하고 활용하는 구조를 가지고 있다. 그런데 실제 상용 서비스가 데이터 손실을 감내할 수 없는 여건이라면, 휘발성 저장 매체인 메모리가 제공해 주지 못하는 데이터 가용성(Availability)은 스냅샷 또는 AOF(Append Only File)을 활용함으로써 확보해야 한다. 이 스냅샷과 AOF를 활용함으로써 데이터 손실을 최소화하고 필요한 경우 유실된 데이터를 복구할 수 있다. 그 주요 특징은 다음과 같다.

[표 Ⅱ-3-11] 레디스 스냅샷과 AOF


레디스 영속성 유형 설명
스냅샷
  • 특정 시점의 메모리내용을 dump.rdb 파일로 디스크에 저장
  • 스냅샷(dump.rdb 파일) 생성을 위해 fork 함수를 통해 Child 프로세스 생성
  • Child 프로세스는 지연기록(COW: Copy On Wirte)의 특성상 최초에는 Parent 프로세스와 메모리영역을 공유하며, fork 이후 변경데이터만 Child 프로세스 고유메모리 영역에 복사
  • 장점: AOF 대비 빠른 명령어 응답시간
AOF
  • 레디스 인스턴스가 수신하는 모든 쓰기 명령을 AOF 파일에 기록
  • 장점: 스냅샷보다 더 우수한 데이터 가용성제공
  • 단점: 스냅샷 대비 디스크 용량 소모가 큼