Spring Data Redis Autoconfiguration ๋ถ„์„

spring data redis ๋Œ€ํ‘œ ์ด๋ฏธ์ง€

๊ณ ์„ฑ๋Šฅ ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ† ์–ด์ธ Redis๋Š” ํƒ์›”ํ•œ ๋ฐ์ดํ„ฐ ์บ์‹ฑ ๋ฐ ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ ๋งŽ์€ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ํ™œ์šฉ๋˜๊ณ  ์žˆ๋‹ค.
์ด์— ๋ฐœ๋งž์ถ”์–ด Spring Data ํ”„๋กœ์ ํŠธ๋Š” Redis ์ƒํ˜ธ ์ž‘์šฉ์— ๋Œ€ํ•œ ๋†’์€ ์ˆ˜์ค€์˜ ์ถ”์ƒํ™”๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ตœ์†Œํ•œ์˜ ๋…ธ๋ ฅ์œผ๋กœ Redis์˜ ์„ฑ๋Šฅ ์ด์ ์„ ํ™œ์šฉํ•˜๋ฉด์„œ ๊ธฐ๋Šฅ์ด ํ’๋ถ€ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•˜๋Š”๋ฐ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” Spring์—์„œ ์ œ๊ณตํ•˜๋Š” Redis ๊ด€๋ จ Auto Configuration์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค„๋ณด๊ณ ์ž ํ•œ๋‹ค. (Lettuce ์œ„์ฃผ๋กœ ์‚ดํŽด๋ด„)

  • ์ƒ˜ํ”Œ ์ฝ”๋“œ ์ž‘์„ฑ์€ spring boot 3.2.3๊ณผ JDK 21 ๋ฒ„์ „์—์„œ ์ž‘์„ฑํ•˜์˜€๋‹ค.
  • ์ƒ˜ํ”Œ ์ฝ”๋“œ ํ™•์ธ์„ ์œ„ํ•œ Redis ์„œ๋ฒ„ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์€ spring boot docker compose๋ฅผ ํ™œ์šฉํ•˜์˜€๋‹ค.

Dependency

์šฐ์„  Spring Data Redis๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ dependency๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
    id 'io.spring.dependency-management' version '1.1.4'
}
...
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.apache.commons:commons-pool2:2.12.0'
    developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
    testAndDevelopmentOnly 'org.springframework.boot:spring-boot-docker-compose'
    ...
}
Groovy
  • spring boot ์—์„œ ์ง€์›ํ•˜๋Š” docker compose ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ถ”๊ฐ€๋กœ spring-boot-docker-compose ์•„ํ‹ฐํŒฉํŠธ๋ฅผ dependency๋กœ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋„ spring boot docker compose๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด
    • testAndDevelopmentOnly ‘org.springframework.boot:spring-boot-docker-compose’ ๋””ํŽœ๋˜์‹œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ๋‹จ์ผ ์„œ๋ฒ„ ํ™˜๊ฒฝ์˜ Redis์ธ ๊ฒฝ์šฐ connection pool์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” commons-pool2 ๋””ํŽœ๋˜์‹œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
    • ๋‹จ์ผ ์„œ๋ฒ„ ํ™˜๊ฒฝ์˜ ๊ฒฝ์šฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด commons-pool2 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด pool์€ ์ž๋™ ํ™œ์„ฑํ™” ๋œ๋‹ค.

Spring Redis Auto Configuration

Spring Boot์—์„œ Redis๋ฅผ ์œ„ํ•œ auto configuration์˜ ์‹œ์ž‘์€ org.springframework.boot:spring-boot-autoconfigure ์•„ํ‹ฐํŒฉํŠธ์˜ org.springframework.boot.autoconfigure.data.redis ํŒจํ‚ค์ง€์— ์žˆ๋Š” RedisAutoConfiguration ํด๋ž˜์Šค๋‹ค.
RedisAutoConfiguration ํด๋ž˜์Šค์— ์ง€์ •๋œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

@AutoConfiguration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
Java
  • application.yml(. properties)์˜ Redis ๊ด€๋ จ ์„ค์ •์€ RedisProperties ํด๋ž˜์Šค์— ๋งตํ•‘๋œ๋‹ค.
  • LettuceConnectoinConfiguration, JedisConnectionConfiguration ์ด ์šฐ์„  ๋™์ž‘ํ•œ๋‹ค.

Spring Data Redis Properties

RedisProperties ํด๋ž˜์Šค๋Š” spring data redis ์„ค์ • ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ๋งตํ•‘ ํด๋ž˜์Šค๋‹ค.
RedisProperties ํด๋ž˜์Šค์˜ ์–ด๋…ธํ…Œ์ด์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€์ •๋˜์–ด ์žˆ๋‹ค.

@ConfigurationProperties(
    prefix = "spring.data.redis"
)
Java

์†์„ฑ ์ด๋ฆ„์— spring.data.redis prefix๊ฐ€ ์ •์˜๋จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
์„œ๋ฒ„ ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ๊ธฐ๋ณธ ์„ค์ • ํ•ญ๋ชฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

ํ”„๋กœํผํ‹ฐ์„ค๋ช…๋””ํดํŠธ
spring.data.redis.client-nameํด๋ผ์ด์–ธํŠธ ์„ค์ • ์ด๋ฆ„์œผ๋กœ ์—ฐ๊ฒฐํ•  ๋•Œ ์„ค์ •ํ•  ํด๋ผ์ด์–ธํŠธ ์ด๋ฆ„ 
spring.data.redis.client-type์—ฐ๊ฒฐ์— ์‚ฌ์šฉํ•  ํด๋ผ์ด์–ธํŠธ ์œ ํ˜•. (lettuce or jedis) ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ž˜์Šค ๊ฒฝ๋กœ์— ๋”ฐ๋ผ ์ž๋™ ๊ฐ์ง€๋จ. 
spring.data.redis.connect-timeoutConnection ํƒ€์ž„์•„์›ƒ. 
spring.data.redis.timeoutRead ํƒ€์ž„์•„์›ƒ. 
spring.data.redis.databaseconnection factory ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ธ๋ฑ์Šค ์„ค์ •. Redis๋Š” ์ธ๋ฑ์Šค๋กœ ์‹๋ณ„๋˜๋Š” ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ์ด ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Œ.0
spring.data.redis.hostRedis ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธlocalhost
spring.data.redis.portRedis ์„œ๋ฒ„ ํฌํŠธ6379
spring.data.redis.usernameRedis ์„œ๋ฒ„ ๋กœ๊ทธ์ธ username 
spring.data.redis.passwordRedis ์„œ๋ฒ„ ๋กœ๊ทธ์ธ password 
spring.data.redis.urlConnection URL ์„ค์ •. ์ด ์„ค์ •์ด ์ง€์ •๋˜๋ฉด host, port, username, password ์„ค์ •์ด ์žฌ์ •์˜ ๋จ. ex) redis://username:password@localhost:6379 
spring.data.redis.ssl.enabledSSL ์ง€์› ํ™œ์„ฑํ™” ์—ฌ๋ถ€ ์„ค์ •. ๋ณ„๋„๋กœ ์ง€์ •ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ bundle์„ ์ œ๊ณตํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ™œ์„ฑํ™” ๋จ. 
spring.data.redis.ssl.bundleSSL bundle ์ด๋ฆ„ 
spring.data.redis.cluster.max-redirectsํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด์—์„œ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ ๋”ฐ๋ผ์•ผ ํ•  ์ตœ๋Œ€ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์ˆ˜. 
spring.data.redis.cluster.nodes์—ฐ๊ฒฐํ•  โ€œhost:portโ€ ์Œ์˜ ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„๋œ ๋ชฉ๋ก. ํด๋Ÿฌ์Šคํ„ฐ ๋…ธ๋“œ์˜ ์ดˆ๊ธฐ ๋ชฉ๋ก์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ ์ ์–ด๋„ ํ•˜๋‚˜์˜ ํ•ญ๋ชฉ์ด ์žˆ์–ด์•ผ ํ•จ. 
spring.data.redis.sentinel.masterRedis ์„œ๋ฒ„์˜ ์ด๋ฆ„. 
spring.data.redis.sentinel.nodes์—ฐ๊ฒฐํ•  โ€œhost:portโ€ ์Œ์˜ ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„๋œ ๋ชฉ๋ก. 
spring.data.redis.sentinel.passwordredis sentinel ์ธ์ฆ์„ ์œ„ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ 
spring.data.redis.sentinel.usernameredis sentinel ์ธ์ฆ์„ ์œ„ํ•œ ๊ณ„์ • 
spring.data.redis.repositories.enabledRedis Repository๋ฅผ ํ™œ์„ฑํ™” ํ• ์ง€ ์—ฌ๋ถ€.true

