Redis와 캐시
서버개발

Redis와 캐시

Redis란

Remote Dictionary Server의 준말로

Remote에 위치하고 프로세스로 존재하는 인 메모리 기반의 NoSQL DB로 Key-Value 구조인 데이터 관리 시스템이다.

비 관계형 데이터를 저장하기에 적합하고 쿼리 연산을 지원하지 않지만, 관계형 데이터베이스보다 빠른 읽기와 쓰기에 용이하다.

문자열, 리스트, 해시, 집합, 정렬된 집합 등의 데이터 구조를 지원하며 대규모 분산 시스템에서 많이 사용된다.

데이터베이스의 캐시, 메시징 시스템, 세션 저장소, 분산 락 관리, 게임 서버 등 여러 분야에서 사용된다.

 

자주 사용되는 곳

- 인증 토큰 등을 저장

- Ranking 보드로 사용

- 유저 API Limit

- Job Queue

 

 

 

 

캐시

한 번 조회된 데이터를 미리 특정 공간에 저장해놓고, 똑같은 요청이 발생하게 되면 다시 데이터를 DB에서 조회하지 않고 저장해놓은 데이터를 제공해서 빠르게 접근하도록 하는 것

 

일반적으로 캐시는 메모리(RAM)을 사용하기 때문에 데이터베이스보다 빠른 데이터 응답을 할 수 있어 사용자에게 빠르게 서비스를 제공할 수 있다.

 

하지만 RAM의 용량은 크지 않기 때문에 데이터를 모두 캐시에 저장해버리면 용량 부족이 일어날 수 있고, 분산 서버 환경에서 공유하기 쉽지 않기 때문에 인 메모리 DB를 사용한다.

 

 

 

 

Redis가 RAM을 캐시로 사용하는 것과의 차이점

Redis는 영구적인 데이터 저장이 가능하다.

 

RAM에 저장된 캐시는 서버가 다운되면 사라지지만, Redis에 저장된 데이터는 보존할 수 있다.

 

Redis는 클라우드 서비스에서도 활용이 가능하다.

클라우드 환경에서는 서버의 RAM을 확장하는 것(Scale-up)이 쉽지 않기 때문에 Redis를 활용해서 필요한 만큼 메모리 용량을 조절할 수 있다.

 

Redis는 여러 서버 간 데이터 공유가 가능하다. 데이터 분산을 지원하기 때문에 대규모 분산 시스템에서 활용에 적합하다.

 

 

 

 

Redis가 RAM과 유사한 속도를 내는 방법

인 메모리 데이터베이스이기 때문에 데이터의 읽기/쓰기가 메모리 상에서 이루어지므로 매우 빠른 속도를 보장한다.

입출력 작업을 비동기적으로 처리하여 대기하는 동안 다른 작업을 수행할 수 있어 전체적인 처리 속도를 향상시킨다.

단일 쓰레드 아키텍처를 사용하여 다중 쓰레드에서 발생할 수 있는 락 등의 오버헤드가 발생하지 않는다.

내부적으로 사용되는 데이터 구조들의 최적화를 통해 메모리 할당을 최소화하고, 최적화된 연산을 사용한다.

데이터 만료 시간을 지정하여 주기적으로 만료된 데이터를 삭제하여 성능을 향상 시킨다.

 

 

 

 

Redis가 분산 서버 환경에서 사용되는 이유

Redis Cluster(Replication + 샤딩) 지원

Replication을 통해 데이터의 가용성을 높이며 복제된 노드에서 읽을 수 있다.

데이터를 여러 노드에 분산해서 저장하는 샤딩 기능을 지원하여 데이터를 효율적으로 처리하고, 커진 데이터베이스에서도 높은 성능을 기대할 수 있다.

 

분산 서버 환경에서 데이터 불일치를 막는 방법

Replication을 통해 하나의 노드에서 변경된 데이터가 다른 노드에도 동기화되므로 분산 환경에서 불일치가 발생하는 것을 막을 수 있다. 데이터 일관성 모델을 사용하여 여러 노드에서 데이터를 어떻게 동기화할 것인지 규칙을 정할 수 있다.

ex) Strong consistency, Eventual consistency, Linearizability

Versioning

데이터 변경 시점을 추적할 수 있다. 노드 간의 데이터의 변경 내역을 동기화하고 충돌을 방지한다.(이중 쓰기 등) CAS(Compare And Swap) 기능을 통해 쉽게 버전 관리를 할 수 있다.

 

