[JAVA] ๐Ÿ˜‡ํ”„๋กœ์ ํŠธ ์˜ˆ์•ฝ๊ธฐ๋Šฅ์—์„œ ๋งˆ์ฃผ์นœ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• (synchronized์™€concurrentHashMap)

๋žธ๋‚˜ยท2024๋…„ 2์›” 21์ผ
5

์ž๋ฐ”

๋ชฉ๋ก ๋ณด๊ธฐ
1/1
post-thumbnail

๐Ÿคฏ๋ฌธ์ œ ๋ฐœ์ƒ ์ƒํ™ฉ

์œ ๋‹ˆ๋ฒ„์Šค์Šคํ…Œ์ด(์ˆ™๋ฐ•์˜ˆ์•ฝ ํ”Œ๋žซํผ) ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์ถ•ํ•˜๋ฉด์„œ, ๊ธฐ๋Šฅ ๊ตฌํ˜„์—๋งŒ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‘์—ˆ์—ˆ๋Š”๋ฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์•˜์—ˆ๋‹ค.

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ๋ช… ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„๋•Œ, ์‚ฌ์šฉ์ž(๊ฒŒ์ŠคํŠธ)๊ฐ€ ๊ฐ™์€ ๋‚ ์งœ ํ˜น์€ ๊ฒน์น˜๋Š” ๋‚ ์งœ์— ๋™์‹œ์— ์˜ˆ์•ฝ์„ ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์šฐ์„  ์ •๋ง ์›์ดˆ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ธฐ ์œ„ํ•ด์„œ ๋„์›Œ๋†“์€ ์„œ๋ฒ„์—์„œ ํŒ€์› ํ•œ๋ช…๊ณผ ํ•จ๊ป˜ ๋™์‹œ์— ์˜ˆ์•ฝ ์š”์ฒญ์„ ํ•ด๋ดค๋‹ค๐Ÿคฃ

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

๊ทธ๋ž˜์„œ ์ˆ˜๊ธฐ๊ฐ€ ์•„๋‹Œ ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋กœ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์„ ํ…Œ์ŠคํŠธํ•ด๋ดค๋‹ค.

๐Ÿ˜คํ…Œ์ŠคํŠธ๋ฐฉ์‹