Connection Pool ๊ด€๋ จ ์„ค์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

ํ”„๋กœํผํ‹ฐ์„ค๋ช…๋””ํดํŠธ
spring.data.redis.{jedis|lettuce}.pool.enabledconnection pool ํ™œ์„ฑํ™” ์—ฌ๋ถ€ ์„ค์ •. commons-pool2 ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ํ™œ์„ฑํ™” ๋จ. Jedis๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์„ผํ‹ฐ๋„ ๋ชจ๋“œ์—์„œ ํ’€๋ง์ด ์•”์‹œ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜๋ฉฐ ์ด ์„ค์ •์€ ๋‹จ์ผ ๋…ธ๋“œ์—์„œ๋งŒ ์ ์šฉ๋จ. connection pool์„ ํ™œ์„ฑํ™” ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” commons-pool2 ๋””ํŽœ๋˜์‹œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค. (๋””ํŽœ๋˜์‹œ๊ฐ€ ์—†์œผ๋ฉด ConnectionFactory ์ƒ์„ฑ์‹œ ์‹คํŒจํ•จ) 
spring.data.redis.{jedis|lettuce}.pool.max-active์—ฐ๊ฒฐ ํ’€์˜ ์ตœ๋Œ€ connection ์ˆ˜ ์„ค์ •. ์ œํ•œ์ด ์—†๋Š” ๊ฒฝ์šฐ ์Œ์ˆ˜ ๊ฐ’์„ ์‚ฌ์šฉ8
spring.data.redis.{jedis|lettuce}.pool.max-idle์—ฐ๊ฒฐ ํ’€์˜ ์ตœ๋Œ€ idle connection ์ˆ˜ ์„ค์ •. ์ œํ•œ์ด ์—†๋Š” ๊ฒฝ์šฐ ์Œ์ˆ˜ ๊ฐ’์„ ์‚ฌ์šฉ8
spring.data.redis.{jedis|lettuce}.pool.min-idle์—ฐ๊ฒฐ ํ’€์ด ํ•ญ์ƒ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ์ตœ์†Œ idle connection ์ˆ˜ ์„ค์ •. ์ด ์„ค์ •์€ time-between-eviction-runs ์„ค์ • ์‹œ๊ฐ„์ด ์–‘์ˆ˜์ธ ๊ฒฝ์šฐ์— ์ ์šฉ๋จ.0
spring.data.redis.{jedis|lettuce}.pool.max-wait์—ฐ๊ฒฐ ํ’€์ด ๋ชจ๋‘ ์‚ฌ์šฉ ์ค‘์ธ ๊ฒฝ์šฐ ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•ด์งˆ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‹œ๊ฐ„ ์„ค์ •. ์ง€์ •๋œ ์‹œ๊ฐ„ ๋™์•ˆ์—๋„ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅํ•œ ํ’€์ด ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ. ์Œ์ˆ˜ ๊ฐ’์„ ์„ค์ •ํ•œ ๊ฒฝ์šฐ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅํ•œ ํ’€์ด ์ƒ๊ธฐ๊ธฐ๊นŒ์ง€ ๊ณ„์† ๋Œ€๊ธฐํ•จ.-1ms
spring.data.redis.{jedis|lettuce}.pool.time-between-eviction-runs์ œ๊ฑฐ ์Šค๋ ˆ๋“œ์˜ ์‹คํ–‰ ์‹œ๊ฐ„ ์ฃผ๊ธฐ ์„ค์ •. ์Œ์ˆ˜ ๊ฐ’์ด ์ง€์ •๋œ ๊ฒฝ์šฐ ์ œ๊ฑฐ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰๋˜์ง€ ์•Š์Œ. ์ œ๊ฑฐ ์Šค๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด์„œ min-idle, max-idle ์— ์„ค์ •๋œ ์ˆ˜์น˜๋ฅผ ๋„˜์–ด์„  ๊ฒฝ์šฐ ๋ถˆํ•„์š”ํ•œ idle connection์„ ์ œ๊ฑฐํ•˜์—ฌ ๋ฆฌ์†Œ์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•จ. 

๊ธฐ๋ณธ ์„ค์ • ์˜ˆ์‹œ

spring:
  data:
    redis:
      # redis ์ ‘์† ํ˜ธ์ŠคํŠธ (default: localhost)
      # redis ์ ‘์† ํ˜ธ์ŠคํŠธ (default: localhost)
      # - redis๋ฅผ spring boot docker compose๋กœ ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ spring์—์„œ ์ƒ์„ฑํ•œ docker ์ปจํ…Œ์ด๋„ˆ๋กœ๋ถ€ํ„ฐ ์ •๋ณด๋ฅผ ์–ป์–ด ์ ‘์† ์ •๋ณด๋ฅผ ์ž๋™ ์…‹ํŒ…ํ•œ๋‹ค.
      # - redis๋ฅผ spring boot docker compose๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ redis ์ ‘์† ํ˜ธ์ŠคํŠธ ์ •๋ณด๋ฅผ ์…‹ํŒ…ํ•œ๋‹ค.
      host: localhost
      # redis ์ ‘์† ํฌํŠธ (default: 6379)
      # - redis๋ฅผ spring boot docker compose๋กœ ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ spring์—์„œ ์ƒ์„ฑํ•œ docker ์ปจํ…Œ์ด๋„ˆ๋กœ๋ถ€ํ„ฐ ์ •๋ณด๋ฅผ ์–ป์–ด ์ ‘์† ์ •๋ณด๋ฅผ ์ž๋™ ์…‹ํŒ…ํ•œ๋‹ค.
      # - redis๋ฅผ spring boot docker compose๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ redis ์ ‘์† ํฌํŠธ ์ •๋ณด๋ฅผ ์…‹ํŒ…ํ•œ๋‹ค.
      port: 6379
      # connection timeout
      connect-timeout: 30s
      # read timeout
      timeout: 10s
YAML

ConnectionDetails ์ถ”์ƒํ™”

Spring Boot 3.1๋ถ€ํ„ฐ ๋„์ž…๋œ ConnectionDetails ์ถ”์ƒํ™”๋Š” ์—ฌ๋Ÿฌ ์›๊ฒฉ ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ ์„ค์ •์„ ์ž๋™ ๊ตฌ์„ฑ์„ ํ†ตํ•ด ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
Redis ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ ConnectionDetails ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™•์žฅํ•œ RedisConnectionDetails ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ด์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • RedisDockerComposeConnectionDetails
    • Spring Boot Docker Compose์— ์˜ํ•ด์„œ ๊ตฌ์„ฑ๋œ redis ์„œ๋น„์Šค์— ๋Œ€ํ•ด์„œ ์‚ฌ์šฉ๋œ๋‹ค.
    • Spring Boot Docker Compose๋Š” ๊ฐœ๋ฐœ ๋ฐ ํ…Œ์ŠคํŠธ์šฉ์ด๋ผ์„œ ๊ทธ๋Ÿฐ์ง€ standalone๋งŒ ์ง€์›ํ•œ๋‹ค.
    • Spring Boot Docker Compose๋กœ ์ž๋™ ์ƒ์„ฑ๋œ redis ์„œ๋ฒ„ docker container์— ๋Œ€ํ•œ ํ˜ธ์ŠคํŠธ ํฌํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•œ๋‹ค.
  • PropertiesRedisConnectionDetails
    • application.yml (. properties)์˜ spring.data.redis ์„ค์ •์— ์˜ํ•ด์„œ ์—ฐ๊ฒฐ ์ •๋ณด์— ๋Œ€ํ•œ ConnectionDetails ์ถ”์ƒํ™”๊ฐ€ ๊ตฌํ˜„๋œ๋‹ค.
    • RedisDockerComposeConnectionDetails์™€ ๋‹ฌ๋ฆฌ standalone, sentinel, cluster ๊ตฌ์„ฑ ์„ค์ •์„ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•œ๋‹ค.
      ConnectionDetails๋ฅผ ํ†ตํ•ด์„œ standalone, sentinel, cluster ์—ฐ๊ฒฐ ์„ค์ •์— ๋Œ€ํ•œ ํด๋ž˜์Šค๊ฐ€ ๊ตฌ์„ฑ์ด ๋˜๋Š”๋ฐ ๊ฐ๊ฐ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
  • standalone – RedisStandaloneConfiguration – ๋‹จ์ผ ์„œ๋ฒ„ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์ ‘์† ์ •๋ณด ์„ค์ •
  • sentinel – RedisSentinelConfiguration – Sentinel ๊ตฌ์„ฑ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์ ‘์† ์ •๋ณด ์„ค์ •
  • cluster – RedisClusterConfiguration – Cluster ๊ตฌ์„ฑ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์ ‘์† ์ •๋ณด ์„ค์ •

