Redis - Hash


이 포스트는 Redis 의 데이터 타입 중 하나인 Hash 타입에 대해 알아본다.


1. 데이터 타입

Redis 에서 데이터 표현 기본 타입은 하나의 Key 와 하나 이상의 Field/Element 값으로 구성하는 것이다.

  • Key
    • ASCII value 저장 가능
  • Value
    • 기본적으로 String 데이터 저장
    • Container 타입의 데이터 저장 가능

Container 타입
Hash, List, Set, Sorted Set 이 포함됨


2. Hash

  • 하나의 key 에 여러 개의 fields 와 value 로 구성된 데이터 저장
  • RDBMS 에서 PK 와 하나 이상의 컬럼으로 구성된 테이블 구조와 매우 흡사한 데이터 유형
  • 하나의 Key 는 Object 명과 하나 이상의 Field 값을 : 으로 결합하여 표현 가능
    예) order:20220719:01
  • 문자 저장 시엔 "" 가 사용, 숫자 저장 시엔 "" 없이 사용
  • Field 개수 제한 없음
$ pwd
/usr/local/opt/redis/bin

$ brew services start redis
==> Successfully started `redis` (label: homebrew.mxcl.redis)

$ redis-cli
127.0.0.1:6379>

2.1. HSET, HGET

127.0.0.1:6379> help HSET

  HSET key field value [field value ...]
  summary: Set the string value of a hash field
  since: 2.0.0
  group: hash

127.0.0.1:6379> help HGET

  HGET key field
  summary: Get the value of a hash field
  since: 2.0.0
  group: hash
  

HSET 으로 하나 이상의 field 값 설정이 가능하다. (=HMSET 과 동일)

127.0.0.1:6379> HSET order:20220719 username "assu" locate "seoul" userage 20
(integer) 3
127.0.0.1:6379> HGET order:20220719 username
"assu"
127.0.0.1:6379> HGET order:20220719 userage
"20"
127.0.0.1:6379> HGET order:20220719 userage1
(nil)

전체 필드와 그 값들 조회 시엔 HGETALL 을 사용한다.


2.2. HGETALL

key 에 매핑되는 모든 field 와 value 를 조회한다.

127.0.0.1:6379> help HGETALL

  HGETALL key
  summary: Get all the fields and values in a hash
  since: 2.0.0
  group: hash
127.0.0.1:6379> HGETALL order:20220719
1) "username"
2) "assu"
3) "locate"
4) "seoul"
5) "userage"
6) "20"

위와 같이 field, value 가 모두 나와 구분이 어려울 땐 HKEYS, HVALS 명령어로 확인할 수 있다.


2.3. HKEYS, HVALS

127.0.0.1:6379> help HKEYS

  HKEYS key
  summary: Get all the fields in a hash
  since: 2.0.0
  group: hash

127.0.0.1:6379> help HVALS

  HVALS key
  summary: Get all the values in a hash
  since: 2.0.0
  group: hash

HKEYS 는 모든 field 리스트를 조회한다.

127.0.0.1:6379> HKEYS order:20220719
1) "username"
2) "locate"
3) "userage"
127.0.0.1:6379> HVALS order:20220719
1) "assu"
2) "seoul"
3) "20"

2.4. HMSET, HMGET

Redis 4.0.0 부터는 HMSET 이 deprecated 된다고 하니 참고.

As of Redis version 4.0.0, this command is regarded as deprecated.
It can be replaced by HSET with multiple field-value pairs when migrating or writing new code.
(https://redis.io/commands/HMSET/)


127.0.0.1:6379> help HMGET

  HMGET key field [field ...]
  summary: Get the values of all the given hash fields
  since: 2.0.0
  group: hash
127.0.0.1:6379> HSET order:20220719 username "assu" locate "seoul" userage 20
(integer) 3
127.0.0.1:6379> HGET order:20220719 username
"assu"

127.0.0.1:6379> HMGET order:20220719 username userage
1) "assu"
2) "20"

2.5. HEXISTS

