관리 메뉴

Unfazedβ—οΈπŸŽ―

Redis ν‚€ (νƒ€μž…λ³„ 데이터 쑰회, KEYS, SCAN 비ꡐ) λ³Έλ¬Έ

DB/Redis

Redis ν‚€ (νƒ€μž…λ³„ 데이터 쑰회, KEYS, SCAN 비ꡐ)

9taetae9 2025. 7. 24. 23:39
728x90

이번 κΈ€μ—μ„œλŠ” Redis의 λ‹€μ–‘ν•œ 데이터 νƒ€μž…μ„ μ•Œμ•„λ³΄κ³ , 각 νƒ€μž…μ— λ§žλŠ” 값을 μ†μ‰½κ²Œ μ‘°νšŒν•˜λŠ” 방법을 μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

1.  νƒ€μž…(TYPE) ν™•μΈν•˜κΈ° 

값을 μ‘°νšŒν•˜κΈ° 전에 κ°€μž₯ λ¨Όμ € ν•  일은 ν•΄λ‹Ή ν‚€κ°€ μ–΄λ–€ 데이터 νƒ€μž…μœΌλ‘œ μ €μž₯λ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μ΄λ•Œ TYPE λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

# 'weather:active:regions'λΌλŠ” ν‚€μ˜ νƒ€μž…μ„ 확인
127.0.0.1:6379[1]> TYPE weather:active:regions
zset

TYPE λͺ…λ Ήμ–΄λŠ” λ‹€μŒκ³Ό 같은 λŒ€ν‘œμ μΈ νƒ€μž…μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

  • string: κ°€μž₯ 기본적인 λ¬Έμžμ—΄. κ°„λ‹¨ν•œ ν…μŠ€νŠΈλΆ€ν„° JSON λ°μ΄ν„°κΉŒμ§€ 담을 수 있음
  • hash: μ—¬λŸ¬ ν•„λ“œ(field)와 κ°’(value) 쌍으둜 이루어진 객체
  • list: 데이터가 μž…λ ₯된 μˆœμ„œλ₯Ό κΈ°μ–΅ν•˜λŠ” λͺ©λ‘
  • set: μˆœμ„œ 없이, μ€‘λ³΅λ˜μ§€ μ•ŠλŠ” κ°’λ“€μ˜ μ§‘ν•©
  • zset (Sorted Set): 점수(score)κ°€ 맀겨져 μ •λ ¬λœ μ§‘ν•©.

이제 각 νƒ€μž…μ΄ 무엇이고, μ–΄λ–»κ²Œ μ‘°νšŒν•˜λŠ”μ§€ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

2. νƒ€μž…λ³„ 데이터 μ‘°νšŒν•˜κΈ°

2.1) String

κ°€μž₯ 기본적이고 널리 μ“°μ΄λŠ” νƒ€μž…μž…λ‹ˆλ‹€.

  • μ–Έμ œ μ‚¬μš©ν• κΉŒ?: μ‚¬μš©μž μ„Έμ…˜ 정보, μΊμ‹œ 된 μ›ΉνŽ˜μ΄μ§€ HTML, κ°„λ‹¨ν•œ μΉ΄μš΄ν„° κ°’ 등을 μ €μž₯ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.
  • 쑰회 λͺ…λ Ήμ–΄: GET
# "weather:forecast:..." 킀에 μ €μž₯된 κ°’ 쑰회
127.0.0.1:6379[1]> GET weather:forecast:2235:832:2000
"{\"temp\":25.3,\"icon\":\"sunny\",\"humidity\":40}"

2.2) Hash

