메뉴

문서정보

목차

Redis 시작하기

1부에서는 Redis에 대한 개념을 잡는다. Redis가 어떤 기능을 제공하는지, 왜 인기 있는지를 확인해 볼 것이다. 그리고 Redis 학습을 위한 기본 환경을 구성할 거다. 1부에서 다룰 내용은 아래와 같다.
  1. Redis 소개.Reids는 무엇인가 ? 무얼 할 수 있을까 ?
  2. Redis와 NoSQL
  3. Redis 설치와 기본 사용
  4. Redis로 할 수 있는 것들, 그렇지 않은 것들

Redis 소개

Redis는 BSD 라이센서를 가지는 오픈소스 인메모리(in-memory) key-value 데이터를 저장하는 데이터베이스다. 인메모리인 만큼, 시스템이 재시작하거나 메모리에 문제가 생기면 모든 데이터가 사라진다. 다만 내구성을 가지는(durability)구성도 가능하다. Key는 문자열(string)을 사용하며, value로는 문자열, 리스트, 맵, 셋(set), 정렬된 셋(sorted set), 하이퍼로그로그(hyperloglogs), 비트맵, 공간색인등 다양한 데이터 구조를 사용 할 수 있다.

Redis는 REmote Dictionary Server의 줄임말이다. DB-Engines ranking자료에 따르면, Redis는 가장 인기 있는 key-value 데이터베이스다. NoSQL 데이터베이스로 범위를 넓히면 3위, 전체 데이터베이스에서는 7위를 차지하고 있는 인기있는 데이터베이스다.

Key-Value 데이터베이스란

key-value 데이터베이스 혹은 key-value 스토어(store)라고 부른다. key-value 데이터베이스는 dictionaryhash table이라고 부르는 데이터스트럭처와 유사한 모습을 가진다. 예를들어 딕셔너리는 여러 개의 필드로 이루어진 객체와 레코드를 가지고 있는데, 각 객체와 레코드를 식별하기 위한 key를 가지고 있다. 응용 소프트웨어는 key를 기준으로 데이터를 쓰고, 찾을 수 있다.

실생활의 많은 데이터들이 key-value 형태로 저장된다. 예를 들어 상품정보를 저장하는 카테고리의 경우 상품 아이디가 key가 되고, 상품의 상세 정보가 value가 된다.

key-value 데이터베이스는 RDB(Relation databases) 와는 다른 방식으로 작동한다. RDB는 잘 정의된 데이터 유형들을 가진 필드들로 구성된 테이블들로 구성된다. 데이터베이스는 하나 이상의 테이블들로 구성이 된다. RDB에서는 데이터베이스를 구성하는 테이블들과 테이블의 필드들을 서로 조합해서 저장하고 읽는다. 필드들은 다양한 타입을 가지고 있으며, 매우 유연하게(다른 말로는 매우 복잡하게)관계를 맺을 수 있다. 이런 특징 때문에 RDB는 복잡한 연산이 필요한 데이터들을 저장하는데 널리 사용한다. 테이블과 필드의 관계를 어떻게 정의하냐에 따라서 성능이 크게 달라질 수 있기 때문에, 전문적인 DBA(데이터베이스 관리자)가 데이터베이스 스키마를 설계하곤 한다.

반면 key-value 데이터베이스는 단순하며(단지 key와 value로만 구성된다) 모든 레코드들이 서로 다른 필드를 가질 수 있다. value로 어떤 데이터를 넣던지 상관 없다는 것이다. xml, json, csv, 단순 문자열 어떤 것이든 상관이 없다. 이러한 구성은 애플리케이션에 상당한 유연성을 제공한다. 단순하며, 스키마가 필요하지 않기 때문에 RDB 보다 훨씬 적은 메모리를 사용하며, 특정 업무에서 큰 성능향상과 개발 편의성을 가져올 수 있다.

 k-v 스토어

key-value 데이터베이스는 성능과 표준화등의 문제로 오랜기간 동안 틈새 시장용으로만 사용했지만 2010년 이후 클라우드 컴퓨터로 시장이 급변하는 과정에서 광범위한 NoSQL의 인기와 함께, 급부상하게 된다.

NoSQL과 Redis

