본문 바로가기

Redis

Why Redis? (Redis vs Memcached)

인스타그램, 네이버, 라인, 우아한형제들 등 국내외 기업에서 사용하고있는 Redis 에 대해 알아보자.

 

 

DB-Engines 의 랭킹에서 볼 수 있듯이 전체 DBMS 에서는 8위, Key-value 스토어로는 가장 많이 사용되어지고 있는 레디스이다.

 

이번 포스팅에서는 Redis의 특징과 대형서비스에서 사용되는 형태에 대해 알아보고, 비슷한 솔루션인 Memcached 와의 차이를 통해 Redis 의 장점에 대해 살펴보려고한다.

 

 이후에는 Redis에서는 어떻게 트랜잭션을 관리하는지 Transaction Manager 에 대해서 포스팅하려고 한다.

 

 

 

 

1. In-memory 기반의 캐시 솔루션


레디스 공식웹 첫 화면의 첫문장, Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. 

 먼저, In-memory 기반 데이터베이스의 특징과 대용량 데이터 처리가 필요한 여러서비스에서 속도를 빠르게 하기 위한 방법인 Cache에 대해서 알아보려고한다.

 

1.1 In-memory DB

Memory의 가격이 용량 대비, 충분히 낮아지면서 빠른 데이터베이스 성능을 위해서 등장한 In-memory 데이터베이스는 Disk 대신 Memory를 사용함으로써, 데이터를 읽고 쓰는 성능을 높였다.

시스템 메모리 계층구조 - 출처 : https://constructor.tistory.com/18

 

 위에 메모리 계층구조에서 볼 수 있듯이 메모리는 디스크에 비해 용량은 작지만 접근이 빠르다. 이는 저장된 데이터를 대상으로 쿼리를 날리는 디스크방식과 다르게 메모리상의 인덱싱을 통해 접근하기 때문이다.

 

 하지만 휘발성인 메모리의 특성상 데이터를 영구적으로 유지하기 힘들다는 단점이있다. 이 때문에 영속성이 필수적이지 않는 데이터들의 빠른 성능을위해 사용되거나, 메모리의 저장된 정보를 디스크에 옮기는 방식으로 데이터를 유지해야한다.

 

 

1.2 Cache

 일상생활에서도 자주 사용하는 물건은 무의식적으로 가까이에 둔다! 혹은 여러 사람이 나한테 똑같은 일을 시키는데, 한 번만 해놓고 저장해둔다면 요구할 때마다 복사해서 돌려주면 되지 않을까?

 이러한 개념의 캐시를 강대명님의 발표에서는 다이나믹 프로그래밍의 Memoization 빗대어 설명하신 것에 감명을 받고 정리해 보았다.  

 우리는 1 부터 N 까지의 곱을 Factorial(N!) 이라고 알고있다.

 

public int factorial(int target) {
    int num = 1;
    for (int i = 2; i <= target; i++) {
        num *= i;
    }
    return num;
}

 

 이처럼 코드로 간단하게 메서드를 만들 수 있는데, 살짝 조건을 추가하자.

 

이번에는 1! 부터 100! 까지 나열해보도록 하자!

 

 for(int i=1; i<=100; i++) {
     System.out.println(factorial(i));
 }

 

위에서 구현한 메서드를 통해 값을 호출한다면 어떤 문제가 발생할까?

 

1! = 1
2! = 1 * 2
3! = 1 * 2 * 3
...
100! = 1 * 2 * 3 * ... * 99 * 100

1 * 2 라는 연산의 입장에서는 똑같은 연산을 1! 을 제외하고 모든곳에서 계속하고있는 것이다.

 

 조금만 더 살펴보자면,

이렇게 똑같은 연산이 나열될 것을 예상한다면, 팩토리얼처럼 규칙적인 연산을 매번 새롭게 시작할 이유가있을까?

 

1! = 1
2! = 1! * 2
3! = 1! * 2 * 3 = 2! * 3
...
N! = (N-1)! * N

수학에서는 이처럼 인접한 항들사이에서의 관계식으로 나타낼 수 있는 것을 점화식이라고 한다.

 

 이 점화식을 통해 한 번 수행된 연산을 기억해두고, 관계가 있는 다른 항에서 기억한 값을 사용하여 중복된 연산을 하지 않는 프로그래밍기법을 Dynamic-Progamming 이라고하고 이때 동일한 계산을 기억하는 것을 Memoization 이라고 한다.

 

public static int[] cache = new int[CACHE_MEMORY];

public void memoization() {

    for (int i = 2; i <= CACHE_MEMORY; i++) {
        cache[i] = cache[i - 1] * i;
    }
}

 

위와 같이 관계식을 통해 불필요한 연산을 줄일 수 있다.

 

 

 

 

1.3 결론

 자주 사용하는 데이터들을 기존 저장소보다 빠르게 꺼내올 수 있는 저장소로 옮기고~
반복적으로 요청하는 값들에 대해서는 메모이제이션의 개념으로 기억해두고 사용하면 어떨까? 

 

이러한 개념이 캐싱이고,

시간의 단축목적으로 임시적으로 데이터를 기억특성상 실시간으로 값을 유지할 필요가없다!

 