์œ„ ํด๋ž˜์Šค ๋ชจ๋‘ ConnectionDetails ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด์„œ ์•Œ๋งž๊ฒŒ ์„ค์ •๋œ๋‹ค.
Spring Boot Docker Compose๋ฅผ ํ†ตํ•ด์„œ Redis ์„œ๋น„์Šค๋ฅผ ๊ตฌ์„ฑํ•œ ๊ฒฝ์šฐ Auto Configuration ๊ณผ์ •์—์„œ ๋‹ค์Œ์— ์„ค๋ช…ํ•  LettuceConnectionConfiguration ํด๋ž˜์Šค์— ์ฃผ์ž…๋˜๋Š” ConnectionDetails ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋””๋ฒ„๊ฑฐ๋ฅผ ํ†ตํ•ด์„œ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
spring boot data redis ConnectionDetails ์ธ์Šคํ„ด์Šค
์ฐธ๊ณ ๋กœ ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด RedisDockerComposeConnectionDetails ์—๋Š” ๋„์ปค ์ปจํ…Œ์ด๋„ˆ์˜ Redis ์„œ๋ฒ„ ํฌํŠธ์™€ ์—ฐ๊ฒฐ๋œ ์—ฐ๊ฒฐ๋œ ํ˜ธ์ŠคํŠธ ํฌํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
spring boot data redis ConnectionDetails์— ํ• ๋‹น๋œ ํฌํŠธ ์ •๋ณด

spring boot data redis Docker Container์™€ ์—ฐ๊ฒฐ๋œ ํ˜ธ์ŠคํŠธ ํฌํŠธ

LettuceConnectionConfiguration, JedisConnectionConfiguration ํด๋ž˜์Šค

RedisAutoConfiguration ํด๋ž˜์Šค์—์„œ Import ํ•˜๊ณ  ์žˆ๋Š” ๋‘ RedisConnectionConfiguration ํด๋ž˜์Šค๋‹ค.
๊ฐ๊ฐ์˜ ํด๋ž˜์Šค์— ์ง€์ •๋œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ดํŽด๋ณด์ž.

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({RedisClient.class})
@ConditionalOnProperty(
    name = {"spring.data.redis.client-type"},
    havingValue = "lettuce",
    matchIfMissing = true
)
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {...}
Java

LettuceConnectionConfiguration ํด๋ž˜์Šค๋Š” Lettuce ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ์ž๋™ ๊ตฌ์„ฑ ์„ค์ •์„ ํ•œ๋‹ค.
spring.data.redis.client-type ์„ค์ •์ด ‘lettuce’๋กœ ์„ค์ •๋˜๊ฑฐ๋‚˜ ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ(matchIfMissing = true) ์ž๋™ ๊ตฌ์„ฑ์ด ๋™์ž‘ํ•˜๋ฉฐ ํ•ด๋‹น ํด๋ž˜์Šค์—์„œ LettuceConnectionFactory ๋นˆ์„ ์ƒ์„ฑ(ํ˜„์žฌ RedisConnectionFactory ๋นˆ์ด ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ) ํ•œ๋‹ค.
JedisConnectionConfiguration ํด๋ž˜์Šค์— ์ง€์ •๋œ ์–ด๋…ธํ…Œ์ด์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class})
@ConditionalOnMissingBean({RedisConnectionFactory.class})
@ConditionalOnProperty(
    name = {"spring.data.redis.client-type"},
    havingValue = "jedis",
    matchIfMissing = true
)
class JedisConnectionConfiguration extends RedisConnectionConfiguration {...}
Java

LettuceConnectionConfiguration์— ์ง€์ •๋œ ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ
@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class})
@ConditionalOnMissingBean({RedisConnectionFactory.class})
์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.
Jedis๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ถ”๊ฐ€์ ์œผ๋กœ Jedis ๋””ํŽœ๋˜์‹œ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•œ๋‹ค.

implementation 'redis.clients:jedis:<version>'
Groovy

๋˜ํ•œ LettuceConnectionConfiguration์—์„œ LettuceConnectionFactory(RedisConnectionFactory)๋ฅผ ์ƒ์„ฑํ•˜์˜€๋‹ค๋ฉด JedisConnectionConfiguration ํด๋ž˜์Šค์˜ ์ž๋™ ๊ตฌ์„ฑ์€ ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.
์ฆ‰ ๋ช…์‹œ์ ์œผ๋กœ spring.data.redis.client-type=jedis๋กœ ์„ค์ •๋œ ๊ฒฝ์šฐ์—๋งŒ JedisConnectionConfiguration ์ž๋™ ๊ตฌ์„ฑ์ด ์ˆ˜ํ–‰๋œ๋‹ค.

CientResources Custom (Lettuce ๋งŒ ํ•ด๋‹น)

ClientResource๋Š” Lettuce์—์„œ Redis ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ์— ํ•„์š”ํ•œ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ทธ๋ฃน, ์Šค๋ ˆ๋“œ ํ’€ ๋ฐ ๊ธฐํƒ€ ์ธํ”„๋ผ ๊ตฌ์„ฑ ์š”์†Œ์™€ ๊ฐ™์€ ๊ณต์œ  ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” Lettuce์˜ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค.
์ด๋Ÿฌํ•œ ๋ฆฌ์†Œ์Šค๋Š” ์ƒ์„ฑํ•˜๋Š”๋ฐ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค๊ธฐ ๋•Œ๋ฌธ์— RedisConnectionFactory ๋นˆ์„ ์ƒ์„ฑํ•  ๋•Œ ์ž๋™์œผ๋กœ DefaultClientResources ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ LettuceConnectionFactory์— ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.
LettuceConnectionConfiguration ํด๋ž˜์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ClientResources ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

@Bean(
    destroyMethod = "shutdown"
)
@ConditionalOnMissingBean({ClientResources.class})
DefaultClientResources lettuceClientResources(ObjectProvider<ClientResourcesBuilderCustomizer> customizers) {
    DefaultClientResources.Builder builder = DefaultClientResources.builder();
    customizers.orderedStream().forEach((customizer) -> {
        customizer.customize(builder);
    });
    return builder.build();
}
Java
  • ClientResources ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด Auto Configuration์— ์˜ํ•ด์„œ ์ž๋™์œผ๋กœ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ ์ด๋•Œ ClientResourcesBuilderCustomizer๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•˜๋Š” Resource ํ•ญ๋ชฉ๋งŒ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ClientResources์˜ ์ผ๋ถ€ ํ•ญ๋ชฉ์„ ๋ณ€๊ฒฝํ•˜๋„๋ก ClientResourcesBuilderCustomizer ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
@Configuration
public class RedisConfiguration {
    @Bean
    public ClientResourcesBuilderCustomizer clientResourceCustomize() {
        return builder -> {
            builder.reconnectDelay( Delay.constant( Duration.ofSeconds(50) ) );
            builder.ioThreadPoolSize( 4 );
            builder.commandLatencyRecorder( CommandLatencyRecorder.disabled() );
            builder.commandLatencyPublisherOptions( DefaultEventPublisherOptions.disabled() );
        };
    }
}
Java

์œ„ clientResourceCustomize ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ค์ •์„ ๋ณ€๊ฒฝํ•œ๋‹ค.

  • ClientResources์—์„œ reconnect delay ์ •์ฑ…์„ ConstantDelay ์ธ์Šคํ„ด์Šค๋กœ ์„ค์ •ํ•œ๋‹ค. (๋””ํดํŠธ๋Š” ExponentialDelay ๋‹ค)
    • ์žฌ์ ‘์†์„ ์œ„ํ•ด์„œ ๋Œ€๊ธฐํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ณ ์ • ์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
    • ExponentialDelay๋Š” ์žฌ์ ‘์† ์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ• ์ˆ˜๋ก Delay ์‹œ๊ฐ„์ด ๊ทธ์— ๋น„๋ก€ํ•˜์—ฌ ์ฆ๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • io thread pool size๋ฅผ 4๊ฐœ๋กœ ๊ณ ์ •ํ•œ๋‹ค. (๋””ํดํŠธ๋Š” processors ์ˆ˜๋‹ค)
  • ์ง€์—ฐ ์‹œ๊ฐ„์— ๋Œ€ํ•œ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘์„ disable ํ•œ๋‹ค.
  • ์ง€์—ฐ ์‹œ๊ฐ„์— ๋Œ€ํ•ด์„œ ์ˆ˜์ง‘๋œ ๋ฉ”ํŠธ๋ฆญ ์ด๋ฒคํŠธ ๋ฐœํ–‰์„ disable ํ•œ๋‹ค.