2010년 부터 인기를 얻게된 NoSQL은 SQL을 질의어로 사용하는 RDB를 제외한 데이터베이스들의 총칭이다. NoSQL은 저장방식에 따른 아래와 같은 종류들이 있다.

Key-Value 스토어

Reids가 여기에 속한다. 아래와 같은 솔류션들이 있다.

Document 스토어

문서지향 데이터베이스(Document-oriented database) 라고 부르기도 한다. 문서지향 정보들의 저장, 검색, 관리를 잘 할 수 있도록 설계된 데이터베이스 소프트웨어다. Key-Value 스토어와 함께, NoSQL의 인기 스토어다.

문서지향 데이터베이스는 Key-Value 스토어의 하위 분류로 볼 수 있다. 차이점은 데이터의 처리방식에 있다. key-value 저장소에서 데이터는 본질적으로 (스키마나 특정한 형식이 없는)불투명한 것으로 간주되지만, 문서지향 시스템은 데이터로부터 정보를 효과적으로 추출하기 위한 문서의 특정한 구조에 의존한다. 예를 들어 블로그의 경우 "제목", "저자", "작성일", "태그", "분류"와 같은 문서 분류 기준을 가지고 있을 것이다. 또한 저장된 문서는 제목, 저자, 분류 ... 등에 대해서 검색을 수행 할 수도 있어야 한다.

이런 이유로 문서지향 시스템은 최신 프로그래밍 기술을 수용하며, 더 복잡하고 거대한 경우가 많다. 전형적인 Key-Value 저장소인 Redis는 한 두 시간이면 기본적인 사용법을 익힐 수 있는 반면, MongoDB의 경우 몇 배나 많은 학습이 필요하다.

Graph

Graph 데이터베이스(GDB)는 데이터를 저장하고 표현하기 위해서 "노드", "엣지", "속성"을 가지는 그래프 이론(graph theory)를 기본으로 하는 데이터베이스 소프트웨어다.

 graph 속성

대표적인 graph 데이터베이스들을 정리했다. 관계형 데이터모델은 데이터의 정보를 사용해서 데이터를 모은다. 예를들어 전화번호에 지역번호 "031(부천을 제외한 경기도)"이 포함된 모든 사용자를 찾는 식이다. 선택한 전화번호 필드에서 문자열이 031인 레코드를 검색하면 된다. 대량의 데이터를 포함하고 있을 경우 많은 시간이 걸릴 수 있기 때문에, 관계형 데이터베이스는 색인으로 이 문제를 해결한다.

기본적으로 관계형 데이터베이스는 레코드 간의 고정된 관계라는 개념을 포함하지 않고 있다. 대신 하나의 레코드의 키를 다른 레코드의 데이터로 저장해서 서로를 연결(링크)하는 방법을 사용한다. 그래서 관계형 데이터베이스는 join등을 이용해서 여러 테이블에 흩어져 있는 데이터의 관계 정보를 수집한다.

예를 들어 관계형데이터베이스에 친구 정보를 저장한다고 가정해 보자. 여기에는 유저 테이블과 친구 테이블, 2개의 테이블이 필요하다. 유저 테이블에는 유저를 식별할 수 있는 userid라는 데이터항목을 저장 할 수 있다. 그리고 친구 테이블에는 userid와 친구의 userid가 들어갈 것이다. 유저의 친구를 찾기 위해서는 유저 테이블에서 userid를 찾은 다음, 친구 테이블에서 userid를 key로 하는 모든 레코드를 추출해야 한다. 그 다음 친구의 상세 정보를 가져오기 위한 작업을 수행해야 한다. 개발자는 조인(join)이라는 연산을 이용해서 이 작업을 수행해야 하는데, 많은 비용이 들어간다.

 친구테이블

위 테이블을 보자. "yundream"의 친구를 찾기 위해서는 user table에서 yundream의 userid를 찾아야 하고, 해당 userid로 friend table에서 검색을 해야 한다. 검색후 다시 user table에서 친구의 상세 정보를 가져와야 한다.

반대로 graph 데이터베이스는 레코드간의 관계를 직접 저장한다. 아래 그림을 보자.

 graph 방식의 친구테이블