ν•˜λ‚˜μ˜ ν‚€ μ•ˆμ— '이름: μ„œμšΈ', 'μœ„λ„: 37.56'처럼 μ—¬λŸ¬ 개의 ν•„λ“œ-κ°’ μŒμ„ μ €μž₯ν•˜λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€. ν•œ μ‚¬λžŒμ˜ λͺ…함 μ •λ³΄μ²˜λŸΌ κ΄€λ ¨ 데이터λ₯Ό 묢어두기에 μ’‹μŠ΅λ‹ˆλ‹€.

  • μ–Έμ œ μ‚¬μš©ν• κΉŒ?: μ‚¬μš©μžμ˜ ν”„λ‘œν•„ 정보(ID, 이름, 이메일 λ“±)처럼 ν•˜λ‚˜μ˜ κ°œλ…μ„ κ΅¬μ„±ν•˜λŠ” μ—¬λŸ¬ 속성을 μ €μž₯ν•  λ•Œ μ ν•©ν•©λ‹ˆλ‹€.
  • 쑰회 λͺ…λ Ήμ–΄: HGETALL (λͺ¨λ“  ν•„λ“œ/κ°’), HGET (νŠΉμ • ν•„λ“œ)
# λͺ¨λ“  정보λ₯Ό ν•œ λ²ˆμ— 쑰회
127.0.0.1:6379[1]> HGETALL weather:location:2235:832
1) "id"
2) "832"
3) "name"
4) "Seoul"
...

# 'name' ν•„λ“œλ§Œ 콕 μ§‘μ–΄ 쑰회
127.0.0.1:6379[1]> HGET weather:location:2235:832 name
"Seoul"

2.3) List

데이터가 λ“€μ–΄μ˜¨ μˆœμ„œλŒ€λ‘œ μ €μž₯λ˜λŠ” μžλ£Œκ΅¬μ‘°μž…λ‹ˆλ‹€. νƒ€μž„λΌμΈμ΄λ‚˜ λŒ€κΈ°μ—΄μ²˜λŸΌ μˆœμ„œκ°€ μ€‘μš”ν•  λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

  • μ–Έμ œ μ‚¬μš©ν• κΉŒ?: μ΅œμ‹  λ‰΄μŠ€ λͺ©λ‘, μ‚¬μš©μžμ˜ 졜근 ν™œλ™ 기둝, μ±„νŒ… λ©”μ‹œμ§€ 큐 등을 κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.
  • 쑰회 λͺ…λ Ήμ–΄: LRANGE (λ²”μœ„λ₯Ό μ§€μ •ν•˜μ—¬ 쑰회)
# 0λ²ˆμ§ΈλΆ€ν„° λ§ˆμ§€λ§‰(-1) λ°μ΄ν„°κΉŒμ§€ λͺ¨λ‘ 쑰회
127.0.0.1:6379[1]> LRANGE weather:active:regions 0 -1
1) "us-east"
2) "us-west"
3) "eu-central"

2.4) Set

List와 λΉ„μŠ·ν•˜μ§€λ§Œ μ€‘λ³΅λœ 값을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” κ³ μœ ν•œ κ°’λ“€μ˜ μ§‘ν•©μž…λ‹ˆλ‹€. μˆœμ„œλŠ” 보μž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

  • μ–Έμ œ μ‚¬μš©ν• κΉŒ?: νŠΉμ • κ²Œμ‹œλ¬Όμ— 'μ’‹μ•„μš”'λ₯Ό λˆ„λ₯Έ μ‚¬μš©μž λͺ©λ‘, νŠΉμ • νƒœκ·Έλ₯Ό κ°€μ§„ λͺ¨λ“  μƒν’ˆ ID λ“± μœ λ‹ˆν¬ν•œ 값듀을 관리할 λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
  • 쑰회 λͺ…λ Ήμ–΄: SMEMBERS (λͺ¨λ“  멀버 쑰회)
127.0.0.1:6379[1]> SMEMBERS weather:alert:types
1) "storm"
2) "flood"
3) "heatwave"

2.5) Sorted Set (ZSet)

Set처럼 μ€‘λ³΅λ˜μ§€ μ•ŠλŠ” 값을 μ €μž₯ν•˜μ§€λ§Œ, 각 κ°’λ§ˆλ‹€ 점수(score)λ₯Ό λΆ€μ—¬ν•˜μ—¬ 점수 κΈ°μ€€μœΌλ‘œ μ •λ ¬ν•  수 μžˆλŠ” νŠΉλ³„ν•œ νƒ€μž…μž…λ‹ˆλ‹€.

  • μ–Έμ œ μ‚¬μš©ν• κΉŒ?: κ²Œμž„ λž­ν‚Ή, μ‹€μ‹œκ°„ 인기 검색어 μˆœμœ„, μš°μ„ μˆœμœ„κ°€ μžˆλŠ” μž‘μ—… λͺ©λ‘ λ“± μˆœμœ„ λ§€κΈ°κΈ°κ°€ ν•„μš”ν•  λ•Œ 졜적의 μ„ νƒμž…λ‹ˆλ‹€.
  • 쑰회 λͺ…λ Ήμ–΄: ZRANGE (점수 κΈ°μ€€ μ˜€λ¦„μ°¨μˆœ), ZREVRANGE (λ‚΄λ¦Όμ°¨μˆœ)