분산 트랜잭션

여러 노드에서 동시에 발생하는 데이터 변경 작업을 Atomic하게 처리할 수 있다. 여러 노드에서 동시에 발생하는 작업을 하나의 트랜잭션으로 처리하여 데이터 일관성을 유지한다.(일괄 롤백)

 

Quorum

분산 시스템에서 Quorum을 사용하여 데이터 일관성을 유지한다. 데이터를 변경할 시 최소한의 노드 수가 동의하여야 변경할 수 있다.

 

 

 

 

RDBMS의 캐시로 사용될 때 일관성 유지

TTL을 설정하여 데이터가 일정 시간이 지나면 만료되도록 설정한다. 이를 통해 데이터가 만료되면 다시 데이터를 읽어와 캐시를 갱신하게 된다. 일정 시간 동안 데이터의 쓰기가 일어나지 않는 데이터에 한하여 좋은 성능을 기대할 수 있다.(한 시간마다 갱신되는 실시간 검색어 순위, 광고 등)

 

캐시 무효화(Invalidation)을 통해 RDBMS에서 변경이 일어나면 해당 테이블의 캐시를 무효화시킨다.

이를 위해 RDBMS에서 트리거를 사용하거나 캐시를 무효화하는 API를 작성하여야 한다.

 

적절한 캐시 정책 설정을 통해 RDBMS의 데이터 변경이 빈번하게 일어나는 경우 캐시를 사용할 때 어떤 데이터를 얼마나 오래 캐시할 것인지에 대한 정책을 설정하여야 한다.

설정을 잘 하게 되면 데이터를 캐시에서 읽어올 확률이 높아지기 때문에 RDBMS의 부하를 줄일 수 있다.

 

 

 

 

Redis와 싱글 스레드

Redis는 메인 스레드를 싱글 스레드로 사용하는데 장단점을 가지고 있다.

인 메모리 데이터베이스기 때문에 CPU-bound가 아닌 Memory-bound 작업이 많이 사용된다.

 

멀티 스레드로 인한 복잡한 동기화 문제를 해결할 필요가 없으며 메모리에서 데이터를 읽는 작업에서 병목 현상이 발생하지 않으므로 빠른 처리 성능을 보장한다.

적은 수의 스레드를 사용하기 때문에 메모리와 CPU 캐시를 더 효율적으로 사용할 수 있다.

싱글 스레드 구조이기 때문에 단일 Redis 인스턴스에서 처리할 수 있는 작업량은 한정되어 있다. CPU 코어 하나의 성능에 따라 Redis의 처리 성능이 결정되기 때문에 더욱 높은 처리량을 요구하는 경우 다른 인 메모리 데이터베이스나 분산 처리 기술을 고려해야 한다.

 

또한, 싱글 스레드 구조이기 때문에 Master-Slave 구조를 사용하는 것이 일반적이다.

Master-Slave 구조를 사용하면 여러 대의 Redis 인스턴스를 사용하여 작업량을 분산시켜 Master에서는 데이터 쓰기 작업을 처리하고 Slave에서는 읽기 작업을 처리한다. 읽기 작업을 처리하는 인스턴스를 추가함으로 써 전체적인 처리량을 증가시킬 수 있다.

 

Slave 인스턴스는 Master 인스턴스의 데이터를 복제(Replication)하므로, Master가 장애가 발생해도 데이터를 계속 읽을 수 있다. 마찬가지로 Slave에서 장애가 발생하더라도 당연히 Master에서 데이터를 읽을 수 있다.

Sentinel이라는 기능도 제공하여 Redis 인스턴스의 상태를 모니터링하고, 문제가 발생하면 자동으로 장애 대응을 수행한다.

 

그렇지만 싱글 스레드 아키텍처라고 오직 하나의 스레드만 사용하지는 않는다.

내부에서 주 스레드를 사용하여 모든 클라이언트의 요청을 처리하고, 몇 개의 부가 작업에 대해서는 백그라운드 스레드를 사용한다. RDB 백업과 AOF 재생성 등의 작업을 처리하며 Redis의 메인 기능을 수행하는 스레드가 아니기 때문에 Redis의 성능에 직접적인 영향을 미치지 않는다.

 

 

 

 

Redis 캐시 전략

캐싱 전략은 시스템 성능 향상을 기대할 수 있는 중요한 기술로, 어느 종류의 데이터를 캐시에 저장할지, 얼마동안 오래된 데이터를 캐시에서 제거할지에 대한 전략이 필요하다.

 

