๐Ÿ”ง ๋™์‹œ์„ฑ ์ œ์–ด ๋ถ„์„

Hyojinยท2024๋…„ 10์›” 31์ผ
0

์ฝ˜์„œํŠธ ์„œ๋น„์Šค ๋™์‹œ์„ฑ ์ œ์–ด ๋ณด๊ณ ์„œ


๋ณด๊ณ ์„œ ์ž‘์„ฑ ๋ฐฐ๊ฒฝ


์ฝ˜์„œํŠธ ์„œ๋น„์Šค์˜ ์ขŒ์„ ์˜ˆ์•ฝ ๋ฐ ํฌ์ธํŠธ ์ถฉ์ „ ๊ธฐ๋Šฅ์€ ์—ฌ๋Ÿฌ ์œ ์ €๊ฐ€ ๋™์‹œ์— ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ๊ณผ ์ถฉ๋Œ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ๋™์‹œ์„ฑ ์ œ์–ด๋Š” ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์€ ๋™์‹œ์„ฑ ์ œ์–ด ๋ฐฉ์‹์œผ๋กœ ๋‚™๊ด€์  ๋ฝ๊ณผ ๋น„๊ด€์  ๋ฝ์„ ์ ์šฉํ•œ ๊ฒฝ์šฐ์˜ ์„ฑ๋Šฅ์„ ๋น„๊ตํ•˜์—ฌ, ์ตœ์ ์˜ ๋™์‹œ์„ฑ ์ œ์–ด ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ ์„ค๋ช…


  • ์ขŒ์„ ์˜ˆ์•ฝ: ์—ฌ๋Ÿฌ ๋ช…์˜ ์œ ์ €๊ฐ€ ๋™์‹œ์— ๋™์ผํ•œ ์ขŒ์„์„ ์˜ˆ์•ฝํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ํ•œ ๋ช…์˜ ์œ ์ €๋งŒ ์„ฑ๊ณต์ ์œผ๋กœ ์˜ˆ์•ฝ๋ฉ๋‹ˆ๋‹ค.
  • ํฌ์ธํŠธ ์ถฉ์ „: ํ•œ ๋ช…์˜ ์œ ์ €๊ฐ€ ํฌ์ธํŠธ ์ถฉ์ „์„ ๋™์‹œ์— ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ, ์ˆœ์ฐจ์ ์œผ๋กœ ์ถฉ์ „๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋™์‹œ์„ฑ ์ œ์–ด ๋ฐฉ์‹


๋‚™๊ด€์  ๋ฝ

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

๋‚™๊ด€์  ๋ฝ์˜ ์ž‘๋™ ๋ฐฉ์‹

  • ๋ฐ์ดํ„ฐ ์ˆ˜์ • ์ค€๋น„
    • ํŠธ๋žœ์žญ์…˜์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ, ์ž ๊ธˆ ์—†์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒ€์ฆ ๋‹จ๊ณ„
    • ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์— ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜์—ฌ ๋ณ€๊ฒฝํ–ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์ถฉ๋Œ ์ฒ˜๋ฆฌ
    • ๋งŒ์•ฝ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— ์˜ํ–ฅ์„ ๋ฏธ์ณค๋‹ค๋ฉด, ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜์€ ์‹คํŒจํ•˜๊ณ  ๋กค๋ฐฑ๋ฉ๋‹ˆ๋‹ค.

๋‚™๊ด€์  ๋ฝ์˜ ์žฅ๋‹จ์ 

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

๋น„๊ด€์  ๋ฝ

  • ๋น„๊ด€์  ๋ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ๋ถ€ํ„ฐ ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฝ์„ ๊ฑธ์–ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ SELECT FOR UPDATE์™€ ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฝ์„ ๊ฑธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„๊ด€์  ๋ฝ์˜ ์žฅ๋‹จ์ 

  • ๋น„๊ด€์  ๋ฝ์˜ ์žฅ์ 
    • ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋น„๊ด€์  ๋ฝ์˜ ๋‹จ์ 
    • ์„ฑ๋Šฅ ์ €ํ•˜์™€ ๋ฐ๋“œ๋ฝ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

