Session storage로 적합한 데이터 베이스는 무엇일까? (Redis vs memcached)
지난시간에 포스팅했던 서버가 두 개 이상일 경우 발생하는 세션 불일치 문제 해결하기에서 별도의 세션 스토리지를 구성하여 세션의 정합성 문제를 해결하려고 할 때, 세션 스토리지로 적합한 데이터베이스는 무엇일까?
선택 기준 : 성능/속도
우리가 만든 웹 서비스를 이용할때 비인가 사용자와 인가된 사용자 모두 접근할 수 있는 요청도 존재하고, 인가된 사용자(로그인 세션이 존재하는 사용자)만이 접근할 수 있는 요청도 존재할 것이다.
이렇게 인가된 사용자만 접근할 수 있는 요청을 처리할때마다 매번 세션 저장소에서 해당 로그인 세션이 존재하는지 확인하는 작업을 진행해야 하기 때문에 성능에 악영향을 주지 않도록 빠르게 세션 정보를 찾아서 제공해야 한다.
In-memory DB vs Disk based DB
데이터베이스의 데이터가 어느 공간에 저장이 되는가에 따라서 In-memory DB와 Disk based DB로 분류된다. 전자는 데이터를 메모리에 저장하여 관리하고, 후자는 데이터를 디스크에 저장하여 관리한다.
Disk based DB
먼저 Disk based DB
의 접근 과정을 알아보자.
Disk based DB
라고 해서 조회한 정보를 디스크에서 직접 찾는것은 아니다.
디스크에 저장된 데이터를 메모리에 임시 저장소(버퍼) 공간을 마련하여 데이터를 페이지(블록) 단위로 읽어온다. 따라서 데이터를 조회할때 바로 디스크에서 찾는것이 아닌 버퍼에서 먼저 찾아보고, 해당 데이터가 버퍼에 존재하지 않을 경우 디스크에있는 페이지(블록)을 다시 읽어오는 방식이다.
이러한 방식을 사용하는 이유는 기본적으로 메모리 I/O 작업이 디스크I/O 작업에 비해 10,000배 이상 빠르기 때문이다.
하지만 이러한 방식에도 디스크에서 데이터를 찾아 페이지 단위로 버퍼로 전송하는 시간이 발생하기 때문에 여러 I/O 작업 처리에 있어서 병목 현상이 발생하게 된다.
이러한 이유로 세션이 존재하는지 확인하는 작업을 여러번 반복해야 하는 서비스에서 세션 스토리지로 Disk based DB
를 사용하는것은 성능적인 측면에서 올바른 선택이 아니라고 생각한다.
In-memory DB
In-memory DB
는 애초에 모든 데이터를 메모리에 저장하기 때문에 Disk I/O 작업이 발생할 일이 없다. 따라서 디스크 기반의 데이터베이스에서 발생하는 병목 현상을 피할 수 있다.
그렇다면 Disk based DB
보다 In-momery DB
가 무조건 더 좋을까?
-> 사용하는 환경과 상황에 따라서 다르다.
In-momery DB
는 주 저장소로 휘발성 메모리인 RAM을 사용하기 때문에 기본적으로 영속성을 보장하지 않는다. 예상치 못한 에러나 오류로 인해 프로세스가 종료된다면 데이터가 모두 유실될 수도 있다.
그렇다면, session을 저장하는 저장소로는 적합할까?
세션은 HTTP의 비연결 지향과 상태없음(stateless)과 같은 특성을 보완하기 위해 사용하는 것이다. 세션에는 주로 로그인한 사용자의 정보를 저장하는데, 이 정보는 영원히 저장되어야 하는 정보가 아니다. 사용자가 로그아웃을 하거나 개발자가 설정해놓은 세션의 timeout에 따라서 세션이 제거된다.
세션에 저장되는 데이터의 위와같은 특성 덕분에 데이터 유실로 인해 발생하는 피해가 다른 데이터에 비해 적다.
극단적인 예로 세션 저장소의 데이터가 유실된다면 사용자는 재 로그인만 진행하면 된다.
따라서 세션 스토리지로 In-memory DB
의 사용이 적절하다고 생각한다.
또한 몇 몇 In-memory DB
는 세션 스토리지 서버에 문제가 생겨서 데이터가 유실되는 것을 방지하기 위해 동일한 데이터를 또 다른 세션 스토리지에 복사하는 [마스터-슬레이브] 복제 방법을 사용하거나 'Consistent Hashing' 알고리즘을 사용하여 가용성을 보장하기도 한다.
In-memory DB 중 어떤 DB를 저장소로 사용해야 할까?
In-memory DB에는 다양한 데이터베이스들이 존재한다. 그 중에서도 세션 저장소로 가장 많이 사용하는Redis
와 Memcached
에 대해서 알아보자.
세션 스토리지를 사용할때 Redis
와 Memcached
자주 언급되는 이유는 두 개 모두 key-value 형태로 메모리에 데이터를 저장하는 방식을 사용하고 있기 때문이다.
저장 구조가 Key-Value 형태로 단순하기 MySQL과 같은 RDBMS처럼 복잡한 연산은 지원하지 않지만 세션의 데이터를 읽고 쓰는 작업과 같이 단순한 작업에 있어서는 빠른 처리가 가능하다.
두 개의 공통점으로는 In Memory 저장소 라는 점과 Key-value 의 저장 방식을 가지고 있다는 점이다.
차이점으로는 첫 번째로 Replication의 지원 여부이다.
Redis
는 서버에 장애가 발생했을시 Replication을 솔루션 자체에서 지원하기 때문에 Replication을 지원하지 않는 Memcached
보다 더 쉽게 서버의 데이터를 복구할 수 있다.
Replication이란?
두 개의 이상의 DBMS 시스템을Mater / Slave
로 나눠서 동일한 데이터를 저장하는 방식입니다.
반면에 Memcached가 사용하는 Consistent Hashing 이란 데이터를 노드의 수에 따라 균등하게 분배하여 저장하는 것이다. 즉, 장애가 발생한 서버의 데이터만 유실되고 나머지 서버들의 데이터는 그대로 유지한 채 운영이 가능하다. Sacle out 방식에서 서버를 늘릴수록 서버 한 대당 저장하는 데이터의 양이 줄어들기 때문에 피해를 줄일 수 있다.
두 번째로 응답 속도에서 차이를 보인다.
Redis
의 경우 대규모 트래픽으로 인해 많은 데이터가 한번에 업데이트 되면 Memcached
에 비해서 불안정한 속도를 보인다. 이것은 Redis
와 Memcached
의 메모리 할당 구조가 다르기 때문이다.
Redis
는 jemalloc이라는 알고리즘을 사용하기 때문에 매번 malloc과 free를 통해서 메모리 할당이 이루어진다. 반면에 Memcached
는 slab 할당자를 이용하여 내부적으로는 메모리를 재할당을 하지 않고 관리하는 형태를 취한다. 따라서 Redis
는 메모리 파편화가 발생하기 때문에 이러한 할당 비용으로 인해 응답 속도가 느려지는 것이다. (매우 드물게 발생하는 문제이다.)
세 번째로 Redis
는 Memcached
에 비해 다양한 자료구조를 지원한다.
String만 지원하는 Memchached
에 비해 Redis
는 String,Set,Sorted Set,List, Hash와 같은 다양한 자료구조를 지원한다. 이는 Redis
가 다른 인메모리 솔루션들과의 차이점 중 가장 강점을 갖는 부분이다.
마지막으로 Redis
는 싱글 스레드로 수행되고 Memcached
는 멀티 스레드로 수행된다.
싱글 스레드로 수행되는 Redis
는 atomic을 보장하고 , race condition(경쟁)을 회피할 수 있지만 long-time 명령 수행시 다른 명령어들을 처리할 수 없는 상태가 되기 때문에 매우 비효율 적으로 동작하게 된다. 따라서 long-time 명령의 수행들을 피해야 한다.
반면에 Memcached
는 멀티 스레드를 지원하기 때문에 scale-up을 통한 서버 확장에 용이하다.
또한 Memcached
가 멀티 스레드를 지원하긴 하지만 수행 시간적인 측면에서 Redis
와 큰 차이가 나지 않는다. 그 이유는 Memcached
의 경우 파싱 과정은 멀티 스레드 형태로 동작하지만 실제 데이터에 접근하는 연산 과정에서 Global cache lock으로 인해 싱글 스레드처럼 동작하기 때문이다.
추가적으로, 위에서 In-memory DB는 기본적으로 영속성을 보장하지 않는다고 설명했는데 `Redis`는 Snapshot과 AOF라는 방법을 통해 영속성을 보장한다. (참고자료 : https://redis.io/topics/persistence)
Redis
와 Memcached
의 차이점을 간략하게 알아보았다.
그렇다면 두 개의 세션 저장소 중 어느것을 선택해야할까?
구글에 Redis vs Memcached 라고 검색하면 aws에서 두 저장소를 비교한 글이 나온다.
두 저장소 중 어떤것이 더 우수하다는 내용은 없다. 다만 Redis의 장점을 조금 더 많이 설명하고 있을 뿐이다. 개발자의 판단에 따라서 요구 사항에 알맞는 솔루션을 선택하면 된다.
정리
Redis > Memcached
- 다양한 자료구조를 지원한다.
- MemCached는 메모리 관리 측면에서 LRU 알고리즘만 사용하지만 Redis는 6가지의 데이터 추출 정책이 존재한다. 따라서 더 종교한 메모리 관리가 가능하다.
- 데이터를 메모리 뿐만 아니라 디스크에도 저장할 수 있기 때문에 데이터 유실시 디스크에서 유실된 데이터를 복구할 수 있다.
- 솔루션 자체에 Repliaction을 지원하기 때문에 서버 장애 발생시 보다 간편하게 서버 복구가 가능하다.
Redis < Memcached
- 메모리 파편화가 발생하지 않기 때문에 트래픽이 갑자기 몰려도 안정적인 데이터를 리턴받을 수 있다.
- (그렇다고 Redis가 안정적인 데이터를 리턴받지 못한다는 것은 아니다.)
- 멀티 스레드를 지원한다.
- Redis는 기본적으로 Copy&Write 방식을 사용하기 때문에 실제 사용하는 메모리보다 훨씬더 많은 메모리를 사용하게 된다. 따라서 Memcached는 Redis에 비해 메모리를 더 적게 사용한다.
결론
Redis
를 다루는 서적에서 Memcached
와 비교하는 부분을 소개할때 아래와 같이 서술되어 있다.
"멤캐시드와 레디스를 같은 캐시 시스템으로서 동등한 위치에서 비교하게 된 것은 레디스가 멤캐시드와 동일한 기능을 제공하면서 영속성, 다양한 데이터 구조와 같은 부가적인 기능을 지원하기 때문이다. 또한 특정한 조건에서는 멤캐시드에 비해서 더 나은 성능을 보여주기도 한다. 이와 같은 이유로 멤캐시드를 대체하는 솔루션으로서 각광받고 있다." - 이것이 레디스다
여기서 말하는 특정한 조건이란 운영 서버에서 Replication을 통한 간편한 서버 복구 기능과 다양한 자료구조를 사용해야 하는 경우라고 생각한다.
글을 쓰다보니 Redis와 Memcached의 차이점을 비교한 글이 되어버린 것 같지만 레디스의 가장 큰 장점이라고 불리는 '다양한 자료구조 사용' 부분이 레디스를 캐시용이 아닌 세션 저장소로 사용할 때는 고려 대상이 아닌 것 같다.
그럼에도 불구하고 이번 프로젝트에서 Redis를 세션 저장소로 선택한 가장 큰 이유는 spring으로 개발할 때 관련 의존성을 빌드하면 레디스를 간편하게 사용할 수 있도록 지원해 준다는 장점 때문이다. 물론 해당 기술의 장점과 단점, 원리를 파악하지 못하고 사용하면 오히려 독이 될 수도 있지만, 원리를 잘 파악하고 사용한다면 개발의 생산성을 높여주는데 큰 도움이 될 수 있다고 생각한다.
'프로젝트 : shoe-auction' 카테고리의 다른 글
[Spring] Cache를 적용하여 응답속도 개선하기 (0) | 2021.03.06 |
---|---|
[Spring] 프로젝트에 Spring Rest Docs 적용하기 (0) | 2021.03.02 |
[Spring] 권한 설정을 통한 특정 리소스 접근 제한하기 (0) | 2021.02.17 |
[Spring] 커스텀 어노테이션으로 로그인 확인과 현재 로그인된 사용자 정보 불러오기 (0) | 2021.02.06 |
서버가 두 개 이상일 경우 발생하는 세션 불일치 문제 해결하기 (0) | 2021.01.27 |