ํ…Œ์ŠคํŠธ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์„œ๋น„์Šค๋ฅผ ๊ฐ„๋žตํ™”ํ•ด์„œ ์ง„ํ–‰ํ–ˆ๋‹ค.

  1. ์˜ˆ์•ฝ์„ ๋‹ด์„ createdBookings map์„ ๋งŒ๋“ ๋‹ค.
  2. ์“ฐ๋ ˆ๋“œ๋ฅผ 100๊ฐœ๋กœ ์ง€์ •ํ•œ ๋’ค, ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์œผ๋กœ ์š”์ฒญ์„ ๋‚ ๋ฆฐ๋‹ค.
  3. bookingDTO(์˜ˆ์•ฝ ์ •๋ณด๋ฅผ ๋‹ด์€ ๊ฐ์ฒด)์˜ checkin_date์™€ checkout_date๊ฐ€ ๊ฐ™์œผ๋ฉด ์˜ˆ์•ฝ์ด ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ
    3-1. ์˜ˆ์•ฝ์ด ์ด๋ฏธ ์กด์žฌํ•œ๋‹ค๋ฉด => createdBookings ๋งต์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
    3-2. ์˜ˆ์•ฝ์ด ์—†๋‹ค๋ฉด => createdBookings ๋งต์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ์ฝ”๋“œ(๋™์‹œ์„ฑ ์ด์Šˆ O)

 @Test
    public void testNoConcurrentBookings() throws InterruptedException {

        long startTime = System.currentTimeMillis();

        CountDownLatch latch = new CountDownLatch(numThreads);
        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);

        Map<String, BookingDto> createdBookings = new HashMap<>();
        BookingDto bookingDto = createBookingDto();

        for (int i = 0; i < numThreads; i++) {
            final String bookingId = UUID.randomUUID().toString();
            executorService.submit(() -> {
                try {
                    // ๋™์ผํ•œ ์ฒดํฌ์ธ ๋ฐ ์ฒดํฌ์•„์›ƒ ๋‚ ์งœ๋ฅผ ๊ฐ–๋Š” ๊ธฐ์กด ์˜ˆ์•ฝ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
                    boolean isDuplicateBooking = checkForDuplicate(createdBookings, bookingDto);
                    // ์ค‘๋ณต๋œ ์˜ˆ์•ฝ์ด ์—†์„ ๊ฒฝ์šฐ์—๋งŒ bookingDto๋ฅผ createdBookings ๋งต์— ์ถ”๊ฐ€
                    if (!isDuplicateBooking) {
                        System.out.println("์ค‘๋ณต๋œ ์˜ˆ์•ฝ ์—†์Œ, createdBookings์— ์ถ”๊ฐ€");
                        createdBookings.put(bookingId, bookingDto);
                    } else {
                        System.out.println("์ค‘๋ณต๋œ ์˜ˆ์•ฝ ๋ฐœ๊ฒฌ, createdBookings์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Œ");
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    latch.countDown();
                }
            });

        }
        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        latch.await();
        executorService.shutdown();
        // ์ƒ์„ฑ๋œ ์˜ˆ์•ฝ์˜ ์ˆ˜๋ฅผ ํ™•์ธ
        System.out.println("createdBookings = " + createdBookings.size());
        assertEquals(1, createdBookings.size());
    }
    
   
   //map์— ๊ฐ™์€ ๋‚ ์งœ๋ฅผ ๊ฐ€์ง„ ์˜ˆ์•ฝ๊ฑด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ
   private boolean checkForDuplicate(Map<String, BookingDto> createdBookings,
            BookingDto newBooking) {
        for (BookingDto existingBooking : createdBookings.values()) {
            if (existingBooking.getBooking_checkin_date()
                    .equals(newBooking.getBooking_checkin_date()) &&
                    existingBooking.getBooking_checkout_date()
                            .equals(newBooking.getBooking_checkout_date())) {
                return true;
            }
        }
        return false;
    }
  // bookingDto๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    private BookingDto createBookingDto() {
        BookingDto bookingDto = new BookingDto();
        bookingDto.setBooking_id(UUID.randomUUID().toString());
        bookingDto.setUser_id("f6b58fa7-a088-453a-8533-d6e1d68eec93");
        bookingDto.setRoom_id("004f28e1-4c1c-40b3-b580-a2293671110f");
        bookingDto.setStatus_id("B01");
        bookingDto.setBooking_checkin_date("2024-02-28");
        bookingDto.setBooking_checkout_date("2024-02-29");
        bookingDto.setBooking_num_of_guest(1);
        bookingDto.setBooking_total_pay_amount(1);
        return bookingDto;
    }

์•„๋ฌด๋Ÿฐ ์กฐ์น˜๋ฅผ ํ•ด์ฃผ์ง€ ์•Š์•˜์„๋•Œ , 100๊ฐœ์˜ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ์ข…์ข… ๋ฐœ์ƒํ–ˆ๋‹ค.