특정 필드가 존재하는지 확인하는 명령어이다.
필드가 존재하면 1, 없으면 0을 리턴한다.

127.0.0.1:6379> help HEXISTS

  HEXISTS key field
  summary: Determine if a hash field exists
  since: 2.0.0
  group: hash
127.0.0.1:6379> HSET order:20220719 username "assu" locate "seoul" userage 20
(integer) 3
127.0.0.1:6379> HEXISTS order:20220719 userage
(integer) 1
127.0.0.1:6379> HEXISTS order:20220719 userage1
(integer) 0

2.6. HDEL

기존에 존재하는 field 를 삭제하는 명령어이다.

127.0.0.1:6379> help HDEL

  HDEL key field [field ...]
  summary: Delete one or more hash fields
  since: 2.0.0
  group: hash
127.0.0.1:6379> HGETALL order:20220719
1) "username"
2) "assu"
3) "locate"
4) "seoul"
5) "userage"
6) "20"
127.0.0.1:6379> HKEYS order:20220719
1) "username"
2) "locate"
3) "userage"
127.0.0.1:6379> HDEL order:20220719 username userage
(integer) 2
127.0.0.1:6379> HGETALL order:20220719
1) "locate"
2) "seoul"
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
127.0.0.1:6379> HEXISTS order:20220719 userage
(integer) 0

2.7. HLEN

해당 key 에 정의된 field 의 수를 조회한다.

127.0.0.1:6379> help HLEN

  HLEN key
  summary: Get the number of fields in a hash
  since: 2.0.0
  group: hash
127.0.0.1:6379> HLEN order:20220719
(integer) 1
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
127.0.0.1:6379> HSET order:20220719 username assu
(integer) 1
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
2) "username"
127.0.0.1:6379> HLEN order:20220719
(integer) 2

2.8. HSTRLEN

field 에 매핑된 value 의 길이를 조회한다.

127.0.0.1:6379> help HSTRLEN

  HSTRLEN key field
  summary: Get the length of the value of a hash field
  since: 3.2.0
  group: hash
127.0.0.1:6379> HSTRLEN order:20220719 username
(integer) 4
127.0.0.1:6379> HGET order:20220719 username
"assu"

2.9. HRANDFIELD

해당 키에서 랜덤하게 하나 혹은 여러 개의 field 를 조회한다.

127.0.0.1:6379> help HRANDFIELD

  HRANDFIELD key [count [WITHVALUES]]
  summary: Get one or multiple random fields from a hash
  since: 6.2.0
  group: hash
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
2) "username"
3) "userage"
127.0.0.1:6379> HRANDFIELD order:20220719
"locate"
127.0.0.1:6379> HRANDFIELD order:20220719
"userage"
127.0.0.1:6379> HRANDFIELD order:20220719 2
1) "username"
2) "userage"
127.0.0.1:6379> HRANDFIELD order:20220719 2
1) "username"
2) "locate"

2.10. HSETNX

해당 field 가 존재하지 않을 때만 value 를 설정한다.

127.0.0.1:6379> help HSETNX

  HSETNX key field value
  summary: Set the value of a hash field, only if the field does not exist
  since: 2.0.0
  group: hash
127.0.0.1:6379> HGETALL order:20220719
1) "locate"
2) "seoul"
3) "username"
4) "assu"
5) "userage"
6) "20"
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
2) "username"
3) "userage"
127.0.0.1:6379> HSETNX order:20220719 talls 163
(integer) 1
127.0.0.1:6379> HSETNX order:20220719 talls 163
(integer) 0
127.0.0.1:6379> HGETALL order:20220719
1) "locate"
2) "seoul"
3) "username"
4) "assu"
5) "userage"
6) "20"
7) "talls"
8) "163"
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
2) "username"
3) "userage"
4) "talls"

2.11. HINCRBY, HINCRBYFLOAT

HINCRBY 는 해당 field 의 value 에 셋팅한 숫자만큼 증감한다.

