Redis sorted set?
์ด์ ํ๋ก์ ํธ์์ ๊ฒ์ดํธ์จ์ด ๋๊ธฐ์ด์ ๊ตฌํํ ๋ Redis์ Sorted Set์ ์ด์ฉํ์๋ค.
API ์์ฒญ์ด ๋ค์ด์์ ๋ ํ์ฌ ๊ฐ์ฉ ์ธ์ ์๋ฅผ ํ์
ํ๊ณ ์๋ง๋ queue์ ์ ์ฌํ๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ์๋ค.
์ดํ (์ฌ์ง์๋ 30์ด์ง๋ง) 3์ด์ ํ๋ฒ์ฉ ๋นํ์ฑ ์ ์ ๋ฅผ ํ์ธํ ๋ค active queue์์ ์ ๊ฑฐํ๊ณ ๋๊ธฐ ํ์์ ์ฎ๊ฒจ์ฃผ๋ ๋ฐฉ์์ผ๋ก ์ค๊ณํ์๋ค.
Sorted Set ํน์ง
- Redis์ ๋ฐ์ดํฐ ๊ตฌ์กฐ
- ์ค๋ณต๋์ง ์๋ ๊ฐ(Unique value)๊ณผ ํด๋น ๊ฐ์ ํ ๋น๋ ์ ์(score)๋ฅผ ํจ๊ป ์ ์ฅ
- ์ ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์ ์ ๋ ฌ๋ ์ปฌ๋ ์
- ๋์ผํ socre๋ฅผ ๊ฐ๋ ๊ฒฝ์ฐ ์ฌ์ ์์ผ๋ก ์ ๋ ฌ
์ฌ๊ธฐ์ ๊ฐ์ด ์ค๋ณต๋์ง ์๋๋ค๋ ์ ๊ณผ ์ ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๋ค๋ ์ ์์ sorted set์ ์ ํํ๋ค.
์ฌ๊ธฐ์ unique value๋ ๊ฐ ์ ์ ์ id, score๋ ์ ์ ๊ฐ ์์ฒญ์ ๋ณด๋ธ ์๊ฐ์ผ๋ก ์ง์ ํ์ฌ ์ ์ฅํ์๋ค. ๋ง์ฝ ๋๊ธฐํ์ ์๋ ์ํ์์ ์์ฒญ์ ๋ ๋ณด๋ด๊ฒ ๋๋ค๋ฉด ์์๊ฐ ๋ฐ๋ฆฌ๊ฒ ๋๋ค..~~ ๋ง์ฐฌ๊ฐ์ง๋ก ํ์ฑ ํ์ ์๋ ์ ์ ๊ฐ ์ผ์ ์๊ฐ๋์ ์์ฒญ์ด ์์ด ์ ์๊ฐ ๊ฐฑ์ ๋์ง ์์ผ๋ฉด ์ ๊ฑฐ ๋์์ด ๋์ด ๋ค์ ์์ฒญํ๋ฉด ๋๊ธฐํด์ผํ๋ค.
๋๊ธฐ์ด ๊ตฌํ ๋ฐฉ์์๋ ๋ ๊ฐ์ง ๋ฐฉ์์ด ์์๋ค
- ์ํ ์ฐฝ๊ตฌ ๋ฐฉ์
- ๋์ด๊ณต์ ๋ฐฉ์
์ํ์ฐฝ๊ตฌ ๋ฐฉ์์ ๋ง ๊ทธ๋๋ก ์ํ ์ฐฝ๊ตฌ์ฒ๋ผ ๋๊ธฐ์ด์ ๋ฑ๋ก๋ ์์๋๋ก ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ์์ด๋ค. ์ฌ์ฉ์๋ค์ด ๋๊ธฐํ ๋ ํ์ฌ ๋๊ธฐ ์์๋ฅผ ์ ์ ์๋ค.
๋์ด๊ณต์ ๋ฐฉ์์ ์ผ์ ์๊ฐ ์ดํ์ ์ผ์ ์ฌ์ฉ์์๊ฒ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ์์ด๋ค. ์ฌ์ฉ์์๊ฒ ์์ธก ๊ฐ๋ฅํ ๋๊ธฐ์๊ฐ์ ์ ๊ณตํ๋ค.
๋๋ ์ํ์ฐฝ๊ตฌ ๋ฐฉ์์ ์ ํํ์๋๋ฐ ์ฒ๋ฆฌ ๊ฐ๋ฅํ ์๋น์ค๊ฐ ์์ผ๋ฉด ์ฆ์ ์์ฒญ์ ํ ๋นํ ์ ์๊ณ , ๋์ด๊ณต์ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ๊ฒฐ๊ตญ ์ฌ์ฉ์๊ฐ ์ ์ ๋์ด๋ ์๋น์ค์ ๋ถํ๋ฅผ ์ค ์๋ ์์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
- priority queues ์ฐ์ ์์ ๋๊ธฐ์ด
- low-latency leadrboards ์ ์ง์ฐ ๋ฆฌ๋๋ณด๋
- secondary indexing ๋ณด์กฐ ์ธ๋ฑ์ฑ
- ๋๊ท๋ชจ ์จ๋ผ์ธ ๊ฒ์์์ ๊ฐ์ฅ ๋์ ์ ์์ ์ ๋ ฌ๋ ๋ชฉ๋ก ์ ์ง (๋ฆฌ๋๋ณด๋)
- ์๋ ์ ํ๊ธฐ - ์ ๋ ฌ๋ set์ ์ฌ์ฉํ์ฌ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์๋ ์ ํ๊ธฐ ๋น๋ โ ๊ณผ๋ํ API ์์ฒญ ๋ฐฉ์ง
public Mono<RegisterUserResponse> registerUser(String userId) {
return reactiveRedisTemplate.opsForZSet().size(USER_QUEUE_ACTIVE_KEY)
.flatMap(activeUsers -> {
if (activeUsers < MAX_ACTIVE_USERS) {
return reactiveRedisTemplate.opsForZSet()
.add(USER_QUEUE_ACTIVE_KEY, userId, getCurrentTime())
.thenReturn(new RegisterUserResponse(activeUsers + 1));
}
return reactiveRedisTemplate.opsForZSet()
.add(USER_QUEUE_WAIT_KEY, userId, getCurrentTime())
.flatMap(success ->
reactiveRedisTemplate.opsForZSet().rank(USER_QUEUE_WAIT_KEY, userId)
)
.map(rank -> new RegisterUserResponse(rank + 1));
});
~~์๋น์ค ๊ตฌํ ํ ์ฒ๋ฆฌ๋์ ํ ์คํธํ์๋๋ฐโฆ active queue์ ์ ์ฌ๋ ๋๋ 100/sec ์ ๋์ ์ฒ๋ฆฌ๋์ด๋ผ๋ฉด, ๋๊ธฐํ์ ๋ค์ด๊ฐ ๋ ๊ฑฐ์ 900/sec ์ด์์ ์ฒ๋ฆฌ๋์ด ๋์๋คโฆ ์ ์ด๋ ๊ฒ ์ฐจ์ด๊ฐ ๋๋์ง ์์ง ์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ๋คโฆ ใ ~~