๐Ÿคฉํ•ด๊ฒฐ ๋ฐฉ๋ฒ• (1) - Synchronized

 @Test
    public void testSynchronizedBookings() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(numThreads);
        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);

        HashMap<String, BookingDto> createdBookings = new HashMap<>();
        BookingDto bookingDto = createBookingDto();

        for (int i = 0; i < numThreads; i++) {
            final String bookingId = UUID.randomUUID().toString();
            executorService.submit(() -> {
                try {
                
                //***** ์ž„๊ณ„๊ตฌ์—ญ ์ง€์ • ์‹œ์ž‘*******//
                    synchronized (lock) {
                        // ๋™์ผํ•œ ์ฒดํฌ์ธ ๋ฐ ์ฒดํฌ์•„์›ƒ ๋‚ ์งœ๋ฅผ ๊ฐ–๋Š” ๊ธฐ์กด ์˜ˆ์•ฝ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
                        boolean isDuplicateBooking = checkForDuplicate(createdBookings, bookingDto);
                        // ์ค‘๋ณต๋œ ์˜ˆ์•ฝ์ด ์—†์„ ๊ฒฝ์šฐ์—๋งŒ bookingDto๋ฅผ createdBookings ๋งต์— ์ถ”๊ฐ€
                        if (!isDuplicateBooking) {
                            System.out.println("์ค‘๋ณต๋œ ์˜ˆ์•ฝ ์—†์Œ, createdBookings์— ์ถ”๊ฐ€");
                            createdBookings.put(bookingId, bookingDto);
                        } else {
                            System.out.println("์ค‘๋ณต๋œ ์˜ˆ์•ฝ ๋ฐœ๊ฒฌ, createdBookings์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Œ");
                        }
                    }
				//***** ์ž„๊ณ„๊ตฌ์—ญ ์ง€์ • ๋*******//

                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    latch.countDown();
                }
            });
        }
        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        latch.await();
        executorService.shutdown();
        // ์ƒ์„ฑ๋œ ์˜ˆ์•ฝ์˜ ์ˆ˜๋ฅผ ํ™•์ธ
        assertEquals(1, createdBookings.size());
    }
    
       //map์— ๊ฐ™์€ ๋‚ ์งœ๋ฅผ ๊ฐ€์ง„ ์˜ˆ์•ฝ๊ฑด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ
   private boolean checkForDuplicate(Map<String, BookingDto> createdBookings,
            BookingDto newBooking) {
        for (BookingDto existingBooking : createdBookings.values()) {
            if (existingBooking.getBooking_checkin_date()
                    .equals(newBooking.getBooking_checkin_date()) &&
                    existingBooking.getBooking_checkout_date()
                            .equals(newBooking.getBooking_checkout_date())) {
                return true;
            }
        }
        return false;
    }
  // bookingDto๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    private BookingDto createBookingDto() {
        BookingDto bookingDto = new BookingDto();
        bookingDto.setBooking_id(UUID.randomUUID().toString());
        bookingDto.setUser_id("f6b58fa7-a088-453a-8533-d6e1d68eec93");
        bookingDto.setRoom_id("004f28e1-4c1c-40b3-b580-a2293671110f");
        bookingDto.setStatus_id("B01");
        bookingDto.setBooking_checkin_date("2024-02-28");
        bookingDto.setBooking_checkout_date("2024-02-29");
        bookingDto.setBooking_num_of_guest(1);
        bookingDto.setBooking_total_pay_amount(1);
        return bookingDto;
    }

synchronized ์ œ์–ด์ž๋ฅผ ํ†ตํ•ด์„œ ์ž„๊ณ„๊ตฌ์—ญ์„ ์ง€์ •ํ•œ ๋’ค, ๋ฝ์„ ์ฃผ์–ด ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•œ๊ฐœ์”ฉ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ๋‹จ ํ•˜๋‚˜์˜ ์˜ˆ์•ฝ๋งŒ ์ƒ์„ฑ๋˜๋ฉด์„œ ๋ฌด์กฐ๊ฑด ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค!