친구들의 정보를 저장한 레코드의 포인터가 저장된다. 레코드를 찾기 위해서 테이블을 검색할 필요가 없기 때문에, 막대한 비용이 들어가는 join에 비해서 효과적으로 친구목록을 검사 할 수 있다. 이렇게 관계를 찾는 작업은 graph 데이터베이스가 훨씬 빠르게 수행 할 수 있다. Graph 데이터베이스의 잇점은 관계가 복잡해질 수록 더 크게 누릴 수 있다.

Column Store

Column-oriented DBMS라고 부르기도 한다. 컬럼지향 데이터베이스는 행이 아닌 열(column)단위로 데이터를 저장하는 데이터베이스 관리 시스템이다. 행이나 열이나 무슨 차이가 있을까라고 생각 할 수 있겠는데, 실제 사용인 크게 다르다. 두 데이터베이스 모두 SQL과 같은 전통적인 데이터베이스 질의언어를 사용해서 데이터를 로드하고 쿼리를 수행할 수 있다. 또한 시스템의 백본이 되어 ETL(추출, 변환, 로드) 작업을 수행하고 시각화 도구를 제공할 수 있다. 그러나 컬럼지향 데이터베이스에 데이터를 저장하면, 행에서 원하지 않는 데이터를 쉽게 제거하고 필요한 데이터에 정확하게 엑세스 할 수 있다.

RDBMS는 행과 열로 이루어진 2차원 테이블에 데이터를 저장한다. 아래는 이러한 테이블의 전형적인 예다.

 RDBMS 테이블

이 간단한 테이블은 고용인번호(EmpId), 이름(Lastname과 Firstname), 봉급(Salary) 정보를 포함하고 있다.

컬럼지향 데이터베이스는 열의 모든 값을 함께 직렬화 하고 다음 열의 값을 직렬화 한다. 위의 예제 테이블은 아래와 같은 방식으로 저장된다.

 Column 저장소

이러한 구성은 같은 필드의 데이터를 구조적으로 가까운 거리에 저장할 수 있다. 하드디스크(혹은 SSD)와 관련된 가장 많은 비용이 들어가는 작업은 Seek다. 컬럼지향 데이터베이스는 Seek를 최소화 함으로써 특정 작업에서 효율적으로 작동할 수 있다. 컬럼지향 데이터베이스의 이러한 특징은 sparse(드문 드문 저장된) 대량의 데이터를 저장하고 분석하는데 효과적이다.

컬럼지향 데이터베이스의 아이템을 보면 RowID를 기본 키로 사용하고 있음을 알 수 있다. 컬럼지향 데이터베이스에서 데이터들은 RowID에 맵핑된다.

주요 컬럼지향 데이터베이스 목록이다.

Redis 설치하기

우분투 리눅스

우분투리눅스 17.10을 기준으로 한다. 다른 우분투 리눅스 버전도 차이는 없다.
# apt-get update
# apt-get install redis-server
Redis 서버 버전을 확인하자.
# redis-server --version
server 명령을 이용해서 Redis 서버를 시작 할 수 있다.
# service redis-server restart
netstat로 redis의 네트워크 바인드 정보를 확인해 보자.
# netstat -nap | grep redis
tcp  0  0 127.0.0.1:6379    0.0.0.0:*    LISTEN   1519/redis-server 1 

루프백 주소(127.0.0.1)의 6379포트에 바인드 하고 있다. 이 상태에서는 원격에서 접근을 할 수 없으나 지금은 원격에서 접근 할 필요는 없으니 원할한 테스트를 위해서 원격에서 사용 할 수 있도록 Redis 네트워크 설정을 변경하자. Redis 설정 파일은 /etc/redis/redis.conf 다. 파일을 열어서 "bind 127.0.0.1"부분을 "bind 0.0.0.0"으로 바꾸고 서비스를 재시작하자.
# cat /etc/redis/redis.conf
...... // 생략
bind 0.0.0.0
..... // 생략

# service redis-server restart
# netstat -nap | grep redis
tcp  0  0 0.0.0.0:6379   0.0.0.0:*    LISTEN      1729/redis-server 0 
redis 클라이언트 프로그램인 redis-cli 로 서버에 접근해보자. redis-server를 설치하면 함께 설치되는 프로그램이다. 만약 원격에서 접근하고 싶다면 redis-client를 설치해야 한다. 서버가 살아있는 확인하는 "ping" 명령을 실행했다.

# apt-get install redis-tools
# redis-cli -h 127.0.0.1
127.0.0.1:6379> ping
PONG