127.0.0.1:6379> help HINCRBY

  HINCRBY key field increment
  summary: Increment the integer value of a hash field by the given number
  since: 2.0.0
  group: hash
127.0.0.1:6379> HGET order:20220719 userage
"20"
127.0.0.1:6379> HINCRBY order:20220719 userage 3
(integer) 23
127.0.0.1:6379> HGET order:20220719 userage
"23"
127.0.0.1:6379> HINCRBY order:20220719 userage -3
(integer) 20
127.0.0.1:6379> HGET order:20220719 userage
"20"
127.0.0.1:6379> HINCRBY order:20220719 username -3
(error) ERR hash value is not an integer

HINCRBYFLOATHINCRBY 와 같은 동작을 하지만 소숫점 기반으로 연산을 한다.

127.0.0.1:6379> help HINCRBYFLOAT

  HINCRBYFLOAT key field increment
  summary: Increment the float value of a hash field by the given amount
  since: 2.6.0
  group: hash
127.0.0.1:6379> HGET order:20220719 userage
"20"
127.0.0.1:6379> HINCRBYFLOAT order:20220719 userage 3
"23"
127.0.0.1:6379> HGET order:20220719 userage
"23"
127.0.0.1:6379> HINCRBYFLOAT order:20220719 userage 3.8
"26.8"
127.0.0.1:6379> HGET order:20220719 userage
"26.8"

2.12. HSCAN

성능을 위해 keys 대신 HSCAN 사용을 권장한다.
Redis 는 싱글 스레드로 동작하기 때문에 어떤 명령어를 수행하면 (=keys 를 쓰는 순간) Redis 는 이 명령을 처리하기 위해 멈춰버린다.
특히, 트래픽이 많은 서버는 keys 때문에 장애를 일으키기도 한다.

scankeys 처럼 한번에 모든 key 를 읽어보는 것이 아니라 count 값을 정하여 그 count 값 만큼 여러 번 Redis 의 key 를 조회하는 것이다.

count 를 작게 잡으면 count 만큼 key 를 조회하는 시간이 적게 걸리고, 대신 모든 데이터를 조회하는 시간은 오래 걸린다.
하지만 그 사이사이 시간에 다른 요청들을 Redis 에서 처리가 가능하다.

count 를 크게 잡으면 count 개수만큼 key 를 조회하는 시간이 오래 걸리고, 대신 모든 데이터를 조회하는 시간은 적게 걸린다.
하지만 그 사이사이 다른 요청을 받는 횟수가 줄어들어 Redis 가 다른 요청을 처리하는데 병목 현상이 생길 수 있다.

keys 의 단점을 보완하면서 성능도 좋은 scan 을 사용하는 것을 권장한다.

cursor 값을 0(default 10) 으로 지정한 SCAN/SSCAN/ZSCAN/HSCAN 명령으로 순회가 시작되고,
이어지는 순회에 사용할 cursor 값과 지정한 패턴(pattern)과 일치하는 키를 최대 지정한 갯수(count)만큼 반환한다.
반환된 cursor 값이 0 이면 순회가 종료되는데 이 과정을 전체 순회(full iteration)이라고 한다.

count 설정값에 따른 퍼포먼스는 Redis scan 명령어 퍼포먼스 에 어떤 분이 잘 정리해주셨습니다.

127.0.0.1:6379> help HSCAN

  HSCAN key cursor [MATCH pattern] [COUNT count]
  summary: Incrementally iterate hash fields and associated values
  since: 2.8.0
  group: hash
127.0.0.1:6379> HKEYS order:20220719
1) "locate"
2) "username"
3) "userage"
4) "talls"
127.0.0.1:6379> HSCAN order:20220719 0 match user* count 1
1) "0"
2) 1) "username"
   2) "assu"
   3) "userage"
   4) "26.8"

참고 사이트 & 함께 보면 좋은 사이트

본 포스트는 주종면 저자의 빅데이터 저장 및 분석을 위한 NoSQL & Redis를 기반으로 스터디하며 정리한 내용들입니다.






© 2020.08. by assu10

Powered by assu10