๊ทธ๋Ÿฌ๋‚˜ ํ™•์‹คํžˆ ์„ฑ๋Šฅ์ƒ์œผ๋กœ๋Š” ๋Š๋ ค์ง„ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ฆ‰, synchronized ์ œ์–ด์ž๋กœ ๋ฝ์„ ์คŒ์œผ๋กœ์จ ๋™์‹œ์„ฑ์€ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๐Ÿคฉํ•ด๊ฒฐ ๋ฐฉ๋ฒ• (2) - ConcurrentHashMap ..?

   @Test
    public void testConcurrentBookingsWithConcurrentHashMap() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(numThreads);
        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);

        Map<String, BookingDto> createdBookings = new ConcurrentHashMap<>();
        BookingDto bookingDto = createBookingDto();

        for (int i = 0; i < numThreads; i++) {
            final String bookingId = UUID.randomUUID().toString();
            executorService.submit(() -> {
                try {
                    // ๋™์ผํ•œ ์ฒดํฌ์ธ ๋ฐ ์ฒดํฌ์•„์›ƒ ๋‚ ์งœ๋ฅผ ๊ฐ–๋Š” ๊ธฐ์กด ์˜ˆ์•ฝ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
                    boolean isDuplicateBooking = checkForDuplicate(createdBookings, bookingDto);
                    // ์ค‘๋ณต๋œ ์˜ˆ์•ฝ์ด ์—†์„ ๊ฒฝ์šฐ์—๋งŒ bookingDto๋ฅผ createdBookings ๋งต์— ์ถ”๊ฐ€
                    if (!isDuplicateBooking) {
                        System.out.println("์ค‘๋ณต๋œ ์˜ˆ์•ฝ ์—†์Œ, createdBookings์— ์ถ”๊ฐ€");
                        createdBookings.putIfAbsent(bookingId, bookingDto);
                    } else {
                        System.out.println("์ค‘๋ณต๋œ ์˜ˆ์•ฝ ๋ฐœ๊ฒฌ, createdBookings์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Œ");
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    latch.countDown();
                }
            });
        }
        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        latch.await();
        executorService.shutdown();
        // ์ƒ์„ฑ๋œ ์˜ˆ์•ฝ์˜ ์ˆ˜๋ฅผ ํ™•์ธ
        System.out.println("createdBookings = " + createdBookings.size());
        assertEquals(1, createdBookings.size());
    }
    
       //map์— ๊ฐ™์€ ๋‚ ์งœ๋ฅผ ๊ฐ€์ง„ ์˜ˆ์•ฝ๊ฑด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ
   private boolean checkForDuplicate(Map<String, BookingDto> createdBookings,
            BookingDto newBooking) {
        for (BookingDto existingBooking : createdBookings.values()) {
            if (existingBooking.getBooking_checkin_date()
                    .equals(newBooking.getBooking_checkin_date()) &&
                    existingBooking.getBooking_checkout_date()
                            .equals(newBooking.getBooking_checkout_date())) {
                return true;
            }
        }
        return false;
    }
  // bookingDto๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    private BookingDto createBookingDto() {
        BookingDto bookingDto = new BookingDto();
        bookingDto.setBooking_id(UUID.randomUUID().toString());
        bookingDto.setUser_id("f6b58fa7-a088-453a-8533-d6e1d68eec93");
        bookingDto.setRoom_id("004f28e1-4c1c-40b3-b580-a2293671110f");
        bookingDto.setStatus_id("B01");
        bookingDto.setBooking_checkin_date("2024-02-28");
        bookingDto.setBooking_checkout_date("2024-02-29");
        bookingDto.setBooking_num_of_guest(1);
        bookingDto.setBooking_total_pay_amount(1);
        return bookingDto;
    }

ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์˜์™ธ์˜ ๊ฒฐ๊ณผ๋ฅผ ์–ป์—ˆ๋‹ค.
๊ตฌ๊ธ€๋ง์„ ํ•ด๋ดค์„ ๋•Œ, concurrentHashMap์„ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋งŽ์ด ์„ ํƒํ•œ๋‹ค๋Š” ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋งŽ์ด ๋ดค๊ธฐ์— ๋‹น์—ฐํžˆ ์„ฑ๊ณต์ผ์ค„ ์•Œ์•˜๋‹ค!

๊ทธ๋Ÿฐ๋ฐ ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์™•์™• ์žˆ์—ˆ๋‹ค. ๋„ํ†ต ์ด์œ ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์–ด์„œ ๋ช‡์‹œ๊ฐ„์„ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ ์•„๋ž˜ ๋‚ด์šฉ์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐพ์•˜๋‹ค.

ConcurrentHashMap์€ ์กฐํšŒ์‹œ Lock์„ ํ• ๊นŒ?

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

ํ•˜๋ฃจ์ข…์ผ ์‚ดํŽด๋ดค์ง€๋งŒ ์–ด๋–ค ๋ถ€๋ถ„์ด ๋ฌธ์ œ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์„œ, ์ถ”ํ›„ concurrentHashMap๊ณผ ๋™์‹œ์„ฑ์— ๋Œ€ํ•ด์„œ ๋” ๊ณต๋ถ€ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค!

๊ฒฐ๋ก 

synchronized๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž„๊ณ„๊ตฌ์—ญ์—์„œ lock์„ ์–ป์–ด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

..๊ทธ๋Ÿฌ๋‚˜!

1.์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๋Œ€์ผ ๊ฒฝ์šฐ์—๋Š” ์ด ์ œ์–ด์ž ๋˜ํ•œ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์–ด๋ ต๋‹ค. synchronized๋Š” ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค์—์„œ๋งŒ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

2.์„ฑ๋Šฅ์— ๋Œ€ํ•œ ์ด์Šˆ๊ฐ€ ์žˆ๋‹ค. ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ ํ…Œ์ŠคํŠธ ํ–ˆ์„ ๋•Œ๋„ ์•ฝ 1.2~1.5๋ฐฐ์˜ ์‹œ๊ฐ„์ด ๋” ๊ฑธ๋ฆฌ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.


๊ทธ๋ ‡๋‹ค๋ฉด?
์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ์ง€ํ”ผํ‹ฐ์—๊ฒŒ ๋ฌผ์–ด๋ดค๋‹ค.