ClinetResources ํด๋ž˜์Šค์— ์ •์˜๋œ ๊ฐ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋“ค์— ๋Œ€ํ•œ ์„ค๋ช…์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

ํ•ญ๋ชฉ์„ค๋ช…๋””ํดํŠธ
ioThreadPoolSizeI/O ์Šค๋ ˆ๋“œ ํ’€์˜ ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๋ฅผ ์„ค์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ ๋Ÿฐํƒ€์ž„์‹œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ processor ์ˆ˜๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํ•œ๋‹ค. ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋Š” ๋ชจ๋“  I/O ์ž‘์—…์ด ์‹คํ–‰๋˜๋Š” ๋‚ด๋ถ€ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ๋„คํŠธ์›Œํฌ(NIO) ๋ฐ ์œ ๋‹‰์Šค ๋„๋ฉ”์ธ ์†Œ์ผ“(EPoll) ์—ฐ๊ฒฐ์„ ์œ„ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ํ’€์„ ํ•„์š”๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ˆซ์ž๋Š” ์‹ค์ œ I/O ์Šค๋ ˆ๋“œ ์ˆ˜๋ฅผ ๋ฐ˜์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ตœ์†Œ I/O ์Šค๋ ˆ๋“œ๋Š” 2๊ฐœ๋‹ค.processors ์ˆ˜
computationThreadPoolSizecompute ์Šค๋ ˆ๋“œ ํ’€์˜ ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๋ฅผ ์„ค์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ ๋Ÿฐํƒ€์ž„์‹œ ์‚ฌ์šฉ๊ฐ€๋Š”ํ•œ processor ์ˆ˜๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํ•œ๋‹ค. ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋Š” ๋ชจ๋“  ๊ณ„์‚ฐ ์ž‘์—…์ด ์‹คํ–‰๋˜๋Š” ๋‚ด๋ถ€ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ตœ์†Œ compute ์Šค๋ ˆ๋“œ๋Š” 2๊ฐœ๋‹ค.processors ์ˆ˜
eventLoopGroupProvider๊ธฐ์กด ๋„คํ‹ฐ ์ธํ”„๋ผ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์Šค๋ ˆ๋“œ ํ’€์— ๋Œ€ํ•œ ์ „์ฒด ์ œ์–ด๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ EventLoopGroupProvider API๊ฐ€ ์ด๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค. EventLoopGroup์€ EventLoopGroupProvider์— ์˜ํ•ด์„œ ์–ป์–ด์ง€๊ณ  ๊ด€๋ฆฌ๋œ๋‹ค. ์ œ๊ณต๋œ EventLoopGroupProvider๋Š” ํด๋ผ์ด์–ธํŠธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜์ง€ ์•Š์œผ๋ฉฐ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ์ข…๋ฃŒํ•ด์•ผ ํ•œ๋‹ค.DefaultEventLoopGroupProvider (ioThreadPoolSize ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค.)
eventExecutorGroup๊ธฐ์กด ๋„คํ‹ฐ ์ธํ”„๋ผ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์Šค๋ ˆ๋“œ ํ’€์— ๋Œ€ํ•œ ์ „์ฒด ์ œ์–ด๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ Client Resource์— ๊ธฐ์กด EventExecutorGroup์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ์ œ๊ณต๋œ EventExecutorGroup์€ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ์ข…๋ฃŒํ•ด์•ผ ํ•œ๋‹ค.DefaultEventExecutorGroup (computationThreadPoolSize ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค.)
eventBus์ด๋ฒคํŠธ ๋ฒ„์Šค ์‹œ์Šคํ…œ์€ ํด๋ผ์ด์–ธํŠธ์—์„œ subscriber์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ „์†กํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ด๋ฒคํŠธ๋Š” ์—ฐ๊ฒฐ ์ƒํƒœ ๋ณ€๊ฒฝ, ๋ฉ”ํŠธ๋ฆญ ๋“ฑ์— ๊ด€ํ•œ ๊ฒƒ์ด๋‹ค. ์ด๋ฒคํŠธ๋Š” Rxjava ์ฃผ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์‹œ๋˜๋ฉฐ ๊ธฐ๋ณธ ๊ตฌํ˜„์€ ๋ฐฑํ”„๋ ˆ์…”์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.DefaultEventBus
commandLatencyCollectorOptionsํด๋ผ์ด์–ธํŠธ๋Š” ๋ช…๋ น์„ dispatch ํ•˜๋Š” ๋™์•ˆ ์ง€์—ฐ ์‹œ๊ฐ„ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐฑ๋ถ„์œ„์ˆ˜, ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ค€(์—ฐ๊ฒฐ ๋˜๋Š” ์„œ๋ฒ„๋ณ„), ๋ฉ”ํŠธ๋ฆญ์„ ๋ˆ„์ ํ• ์ง€ ๋˜๋Š” ์ˆ˜์ง‘ ํ›„ ์ดˆ๊ธฐํ™” ํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. commandLatencyCollectorOptions ์„ค์ •์€ ๊ธฐ๋ณธ์ ์œผ๋กœ enabled ๋˜์–ด ์žˆ์œผ๋ฉฐ commandLatencyCollectorOptions(โ€ฆ)๋ฅผ DefaultCommandLatencyCollectorOptions.disabled()๋กœ ์„ค์ •ํ•˜์—ฌ ๋น„ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. – 6.0 ๋ฒ„์ „ ๋ถ€ํ„ฐ ๋ฉ”์„œ๋“œ๋Š” deprecated ๋˜์—ˆ๋‹ค. spring ์ง€์—ฐ ์‹œ๊ฐ„ ์ˆ˜์ง‘๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํด๋ž˜์Šค ๊ฒฝ๋กœ์— LatencyUtils๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.DefaultCommandLatencyCollectorOptions
commandLatencyCollectorํด๋ผ์ด์–ธํŠธ๋Š” ๋ช…๋ น์„ dispatch ํ•˜๋Š” ๋™์•ˆ ์ง€์—ฐ ์‹œ๊ฐ„ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ช…๋ น ๋Œ€๊ธฐ ์‹œ๊ฐ„ ๋ฉ”ํŠธ๋ฆญ์€ ์—ฐ๊ฒฐ ๋˜๋Š” ์„œ๋ฒ„ ์ˆ˜์ค€์—์„œ ์ˆ˜์ง‘๋œ๋‹ค. ๋ช…๋ น ์ง€์—ฐ ์‹œ๊ฐ„ ์ˆ˜์ง‘์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™” ๋˜์–ด ์žˆ์œผ๋ฉฐ commandLatencyCollectorOptions(โ€ฆ)๋ฅผ DefaultCommandLatencyCollectorOptions.disabled()๋กœ ์„ค์ •ํ•˜์—ฌ ๋น„ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. – 6.0 ๋ฒ„์ „ ๋ถ€ํ„ฐ ๋ฉ”์„œ๋“œ๋Š” deprecated ๋˜์—ˆ๋‹ค.DefaultCommandLatencyCollector spring 6.0 ๋ถ€ํ„ฐ deprecated ๋จ.
commandLatencyRecordercommandLatencyCollector๋ฅผ ๋Œ€์ฒดํ•˜์—ฌ ๋‚˜์˜จ ํ•„๋“œ๋กœ ๋ณด์ธ๋‹ค. CommandLatencyRecorder๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฉฐ ๊ตฌํ˜„์ฒด๋Š” CommandLatencyCollector ์ด๋‹ค. 6.0๋ฒ„์ „ ์ดํ›„ ๋ถ€ํ„ฐ ์‚ฌ์šฉ๋˜๋Š” ์ง€์—ฐ ์‹œ๊ฐ„ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•œ ์ธ์Šคํ„ด์Šค๋กœ ๋ณด์ธ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ CommandLatencyCollector ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ง€๋ฉฐ CommandLatencyCollectorOptions๊ฐ€ null ์ธ ๊ฒฝ์šฐ์—๋Š” DefaultCommandLatencyCollectorOptions๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™” ๋˜์–ด ์žˆ์œผ๋ฉฐ commandLatencyRecorder(CommandLatencyRecorder.disabled()) ๋กœ ๋น„ํ™œ์„ฑํ™” ํ•˜๋Š”๋“ฏ ํ•˜๋‹ค.DefaultCommandLatencyCollector
commandLatencyPublisherOptionseventBus๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ช…๋ น ๋Œ€๊ธฐ ์‹œ๊ฐ„ ๋ฉ”ํŠธ๋ฆญ์„ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ง€์—ฐ ์‹œ๊ฐ„ ์ด๋ฒคํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 10๋ถ„๋งˆ๋‹ค ๋ฐœํ–‰๋œ๋‹ค. ์ด๋ฒคํŠธ ๊ฒŒ์‹œ๋ฅผ ๋น„ํ™œ์„ฑํ™” ํ•˜๋ ค๋ฉด commandLatencyPublisherOptions(โ€ฆ) ๋ฅผ DefaultEventPublisherOptions.disabled() ๋กœ ์„ค์ •ํ•˜์—ฌ ๋น„ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.DefaultEventPublisherOptions
dnsResolver3.5, 4.2 ๋ฒ„์ „ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ java.net.InetAddress๋กœ ํ™•์ธํ•˜๋„๋ก DNS resolver๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ ํ™•์ธ ๋ฐ ์กฐํšŒ ๊ฒฐ๊ณผ ์บ์‹ฑ์„ ์‚ฌ์šฉํ•˜๋Š” JVM DNS resolver๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. DNS ๊ธฐ๋ฐ˜ Redis-HA ์„ค์ •(ex. AWS ElasticCache)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž๋Š” ๋‹ค๋ฅธ DNS resolver๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. Lettuce์—๋Š” java์˜ DnsContextFactory๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ ํ™•์ธํ•˜๋Š” DirContextDnsResolver๊ฐ€ ํ•จ๊ป˜ ์ œ๊ณต๋œ๋‹ค. DirContextDnsResolver๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜์ง€ ์•Š๊ณ  ์‹œ์Šคํ…œ DNS ๋˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ DNS ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ ์กฐํšŒ์—์„œ DNS ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. 4.4 ๋ฒ„์ „ ๊ธฐ๋ณธ๊ฐ’์€ DnsResolvers.UNRESOLVED๋กœ ์„ค์ •๋˜์–ด Bootstrap.connect()์—์„œ DNS ์ด๋ฆ„์„ ํ™•์ธํ•˜๋Š” netty์˜ AddressResolver๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.DnsResolvers.UNRESOLVED
reconnectDelay์žฌ์—ฐ๊ฒฐ ์‹œ๋„๋ฅผ ์ง€์—ฐ์‹œํ‚ค๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์žฌ์—ฐ๊ฒฐ ์ง€์—ฐ์„ ๊ตฌ์„ฑํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ ์ƒํ•œ์ด 30์ดˆ์ธ exponential delay๋‹ค.Delay.exponential()