따라서 휘발성이있어 값을 유지하기는 어렵지만, 데이터에 대한 빠른접근이 가능한 메모리기반 솔루션들이 사용되는 이유이다!

 

 

2. Redis vs Memcached


이번에는 캐시솔루션으로 가장 많이 사용되고있는 Redis 와 Memcached 를 비교해보도록 하자.

 

2.1 생산성의 차이 : Collection

 Redis 를 소개하는 대표적인 수식어는 'Collection 을 제공하는' 이다.
다른 솔루션과의 가장 큰 차별점인 자료구조를 지원한다는 것이 어떤 의미가 있는지 살펴보자.

 

 Redis를 통해서, 하나의 서버내에서만 공유했던 자료구조들에 대해, 자료구조를 지원하는 원격저장소로써 여러 서버에서 데이터를 효율적으로 공유하는 것이 가능하다.  이는 개발의 편의성과 개발의 난이도 측면에서, 많은 문제들을 해결하여 개발시간을 단축시키기 때문에 핵심 비즈니스로직에 집중할 수 있는 것을 의미한다! (강대명님의 우아한 Redis)

 

개발의 난이도 측면 예를 살펴보자.

 

 유저의 친구리스트를 Key-value 형태로 관리하려고 한다. (현재 A라는 친구존재)
이때 친구리스트에 B를 추가하는 작업과 C를 추가하는 작업이 독립적인 발생했다.

다음과 같은 경우의 수가 가능
1. B 작업의 write가 끝나고 -> C 작업이 진행 : 친구리스트에는 정상적으로 A,B,C 가 있을 것이다.
2.B 작업의 write가 끝나기 전 -> C 작업의 write : A,B 의 상태가 A,C 로 덮어쓰여지게됨 (혹은 순서가 바뀜)

Redis의 자료구조는 Single Thread 특성상 기본적으로 Atomic 하기 때문에 이러한 경우를 피할 수 있다!

 

이외에도 Strings, Hash 를 통해 토큰저장소로 사용되기도하고, 랭킹시스템을 구현하려고할 때, Sorted-Set 을 사용한다면, 손쉽게 최적화가 잘 되어있는 랭킹시스템을 구현할 수 있다.   

Best-practices 에서 다양한 형태로 사용되는 것을 참고하자.   

 

2.2 목적의 차이 : Persistent

 앞서 인메모리 데이터베이스에 대해 설명할 때 휘발성인 메모리특성상 데이터를 유지하기 힘들다고 설명했다.
하지만 Memcached와 다르게 Redis에서는 Persistent 기능을 제공한다!

 

 

 Redis 의 또 다른 특징 중 하나는 메모리의 상태를 디스크에 저장하여 값을 보존한다는 것이다.

 

메모리 상태의 스냅샷을 남기는 RDB 기능, 명령어를 기록해두는 AOF 기능을 통해 가능하다. 이 때문에 Redis를 Key-value 스토어로도 사용한다. 하지만 이것 때문에 메모리를 두 배로 사용하는 문제가 발생하여 운영중에 장애를 일으키는 가장 큰 원인이기도하다!

 

그럼에도 불구하고, 다른 RDBMS가 제공하는 기능과 유사한 복제기능과 함께 동작하는 방식을 이해하고 설계한다면, 장애가 발생하여 메모리의 데이터가 사라지더라도 복구할 수 있다.(잘 사용하는 방법)

 

2.3 Redis vs Memcached 결론

 이외에도 Memcached에 비하여 Redis는 다양한 데이터 삭제 정책(eviction), 한 개의 키에 저장할 수 있는 크기 등에 이점이 있다.

반면, Memcached에 비해 응답속도가 균일하지 못하다는 단점이있는데, 이는 극단적일 때 발생하는 치명적인 문제가 아니라고 소개하고있다.(Redis 운영 관리)

 

 즉, 메모리 파편화가 극단적으로 발생하는 상황이 아니라면, 생산성이 좋고 다양한 기능을 가지고 있는 Redis가 거의 모든 경우에서 유리하다.  

 

마무리


 레디스는 수정해서 사용이 가능한 BSD 라이센스 따르는(모듈제외) 오픈소스이다. 또한 전세계에서 salvatore sanfilippo 만이 커밋 할 수 있는 솔루션이다. 그의 깃헙 레포지토리에서는, Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps. 라고 설명하고있다.

 

 하지만, 사용하기 쉬우면서 성능도 좋은 똑똑한 Redis 이지만, 어떻게 사용할지 정확히 모르고 서비스에 도입한다면 Redis 의 진가를 발휘하지 못하고, 예기치 못한 장애와 마주할 것 같다.. 

 

 단순히 신기술을 '나도 써봤다'가 아니라, 공부하는 입장에서 다음과 같은 것들을 앞으로 깊게 다뤄보려고한다!

More Depth

  • Redis Transactions
  • Redis 운영 및 관리 - Single Thread, Replication, Redis HA, Sentinal
  • Redis Persistent - RDB, AOF
  • eviction
  • Redis Pub/Sub
  • Redis Stream
  • 확률적 자료구조
  • Redis Modules

 

 

참고