비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
Redis란?
Redis의 의미를 인터넷에 검색해보면 아래와 같이 나온다.
레디스(Redis)는 Remote Dictionary Server의 약자로서, “키-값” 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터베이스 관리 시스템(DBMS)이다.
너무 어렵게 적혀져있다. First Word 법칙에 따라 쉽게 바꿔서 이해해보자.
Redis는 데이터 처리 속도가 엄청 빠른 NoSQL 데이터베이스이다. 이렇게 기억하고 있어도 충분하다. NoSQL 데이터베이스를 풀어서 얘기하자면 Key-Value의 형태로 저장하는 데이터베이스라고 생각하면 된다.
Redis의 장점
Redis는 다양한 장점을 가지고 있다. 여러 특징 중 딱 1가지만 확실하게 기억해라.
레디스(Redis)는 인메모리(in-memory)에 모든 데이터를 저장한다. 그래서 데이터의 처리 성능이 굉장히 빠르다.
MySQL과 같은 RDBMS의 데이터베이스는 대부분 디스크(Disk)에 데이터를 저장한다. 하지만 Redis는 메모리(RAM)에 데이터를 저장한다. 디스크(Disk)보다 메모리(RAM)에서의 데이터 처리속도가 월등하게 빠르다. 이 때문에 Redis의 데이터 처리 속도가 RDBMS에 비해 훨씬 빠르다
Redis의 사용 사례를 검색해보면 아주 다양하다. 검색했을 때 아래와 같은 사용 사례를 확인할 수 있다.
- 캐싱 (Caching)
- 세션 관리 (Session Management)
- 실시간 분석 및 통계 (Real-time Analystics)
- 메시지 큐 (Message Queue)
- 지리공간 인덱싱 (Geospatial Indexing)
- 속도 제한 (Rate Limiting)
- 실시간 채팅 및 메시징 (Real-time Chat And Messaging)
레디스를 조회 성능을 개선할 때는 이 7가지 명령어만 알아도 충분하다. 그러다 레디스를 쓰면서 추가적으로 필요한 기능이 있으면 그때그때 찾아서 사용하면 된다.
데이터(Key, Value) 저장하기
# set [key 이름] [value]
$ set jaeseong:name "jaeseong park" # 띄워쓰기 해서 저장하려면 쌍따옴표로 묶어주면 됨
$ set jaeseong:hobby soccer
데이터 조회하기 (Key로 Value 값 조회하기)
# get [key 이름]
$ get jaeseong:name
$ get jaeseong:hobby
$ get pjs:name # 없는 데이터를 조회할 경우 (nil)이라고 출력됨
저장된 모든 key 조회하기
$ keys *
데이터 삭제하기 (Key로 데이터 삭제하기)
# del [key 이름]
$ del jaeseong:hobby
$ get jaeseong:hobby # 삭제됐는 지 확인
데이터 저장 시 만료시간(TTL Time to leave) 정하기
레디스는 RDBMS와는 다르게 데이터 저장 시 만료시간을 설정할 수 있다. 즉, 영구적으로 데이터를 저장하지 않고 일정 시간이 되면 데이터가 삭제되도록 셋팅할 수 있다.
레디스의 특성상 메모리 공간이 한정 되어 있기 때문에 모든 데이터를 레디스에 저장할 수 없다. 따라서 만료시간(TTL)을 활용해 자주 사용하는 데이터만 레디스에 저장해놓고 쓰는 식으로 활용한다.
# set [key 이름] [value] ex [만료 시간(초)]
$ set jaeseong:pet dog ex 30
만료시간(TTL) 확인하기
# ttl [key 이름]
# 만료 시간이 몇 초 남았는 지 반환
# 키가 없는 경우 -2를 반환
# 키는 존재하지만 만료 시간이 설정돼 있지 않은 경우에는 -1을 반환
$ ttl jaeseong:pet
$ ttl jaeseong:name
$ ttl pjs:name
모든 데이터 삭제하기
$ flushall
Redis에서 Key 네이밍 컨벤션 익히기
💡 Redis의 Key 이름을 잘 짓는 건 굉장히 중요하다. 따라서 현업에서 자주 사용하는 Key 네이밍 컨벤션을 배워보자. (꼭 이렇게 적어야만 하는 건 아니니 필요에 따라 응용해서 사용해도 된다.)
현업에서 자주 활용하는 네이밍 컨벤션
회사마다 여러가지 컨벤션이 존재하겠지만 딱 한가지만 기억하자.
콜론(
:
)을 활용해 계층적으로 의미를 구분해서 사용
예시를 살펴보면 바로 이해가 될 것이다.
users:100:profile
: 사용자들(users) 중에서 PK가 100인 사용자(user)의 프로필(profile)products:123:details
: 상품들(products) 중에서 PK가 123인 상품(product)의 세부사항(details)
이런 식으로 컨벤션을 정했을 때의 장점이 있다.
- 가독성 : 데이터의 의미와 용도를 쉽게 파악할 수 있다.
- 일관성 : 컨벤션을 따름으로써 코드의 일관성이 높아지고 유지보수가 쉬워진다.
- 검색 및 필터링 용이성 : 패턴 매칭을 사용해 특정 유형의 Key를 쉽게 찾을 수 있다 .
- 확장성 : 서로 다른 Key와 이름이 겹쳐 충돌할 일이 적어진다.
캐시(Cache), 캐싱(Caching)이란?
캐시(Cache)란?
캐시(Cache)란, 원본 저장소보다 빠르게 가져올 수 있는 임시 데이터 저장소를 의미한다.
캐싱(Caching)이란?
캐싱(Caching)이란 캐시(Cache, 임시 데이터 저장소)에 접근해서 데이터를 빠르게 가져오는 방식을 의미한다.
현업에서는 아래와 같이 얘기하는 편이다.
“이 API는 응답 속도가 너무 느린데? 이 응답 데이터는 캐싱(Cahing) 해두고 쓰는 게 어때?’
이 말을 풀어서 설명하자면 ‘API 응답 결과를 원본 저장소보다 빠르게 가져올 수 있는 임시 데이터 저장소에 저장해두고, 빠르게 조회할 수 있게 만드는 게 어때?’라는 의미이다.
데이터를 캐싱할 때 사용하는 전략 (Cache Aside, Write Around)
Cache Aside (= Look Aside, Lazy Loading) 전략
데이터를 조회할 때 주로 사용하는 전략이 Cache Aside 전략이다. Look Aside 전략 또는 Lazy Loading 전략이라고 부른다. 이 전략은 어떤 식으로 작동하는 지 하나씩 알아보자.
처음으로 게시판 서비스를 배포했다고 가정하고 Cache Aside 작동 방식을 이해해보자.
- 처음 게시판 서비스를 배포했기 때문에 데이터베이스와 레디스에는 아무런 데이터도 저장이 안 되어 있다.
- 일부 사용자가 들어와 게시글 작성을 함으로써 데이터를 저장한다. 이 데이터는 데이터베이스에 저장된다. (레디스에는 저장되지 않는다.)
- 사용자가 데이터를 조회하려고 요청한다. 이 때, 데이터베이스로부터 바로 데이터 조회를 하기 전에 레디스에 있는 지 먼저 확인한다.
- 레디스에 데이터가 없는 걸 확인한 뒤에 데이터베이스로부터 데이터를 조회해서 응답한다.
- 데이터베이스로부터 조회한 데이터를 응답한 뒤에 레디스에도 데이터를 저장해둔다.
- 다시 한 번 사용자가 데이터를 조회하려고 요청한다.
- 레디스에 조회하고자 하는 데이터가 있는 지 확인했더니, 데이터가 존재해서 레디스로부터 데이터를 바로 가져와버린다.
데이터를 요청했을 때 캐시에 데이터가 있는 경우를 보고 Cache Hit이라고 한다. 데이터를 요청했을 때 캐시에 데이터가 없는 경우를 보고 Cache Miss라고 한다.
이게 Cache Aside 전략을 적용시킨 형태이다. 실제 예시에서 흐름을 봤으니 기억하기 좋게 다시 한 번 정리해보자. 이번에는 한 문장으로 요약해보자.
Cache Aside 전략은 캐시(Cache)에서 데이터를 확인하고, 없다면 DB를 통해 조회해오는 방식이다.
(전략 이름을 외우는 게 중요한 게 아니다. 과정을 기억하는 게 중요하다.)
Write Around 전략
Cache Aside 전략이 데이터를 어떻게 조회할 지에 대한 전략이었다면, Write Around 전략은 데이터를 어떻게 쓸 지(저장, 수정, 삭제)에 대한 전략이다. Write Around 전략은 Cache Aside 전략과 같이 자주 활용되는 전략이다. Write Around 전략이 어떤 방식인지 ‘저장’의 예시로 알아보자.
Cache Aside, Write Around 전략의 한계점 / 해결 방법
Cache Aside, Write Around 전략의 한계점
-
캐시된 데이터와 DB 데이터가 일치하지 않을 수 있다. Cache Asdie와 Write Around 전략을 같이 썼을 때의 한계점 중 하나는 캐시된 데이터와 DB 데이터가 일치하지 않을 수 있다는 점이다. 조금 어렵게 표현하자면 데이터의 일관성을 보장할 수 없다는 뜻이다. Write Around 전략에 따르면 데이터를 수정할 때 DB만 업데이트를 시키기 때문에 기존에 저장된 레디스의 데이터 값과 DB의 데이터 값은 다를 수 밖에 없다. 예를 들어, 분명 프로필 수정에서 내 이름을 ‘박재성’에서 ‘박선재’로 바꿨는데, 내 프로필 조회를 해봤더니 내 이름이 여전히 ‘박재성’이라고 표시된다는 뜻이다.
-
캐시에 저장할 수 있는 공간이 비교적 작다. DB는 디스크(Disk)에 저장해서 많은 양을 저장하기 용이하지만, 캐시는 메모리(RAM)에 저장하기 때문에 DB에 비해 많은 양의 데이터를 저장할 수가 없다.
이 한계를 어떻게 극복할까?
- 캐시된 데이터와 DB 데이터가 일치하지 않을 수 있다.
캐시와 DB의 데이터를 일치시키기 위해, 데이터를 수정할 때마다 동시에 업데이트 시키면 성능적으로 느려진다. 그렇다고 성능 향상을 위해 DB의 데이터만 업데이트 시키면 캐시와 DB의 데이터가 일치하지 않게 된다.
하지만 어쩔 수 없다. 어떤 선택을 하든 기회 비용(Trade Off)이 발생한다. 무언가를 얻으면 무언가를 포기해야 한다. 대부분의 개발 기술들이 장점이 있으면 단점이 있다. 따라서 데이터 조회 성능 개선 목적으로 레디스를 쓰는 경우에는 데이터의 일관성을 포기하고 성능 향상을 택한 것이다.
이러한 이유로 인해 캐시를 적용시키기에 적절한 데이터는 다음과 같다.
- 자주 조회되는 데이터
- 잘 변하지 않는 데이터
- 실시간으로 정확하게 일치하지 않아도 되는 데이터 하지만 장기간 데이터가 일치하지 않는 건 문제가 될 수 있다. 따라서 적절한 주기로 데이터를 동기화시켜주어야 한다. 이 때 활용하는 기능이 레디스의 TTL 기능(만료 시간 설정 기능)이다. 일정 시간이 지나면 데이터가 캐시에서 삭제된다. 그럼 특정 사용자가 조회를 하는 순간 Cache Miss가 발생한다. DB의 데이터를 새로 조회해와서 캐시에 데이터를 넣게 된다. 즉, 데이터가 새롭게 갱신되는 효과가 있는 것이다.
- 캐시에 저장할 수 있는 공간이 비교적 작다. 위에서 활용했던 TTL 기능(만료 시간 설정 기능) 을 활용하면 캐시의 공간을 효율적으로 쓸 수 있다. 왜냐면 자주 조회하지 않는 데이터는 만료 시간에 의해 데이터가 삭제되기 때문이다.
Cache Aside, Write Around 전략을 사용할 때 주로 TTL을 같이 활용한다.