Configuration ํด๋ž˜์Šค์—์„œ ConnectionFactory์˜ Client Configuration ๋ณ€๊ฒฝํ•˜๊ธฐ

ClientResources์˜ ํ•ญ๋ชฉ์„ Configuration ํด๋ž˜์Šค์—์„œ ClientResourcesBuilderCustomizer๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ LettuceClientConfigurationBuilderCustomizer๋ฅผ ์ด์šฉํ•˜์—ฌ ConnectionFactory์˜ Client ์„ค์ • ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
Lettuce๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค์ •์„ ๋ณ€๊ฒฝํ•˜๋Š” ์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

@Bean
public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigCustomize() {
    return builder -> {
        if ( builder instanceof
                LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder poolingBuilder ) {
            // Pool configuration
            GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
            poolConfig.setMaxIdle(10);
            poolConfig.setMinIdle(5);
            poolConfig.setMaxTotal(20);
            poolConfig.setMaxWait(Duration.ofSeconds( 30 ));
            poolingBuilder.poolConfig( poolConfig );
        }

        builder.shutdownTimeout( Duration.ofMillis( 1000L ) );
    };
}
Java

์œ„ ์ฝ”๋“œ๋Š”

  • pool ์„ค์ •์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” LettucePoolingClientConfigurationBuilder ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ max-idle, min-idle, max-total, max-wait ์„ค์ •์„ ๊ฐ๊ฐ 10๊ฐœ, 5๊ฐœ, 20๊ฐœ, 30์ดˆ๋กœ ๋‹ค์‹œ ์žฌ์„ค์ •์„ ํ•œ๋‹ค.
  • lettuce shutdown timeout ์„ค์ •์„ 1000ms๋กœ ์„ค์ •ํ•œ๋‹ค. (default: 100ms)
    • spring.data.redis.lettuce.shutdown-timeout ์„ค์ •์ด ์ง€์ •๋˜์–ด ์žˆ๋‹ค๋ฉด override ํ•œ๋‹ค.

lettuceClientConfigCustomize ๋นˆ์ด ์–ด๋–ป๊ฒŒ ํ˜ธ์ถœ๋˜๋Š”์ง€ LettuceConnectionConfiguration ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณด์ž.
LettuceConnectionFactory ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
@ConditionalOnThreading(Threading.PLATFORM)
LettuceConnectionFactory redisConnectionFactory(
		ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
		ClientResources clientResources) {
	return createConnectionFactory(builderCustomizers, clientResources);
}
Java

์œ„ ์ฝ”๋“œ์—์„œ ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ง์ ‘ ์ž‘์„ฑํ•œ lettuceClientConfigCustomize ๋นˆ์ด ์ฃผ์ž…๋˜๊ฒŒ ๋œ๋‹ค.
createConnectionFactory(builderCustomizers, clientResources) ๋ฉ”์„œ๋“œ ๊ตฌํ˜„์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

private LettuceConnectionFactory createConnectionFactory(
		ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
		ClientResources clientResources) {
	LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(builderCustomizers, clientResources,
			getProperties().getLettuce().getPool());
	return createLettuceConnectionFactory(clientConfig);
}
Java

getLettuceClientConfiguration(builderCustomizers, clientResources, getProperties().getLettuce().getPool()); ๋ฉ”์„œ๋“œ๊ฐ€ Lettuce Client ์„ค์ •์„ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
๋”ฐ๋ผ๊ฐ€ ๋ณด์ž.

private LettuceClientConfiguration getLettuceClientConfiguration(
		ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
		ClientResources clientResources, Pool pool) {
	LettuceClientConfigurationBuilder builder = createBuilder(pool);
	applyProperties(builder);
	if (StringUtils.hasText(getProperties().getUrl())) {
		customizeConfigurationFromUrl(builder);
	}
	builder.clientOptions(createClientOptions());
	builder.clientResources(clientResources);
	builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
	return builder.build();
}
Java

์ง์ ‘ ์ž‘์„ฑํ•œ lettuceClientConfigCustomize ๋นˆ์ด ์—ฌ๊ธฐ๊นŒ์ง€ ํ˜๋Ÿฌ ๋“ค์–ด์™”๋‹ค.
๊ฐ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์˜ ๋™์ž‘์„ ์‚ดํŽด๋ณด๋ฉด

  • createBuilder(pool) : pool ์„ค์ •์ด enabled์ธ ๊ฒฝ์šฐ LettucePoolingClientConfigurationBuilder๋ฅผ ์•„๋‹Œ ๊ฒฝ์šฐ LettuceClientConfigurationBuilder๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
  • applyProperties(builder) : builder์— application ํ”„๋กœํผํ‹ฐ ์„ค์ •๋‚ด์šฉ์„ ์ ์šฉํ•œ๋‹ค. (spring.data.redis.~~~)
    • ssl enabled ์—ฌ๋ถ€ ์„ค์ • ์ ์šฉ (spring.data.redis.ssl.enabled)
    • timeout ์„ค์ • ์ ์šฉ (spring.data.redis.timeout)
    • lettuce์˜ shutdown timeout ์„ค์ • ์ ์šฉ (spring.data.redis.lettuce.shutdown-timeout)
    • client name ์„ค์ • ์ ์šฉ (spring.data.redis.client-name)
  • customizeConfigurationFromUrl(builder) : spring.data.redis.url ์„ค์ •์ด ์ ์šฉ๋œ ๊ฒฝ์šฐ url ๋‚ด์šฉ์„ ํŒŒ์‹ฑ ํ•˜์—ฌ scheme๊ฐ€ rediss์ธ ๊ฒฝ์šฐ use ssl์„ true๋กœ ์„ค์ •ํ•œ๋‹ค.
  • builder.clientOptions(createClientOptions()) : ClientOptions ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ ์šฉํ•œ๋‹ค. ClientOptions์— ์ ์šฉ๋˜๋Š” ์„ค์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
    • application.yml (.properties) ์„ค์ •์— cluster refresh ๊ด€๋ จ ์„ค์ •์„ ์ ์šฉํ•œ๋‹ค. (spring.data.redis.lettuce.cluster.refresh)
    • connection timeout ์„ค์ •์„ ์ ์šฉํ•œ๋‹ค. (spring.data.redis.connect-timeout)
    • SSL bundle์ด ์ง€์ •๋œ ๊ฒฝ์šฐ bundle์— ์ง€์ •๋œ SSL ์„ค์ •์„ ์ ์šฉํ•œ๋‹ค. (spring.data.redis.ssl.bundle)
  • builder.clientResources : ClientResources ์ธ์Šคํ„ด์Šค๋ฅผ ์ ์šฉํ•œ๋‹ค.
  • builderCustomizers.orderedStream().forEach( ( customizer ) โ†’ customizer.customize( builder ) )
    • ์ง์ ‘ ์ž‘์„ฑํ•œ lettuceClientConfigCustomize ์ธ์Šคํ„ด์Šค๊ฐ€ ์ ์šฉ๋œ๋‹ค.
    • customizer.customize(builder) ํ˜ธ์ถœ์€ ๊ฒฐ๊ตญ ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™๊ฒŒ ๋œ๋‹ค.