์ขŒ์„ ์˜ˆ์•ฝ

๋™์‹œ์„ฑ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

    @Test
    public void ์ขŒ์„_์˜ˆ์•ฝ_๋™์‹œ์„ฑ_์ œ์–ด() throws Exception {
        // Given
        int threadCount = 100;
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        List<Future<ReserveSeatsResponseCommand>> futures = new ArrayList<>();

        // When
        for (int i = 0; i < threadCount; i++) {
            final Long userId = (long) i + 1;
            ReserveSeatsCommand command = new ReserveSeatsCommand(userId, concertId, scheduleId, seatIds);
            Future<ReserveSeatsResponseCommand> future = executorService.submit(() -> {
                try {
                    return reservationFacade.reserveSeats(command);
                } catch (Exception e) {
                    log.error("Reservation failed: {}", e.getMessage());
                    return null;
                }
            });
            futures.add(future);
        }

        // ์„ฑ๊ณต ๋ฐ ์‹คํŒจ ์นด์šดํ„ฐ
        int successCount = 0;
        int failureCount = 0;

        // ์Šค๋ ˆ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        for (Future<ReserveSeatsResponseCommand> future : futures) {
            ReserveSeatsResponseCommand reservation = future.get();
            if (reservation != null) {
                successCount++;
                log.info("Reservation successful: {}", reservation.getReservationId());
            } else {
                failureCount++;
            }
        }
        log.info("successCount: {}", successCount);
        log.info("failureCount: {}", failureCount);

        // Then
        assertEquals(1, successCount);
        assertEquals(99, failureCount);

        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ์™„๋ฃŒํ•œ ํ›„ ์˜ˆ์•ฝ ์ƒํƒœ ํ™•์ธ
        List<Seat> reservedSeats = seatRepository.findSeatsByScheduleId(seatIds, scheduleId);
        reservedSeats.forEach(seat -> {
            assertEquals(seat.getStatus(), TEMPORARILY_RESERVED);
        });

        executorService.shutdown();
    }

๋‚™๊ด€์  ๋ฝ ์ ์šฉ ํ›„ ์‹คํ–‰ ๊ฒฐ๊ณผ

  • 1000๊ฐœ์˜ ์Šค๋ ˆ๋“œ ํ…Œ์ŠคํŠธ

๋น„๊ด€์  ๋ฝ ์ ์šฉ ํ›„ ์‹คํ–‰ ๊ฒฐ๊ณผ

  • 1000๊ฐœ์˜ ์Šค๋ ˆ๋“œ ํ…Œ์ŠคํŠธ

๋‚™๊ด€์  ๋ฝ๊ณผ ๋น„๊ด€์  ๋ฝ ํ…Œ์ŠคํŠธ ๋น„๊ต

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋‚™๊ด€์  ๋ฝ์„ ์ ์šฉํ•œ ํ…Œ์ŠคํŠธ: 6์ดˆ 278๋ฐ€๋ฆฌ์ดˆ
  • ๋น„๊ด€์  ๋ฝ์„ ์ ์šฉํ•œ ํ…Œ์ŠคํŠธ: 7์ดˆ 105๋ฐ€๋ฆฌ์ดˆ

๋‚™๊ด€์  ๋ฝ์„ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ๋Š” ์žฌ์‹œ๋„ ๊ธฐ๋Šฅ์ด ์—†์œผ๋ฏ€๋กœ, ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, ๋น„๊ด€์  ๋ฝ์€ ๋Œ€๊ธฐ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์ „์ฒด ์‹คํ–‰ ์‹œ๊ฐ„์ด ๋” ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ์‹คํŒจ ์‹œ ์žฌ์‹œ๋„ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—†๋Š” ์ƒํ™ฉ์—์„œ๋Š” ๋‚™๊ด€์  ๋ฝ์ด ๋” ํšจ์œจ์ ์ด๋ผ๋Š” ๊ฒฐ๋ก ์„ ๋‚ด๋ ธ์Šต๋‹ˆ๋‹ค.