# λž­ν‚Ή 0μœ„λΆ€ν„° λκΉŒμ§€ μ μˆ˜μ™€ ν•¨κ»˜ 쑰회 (μ˜€λ¦„μ°¨μˆœ)
127.0.0.1:6379[1]> ZRANGE weather:temperature:ranking 0 -1 WITHSCORES
1) "seoul"
2) "15.5"
3) "busan"
4) "18.2"

3.  μœ μš©ν•œ μΆ”κ°€ λͺ…λ Ήμ–΄

데이터λ₯Ό μ‘°νšŒν•˜λŠ” 것 외에도 ν‚€μ˜ μƒνƒœλ₯Ό ν™•μΈν•˜λŠ” μœ μš©ν•œ λͺ…령어듀이 μžˆμŠ΅λ‹ˆλ‹€.

  • ν‚€κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ 확인: EXISTS [key]
    • 1을 λ°˜ν™˜ν•˜λ©΄ 쑴재, 0이면 μ‘΄μž¬ν•˜μ§€ μ•ŠμŒ
  • ν‚€μ˜ 남은 수λͺ…(초) 확인: TTL [key]
    • 3600 처럼 남은 μ‹œκ°„μ΄ λ°˜ν™˜λ˜κ±°λ‚˜, -1 (영ꡬ), -2 (μ‘΄μž¬ν•˜μ§€ μ•ŠμŒ)κ°€ λ°˜ν™˜
  • ν‚€κ°€ μ‚¬μš©ν•˜λŠ” λ©”λͺ¨λ¦¬ μš©λŸ‰ 확인: MEMORY USAGE [key]
    • λ°”μ΄νŠΈ(byte) λ‹¨μœ„λ‘œ λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰ 제곡

4. 주의점

λ°μ΄ν„°λ² μ΄μŠ€μ˜ λͺ¨λ“  ν‚€λ₯Ό νƒμƒ‰ν•˜λŠ” KEYS weather:* λͺ…λ Ήμ–΄λŠ” 운영 쀑인 Redis μ„œλ²„μ—μ„œ μ‚¬μš©μ— μ£Όμ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€. ν‚€κ°€ 수백만 개 이상일 경우, KEYS λͺ…λ Ήμ–΄ ν•˜λ‚˜κ°€ μ„œλ²„ 전체λ₯Ό λͺ‡ μ΄ˆκ°„ λ©ˆμΆ”κ²Œ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λŒ€μ‹ , μ„œλ²„μ— λΆ€ν•˜λ₯Ό μ£Όμ§€ μ•Šκ³  μ•ˆμ „ν•˜κ²Œ ν‚€λ₯Ό νƒμƒ‰ν•˜λŠ” SCAN λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 ꢌμž₯λ©λ‹ˆλ‹€.

# μ»€μ„œλ₯Ό 0λΆ€ν„° μ‹œμž‘ν•΄μ„œ 'weather:*' νŒ¨ν„΄μ˜ ν‚€λ₯Ό 10κ°œμ”© μ μ§„μ μœΌλ‘œ 탐색
127.0.0.1:6379[1]> SCAN 0 MATCH weather:* COUNT 10

 

KEYS의 Blocking 방식

KEYS λͺ…λ Ήμ–΄μ˜ μ„±λŠ₯ μ €ν•˜ λ¬Έμ œλŠ” Redis의 단일 μŠ€λ ˆλ“œ(Single-Thread) μ‹€ν–‰ λͺ¨λΈμ— κΈ°μΈν•©λ‹ˆλ‹€. RedisλŠ” λŒ€λΆ€λΆ„μ˜ λͺ…λ Ήμ–΄λ₯Ό 단일 μŠ€λ ˆλ“œ μƒμ—μ„œ 순차적으둜 μ²˜λ¦¬ν•˜λ―€λ‘œ, ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…λ§Œ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