Docker

호스트운영체제에 테스트와 개발로 이것 저것 설치했다가는 나중에 관리하기 어려워질 수 있다. 그렇다고 VM을 실행하기에는 쓸데 없이 무겁다. 이럴 때 Docker를 이용하자. Docker 설치는 도커 설치문서를 참고하자.

$ docker run --name test-redis -d redis
도커 컨테이너의 IP는 inspect명령으로 확인 할 수 있다.
# docker inspect my-redis | grep IPAddress
        "SecondaryIPAddresses": null,
        "IPAddress": "172.17.0.2",
            "IPAddress": "172.17.0.2",
redis-cli로 접근해보자.
$ redis-cli -h 172.17.0.2
172.17.0.2:6379> ping
PONG

Redis의 기본

Reids는 거의 모든 인터넷 서비스에서 사용하는 핵심 소프트웨어다. Redis의 어떤 점이 특별해서 핵심 소프트웨어로 사용하게 됐을까 ? 어디에 써야하고, 어떤 단점들이 있을까 ? 이러한 질문에 답하기 위해서는 Reids가 무엇인지, 그리고 어떤 목적으로 만들어졌는지를 이해해야 한다.

종종 Redis는 메모리에 저장되는(in-memory) persistent key-value 스토어라고 설명한다. 하지만 이것은 좋은 설명은 아니다. Redis는 데이터를 메모리에 저장한다. 데이터의 일부를 persistent한 디스크에 저장할 수 있기는 하지만 persistent는 Redis의 특징이 아니다. Redis는 간단한 key-value 저장소일 뿐이다. 이 이상의 어떤 것을 기대하는 건 좋은 생각이 아니다.(마법의 은탄환은 없다.)

Redis는 다섯 가지 정도의 고정된 데이터 구조를 제공한다. 이 고정된 데이터 구조도 key-value 기반이다. 즉 DBMS 처럼 복잡하고 유연하고 융통성있는 데이터 모델을 만들 수는 없다. Redis 범용적인 목적이 아닌 특정한 목적에 특화된 데이터베이스다. 반면 범용성, 유연성을 버린대신에 쓰기 쉽고, (적당한 목적에만 사용한다면) 아주 빠른 성능을 보장받을 수 있다.

Redis의 단순함이 기능적 제약이라고 생각 할 수 있을 것이다. 하지만 list, hash, set 등의 데이터를 저장하기 위해서 굳이 필요도 없는 복잡한 기능을 가진, 그리고 그 댓가로 느린 성능을 감수해야 하는(성능이 좋지 않다는 것은 그 만큼 더 많은 돈을 써야 한다는 것을 의미한다.) DBMS를 사용 할 필요가 있을까 ?

실제 인터넷 서비스는 최소한 2개 이상의 데이터베이스와 데이터베이스 모델을 사용한다. 인터넷 서비스가 복잡해지고, 요청량이 많아지면서 하나의 데이터베이스로는 서비스에 대응 하기가 힘들어졌기 때문이다. Mysql로 모든 걸 다 처리하던 2000년 초반을 생각하면 안된다.

특히 왠만한 규모의 인터넷 서비스는 Redis와 같은 in-memory 데이터베이스로 컨텐츠를 모두 캐시해서 제공하는 것으로 서비스의 성능과 확장성을 보장받는다고 보면 된다.

데이터베이스 만들기

MySQL 같은 RDBMS는 하나 이상의 테이블로 구성된 데이터베이스를 만든다. Redis도 데이터베이스 구조를 가지고 있다. 테이블로 구성된 RDBMS와는 달리 하나 이상의 테이블이 아닌 하나 이상의 데이터 셋으로 구성된다는 차이가 있다.

MySQL은 User, Product와 같은 문자열 기반의 데이터베이스 이름이 가능하지만 Redis는 0,1,2와 같은 숫자로 데이터베이스를 선택 할 수 있다. Redis의 기본 데이터베이스는 0이다. CONFIG GET databases명령으로 데이터베이스 갯수를 알 수 있다.
172.17.0.2:6379> CONFIG GET databases
1) "databases"
2) "16"
0에서 15까지, 16개의 데이터베이스를 제공함을 알 수 있다. select 명령을 이용해서 작업할 데이터베이스를 선택 할 수 있다.
172.17.0.2:6379> select 5
OK
172.17.0.2:6379[5]> 
5번 데이터베이스에서 작업하고 있음을 알 수 있다.

