In-Memory 기반 Key-Value 구조의 NoSQL, Redis(Remote Dictionary System)

레디스(Redis)는 시스템 메모리를 사용하여 Key-Value 형식으로 데이터를 저장하는 오픈소스 NoSQL의 일종이다. 비슷한 기능을 제공하는 Memcached에 비하여 데이터의 영속성(Persistence)을 보장하고 다양한 데이터 구조를 지원하여 최근 많이 사용되고 있다.

레디스의 구조와 활용, 모니터링 솔루션 등에 대해서 알아보자.

1. Redis 소개

(1) 정의

  • Redis는 프로세스로 실행되는 In-Memory 기반 Key-Value 구조의 데이터 관리 시스템이다.

(2) 특징

  • Key-Value 구조란 일반적인 RDBMS의 관계형 구조가 아닌 비관계형으로 키와 값만을 유지하는 단순한 구조를 말한다. RDBMS의 SQL과 같은 질의 언어를 사용해서 데이터를 다루는 것이 아니라 API를 통해 읽기와 쓰기가 가능하다. 이런 특징으로 Redis는 NoSQL로 분류 된다.
  • 읽기 분산을 위한 복제(Replication)와 쓰기 분산을 위한 샤딩(Sharding)을 지원한다.

(3) 자료 구조

자료 형태자료 구조
Stringkey -> “Hello world”
Hashkey -> {A:”foo”, B:”bar”}
Listkey -> [A->B->C->D]
Setkey -> {A, B, C, D}
Sorted Setkey -> {A:0.3, B:0.4, C:182}

(4) Redis 동작 방식

레디스 동작 방식

2. Redis 운영모드

(1) 단일 인스턴스(Standalone)

  • HA(High Availability)를 지원 하지 않는다.

(2) 센티넬(Sentinel)

  • Master/Slave Replication
  • Redis Process와 별개로 Sentinel Process 실행
  • Sentinel Process들(3대 이상 권장, 과반 이상의 Vote 필요)이 장애 감지, Master 문제 발생 시 자동 Failover(HA 지원)
레디스 마스터, 슬래이브, 센티널 구조

[설치 (Master, Slave)]

<Master 설정>

# service redis_6379 stop
# vi /etc/redis/6379.conf (수정없이 enter 입력했으면 default는 6379.conf)
bind 0.0.0.0
protected-mode yes
/* set redis password -> optional 선택사항 이지만 설정하면 다른부분에 auth를 추가해야 함 */
requirepass [auth_string]

replicaof [masterip] [masterport]
replica-read-only yes

실행

# service redis_6379 start# redis-cliinfo replication

<Slave(Sentinel) 설정>

# cd redis-7.2.4
# cp sentinel.conf /etc/redis/redis_sentinel_26379.conf
# vi /etc/redis/redis_sentinel_26379.conf
bind 0.0.0.0port 26379
/* sentinel monitor mymaster <masterip> <masterport> <quorum> */
sentinel monitor mymaster 192.168.30.135 6379 2
/* set redis master node password if master node is password protected */
sentinel auth-pass mymaster [auth_string]
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
pidfile /var/run/redis_sentinel_26379.pid
logfile /var/log/redis_sentinel_26379.log

서비스 실행을 위한 스크립트 생성

# cp /etc/init.d/redis_6379 /etc/init.d/redis_sentinel_26379
# vi /etc/init.d/redis_sentinel_26379

아래와 같이 편집

#!/bin/sh

EXEC=/usr/local/bin/redis-sentinel
CLIEXEC=/usr/local/bin/redis-cli
PIDFILE=/var/run/redis_sentinel_26379.pid
CONF="/etc/redis/redis_sentinel_26379.conf"
REDISPORT="26379"

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
            echo "$PIDFILE exists, process is already running or crashed"
        else
            echo "Starting Redis Sentinel server..."
            $EXEC $CONF &
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
            echo "$PIDFILE does not exist, process is not running"
        else
            PID=$(cat $PIDFILE)
            echo "Stopping ..."
            $CLIEXEC -p $REDISPORT shutdown
            while [ -x /proc/${PID} ]
            do
                echo "Waiting for Redis to shutdown ..."
                sleep 1
            done
            echo "Redis Sentinel stopped"
        fi
        ;;
    status)

실행

# chmod ugo+x /etc/init.d/redis_sentinel_26379
# service redis_sentinel_26379 start