KEYS λͺ…λ Ήμ–΄λŠ” λŒ€ν‘œμ μΈ λΈ”λ‘œν‚Ή(Blocking) μ—°μ‚°μœΌλ‘œ, λ‹€μŒκ³Ό 같은 과정을 단 ν•œ 번의 μž‘μ—…μœΌλ‘œ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

  1. 전체 ν‚€μŠ€νŽ˜μ΄μŠ€(Keyspace) 순회: RedisλŠ” λ°μ΄ν„°λ² μ΄μŠ€μ— μ‘΄μž¬ν•˜λŠ” λͺ¨λ“  ν‚€λ₯Ό μˆœνšŒν•˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€. λ°μ΄ν„°μ…‹μ˜ 크기가 클수둝 이 κ³Όμ •μ˜ μ‹œκ°„ λ³΅μž‘λ„λŠ” O(N)으둜 μ„ ν˜• μ¦κ°€ν•©λ‹ˆλ‹€.
  2. νŒ¨ν„΄ λ§€μΉ­: μˆœνšŒν•˜λŠ” 각 킀에 λŒ€ν•΄ μ£Όμ–΄μ§„ νŒ¨ν„΄κ³Όμ˜ 일치 μ—¬λΆ€λ₯Ό κ²€μ‚¬ν•©λ‹ˆλ‹€.
  3. κ²°κ³Ό μ§‘ν•© ꡬ성: μΌμΉ˜ν•˜λŠ” 킀듀을 λ©”λͺ¨λ¦¬ λ‚΄μ˜ κ²°κ³Ό 집합에 μΆ”κ°€ν•©λ‹ˆλ‹€.
  4. κ²°κ³Ό λ°˜ν™˜: 전체 ν‚€μŠ€νŽ˜μ΄μŠ€ μˆœνšŒκ°€ μ™„λ£Œλœ 후에야 κ΅¬μ„±λœ κ²°κ³Ό 집합을 ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

이 λͺ¨λ“  과정이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ ν•΄λ‹Ή μŠ€λ ˆλ“œκ°€ λ‹€λ₯Έ μ–΄λ–€ μž‘μ—…λ„ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜κ³  μ™„μ „νžˆ μ μœ λ©λ‹ˆλ‹€. λ§Œμ•½ 수백만 개의 ν‚€λ₯Ό μˆœνšŒν•˜λŠ” 데 수 μ΄ˆκ°€ μ†Œμš”λœλ‹€λ©΄, κ·Έ μ‹œκ°„ λ™μ•ˆ Redis μΈμŠ€ν„΄μŠ€λŠ” λ‹€λ₯Έ λͺ¨λ“  ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ„ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜λŠ” 응닡 λΆˆκ°€λŠ₯(unresponsive) μƒνƒœκ°€ λ©λ‹ˆλ‹€. μ΄λŠ” μ„œλΉ„μŠ€ μ „μ²΄μ˜ μ§€μ—° μ‹œκ°„(Latency) κΈ‰μ¦μœΌλ‘œ μ΄μ–΄μ§‘λ‹ˆλ‹€.


SCAN의 Non-Blocking 방식

SCAN은 μ΄λŸ¬ν•œ λΈ”λ‘œν‚Ή 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 점진적 순회 방식을 μ±„νƒν–ˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” μž₯μ‹œκ°„ μ†Œμš”λ  수 μžˆλŠ” μž‘μ—…μ„ μ—¬λŸ¬ 개의 짧은 λ‹¨κ³„λ‘œ λΆ„ν• ν•˜μ—¬ μ‹€ν–‰ν•˜λŠ” Non-Blocking μ—°μ‚°μž…λ‹ˆλ‹€.