void customize(LettuceClientConfigurationBuilder builder) {
	if ( builder instanceof
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder poolingBuilder ) {
    // Pool configuration
	    GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
	    poolConfig.setMaxIdle(10);
	    poolConfig.setMinIdle(5);
	    poolConfig.setMaxTotal(20);
	    poolConfig.setMaxWait(Duration.ofSeconds( 30 ));
	    poolingBuilder.poolConfig( poolConfig );
	}

	builder.shutdownTimeout( Duration.ofMillis( 1000L ) );
}
Java

ClientOptions (Lettuce๋งŒ ํ•ด๋‹น)

LettuceClientConfiguration๋ฅผ ์ƒ์„ฑ์‹œ์— ClientOptions ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ LettuceClientConfiguration ์ธ์Šคํ„ด์Šค์— ์ ์šฉํ•œ๋‹ค.
ClientOptions ํด๋ž˜์Šค๋Š” Spring ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜๋Š” Redis ํด๋ผ์ด์–ธํŠธ์˜ ๋™์ž‘์„ ๊ตฌ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ๋ถ€๋ถ„์ด๋‹ค.
ํด๋ผ์ด์–ธํŠธ๊ฐ€ Redis ์„œ๋ฒ„์™€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๋ฐฉ์‹์—์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ, ๋ช…๋ น ์‹คํ–‰, ๋ณด์•ˆ ๋ฐ ์„ฑ๋Šฅ ์ตœ์ ํ™”์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.
๋‹ค์Œ์€ ClientOptions ํด๋ž˜์Šค์˜ ๊ฐ ํ•„๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์ด๋‹ค.

ํ•ญ๋ชฉ์„ค๋ช…๋””ํดํŠธ
autoReconnectํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ์ด ๋Š๊ธด ํ›„ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ์—ฐ๊ฒฐํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ๋‹ค. ํ™œ์„ฑํ™” ๋œ ๊ฒฝ์šฐ ๋„คํŠธ์›Œํฌ ๋ฌธ์ œ๋กœ ์ธํ•œ ์—ฐ๊ฒฐ ์ค‘๋‹จ ํ›„ ์ž๋™ ์žฌ์—ฐ๊ฒฐ ์‹œ๋„๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค.true
cancelCommandsOnReconnectFailure์žฌ์—ฐ๊ฒฐ ์‹œ๋„๊ฐ€ ์‹คํŒจํ–ˆ์„ ๋•Œ ๋ณด๋ฅ˜ ์ค‘์ธ ๋ชจ๋“  ๋ช…๋ น์„ ์ทจ์†Œํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์ด๋Š” ์žฌ์—ฐ๊ฒฐ ๊ณผ์ •์—์„œ ๋ช…๋ น์ด ๋ฌดํ•œํžˆ ๋Œ€๊ธฐํ•˜๋Š” ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.false
decodeBufferPolicy์‘๋‹ต ๋ฒ„ํผ๋ฅผ ์–ด๋–ป๊ฒŒ ๋””์ฝ”๋”ฉํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์ •์ฑ…์ด๋‹ค. ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๊ณผ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.ratio(3)
disconnectBehavior์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ์„ ๋•Œ ํด๋ผ์ด์–ธํŠธ ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค. ๋ช…๋ น์ด ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ์žฌ์‹œ๋„ํ•˜๊ฒŒ ํ•˜๋Š” ๋“ฑ์˜ ํ–‰๋™์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.DEFAULT
pingBeforeActivateConnection์ƒˆ ์—ฐ๊ฒฐ์ด ํ™œ์„ฑํ™”๋˜๊ธฐ ์ „์— PING ๋ช…๋ น์„ ๋ณด๋‚ด ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜์ง€ ์•Š๋Š” ์—ฐ๊ฒฐ์„ ๋ฏธ๋ฆฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.true
protocolVersion์‚ฌ์šฉํ•  Redis ํ”„๋กœํ† ์ฝœ ๋ฒ„์ „์„ ์ง€์ •ํ•œ๋‹ค. 
publishOnScheduler๋ช…๋ น์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•  ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์ •์˜ํ•œ๋‹ค. ์ด๋Š” ๋ช…๋ น ์ฒ˜๋ฆฌ์˜ ์„ฑ๋Šฅ๊ณผ ํšจ์œจ์„ฑ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ์ด ์˜ต์…˜์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋‹จ์ผ ํ˜น์€ ์†Œ์ˆ˜์˜ Redis ์—ฐ๊ฒฐ๋กœ ์ƒ๋‹นํ•œ ์–‘์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์‹œํ€€์Šค์—์„œ ๋‹จ์ผ ์Šค๋ ˆ๋“œ์™€ ๊ฐ™์€ ๋™์ž‘์œผ๋กœ ์ธํ•ด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์˜ต์…˜์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋ฐ์ดํ„ฐ/์™„๋ฃŒ ์‹ ํ˜ธ์— ๋Œ€ํ•ด ClientResources๋ฅผ ํ†ตํ•ด ๊ตฌ์„ฑ๋œ EventExecutorGroup์„ ์‚ฌ์šฉํ•œ๋‹ค.false
readOnlyCommands์ฝ๊ธฐ ์ „์šฉ ๋ช…๋ น์„ ํ—ˆ์šฉํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์ด๋Š” ์ฃผ๋กœ ํด๋Ÿฌ์Šคํ„ฐ ํ™˜๊ฒฝ์—์„œ ์Šฌ๋ ˆ์ด๋ธŒ ๋…ธ๋“œ์— ์ฝ๊ธฐ ๋ช…๋ น์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋œ๋‹ค. 
requestQueueSizeํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ด์ง€ ์•Š์€ ๋ช…๋ น์„ ๋Œ€๊ธฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ํ์˜ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์ด ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์ง€์—ฐ์ด๋‚˜ ์„œ๋ฒ„ ์ฒ˜๋ฆฌ ๋Šฅ๋ ฅ์„ ๊ณ ๋ คํ•œ ์œ ์—ฐํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.Integer.MAX_VALUE
scriptCharset์Šคํฌ๋ฆฝํŠธ ๋ช…๋ น์„ ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉํ•  ๋•Œ ์‚ฌ์šฉํ•  ๋ฌธ์ž ์ธ์ฝ”๋”ฉ์„ ์ง€์ •ํ•œ๋‹ค.UTF-8
socketOptions์†Œ์ผ“ ์—ฐ๊ฒฐ์— ์ ์šฉํ•  ์˜ต์…˜์„ ์„ค์ •ํ•œ๋‹ค. ํƒ€์ž„์•„์›ƒ, ๋ฒ„ํผ ํฌ๊ธฐ, KeepAlive๋“ฑ์˜ ์˜ต์…˜์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.AutoConfiguration์—์„œ ์„ค์ •ํ•ด์ค€๋‹ค.
sslOptionsSSL/TLS๋ฅผ ํ†ตํ•œ ๋ณด์•ˆ ์—ฐ๊ฒฐ ์„ค์ •์„ ์ •์˜ํ•œ๋‹ค. ํ‚ค ์ €์žฅ์†Œ, ํŠธ๋Ÿฌ์ŠคํŠธ ์ €์žฅ์†Œ, ์‚ฌ์šฉํ•  ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋“ฑ์„ ํฌํ•จํ•œ๋‹ค.AutoConfiguration์—์„œ ์„ค์ •ํ•ด์ค€๋‹ค.
suspendReconnectOnProtocolFailureํ”„๋กœํ† ์ฝœ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์—ฐ๊ฒฐ์ด ์‹คํŒจํ–ˆ์„ ๋•Œ ์žฌ์—ฐ๊ฒฐ์„ ์ผ์‹œ ์ค‘๋‹จํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ๋‹ค.false
timeoutOptions๋ช…๋ น ์‹คํ–‰ ๋ฐ ์ „์ฒด ์—ฐ๊ฒฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด timeout์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค์ •ํ•œ๋‹ค. 