(3) 클러스터(Cluster)

  • Data Port(예:6379)와 Cluster Bus(Dataport + 10000)를 사용하여 두 개의 프로세스 실행
  • Hashslot이라는 개념을 사용해서 Sharding 구성, 각 노드별 범위 할당 가능
  • 일반적으로 Failover 처리를 위해서 Cluster의 노드를 N대로 구성(Master 1대, Slave N-1대)
  • Redis Cluster 지원 Client를 사용해야 Redirect 가능
  • 해당 키를 요청받은 노드가 가지고 있으면 바로 리턴, 그렇지 않은 경우는 저장된 노드를 리턴 하므로 리턴된 정보를 재요청 해야 한다.
레디스 클러스터 구조

[설치 (Redis-cluster)]

<Node 설치>

/opt/redis 디렉토리를 생성하여, Redis 설치 디렉토리(그대로 입력했다면 redis-stable일 것이다)의 redis.conf 파일을 /opt/redis에 복사한다.
그리고 /opt/redis 아래에 7000, 7001이라는 폴더를 생성한다. (/opt/redis/7000, /opt/redis/7001)
/opt/redis/7000에 7000.conf 파일을 생성하여 아래와 같이 입력한다.

include /opt/redis/redis.conf

bind 0.0.0.0
daemonize yes
protected-mode no

port 7000
pidfile /opt/redis/7000/redis_7000.pid
logfile /opt/redis/7000/redis-7000.log
dir /opt/redis/7000
dbfilename dump_7000.rdb

requirepass [redis password]
masterauth [redis password]

cluster-config-file node-7000.conf
cluster-enabled yes
cluster-node-timeout 5000

rename-command keys ""

appendonly no

같은 서버 또는 다른 서버에 Redis Instance를 추가해서 위와 같이 설정하고 포트를 구분해서 Slave를 구성할 수 있다.

<클러스터 구성>

redis-cli -a cslee0123 --cluster create 192.168.1.167:7000 192.168.1.168:7000 192.168.1.169:7000

<슬레이브 추가(각 노드별)>

redis-cli -a cslee0123 --cluster add-node 192.168.1.168:7001 192.168.1.167:7000 --cluster-slave
redis-cli -a cslee0123 --cluster add-node 192.168.1.169:7001 192.168.1.168:7000 --cluster-slave
redis-cli -a cslee0123 --cluster add-node 192.168.1.167:7001 192.168.1.169:7000 --cluster-slave

[Redis-cluster 지원 Library]

  • Java: jedis
  • .NET: StackExchange.Redis
  • Go: Radix, go-redis/redis
  • Node.js: node-redis, ioredis
  • Python: redis-py

3.Redis 활용

(1) SNS

방문자 수, 순위, 좋아요 등의 실시간 랭킹 시스템 : Redis의 Sorted Set(ZSET) 자료 구조를 이용하여 구현 가능.
예) ZREVRANK ranking 0 9 WITHSCORES : ranking 값으로 상위 10개 조회

(3) 데이터 캐싱

연산이 동일한 결과 데이터, 일정주기 갱신 데이터 : 분산되어 있는 웹서버의 로그인 세션 공유를 위해 Redis 한 곳에서 관리

(3) 사용자의 세션 관리

임시비밀번호 저장, JWT 저장, 일일 방문자(UV) 계산(순 방문자수는 하루에 여러 번 방문해도 한 번만 카운트, 접속한 사용자 ID에 Flag를 1로 설정, 여러 번 접속해도 Flag는 1이므로 Flag가 1인 사용자 ID 의 개수)

4. Redis 모니터링

(1) Redis Info를 통한 정보

  • RSS : 피지컬 메모리의 사용량
  • Used Memory : Redis가 사용 중인 메모리
  • Connection : Client 수, 싱글 쓰레드인 레디스에 커넥션 연결/해제가 빈번한 것은 성능 저하 요인

(2) System 정보

  • CPU : OS의 CPU 사용율
  • Disk : Disk rd/wr, 디스크 사용율 등
  • Network : rcv/snd

(3) OS의 CPU 사용률이 100%에 가까운 경우

  • 시간복잡도가 O(n) 계열인 특정 명령 의 사용이 빈번한 경우, Keys, flushAll, flushDB, get All Collections 등

(4) Hits / Misses

  • Hits와 Misses는 조회(Get) 실행시 Key가 존재하면 Hit Count 증가, 없으면 Miss Count 증가
  • Hit Ratio = Keyspace-hits / (Keyspace-hits + Keyspace-misses)

5. Redis 모니터링 솔루션


[참고 문헌]

  • Redis 운영 관리 (저자 강대명)