Key & value 를 만들어보자.

Redis는 key-value 스토어 이상의 다양한 데이터 스트럭처를 제공한다. 하지만 key/value가 기본이 되는 데이터 스트럭처다. 다른 데이터 스트럭처도 key/value의 확장이므로 key/value를 저장하는 방법을 먼저 살펴봐야 할 것 같다.

키(Key)는 데이터를 식별하기 위해서 사용하는 전체 데이터베이스에서 유일한 값이다. 예를 들어서 유저 정보를 저장한다고 하면 users:yundream과 같은 key를 만들 수 있을 것이다. 개발자는 key 이름만으로 yundream이라는 유저의 정보를 담고 있다는 정보를 얻을 수 있다. key 이름을 만들기 위한 특별한 규칙이 있는 건 아니지만 보통 콜론(":")을 이용해서 계층적으로 구성한다. 쇼핑카트라면 cart:yundream 처럼 구성할 수 있을 것이다. 아니면 아래 처럼 key 이름을 설계 할 수 있을 것이다. 값(Value)은 key에 저장된 실제 데이터다. 여기에는 문자열, 숫자(integers) 혹은 XML, JSON, YAML과 같은 직렬화된 객체를 저장 할 수도 있다. Redis는 값을 바이트의 배열로 취급하기 때문에 그 값이 무엇인지 신경쓰지 않는다. 어떤 형식의 데이터를 저장할지는 순전히 애플리케이션 개발자의 마음에 달렸다. 이 문서에서는 integer, string, JSON 만 다룰 것이다.

user:yundream에 yundream 유저의 정보를 저장해 보자.
> set users:yundream '{"name":"yundream", "email", "yundream@gmail.com", "role":"admin"}'
OK
Redis의 모든 명령은 위의 형식 즉, "명령 파라메터..."를 따른다. 위 예제에서 명령은 set이고, 파라메터는 "user:yundream"과 "{"name":"yundream", "email", "yundream@gmail.com", "role":"admin"}" 2개다. 첫번째 파라메터는 key, 두번째 파라미터는 value다. 예제에서는 JSON 데이터를 저장했는데, 어떤 식의 데이터도 상관은 없다. 예를 들어 아래와 같이 csv 형태의 데이터를 저장 할 수도 있다.
> set users:yundream 'yundream,yundream@gmail.com,admin'
get 명령을 이용해서, key/value를 가져올 수 있다.
> get users:yundream
"yundream,yundream@gmail.com,admin"

Redis Query

set과 get을 이용해서 key/value 값을 쓰고 읽는 것을 살펴봤다. 여기에서 우리는 Redis 데이터와 질의 특성을 알 수 있다.

Reids는 Key가 모든 것이라는 것이다. Value는 아무것도 아니다. Value로 질의를 할 수 없다. 예를들어 yundream 이나 yundream@gmail.com 혹은 admin등으로 질의를 할 수 없다. 따라서 admin 유저 목록을 검색하는 등의 작업은 불가능하다.

MySQL과 같은 데이터베이스에 비교하자면 쿼리가 제한적이며, 유연성과 범용성이 극히 떨어지는 것에 대해서 우려를 표할 수 있을 것이다. MySQL에 비하면 너무 원시적이고 실용적이지 않은 것처럼 보인다. Reids는 size-fits-all 솔류션이 아니다. Redis는 특정 영역에서 최대한의 효율성을 달성하기 위해서 특화된 기능을 가진 솔류션이다. Redis가 주력하고 있는 이 특정 영역은 MySQL 같은 RDBMS로도 할 수 있다(Redis와 비교하자면 MySQL은 size-fits-all 솔류션이기 때문이다). 하지만 이 지점에서 Redis는 MySQL과는 비교 할 수 없는 효율성, 성능, 개발 및 운영편의성(단순하다는 것은 개발과 운영이 쉽다는 것을 의미한다.)을 가져다 준다. 또한 우리는 RDBMS로 할 수 없었던 혹은 할 수는 있으나 너무 비효율적이라서 시도하지 않았던 새로운 데이터베이스 모델을 만들 수도 있다.