decodeBufferPolicy 
1. ratio ์ •์ฑ…
   – ์ง‘๊ณ„ ๋ฒ„ํผ์˜ ์šฉ๋Ÿ‰๊ณผ ์‚ฌ์šฉ๋Ÿ‰์„ ๊ณ ๋ คํ•œ ๋น„์œจ ๊ธฐ๋ฐ˜์˜ ์ •์ฑ…์ด๋‹ค. ์‚ฌ์šฉ ๋น„์œจ์„ ๊ณ ๋ คํ•˜์—ฌ CPU ์‚ฌ์šฉ๋Ÿ‰๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ตœ์ ํ™” ํ•œ๋‹ค. ๊ฐ’์ด ๋†’์„ ์ˆ˜๋ก ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋Š˜์–ด๋‚œ๋‹ค. parameter๋กœ ์ „๋‹ฌ๋˜๋Š” bufferUsageRatio๋Š” ๋ฒ„ํผ ์‚ฌ์šฉ ๋น„์œจ์ด๋‹ค.
๊ฐ’์ด 1์ด๋ฉด 50%, ๊ฐ’์ด 2์ด๋ฉด 66%, ๊ฐ’์ด 3์ด๋ฉด 75% ์™€ ๊ฐ™์ด ๊ณ„์‚ฐ๋œ๋‹ค. 0์—์„œ 2^31 – 1 ์‚ฌ์ด์˜ ๊ฐ’์ด์–ด์•ผ ํ•˜๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ 50%์—์„œ 90%๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” 1์—์„œ 10์‚ฌ์ด์˜ ๊ฐ’์„ ์„ค์ •ํ•œ๋‹ค.

2. always ์ •์ฑ…
    – ๊ฐ ๋””์ฝ”๋”ฉ ๋‹จ๊ณ„ ํ›„์— ์ฝ์€ ๋ฐ”์ดํŠธ๋ฅผ ์‚ญ์ œํ•˜๋Š” ์ •์ฑ…์ด๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ์ด ๊ฐ€์žฅ ๋†’์€ ์ „๋žต์ด์ง€๋งŒ CPU ๋ถ€๋‹ด๋„ ํ•จ๊ป˜ ์ปค์ง„๋‹ค.

3. alwaysSome ์ •์ฑ…
    – ๊ฐ ๋””์ฝ”๋”ฉ ๋‹จ๊ณ„ ํ›„์— ์ผ๋ถ€ ์ฝ๊ธฐ ๋ฐ”์ดํŠธ๋ฅผ ์‚ญ์ œํ•˜๋Š” ์ •์ฑ…์ด๋‹ค. ๋‚ด๋ถ€ ๊ตฌํ˜„์— ๋”ฐ๋ผ ์ฝ๊ธฐ ๋ฐ”์ดํŠธ์˜ ์ผ๋ถ€ ๋˜๋Š” ์ „๋ถ€๋ฅผ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์ „ํ˜€ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  ์ž ์žฌ์ ์œผ๋กœ ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„๋ฅผ ๊ฐ์ˆ˜ํ•˜๋ฉด์„œ ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๋Œ€์—ญํญ ์†Œ๋น„๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

disconnectBehavior
1. DEFAULT
    – autoReconnect ์˜ต์…˜์ด true์ธ ๊ฒฝ์šฐ ๋ช…๋ น์„ ์ˆ˜๋ฝํ•˜๊ณ , autoReconnect ์˜ต์…˜์ด false์ธ ๊ฒฝ์šฐ ๋ช…๋ น์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค.

2. ACCEPT_COMMANDS
     – ์—ฐ๊ฒฐ์ด ๋Š๊ธด ์ƒํƒœ์—์„œ๋„ ๋ช…๋ น์„ ์ˆ˜๋ฝํ•œ๋‹ค.

3. REJECT_COMMANDS
     – ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ ์ƒํƒœ์—์„œ๋Š” ๋ช…๋ น์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค.

RedisConnectionFactory ์ƒ์„ฑ (LettuceConnectionFactory)

์ง€๊ธˆ๊นŒ์ง€ ์œ„์—์„œ ์‚ดํŽด๋ณธ ClientResources, LettuceClientConfiguration, ConnectionDetails ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด์„œ RedisConnectionFactory๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
์ตœ์ข…์ ์œผ๋กœ LettuceConnectionFactory์—๋Š” LettuceClientConfiguration๊ณผ RedisConfiguration ์ธ์Šคํ„ด์Šค๊ฐ€ ์ ์šฉ์ด ๋œ๋‹ค.
RedisConfiguration ์ธ์Šคํ„ด์Šค๋Š” application.yml (.properties) ์„ค์ •์˜ ๋‹ค์Œ ํ•ญ๋ชฉ์— ๋”ฐ๋ผ์„œ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฒฐ์ •๋œ๋‹ค.

ํ”„๋กœํผํ‹ฐRedisConfiguration ์ธ์Šคํ„ด์Šค์„ค๋ช…
spring.data.redis.sentinelRedisSentinelConfigurationSentinel ๊ตฌ์„ฑ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์ ‘์† ์„ค์ • ์ •๋ณด
spring.data.redis.clusterRedisClusterConfigurationCluster ๊ตฌ์„ฑ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์ ‘์† ์„ค์ • ์ •๋ณด
spring.data.redis.host spring.data.redis.portRedisStandaloneConfiguration๋‹จ์ผ ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์ ‘์† ์„ค์ • ์ •๋ณด

spring.data.redis.sentinel, spring.data.redis.cluster๊ฐ€ ๋ชจ๋‘ ์„ค์ •๋œ ๊ฒฝ์šฐ์—๋Š” spring.data.redis.sentinel ์„ค์ •์ด ์ ์šฉ๋œ๋‹ค.
์ •๋ฆฌํ•˜์ž๋ฉด RedisConnectionFactory(LettuceConnectionFactory) ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
spring data redis RedisConnectionFactory ์ƒ์„ฑ ๊ณผ์ •

RedisTemplate Serializers

Spring Data Redis์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ํƒ€์ž…๊ณผ raw ๋ฐ์ดํ„ฐ ๊ฐ„์˜ ๋ณ€ํ™˜์€ org.springframework.data.redis.serializer ํŒจํ‚ค์ง€์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ด ํŒจํ‚ค์ง€์—๋Š” ์ง๋ ฌํ™” ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ์ง๋ ฌํ™”๊ธฐ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

  • RedisSerializer๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์–‘๋ฐฉํ–ฅ ์ง๋ ฌํ™”๊ธฐ
  • Element๋ฅผ ์ฝ๊ณ  ์“ฐ๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” RedisElementReader ๋ฐ RedisElementWriter
    ๋‘ ์ง๋ ฌํ™”๊ธฐ์˜ ์ฐจ์ด์ ์€ RedisSerializer๋Š” byte[]๋กœ ์ง๋ ฌํ™”ํ•˜๋Š” ๋ฐ˜๋ฉด, Reader์™€ Writer๋Š” ByteBuffer๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์œ„ ๋‘ ๊ฐ€์ง€ ์œ ํ˜• ์ด์™ธ์—๋„ ์—ฌ๋Ÿฌ ์ง๋ ฌํ™”๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • RedisCache์™€ RedisTemplate์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” JdkSerializationRedisSerializer
  • StringRedisSerializer
  • Spring OXM ์ง€์›์„ ํ†ตํ•ด ๊ฐ์ฒด/XML ๋งคํ•‘์„ ์œ„ํ•œ OxmSerializer
  • JSON ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด Jacson2JsonRedisSerializer ๋˜๋Š” GenericJackson2JsonRedisSerializer