SCAN은 μ»€μ„œ(cursor) 기반의 λ©”μ»€λ‹ˆμ¦˜μ„ μ‚¬μš©ν•©λ‹ˆλ‹€.

  1. 순회 μ‹œμž‘: ν΄λΌμ΄μ–ΈνŠΈλŠ” SCAN 0 MATCH... 와 같이 μ»€μ„œ 값을 0으둜 μ„€μ •ν•˜μ—¬ 순회λ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.
  2. μ œν•œλœ 순회 및 응닡: RedisλŠ” λ‚΄λΆ€μ μœΌλ‘œ μ •ν•΄μ§„ μ–‘μ˜ μž‘μ—…λ§Œ μˆ˜ν–‰ν•˜μ—¬ 일뢀 ν‚€λ₯Ό μŠ€μΊ”ν•˜κ³ , ν•΄λ‹Ή μŠ€μΊ”μ—μ„œ 발견된 결과와 ν•¨κ»˜ λ‹€μŒ 순회λ₯Ό μ‹œμž‘ν•  지점인 μƒˆλ‘œμš΄ μ»€μ„œ 값을 λ°˜ν™˜ν•©λ‹ˆλ‹€. 이 연산은 맀우 짧은 μ‹œκ°„ μ•ˆμ— μ™„λ£Œλ©λ‹ˆλ‹€.
  3. λ‹€λ₯Έ μš”μ²­ 처리: λ‹€μŒ SCAN μš”μ²­μ΄ λ“€μ–΄μ˜€κΈ° μ „κΉŒμ§€, Redis μŠ€λ ˆλ“œλŠ” λ‹€λ₯Έ ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ„ μ²˜λ¦¬ν•  수 μžˆλŠ” μ—¬μœ λ₯Ό κ°–κ²Œ λ©λ‹ˆλ‹€. λ”°λΌμ„œ μ„œλ²„λŠ” μ§€μ†μ μœΌλ‘œ 응닡 κ°€λŠ₯ν•œ μƒνƒœλ₯Ό μœ μ§€ν•©λ‹ˆλ‹€.
  4. 순회 재개: ν΄λΌμ΄μ–ΈνŠΈλŠ” 이전 λ‹¨κ³„μ—μ„œ λ°˜ν™˜λœ μƒˆλ‘œμš΄ μ»€μ„œ 값을 μ‚¬μš©ν•˜μ—¬ SCAN λͺ…령을 λ‹€μ‹œ μ „μ†‘ν•¨μœΌλ‘œμ¨ 순회λ₯Ό μ΄μ–΄κ°‘λ‹ˆλ‹€.
  5. 순회 μ™„λ£Œ: Redisκ°€ λ‹€μ‹œ 0번 μ»€μ„œλ₯Ό λ°˜ν™˜ν•˜λ©΄, 전체 ν‚€μŠ€νŽ˜μ΄μŠ€ μˆœνšŒκ°€ μ™„λ£Œλ˜μ—ˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.

SCAN은 전체 순회λ₯Ό μ™„λ£Œν•˜κΈ°κΉŒμ§€μ˜ 총 μ‹€ν–‰ μ‹œκ°„μ€ 더 κΈΈ 수 μžˆμœΌλ‚˜, 각 단계λ₯Ό 짧게 λ‚˜λˆ„μ–΄ μ‹€ν–‰ν•¨μœΌλ‘œμ¨ μ„œλ²„ μ „μ²΄μ˜ μš΄μ˜μ— 영ν–₯을 λ―ΈμΉ˜λŠ” λΈ”λ‘œν‚Ή ν˜„μƒμ„ λ°©μ§€ν•˜κ³  μ•ˆμ •μ μΈ μ„œλΉ„μŠ€ μš΄μ˜μ„ 보μž₯ν•©λ‹ˆλ‹€.

 

 

λ”°λΌμ„œ, 운영 ν™˜κ²½μ—μ„œ μ„œλΉ„μŠ€μ˜ κ°€μš©μ„±κ³Ό μ•ˆμ •μ„±μ„ 보μž₯ν•˜κΈ° μœ„ν•΄μ„œλŠ” KEYS λŒ€μ‹  SCAN을 μ‚¬μš©μ΄ ꢌμž₯λ©λ‹ˆλ‹€.

728x90

'DB > Redis' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Spring Data Redis] RedisTemplate.opsForValue().get(key)  (0) 2025.07.17