앞으로 Reids를 학습하면서 좀 더 구체적인 예를 살펴보겠다. Redis의 이러한 현실과 특징을 이해하는 것은 중요하다.

Memory & Persistence

Redis는 in-memory persistent 스토어다. 메모리에 저장된 데이터는 영구히 남지 않기 때문에 persistent 스토어라고 말하는 것은 모순이 있는 것 같다. Redis가 비록 메모리에 우선해서 데이터를 저장하기는 하지만 메모리에 저장된 데이터를 디스크에 스냅샷 할 수 있다. 당신은 "N 개의 key가 변경됐을 때" 혹은 "N 초가 지난 후에"등의 조건으로 디스크에 스냅샷을 남길 수 있다.

특정 조건을 만족할 때 스냅샷을 뜨는 방법으로는 데이터를 잃어버릴 수 있다. 이에 대한 대안으로 key가 변경될 때마다 디스크를 업데이트하는 append 모드에서 Redis를 실행 할 수 있다.

스냅샷을 저장하든 append 모드에서 redis를 실행시키든, Redis의 일차 데이터 저장소는 메모리다. 이는 Redis 운용에 많은 비용이 든다는 것을 의미한다. RAM은 여전히 서버 하드웨어에서 가장 비싼 부분이기 때문이다. 때문에 Redis에 이미지와 같은 대량의 데이터를 저장하는 것은 좋은 생각이 아니다. 한때 Redis는 가상 메모리(virtual memory)에 대한 지원을 추가했으나 이는 실패로 간주되고 있으며 더 이상 이 기능을 사용하지 않고 있다.

속도와 데이터모델

Redis는 데이터를 메모리에 저장한다. 이는 "매우 빠르게 데이터를 저장하고 꺼낼 수 있음"을 의미한다. 실제 Redis는 애플리케이션의 성능 특히 응답속도를 높이기 위한 목적으로 널리 사용한다. 애플리케이션 성능을 향상시키기 위한 가장 쉬운 방법은 자주 사용하는 정보를 메모리에 캐시하는 거다.

그렇다면 Redis 의 장점은 "단지 속도"인가라는 질문을 던질 수 있을 것이다. 물론 속도는 중요한 요소이지만 Redis가 다른 솔류션에 비해서 장점을 가지는 또 다른 이유로 "특수한 데이터 구조"에 있다. 그리고 이 특수한 데이터 구조는 현대적인 인터넷 서비스를 효율적으로 지원할 수 있도록 설계돼있다.

그리고 Redis는 기존의 관계형 데이터베이스 위에 새로운 데이터모델을 얹기 위한 목적으로도 사용 할 수 있다. 예를 들어 관계형 데이터베이스에서 어떤 정보를 가져오기 위해서 Join을 포함한 몇 번의 쿼리가 실행될 수 있는데, Redis를 이용해서 이 과정을 최소화 할 수 있다. 예를 들어 Redis는 세션정보를 유지하기 위한 목적으로 사용 한다. 처음에는 관계형데이터베이스에서 몇 번의 쿼리로 세션정보를 만들어야 겠지만, 이렇게 가져온 세션정보는 Redis에 저장을 한다. 이 후에는 관계형 데이터베이스가 아닌 Redis에서 세션정보를 가져온다. 이런 패턴은 처음 사용할 때는 부자연스러워 보일 수 있다. 관계형 데이터베이스 설계하는 것도 복잡한데, Redis를 학습하고 코드를 수정해야 하기 때문이다. 하지만 이러한 노력은 Redis를 사용함으로써 얻는 이득에 비하면 사소한 비용이 되는 경우가 많다.

복습

  1. MySQL이 있는데, Redis를 사용하는 이유가 뭘까 ?
  2. Redis 서버를 설치하고 Redis 클라이언트로 접속 한다. 1번 데이터베이스를 선택해서 SET, GET 명령을 테스트해본다.
  3. Redis 서버를 재시작해보자. 혹은 Redis 서버가 설치된 운영체제를 리부팅 한 후, Redis 서버에 연결해보자. 이전에 저장한 데이터가 남아 있는가 ?
  4. Redis는 메모리에 데이터를 저장하기 때문에 데이터 지속성을 보장하지 않는다. 어떤 목적으로 사용해야 할까 ?
목차 Redis 데이터 스트럭처 - Strings »