did_story
[Redis] Redis๋ฅผ ํ์ฉํ ๋ฉํ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ตฌ์กฐ ์ค๊ณ๊ธฐ ๋ณธ๋ฌธ
[Redis] Redis๋ฅผ ํ์ฉํ ๋ฉํ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ตฌ์กฐ ์ค๊ณ๊ธฐ
์ด์ ์์ 2025. 8. 29. 15:591. ๋ฐ๋จ: ๋ถ์์ ํ ๋ฉํ๋ฐ์ดํฐ ์ฒ๋ฆฌ
๋งํฌ ์ ์ฅ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๋ ๊ณผ์ ์์, ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ก์ง์ ๋ฌธ์ ๊ฐ ์๋ค๋ ์ฌ์ค์ ๋ฐ๊ฒฌํ๋ค.
ํ ๋ฒ์ ์์ฒญ๋น ํ๊ท 700ms์ ์๊ฐ์ด ์์๋์๊ณ , ๋์์ ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ์์ฒญ์ ๋ณด๋์ ๋ ์ผ๋ถ๋ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋์์ง๋ง, ์ผ๋ถ๋ URL๋ง ์ ์ฅ๋๊ฑฐ๋ ์์ ์ ์ฅ์ด ๋์ง ์๋ ์ํฉ์ด ๋ฐ์ํ๋ค.
์ฆ, ๋์ผํ API ํธ์ถ์์๋ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง๋ ๋ถ์์ ์ฑ์ด ์์๊ณ , ์ด ๋ฌธ์ ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ง์ ์ ์ธ ์
์ํฅ์ ๋ผ์น ๊ฒ์ด๋ผ ์์ํ๋ค. (์ฝ๋๋ฅผ ํ์คํ ์๋ชป ์งฐ๋ค..)
2. ํด๊ฒฐ์ฑ ์ ์ฐพ๋ค: Redis๋ฅผ ๋ ์ฌ๋ฆฌ๋ค
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ๋ฌ ๋ฐฉ์์ ๊ณ ๋ฏผํ๋ ์ค, ๊ณผ๊ฑฐ ์ฑํ ์๋ฒ๋ฅผ ๊ตฌํํ ๋ ์ฌ์ฉํ๋ Redis๊ฐ ๋ ์ฌ๋๋ค.
Redis๋ ๋จ์ํ ์บ์ ์๋ฒ๋ฅผ ๋์ด์ ์ธ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ์ ๋น ๋ฅธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ, ๋ค์ํ ์๋ฃ๊ตฌ์กฐ ์ง์, TTL ๊ธฐ๋ฐ ์๋ ๋ง๋ฃ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
ํนํ, “๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ ๋ฉํ๋ฐ์ดํฐ์ ์ํ์ ๊ฒฐ๊ณผ๋ฅผ ์์๋ก ์ ์ฅํ๋ ๊ณต๊ฐ”์ด ํ์ํ๋ ๋ด ์ํฉ๊ณผ Redis์ ํน์ฑ์ด ์ ๋ง์๋จ์ด์ก๋ค.
3. ์ํคํ ์ฒ ์ค๊ณ: Queue + Status + Cache
Redis๋ฅผ ๋์ ํ๋ฉด์ ์ ์ฒด ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ์ด ์ค๊ณํ๋ค.
- Request Queue
ํด๋ผ์ด์ธํธ๊ฐ URL์ ์ ์ถํ๋ฉด, ์๋ฒ๋ requestId๋ฅผ ๋ฐ๊ธํ ๋ค Redis Queue(List ๋๋ Stream)์ ๋ฑ๋กํ๋ค.public Map<String, String> enqueue(MetadataRequestDto req) throws JsonProcessingException { Map<String, String> job = Map.of("requestId", req.getId(), "url", req.getUrl()); redisTemplate.opsForList().leftPush("metadata:queue", objectMapper.writeValueAsString(job)); return Map.of("requestId", requestId); } - Worker/Processor
๋ณ๋์ ์์ปค๊ฐ Queue์์ ์์ฒญ์ ๊บผ๋ด ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ค.@Scheduled(fixedDelay = 1000) public void processQueueBatchAsync() { // batchSize๋ ์ ๋นํ.. for (int i = 0; i < batchSize; i++) { String jobJson = redisTemplate.opsForList().rightPop("metadata:queue"); if (jobJson == null) break; asyncProcessor.processJobAsync(jobJson); } } - Result Cache (String/JSON)
์ต์ข ๋ฉํ๋ฐ์ดํฐ ๊ฒฐ๊ณผ๋ฅผ JSON ํํ๋ก ์ ์ฅํ๋ค. ์ด ์ญ์ TTL์ ์ค์ ํ์ฌ ์ผ์ ์๊ฐ์ด ์ง๋๋ฉด ์๋์ผ๋ก ์ญ์ ๋๋ค.@Async public CompletableFuture<Object> processJobAsync(String jobJson) { try { Map<String, String> job = objectMapper.readValue(jobJson, new TypeReference<>() {}); String requestId = job.get("requestId"); String url = job.get("url"); return processor.fetchMetadata(url) .toFuture() .thenApplyAsync(metadata -> { try { String resultJson = objectMapper.writeValueAsString(metadata); redisTemplate.opsForValue().set("metadata_result:" + requestId, resultJson, ...); } catch (Exception e) { log.error(" ๋ฉํ๋ฐ์ดํฐ JSON ์ง๋ ฌํ ์คํจ", e); } return null; }) .exceptionally(e -> { log.error(" Async ๋ฉํ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์คํจ", e); return null; }); } catch (Exception e) { log.error(" Async ๋ฉํ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์คํจ", e); } return CompletableFuture.completedFuture(null); } - Status ๋ฐํ (Hash)
๊ฐ requestId์ ์ํ(pending, done)๋ฅผ Hash ๊ตฌ์กฐ๋ก ๋ฐํํ๋ค.public Map<String, Object> getStatus(String requestId) throws JsonProcessingException { String resultJson = redisTemplate.opsForValue().get("metadata_result:" + requestId); if (resultJson == null) { return Map.of("status", "pending"); } MetadataResponseDto result = objectMapper.readValue(resultJson, MetadataResponseDto.class); return Map.of("status", "done", "data", result); } - ํด๋ผ์ด์ธํธ ํด๋ง
ํด๋ผ์ด์ธํธ๋ requestId๋ฅผ ์ฌ์ฉํด ์ํ์ ๊ฒฐ๊ณผ๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์กฐํํ๋ค. ์๋ฃ๋๋ฉด ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ UI์ ๋ฐ์ํ๋ค.
์ด ๊ตฌ์กฐ ๋๋ถ์, ์์ฒญ์ ์ฆ์ ์๋ตํ ์ ์๊ณ , ์ค์ ๋ฌด๊ฑฐ์ด ๋ฉํ๋ฐ์ดํฐ ํ์ฑ ๋ก์ง์ ์์ปค๊ฐ ๋ค์์ ์ฒ๋ฆฌํ๊ฒ ๋์๋ค.
4. ์ด์ ์ ๊ณ ๋ คํ ๋ถ๋ถ
- ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ: Redis์ eviction ์ ์ฑ ๋๋ฌธ์ ํ๋ ์ํ ๋ฐ์ดํฐ๊ฐ ๋ ์๊ฐ์ง ์๋๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ ๋ฅผ ํ๋ณดํด์ผํ๋ค.
- ๋ฉฑ๋ฑ์ฑ: ๊ฐ์ requestId๊ฐ ์ค๋ณต ์ฒ๋ฆฌ๋์ง ์๋๋ก Key๊ฐ์ UUID๋ก ์ฒ๋ฆฌํ๋ค.
- ๋ชจ๋ํฐ๋ง: ์์ฒญ ์ฒ๋ฆฌ๋, ํ๊ท ์ง์ฐ ์๊ฐ, ์คํจ์จ ๋ฑ์ ์งํ๋ก ์์งํด ์ด์ ์ํฉ์ ๊ฐ์ํ๋ฅผ ํ์๋ค (๊ทธ๋ผํ๋, ํ๋ก๋ฉํ ์ฐ์ค ์ฌ์ฉ).
5. ๊ฒฐ๋ก
Redis๋ ๋จ์ํ “์บ์ ์๋ฒ”๋ผ๋ ์ด๋ฏธ์ง๋ฅผ ๋์ด์, ๋น๋๊ธฐ ์์ ํ + ์ํ ์ ์ฅ์ + ์์ ์บ์ ์ญํ ์ ๋์์ ์ํํ ์ ์๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ค. Redis ๊ธฐ๋ฐ ์ํคํ ์ฒ๋ฅผ ์ ์ฉํ ํ, ๋ฉํ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์์ฒญ์ ํ๊ท ์๋ต ์๊ฐ์ด 700ms์์ 400ms๋ก ์ฝ 43% ๋จ์ถ๋์๋ค. ๋จ์ํ ์์ ์ฑ๋ฟ๋ง ์๋๋ผ ์ฑ๋ฅ ๊ฐ์ ํจ๊ณผ๋ ํจ๊ป ์ป์ ์ ์์๋ค.
์์ผ๋ก๋ Redis Streams, Consumer Group, Dead Letter Queue ๋ฑ์ ๋์
ํด ํ์ฅ์ฑ๊ณผ ๋ณต์๋ ฅ์ ๋์ฑ ๊ฐํํ ๊ณํ์ด๋ค. (๊ณต๋ถํ ๊ฒ ๋ง๋ค.. ์ฆ๊ฒ๋ค..!!)
'BackEnd๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Redis] Redis๋ ๋ฌด์์ผ๊น? (1) | 2025.08.29 |
|---|---|
| ์ ์ด ํ๊นจ๋ 404 ์๋ฌ... ์ด์ ๋?! (1) | 2025.06.11 |