캐시 관련 용어

 

 

 

캐시 읽기 전략

Look Aside 패턴

데이터를 캐시에서 우선으로 확인하고 데이터가 없으면 DB에서 조회한다. 반복적인 읽기가 많은 호출에 적합하며 단건 호출 빈도가 높은 서비스가 아닌, 동일 쿼리를 수행하는 서비스에 적합한 아키텍처이다.

 

Read Through 패턴

캐시에서만 데이터를 읽어오는 전략으로, 데이터 동기화를 라이브러리 또는 캐시 제공자에게 위임하여 데이터를 조회하는데 있어 전체적으로 속도가 느리지만 캐시와 DB 간의 데이터 동기화가 항상 이루어져 데이터 정합성 문제를 해결할 수 있다. 하지만 캐시에 문제가 발생한 경우 서비스 전체 중단에 빠질 수 있어 Cluster를 구성하여야 한다.

 

 

 

 

캐시 쓰기 전략

Write Back 패턴

일반적인 캐시 사용 패턴보다 쓰기 작업이 많아 insert 쿼리를 한꺼번에 처리하기 위해 사용된다.

여러 유저가 동시에 제출 버튼을 누르게 되면 DB에 쓰기 요청이 몰리게 되면서 DB 서버에 많은 부하가 생긴다. 그래서 이 패턴을 사용하면 캐시 메모리에 데이터를 저장해 놓고, 이후 DB 디스크에 업데이트 해주면 안전하게 쓰기 작업을 이행할 수 있다.

(insert를 1개씩 여러 번하는 것보다 여러 개를 한 번에 삽입하는 것이 훨씬 빠르기 때문)

그러나 DB에 저장하기 전에 캐시 서버가 죽으면 데이터가 유실되기 때문에 다시 재생 가능하거나 무거운 데이터가 write back 방식을 사용한다.

 

Write Through 패턴

데이터베이스와 캐시에 동시에 데이터를 저장하는 전략으로 데이터를 먼저 캐시에 저장한 다음 바로 DB에 저장하여 DB 동기화 작업을 캐시에게 위임한다. DB와 캐시가 항상 동기화되어 있어 캐시의 데이터가 항상 최신 상태를 유지하기 때문에 일관성을 유지할 수 있어 데이터가 유실되지 않아야 하는 환경에서 사용하지만 성능이 감소된다.

 

Write Around 패턴

모든 데이터를 DB에 저장하고 캐시를 갱신하지 않아 Write Through 패턴보다 훨씬 빠르며 캐시 미스가 발생하는 경우에만 DB와 캐시에도 데이터를 저장한다. 그렇기 때문에 데이터베이스가 저장된 데이터가 불일치가 발생할 수 있으며 데이터가 수정, 삭제 될 때마다 캐시 또한 삭제, 변경해야하며, 캐시의 만료시간을 짧게 조정해야 한다.

읽기 패턴과 결합해서 많이 사용되는 패턴이다.

 

 

 

 

 

캐시 공유

캐시는 여러 인스턴스에서 공유하도록 설계되어 각 인스턴스가 읽고 수정할 수 있다. 그렇기 때문에 데이터를 수정하게 되는 경우 데이터 정합성 문제가 발생하지 않도록 다른 인스턴스가 변경을 덮어쓰지 않도록 해야 한다.

 

캐시 데이터를 변경하기 직전에 데이터가 검색된 이후 변경되지 않았는지 확인해야 한다. 변경되지 않았다면 즉시 업데이트하고 변경되었다면 업데이트 여부를 어플리케이션 레벨에서 결정할 수 있도록 수정해야 한다.

 

다른 방법으로는, 캐시 데이터를 업데이트 하기 전에 Lock을 잡아 처리한다. 이로 인해 성능 이슈가 발생할 수 있기 때문에 데이터 사이즈가 작아 빠르게 업데이트가 가능하고 빈번하게 업데이트가 일어나는 경우 용이하다.

 

 

 

 

 

참고

 

[REDIS] 📚 레디스 소개 & 사용처 (캐시 / 세션) - 한눈에 쏙 정리

Redis (Remote Dictionary Server) Redis는 Remote(원격)에 위치하고 프로세스로 존재하는 In-Memory 기반의 Dictionary(key-value) 구조 데이터 관리 Server 시스템이다. 여기서 key-value 구조 데이터란, mysql 같은 관계형

inpa.tistory.com