ํฌ์ธํŠธ ์ถฉ์ „

๋™์‹œ์„ฑ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

    @Test
    void ํฌ์ธํŠธ_์ถฉ์ „_๋™์‹œ์„ฑ_์ œ์–ด() throws InterruptedException {
        int THREAD_COUNT = 1000;

        RechargeCommand command = new RechargeCommand(1L, 100L);

        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
        CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
        for (int i = 0; i < THREAD_COUNT; i++) {
            executorService.submit(() -> {
                try {
                    pointService.rechargePoint(command);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executorService.shutdown();

        Point point = pointRepository.point(1L);
        
        // DB์—๋Š” 1000 ํฌ์ธํŠธ๊ฐ€ ์ €์žฅ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.
        assertThat(point.getPointAmount()).isEqualTo(new BigDecimal("101000.00"));

    }

๋‚™๊ด€์  ๋ฝ ์ ์šฉ ํ›„ ์‹คํ–‰ ๊ฒฐ๊ณผ

  • 1000๊ฐœ์˜ ์Šค๋ ˆ๋“œ ํ…Œ์ŠคํŠธ

๋น„๊ด€์  ๋ฝ ์ ์šฉ ํ›„ ์‹คํ–‰ ๊ฒฐ๊ณผ

  • 1000๊ฐœ์˜ ์Šค๋ ˆ๋“œ ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ ๊ฒฐ๋ก 

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋‚™๊ด€์  ๋ฝ์„ ์ ์šฉํ•œ ํ…Œ์ŠคํŠธ: 6์ดˆ 693๋ฐ€๋ฆฌ์ดˆ
  • ๋น„๊ด€์  ๋ฝ์„ ์ ์šฉํ•œ ํ…Œ์ŠคํŠธ: 4์ดˆ 770๋ฐ€๋ฆฌ์ดˆ

ํฌ์ธํŠธ ์ถฉ์ „ ๊ธฐ๋Šฅ์˜ ๊ฒฝ์šฐ, ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ํ•˜๋ฉด์„œ ๋ชจ๋“  ์š”์ฒญ์— ์ถฉ์ „์ด ๋ณด์žฅ๋˜์–ด์•ผ ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋™์‹œ์— 10๋ฒˆ์˜ ์ถฉ์ „ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค๋ฉด, 10๋ฒˆ ๋ชจ๋‘ ์ถฉ์ „์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋น„๊ด€์  ๋ฝ์€ ๋Œ€๊ธฐ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์ฆ‰์‹œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, ๋‚™๊ด€์  ๋ฝ์€ ์ถฉ๋Œ ํ›„ ์žฌ์‹œ๋„ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„์ด ๋” ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ @Retryable(value = {OptimisticLockingFailureException.class}, maxAttempts = 10, backoff = @Backoff(delay = 100))๋กœ ์„ค์ •ํ–ˆ์ง€๋งŒ, ์ด๋กœ ์ธํ•ด ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.

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

๋ ˆ๋””์Šค ๋ถ„์‚ฐ๋ฝ ํ…Œ์ŠคํŠธ

๋ ˆ๋””์Šค ๋ถ„์‚ฐ๋ฝ์€ ๋‹ค์Œ ๊ธ€์„ ์ฐธ๊ณ ํ•˜์—ฌ ์„ค์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class RedissonLockAspect {

    private final RedissonClient redissonClient;

    @Around("@annotation(com.hhplu.hhplusconcert.common.annotation.RedissonLock)")
    @Transactional
    public Object redissonLock(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RedissonLock annotation = method.getAnnotation(RedissonLock.class);
        String lockKey = method.getName() + CustomSpringELParser.getDynamicValue(signature.getParameterNames(), joinPoint.getArgs(), annotation.value());

        RLock lock = redissonClient.getLock(lockKey);

        try {
            boolean lockable = lock.tryLock(annotation.waitTime(), annotation.leaseTime(), TimeUnit.MILLISECONDS);
            if (!lockable) {
                log.info("Lock ํš๋“ ์‹คํŒจ={}", lockKey);
                throw new Exception("Lock ํš๋“ ์‹คํŒจ");
            }
            log.info("๋กœ์ง ์ˆ˜ํ–‰");
            return joinPoint.proceed();
        } catch (InterruptedException e) {
            log.info("์—๋Ÿฌ ๋ฐœ์ƒ");
            throw e;
        } finally {
            log.info("๋ฝ ํ•ด์ œ");
            lock.unlock();
        }

    }

}
@Service
@RequiredArgsConstructor
public class PointFacade {
    private final PointService pointService;

    @RedissonLock(value = "#command.getUserId()")
    public GetPointCommand rechargePoint(RechargeCommand command) {
       return pointService.rechargePoint(command);
    }
}

์ฐธ๊ณ 

Redis(Redisson) ๋ถ„์‚ฐ๋ฝ์„ ํ™œ์šฉํ•˜์—ฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ

๋ถ„์‚ฐ๋ฝ ์ ์šฉ ํ›„ ์‹คํ–‰ ๊ฒฐ๊ณผ

  • 1000๊ฐœ์˜ ์Šค๋ ˆ๋“œ ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ ๊ฒฐ๋ก :

๋ถ„์‚ฐ ๋ฝ์„ ํ†ตํ•ด 1000๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ํฌ์ธํŠธ ์ถฉ์ „ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•œ ๊ฒฐ๊ณผ, ๋ฝ ํš๋“ ๋ฐ ํ•ด์ œ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๋กœ ์ธํ•ด ์ „์ฒด ์‹คํ–‰ ์†๋„๊ฐ€ ๋‹ค์†Œ ๋А๋ ค์ง€๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. Redisson์˜ ๋ถ„์‚ฐ ๋ฝ์€ ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜์ง€๋งŒ, ๋†’์€ ํŠธ๋ž˜ํ”ฝ ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฝ ํš๋“ ์‹œ๋„์˜ ๊ฒฝ์Ÿ์œผ๋กœ ์ธํ•ด ์ง€์—ฐ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ํŒŒ์•…ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ตœ์ข… ๊ฒฐ๋ก :

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

์ดˆ๊ธฐ ์„ค๊ณ„ ๋ฐฉ์นจ์— ๋”ฐ๋ผ, ์ž์› ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์ขŒ์„ ์˜ˆ์•ฝ ์‹œ์Šคํ…œ์—๋Š” ๋‚™๊ด€์  ๋ฝ์„ ์ ์šฉํ•˜์—ฌ, ๋ถˆํ•„์š”ํ•œ ๋ฝ ์ ์œ ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋ฉฐ ๋น ๋ฅธ ์„ฑ๋Šฅ์„ ๋ณด์žฅํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, ํฌ์ธํŠธ ์ถฉ์ „ ๊ธฐ๋Šฅ์—๋Š” ๋น„๊ด€์  ๋ฝ์„ ์‚ฌ์šฉํ•˜์—ฌ, ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ผ๊ด€์„ฑ ์œ ์ง€๊ฐ€ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์— ์•ˆ์ •์ ์ธ ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ๋„์ž…ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ถ„์‚ฐ ๋ฝ์€ ํ–ฅํ›„ ํ™•์žฅ์„ฑ์ด ํ•„์š”ํ•œ ํ™˜๊ฒฝ์ด๋‚˜ ๋ณ„๋„์˜ ๋„คํŠธ์›Œํฌ ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•˜์—ฌ, ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ ์šฉ ๋ฐฉ์•ˆ์„ ๊ณ ๋ คํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

profile
์–ด์ œ์˜ ๋‚˜๋ณด๋‹ค ์„ฑ์žฅํ•œ ์‚ฌ๋žŒ์ด ๋  ์ˆ˜ ์žˆ๋„๋ก ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด

Powered by GraphCDN, the GraphQL CDN