์ €์žฅ ํ˜•์‹์€ ๊ฐ’์œผ๋กœ๋งŒ ์ œํ•œ๋˜์ง€ ์•Š๊ณ  ํ‚ค, ๊ฐ’ ๋˜๋Š” ํ•ด์‹œ์— ์ œํ•œ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ RedisCache ๋ฐ RedisTemplate์€ Java ๋„ค์ดํ‹ฐ๋ธŒ ์ง๋ ฌํ™”๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ๋œ๋‹ค. Java ๋„ค์ดํ‹ฐ๋ธŒ ์ง๋ ฌํ™”๋Š” ํ™•์ธ๋˜์ง€ ์•Š์€ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ์ทจ์•ฝํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ํด๋ž˜์Šค๋ฅผ ์•…์šฉํ•˜๋Š” ํŽ˜์ด๋กœ๋“œ๋กœ ์ธํ•ด ์›๊ฒฉ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ๋‹ค. ์กฐ์ž‘๋œ ์ž…๋ ฅ์œผ๋กœ ์ธํ•ด ์—ญ์ง๋ ฌํ™” ๋‹จ๊ณ„์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์›ํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ํ™˜๊ฒฝ์—์„œ๋Š” ์ง๋ ฌํ™”๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค๋ฅธ ๋ฉ”์‹œ์ง€ ํ˜•์‹(JSON๊ณผ ๊ฐ™์€)์„ ๋Œ€์‹  ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ฐ•๋ ฅํžˆ ๊ถŒ์žฅํ•œ๋‹ค๊ณ  Spring ๋ฌธ์„œ์—์„œ๋Š” ๋งํ•œ๋‹ค.
๋‹ค์Œ ์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” Redis์˜ ํ‚ค์™€ ๊ฐ’์— ๋Œ€ํ•œ ์ง๋ ฌํ™”๊ธฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค.

// lettuceConnectionFactory ์ธ์Šคํ„ด์Šค๋Š” spring data redis auto configuration์— ์˜ํ•ด์„œ ์ž๋™ ์ƒ์„ฑ๋จ
@Bean
public RedisTemplate<String, Object> redisTemplate( LettuceConnectionFactory lettuceConnectionFactory ) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory( lettuceConnectionFactory );

    // set key serializer
    // template.setKeySerializer( new StringRedisSerializer(StandardCharsets.UTF_8) ); ์™€ ๋™์ผํ•จ
    template.setKeySerializer( RedisSerializer.string() );
    template.setHashKeySerializer( RedisSerializer.string() );

    // set value serializer
    // template.setDefaultSerializer( new GenericJackson2JsonRedisSerializer() ); ์™€ ๋™์ผํ•จ
    template.setDefaultSerializer( RedisSerializer.json() );
    template.setValueSerializer( RedisSerializer.json() );
    template.setHashValueSerializer( RedisSerializer.json() );

    return template;
}
Java

Serializer๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด Auto Configuration์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” RedisTemplate ๋Œ€์‹ ์— ์ง์ ‘ ๋นˆ์„ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.
์œ„ ์ฝ”๋“œ๋Š”

  • ํ‚ค์™€ ํ•ด์‹œํ‚ค์— ๋Œ€ํ•œ Serializer๋กœ StringRedisSerializer๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค.
  • ๊ฐ’๊ณผ ํ•ด์‹œ๊ฐ’์— ๋Œ€ํ•œ Serializer๋กœ GenericJackson2JsonRedisSerializer๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค.

RedisTemplate ์‚ฌ์šฉ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

์ง€๊ธˆ๊นŒ์ง€ Spring Redis Auto Configuration ๋ฐ RedisTemplate์— Serializer๋ฅผ ์ ์šฉํ•œ ์„ค์ •์„ ํ† ๋Œ€๋กœ ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์•˜๋‹ค. UUID ํ˜•์‹์˜ ํ‚ค์— Person ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๋Š” ์ฝ”๋“œ๋‹ค.

package com.example.spring.redis.model;

import lombok.Builder;
import org.springframework.data.annotation.Id;

import java.util.UUID;

@Builder
public record Person(@Id UUID id,
                     String personName,
                     Integer personAge,
                     String personNation,
                     String comment) {
    public Person( UUID id, String personName, Integer personAge, String personNation, String comment ) {
        this.id = (id == null) ? UUID.randomUUID() : id;
        this.personName = personName;
        this.personAge = personAge;
        this.personNation = personNation;
        this.comment = comment;
    }
}
Java

Redis ์—ฐ๊ฒฐ์„ ์œ„ํ•œ Configuration

@Configuration
@RequiredArgsConstructor
public class RedisConfiguration {

    @Bean
    public ClientResourcesBuilderCustomizer clientResourceCustomize() {
        return builder -> {
            builder.reconnectDelay( Delay.constant( Duration.ofSeconds(50) ) );
            builder.ioThreadPoolSize( 4 );
            builder.commandLatencyRecorder( CommandLatencyRecorder.disabled() );
            builder.commandLatencyPublisherOptions( DefaultEventPublisherOptions.disabled() );
        };
    }

    @Bean
    public LettuceClientConfigurationBuilderCustomizer lettucyClientConfigCustomize() {
        return builder -> {
            if ( builder instanceof
                    LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder poolingBuilder ) {
                // Pool configuration
                GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
                poolConfig.setMaxIdle(10);
                poolConfig.setMinIdle(5);
                poolConfig.setMaxTotal(20);
                poolConfig.setMaxWait(Duration.ofSeconds( 30 ));
                poolingBuilder.poolConfig( poolConfig );
            }

            builder.shutdownTimeout( Duration.ofMillis( 1000L ) );

        };
    }

    // lettuceConnectionFactory ์ธ์Šคํ„ด์Šค๋Š” spring data redis auto configuration์— ์˜ํ•ด์„œ ์ž๋™ ์ƒ์„ฑ๋จ
    @Bean
    public RedisTemplate<String, Object> redisTemplate( LettuceConnectionFactory lettuceConnectionFactory ) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory( lettuceConnectionFactory );

        // set key serializer
        // template.setKeySerializer( new StringRedisSerializer(StandardCharsets.UTF_8) ); ์™€ ๋™์ผํ•จ
        template.setKeySerializer( RedisSerializer.string() );
        template.setHashKeySerializer( RedisSerializer.string() );

        // set value serializer
        // template.setDefaultSerializer( new GenericJackson2JsonRedisSerializer() ); ์™€ ๋™์ผํ•จ
        template.setDefaultSerializer( RedisSerializer.json() );
        template.setValueSerializer( RedisSerializer.json() );
        template.setHashValueSerializer( RedisSerializer.json() );

        return template;
    }
}
Java

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

@ExtendWith( SpringExtension.class )
@ContextConfiguration( classes = { RedisConfiguration.class } )
@DataRedisTest
@EnableAutoConfiguration
public class RedisTest {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    final UUID id = UUID.randomUUID();

    @Test
    @DisplayName( "redis insert test" )
    void insert_person_redis_test() {
        Person person = Person.builder()
                .id( id )
                .personName( "test-name" )
                .personAge( 100 )
                .personNation( "korea" )
                .comment( "first commit data" )
                .build();

        redisTemplate.opsForValue().set( id.toString(), person );

        // find data
        Object object = redisTemplate.opsForValue().get( id.toString() );
        Assertions.assertThat( object ).isInstanceOf( Person.class );
        Person find = ( Person ) object;
        Assertions.assertThat( find.id().toString() ).isEqualTo( id.toString() );
    }
}
Java

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ Redis์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด JSON ํ˜•์‹์œผ๋กœ ์ €์žฅ๋œ ๊ฒƒ์„ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
spring data redis ๋ฐ์ดํ„ฐ ์กฐํšŒ
spring data redis ๋ฐ์ดํ„ฐ ์กฐํšŒ ๊ฒฐ๊ณผ
Spring Data Redis๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์—ฐ๊ฒฐ ์„ค์ •์„ ์œ„ํ•ด์„œ ์ˆ˜ํ–‰๋˜๋Š” Redis Auto Configuration์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์•˜๋‹ค.
application.yml (.properties)์˜ spring.data.redis ์„ค์ •๊ณผ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•˜๋Š” ClientResources, ClientConfiguration์— ๋Œ€ํ•œ customize ๋นˆ๊ณผ RedisTemplate์— ์ ์šฉํ•  Serializer๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์†์‰ฝ๊ฒŒ Redis๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋.


์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” GITLAB ๋งํฌ ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.