Redis ์Šค์บ” ๋•Œ๋ ค์„œ ์„ฑ๋Šฅ ์ด์Šˆ ๋ฐœ์ƒํ•  ์ฐ

2023. 6. 17. 19:27ใ†๐Ÿ“๊ธฐ๋ก

๊ฐœ์š”

Redis ์‚ฌ์šฉํ•  ๋•Œ ์‚ฝ์งˆํ•œ ์ฐ ํ’€์–ด๋ด…๋‹ˆ๋‹ค.

์ด ์‚ฝ์งˆ์˜ ์›์ธ์€ 2๊ฐ€์ง€ ์ •๋„๋กœ ์ถ•์•ฝํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, 1) Redis ๋Š” ์‹ฑ๊ธ€์Šค๋ ˆ๋“œ ๊ตฌ์กฐ๋ž€ ๊ฑธ ๊ฐ„๊ณผํ•œ ์ , 2) Redis์— scan ๋ช…๋ น์–ด๋ฅผ ๋‚ ๋ฆฌ๋ฉด ์–ด๋–ค ์ผ์ด ๋ฒŒ์–ด์ง€๋Š”์ง€ ๊ฐ„๊ณผํ•œ ์ ์ž…๋‹ˆ๋‹ค.

 

ํ™˜๊ฒฝ 

- Java 11

- Redis Reactive 2.7

 

Redis ์˜ ํŠน์ง•

์šฐ์„  Redis ๋Š” ์‹ฑ๊ธ€์Šค๋ ˆ๋“œ ๊ตฌ์กฐ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์š”์ฒญ๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํ•˜๋‚˜์˜ ์ž‘์—…์—์„œ ๊ธด ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฉด ๊ทธ ๋’ค์˜ ์ž‘์—…์€ blocking ๋˜์–ด ์‹œ์Šคํ…œ ์ „์ฒด์ ์œผ๋กœ ์„ฑ๋Šฅ์ด ๋Š๋ ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ‘๋ชฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ฃ . 

 

๊ทธ๋Ÿผ Redis ์˜ ์–ด๋–ค ์ž‘์—…์ด ๊ธด ์‹œ๊ฐ„์„ ์†Œ์š”ํ•˜๋Š” ๊ฑธ๊นŒ์š”? ์•„๋ž˜ ์ด๋ฏธ์ง€๋ฅผ ๋ณด์‹œ๋ฉด ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์ธ Redis ๋Š” ๋น„๊ต์  ๋น ๋ฅธ ์†๋„๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ๋น ๋ฅธ Redis ์˜ ์„ฑ๋Šฅ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๋Š” ๋ช…๋ น์–ด๊ฐ€ ๋ช‡๊ฐ€์ง€ ์žˆ๋Š”๋ฐ, ๋Œ€ํ‘œ์ ์œผ๋กœ scan ์ด ์žˆ์Šต๋‹ˆ๋‹ค. scan ๋ช…๋ น์–ด๋Š” Redis์—์„œ ํŠน์ • ํŒจํ„ด์„ ๊ฐ–๋Š” key๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋Š” scan() ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ด "KEY" ๋ผ๋Š” ํ‚ค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ช…๋ น์–ด์ž…๋‹ˆ๋‹ค.  ํ•ด๋‹น ํ‚ค์— ํ•ด๋‹น๋˜๋Š” ๊ฐ’์„ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ณ‘๋ชฉ ๋ฐœ์ƒ ์ง€์ 

public List<Object> sample() {
    return redisOperations.opsForSet()
            .scan("KEY")
            .collectList()
            .block();
}

ํ•˜์ง€๋งŒ Scan ๋ช…๋ น์–ด๋Š” Redis ์ „์ฒด์˜ ํ‚ค ๊ฐ’์„ ํ•˜๋‚˜์”ฉ ์กฐํšŒํ•˜๋ฏ€๋กœ  O(N) ์˜ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ ธ ์„ฑ๋Šฅ ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰ key-value ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ธ Redis ์— ์‹œ๊ฐ„๋ณต์žก๋„ O(1)์ด ์•„๋‹Œ O(N) ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์ฃ . Redis ์— ์ €์žฅ๋œ key ์ˆ˜๊ฐ€ ์ ์„ ๋• ๊ดœ์ฐฎ๊ฒ ์ง€๋งŒ, ์ €์žฅ๋˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ ์ฐจ ๋Š˜์–ด๋‚  ์ˆ˜๋ก ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿด ๊ฒฝ์šฐ์—” scan() ์ด ์•„๋‹Œ members() ๋‚˜ isMember() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹œ๊ฐ„๋ณต์žก๋„ O(1)๋กœ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.  members ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•œ ๋ฒˆ์˜ ์กฐํšŒ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ณ , ๋น ๋ฅธ ์†๋„๋กœ ์กฐํšŒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. 

์‹ค์ œ๋กœ ํ•€ํฌ์ธํŠธ์—์„œ ๋ณ‘๋ชฉ์ง€์ ์„ ์‚ดํŽด๋ณด๋‹ˆ, scan() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๋ถ€๋ถ„์—์„œ ์‘๋‹ต ์‹œ๊ฐ„์ด ๋น„์•ฝ์ ์œผ๋กœ ์˜ค๋ž˜๊ฑธ๋ฆฐ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค ๐Ÿฅฒ

 

๊ฐœ์„ ๋œ ์ฝ”๋“œ

์œ„ ์ฝ”๋“œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ๋ฐ”๊พธ์–ด ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

// old
public Set<Object> sample() {
    return redisOperations.opsForSet()
            .scan("KEY") // ๋ณ‘๋ชฉ ์ง€์ 
            .collectList()
            .block();
}

// improved
public Set<Object> sample() {
    return redisOperations.opsForSet()
            .members("KEY")
            .collect(Collectors.toSet())
            .block();
}

์ฝ”๋“œ์ƒ ์‹œ๊ฐ„ ์ธก์ •์˜ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. 

scan() ๊ณผ members() ๋ฉ”์„œ๋“œ์˜ ์‹œ๊ฐ„ ์ฐจ์ด๊ฐ€ ๋ฌด๋ ค 20๋ฐฐ ๊ฐ€๊นŒ์ด ๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

๋งˆ๋ฌด๋ฆฌ

Redis ์˜ ์‹ฑ๊ธ€์Šค๋ ˆ๋“œ ํŠน์„ฑ๊ณผ scan ๋ช…๋ น์–ด๋ฅผ ๋‚ ๋ฆฌ๋ฉด O(N) ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ๊ฑธ๋ฆฌ๋Š” ์ ์„ ์žŠ์€ ์ฑ„ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ฐœ์ƒํ•œ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค. ํ•€ํฌ์ธํŠธ์—์„œ ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ์•Œ๋ ค์ฃผ์ง€ ์•Š์•˜๋”๋ผ๋ฉด ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜์น  ๋ป”ํ•œ ๋‚ด์šฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

์‚ฌ์‹ค ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•œ ๋‚ด์šฉ์ด๋ผ ๊ธ€๋กœ ์จ๋„ ๋˜๋‚˜ ์‹ถ์—ˆ์ง€๋งŒ, ๋‹น์—ฐํ•œ ์ผ๋„ ๊ฐ„๊ณผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ๋ฐ˜์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ผ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๋ก ์€ ์ œ๋Œ€๋กœ ์•Œ๊ณ  ์“ฐ์ž!