๐Ÿ‘ฉโ€๐Ÿ’ป ์งˆ๋ฌธ : synchronized๋Š” ๋‹จ์ผ ํ”„๋กœ์„ธ์Šค์—์„œ๋งŒ ๋™์ž‘ํ•˜๊ธฐ๋•Œ๋ฌธ์— ์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๋Œ€์ธ ๊ฒฝ์šฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ต๋‹ค๊ณ  ํ•˜์ž–์•„. ๊ทธ๋Ÿผ ์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๋Œ€์ธ ๊ฒฝ์šฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•ด? ํ‚ค์›Œ๋“œ ์œ„์ฃผ๋กœ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ์–ด?

๐Ÿ‘ฉโ€๐Ÿ’ป ๋‹ต๋ณ€ :
๋งž์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋Œ€์˜ ์„œ๋ฒ„์—์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ธฐ์ˆ ๊ณผ ์›์น™์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ํ‚ค์›Œ๋“œ ์œ„์ฃผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค:

๋ถ„์‚ฐ ๋ฝ (Distributed Locking):

ZooKeeper, etcd ๋“ฑ์˜ ๋ถ„์‚ฐ ์‹œ์Šคํ…œ: ๋ถ„์‚ฐ๋œ ์„œ๋ฒ„ ๊ฐ„์— ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ๊ณต์œ ๋œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ๋ฝ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ:

๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜ (Distributed Transactions): ์—ฌ๋Ÿฌ ์„œ๋ฒ„ ๊ฐ„์˜ ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜์—ฌ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋ณต์žกํ•˜๊ณ  ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฒ„์ „ ๊ด€๋ฆฌ (Versioning):

Optimistic Concurrency Control (OCC): ๊ฐ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•ด ๋ฒ„์ „์„ ๊ด€๋ฆฌํ•˜์—ฌ ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•˜๊ณ  ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์‹œ์„ฑ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ (Asynchronous Processing):

๋ฉ”์‹œ์ง€ ํ ๋ฐ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜: ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์„œ๋ฒ„ ๊ฐ„์˜ ํ†ต์‹ ์„ ์ตœ์†Œํ™”ํ•˜์—ฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ถ„ํ• ๊ณผ ์ •๋ณต (Sharding):

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒค๋”ฉ: ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ์„œ๋ฒ„์— ๋ถ„์‚ฐํ•˜์—ฌ ๋ถ€ํ•˜๋ฅผ ๋ถ„์‚ฐํ•˜๊ณ  ๋™์‹œ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์บ์‹œ ํ™œ์šฉ:

๋ถ„์‚ฐ ์บ์‹ฑ ์‹œ์Šคํ…œ: ๊ณตํ†ต ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์บ์‹ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋นˆ๋ฒˆํ•œ ์ฝ๊ธฐ ์ž‘์—…์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ด๊ณ  ์‘๋‹ต ์‹œ๊ฐ„์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋™๊ธฐํ™” ์—†๋Š” ์•„ํ‚คํ…์ฒ˜ (Asynchronous Architectures):

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜: ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ์„œ๋น„์Šค๋“ค์„ ์กฐํ•ฉํ•˜์—ฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
CAP ์ด๋ก :

Consistency, Availability, Partition Tolerance: ์ด ์„ธ ๊ฐ€์ง€ ์ค‘ ๋‘ ๊ฐ€์ง€๋งŒ ์„ ํƒ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์‹œ์Šคํ…œ์˜ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์„ ํƒ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
Quorum ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ:

๋ถ„์‚ฐ ์‹œ์Šคํ…œ์—์„œ ๋‹ค์ˆ˜๊ฒฐ์„ ์ด์šฉํ•œ ์˜์‚ฌ ๊ฒฐ์ •: ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ ์ž‘์—…์— ๋Œ€ํ•œ ๋‹ค์ˆ˜ ๊ฒฐ์ •์„ ํ†ตํ•ด ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ๊ฐ€์šฉ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ๊ธฐ์ˆ ๊ณผ ์›์น™์„ ์กฐํ•ฉํ•˜์—ฌ ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์„œ์นญํ•ด๋ดค์„๋•Œ๋„ ๋ถ„์‚ฐ๋ฝ, ๋ ˆ๋””์Šค, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ๋“ฑ์˜ ํ‚ค์›Œ๋“œ๊ฐ€ ๋งŽ์ด ๋‚˜์™€์„œ, ์ถ”ํ›„์— ์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๋Œ€์ธ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋„ ๊ณต๋ถ€ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

profile
๋ฐฑ์—”๋“œ๊ฐœ๋ฐœ์ž

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