본문 바로가기
프로그래밍/redis

[Redis] Hashes을 이용하여 매핑 만들기 ( Strings VS Hashes )

by 사바라다 2020. 12. 31.

안녕하세요. 우리는 저번시간에 [Redis] Redis 자료구조 알아보기 포스팅을 통해 Redis가 가지고 있는 유용한 자료구조와 그 사용법 및 활용되는 곳에 대해서 간단히 알아보았습니다. 오늘은 이어서 제가 토이 프로젝트에 사용한 방법에 대해서 여러분들께 공유드리는 포스팅을 한번 진행해보려고 합니다.

오늘 여러분들께 보여드릴 것은 Hashes 자료구조를 이용하여 매칭되는 서로의 Key와 Value를 뒤집어서도 매핑할 수 있게하는 것입니다.

문제 상황

기존에 프로젝트에서 Tag를 저장하고 있는 테이블이 있었습니다. 이 테이블은 primary key인 id 값과 그 이름인 value 값을 가지고 있습니다. idvalue는 1 대 1 대응이되고 있었습니다. 사용하는 곳은 여느 태그들과 마찬가지입니다. 만약 포스팅이라고 한다면 해당 태그를 가지고 있는 테이블을 확인하고자 할 때 사용합니다.

그런데 여기에 외부에서 데이터를 가져오게 되었고 그 매핑을 Tag 테이블의 id가 아닌 value로 하게 되었습니다. 이렇게 했을 때 value 컬럼에는 index가 걸려있지 않기 때문에 데이터를 가져오는것에 있어서 성능적으로 전체 테이블을 검색하게 된다는 단점이 존재하게 됩니다.

저는 이러한 문제점을 해결하기 위해 Redis의 Hashes를 이용하여 태그의 이름을 통해 ID를 찾을 수 있게 역방향 매핑을 진행하였습니다.

Strings VS Hashes (hashes를 사용했을 때 좋은점)

위 문제 상황은 기존의 매핑을 뒤집은 리버스 매핑이기 때문에 Key는 태그의 이름이며 Value는 Id가 됩니다. 즉, 데이터의 형태는 아래와 같습니다.

  • key : 자료구조, value : 1
  • key : Redis, value : 2
  • key : AOP, value : 3
  • key : 자바, value : 4

이전 [Redis] Redis 자료구조 알아보기 포스팅을 통해 데이터를 다양한 자료구조를 통해서 저장할 수 있다는 사실을 알게 되었습니다. 그렇다면 위 데이터는 어떻게 저장하면 좋을까요? Set과 Sorted Set은 값을 매핑해주는 곳에서는 적절하지 않습니다. 따라서 Strings와 Hashes를 비교해보도록 하겠습니다.

Strings를 이용하여 구현한다면 set {메인 Key}:{서브 Key} value의 형태로 데이터를 저장할 것 입니다. 메인 Key를 ReserveMapping 이라고 가정하고 예제를 만들어 본다면 아래와 같을것입니다.

set ReverseMapping:자료구조 1
set ReverseMapping:Redis 2
set ReverseMapping:AOP 3
set ReverseMapping:자바 4
get ReverseMapping:자료구조

Hashes를 이용해 구현한다면 hset {메인 Key} {서브 Key} value의 형태로 저장할 것 입니다. 예제를 만들어본다면 아래와 같을 것입니다.

hset ReverseMapping 자료구조 1
hset ReverseMapping Redis 2
hset ReverseMapping AOP 3
hset ReverseMapping 자바 4
hget ReverseMapping 자료구조

먼저 Strings를 사용한다고 했을때의 이점은 TTL(Time To Live)을 각각 걸 수 있다는 점입니다. Redis에는 메인 Key에만 설정할 수 있는 명령어가 있습니다. 대표적인게 TTL 인데요. TTL 이란 Key가 언제까지 살아 있을 것인가 하는 것입니다. 영원히 살아있을 수 도 있겠지만 일정 기간 저장하고 싶을 때가 있습니다. 이때 TTL을 사용할 수 있습니다.

Hashes 자료구조의 장점은 적은 량의 데이터를 저장할 때는 사용하는 메모리를 최대한 아낄 수 있다는 점과 Key에 subKey의 이름을 넣지 않음으로써 무분별 하게 Key를 사용하지 않아도 된다는 것에 있습니다.

무분별 하게 Key를 사용하지 않을 수 있다는 것에 대해서 설명하겠습니다. Keys는 대략 42억개 정도의 데이터를 넣을 수 있습니다. Strings로 각각 Key를 만들게 되면 데이터의 갯 수만큼 Key를 만들게 됩니다. Hashes를 사용하여 그룹핑한 데이터는 묶어 둔다면 Key는 1개만 사용하면 만족할 수 있게 되는것입니다.

Hashes를 잘 사용하면 Strings를 사용하는 것 보다 메모리를 아낄 수 있습니다. 기본적으로 redis는 Hash table을 이용하여 Key - value 쌍을 관리합니다. 하지만 hashes, sets 와 같은 자료구조들은 데이터의 량이 일정크기 이하라고 한다면 ziplist 자료구조를 통해 관리하게됩니다. 이러한 ziplist는 선형적인 자료구조로써 hashtable에 비하여 적은 메모리를 사용합니다. 인스타그램의 포스팅을 참고해봤을 때 약 70% 가량의 메모리 이득이 있었다는 것을 확인할 수 있었습니다.

ziplist로 사용할 크기는 아래와 같이 redis 설정에서 변경할 수 있습니다. 주의하실 점은 ziplist는 선형적인 자료구조이기때문에 O(N)의 시간복잡도를 가집니다. 때문에 적절한 크기선정이 필요합니다.

hash-max-ziplist-entries 512 # 필드 수가 512개 이하면 ziplist 이상이면 hashtable 저장
hash-max-ziplist-value 64 # value의 크기가 64바이트까지는 ziplist 저장

마무리

저는 위 내용을 조사한 후 Hashes 자료구조를 사용하기로 마음먹었습니다.

오늘은 이렇게 제가 Redis의 어떤 자료구조를 사용할 지에 대해서 고민했던 내용을 공유드리는 자리를 가져보았습니다. 저도 조사하면서 되게 많은 공부가 되었기에 여러분들께도 도움이됬으면 하는 바램입니다.

감사합니다.

참조

instagram-engineering_storing-hundreds-of-millions-of-simple-key-value-pairs-in-redis-1091ae80f74c

redis_data-types

redis_memory-optimization

redislabs_9-2-sharded-structures/9-2-1-hashes

redisgate_ds_ziplist_hashes

댓글