Skip to content

๐Ÿงช MVP2: ์„œ๋ฒ„ ์ตœ๋Œ€ ๋ถ€ํ•˜ ์ฐพ๊ธฐ

KyungMin Lee edited this page Aug 29, 2024 · 1 revision

ํ…Œ์ŠคํŠธ ๊ณ„ํš

  1. ์›๋ณธ ์ƒํƒœ
  2. ์ŠคํŠธ๋ฆผ ๊ฐœ์„ 
  3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ํ’€ ๊ฐœ์„ 
  4. ๋ฒŒํฌ ์‚ฌ์ด์ฆˆ ๊ฐœ์„ 

ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ

  1. Read uncommited database mode
  2. ๋ณตํ•ฉ ์ธ๋ฑ์Šค 2๊ฐœ
  3. 50๋งŒ๊ฐœ ๋ฐ์ดํ„ฐ insert
  4. 5๋งŒ๊ฐœ์˜ ๋ฐ์ดํ„ฐ, Lambda๋กœ insert (warm up)
  5. 10๊ฐœ์˜ ์ธ์Šคํ„ด์Šค์—์„œ vUser 50๊ฐœ๋กœ ๋ฌดํ•œ ์š”์ฒญ(100๊ฐœ ๋กœ๊ทธ์”ฉ)

1. ์›๋ณธ์ƒํƒœ

์ตœ์ ํ™” ์ „ ํ†ฐ์บฃ(100 fixed)
์ตœ๋Œ€ RPS 803
์‹œ์ž‘ ์‹œ๊ฐ„ 03:15
RPS 0์‹œ๊ฐ„ 04:25
diff 1:10

์ตœ๋Œ€ RPS๊ฐ€ 803์—์„œ 1:10 ์ดˆ๋งŒ์— ์„œ๋ฒ„ down

2. ์ŠคํŠธ๋ฆผ ๊ฐœ์„ 

๊ฐ€์„ค

  • ์š”์ฒญ ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•ด์„œ ๊ฒ€์ฆ๊ณผ ๋ณ€ํ™˜์„ ํ•œ๋‹ค
  • ์ŠคํŠธ๋ฆผ์€ ์ผํšŒ์šฉ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ GC๊ฐ€ ๋ ์ง€๋ผ๋„ ๋ฉ”๋ชจ๋ฆฌ ๋ถ€ํ•˜๊ฐ€ ํด๊ฒƒ์ด๋‹ค
  • Controller Layer์˜ ๊ฒ€์ฆ๊ณผ, Service Layer์˜ ๊ฒ€์ฆ์ด ์ค‘๋ณต๋จ

๊ฐœ์„ 

  • ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ์„ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋ณ€๊ฒฝ
    • ๋ถˆํ•„์š”ํ•œ ์ผํšŒ์šฉ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์ง€
  • Contorller Layer์˜ ์ค‘๋ณต ๊ฒ€์ฆ ์ 
stream ์ตœ์ ํ™” ํ†ฐ์บฃ(100 fixed)
์ตœ๋Œ€ RPS 967
์‹œ์ž‘ ์‹œ๊ฐ„ 55:13
RPS 0์‹œ๊ฐ„ 56:01
diff 0:48

๊ฒฐ๊ณผ

48์ดˆ๋งŒ์— ์ฃฝ์—ˆ์ง€๋งŒ ์ตœ๋Œ€ ์ฒ˜๋ฆฌ์œจ 803 โ†’ 967 ๋˜์–ด์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋” ๋นจ๋ฆฌ ์ฐจ์„œ ์ฃฝ์—ˆ๋‹ค

3-1.๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ํ’€ ๊ฐœ์„ 

๊ฐ€์„ค

  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋” ๋งŽ์•„์ ธ์„œ OOM์ด ์ƒ๊ฒจ ์ฃฝ๋Š”๋‹ค
  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์ง€ ์•Š๋„๋ก ๋น ๋ฅด๊ฒŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ Flush๋ฅผ ํ•ด์ค€๋‹ค

๊ฐœ์„ 

  • ์‚ฌ์šฉํ•˜์ง€ ์•Š๋˜ ๋” ๋งŽ์€ connection์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์…˜
  • 10๊ฐœ์˜ 50%์—์„œ 80%๋กœ ์ฆ์„ค
stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 50% stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80%
์ตœ๋Œ€ RPS 967 891
์‹œ์ž‘ ์‹œ๊ฐ„ 55:13 13:33
RPS 0์‹œ๊ฐ„ 56:01 14:36
diff 0:48 1:03

๊ฒฐ๊ณผ

์ตœ๋Œ€ ์ฒ˜๋ฆฌ์œจ์€ ๋Š˜์—ˆ๋Š”๋ฐ, ์—ญ์‹œ ์ฃฝ์—ˆ๋‹ค

3-1. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ํ’€ ๊ฐœ์„ 

๊ฐ€์„ค

  • ๋” ๋นจ๋ฆฌ ๋งŽ์€ ์–‘์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ์˜ Flush ๊ฐ€ ํ•„์š”ํ• ๊ฒƒ์ด๋‹ค

๊ฐœ์„ 

  • connections pool 10 โ†’20 (8 โ†’ 16)
stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80% stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80%+ ํžˆ์นด๋ฆฌ 20
์ตœ๋Œ€ RPS 891 1073
์‹œ์ž‘ ์‹œ๊ฐ„ 13:33 20:39
RPS 0์‹œ๊ฐ„ 14:36 21:37
diff 1:03 58

๊ฒฐ๊ณผ

์ฒ˜๋ฆฌ์œจ์€ ๋Š˜์—ˆ๋Š”๋ฐ ์—ญ์‹œ ์ฃฝ์—ˆ๋‹ค

4-1. ๋ฒŒํฌ ์‚ฌ์ด์ฆˆ ๊ฐœ์„ 

๊ฐ€์„ค

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ์˜ flush ํ•˜๋Š” ๋Œ€์—ญํญ์€ ๋Š˜๋ ธ์œผ๋‹ˆ, ์–‘์„ ๋Š˜๋ ค์•ผํ•œ๋‹ค
  • bulk insert ์‚ฌ์ด์ฆˆ๋ฅผ ๋Š˜๋ฆฌ๋ฉด ๊ฐœ์„ ๋  ๊ฒƒ์ด๋‹ค

๊ฐœ์„ 

  • bulk size 100 โ†’ 1000
stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80% + ํžˆ์นด๋ฆฌ 20 stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80% + ํžˆ์นด๋ฆฌ 20 + bulk size 1000
์š”์ฒญ ์ˆ˜ 40000
์ตœ๋Œ€ RPS 1073 716
์‹œ์ž‘ ์‹œ๊ฐ„ 20:39 26:34
RPS 0์‹œ๊ฐ„ 21:37 27:52(response time peak)
diff 58

๊ฒฐ๊ณผ

์„œ๋ฒ„๊ฐ€ ์ฃฝ์ง€๋Š” ์•Š์•˜์œผ๋‚˜ ์‘๋‹ต์‹œ๊ฐ„์ด 2์ดˆ ์ด์ƒ ๊ฑธ๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊น€

4-2. ๋ฒŒํฌ ์‚ฌ์ด์ฆˆ ๊ฐœ์„ 

๊ฐ€์„ค

  • ๋” ๋งŽ์€ ์–‘์”ฉ flushํ•ด์•ผํ•œ๋‹ค

๊ฐœ์„ 

  • bulk size 1000 โ†’ 2000
stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80% + ํžˆ์นด๋ฆฌ 20 + bulk size 1000 stream + ํ†ฐ์บฃ + ์Šค๋ ˆ๋“œํ’€ 80% + ํžˆ์นด๋ฆฌ 20 + bulk size 2000
์š”์ฒญ ์ˆ˜ 40000 37167
์ตœ๋Œ€ RPS 716 655
์‹œ์ž‘ ์‹œ๊ฐ„ 26:34 48:15
RPS 0์‹œ๊ฐ„ 27:52(response time peak) 49:45

๊ฒฐ๋ก 

๊ฐœ์„ ์ ์ด ์—†๋‹ค

โ†’ ๋กœ์ง ์ ๊ฒ€

5. ๋กœ์ง ๊ฐœ์„ 

์‚ฌ์‹ค์ƒ ๋กœ์ง์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ์„ ํ™•์ธ

log๋ฅผ flush ํ•  ์กฐ๊ฑด

  1. queue.size() > defailtBulkSize
    • ํ์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ flushํ•ด์•ผ ํ•  bullksize๋ณด๋‹ค ํฌ๋‹ค
  2. currentTime > lastflushTime + defaultTimeout
    • ๋งˆ์ง€๋ง flush ์‹œ๊ฐ„๋ณด๋‹ค timeout ์‹œ๊ฐ„์ด ์ง€๋‚œ๋‹ค

๊ธฐ์กด ์ฝ”๋“œ

void leaderTask(Consumer<List<Log>> saveFunction) {
    while (!Thread.currentThread().isInterrupted()) {
        try {
            final Log log = logQueue.poll(defaultTimeout, TimeUnit.MILLISECONDS);
            /*
             * Log๊ฐ€ ์ฒœ์ฒœํžˆ ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ Timeout์— ํ•œ ๋ฒˆ์”ฉ ์ €์žฅ
             *
             * Log๊ฐ€ ๋†’์€ ๋ถ€ํ•˜๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ Bulk Size๋งŒํผ ํ•œ ๋ฒˆ์— ์ €์žฅ
             *
             * Timeout๋™์•ˆ ๋“ค์–ด์˜จ Log๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ ๋ฐ˜๋ณต๋ฌธ cycle ์ˆ˜ํ–‰
             */
            if (log == null) {
                continue;
            }
            List<Log> logs = new ArrayList<>();
            logs.add(log);
            //drainTo๋Š” Queue์— ์žˆ๋Š” ์š”์†Œ๋ฅผ maxElements๋งŒํผ ๊บผ๋‚ด์„œ Collection์— ๋‹ด์•„์ค€๋‹ค.
            logQueue.drainTo(logs, defaultBulkSize - 1);
            // Follower Thread Pool์— ์ €์žฅ ์š”์ฒญ
            followerExecutor.execute(() -> saveFunction.accept(logs));

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("Leader thread was interrupted. Exiting.", e);
            break;
        } catch (Exception e) {
            log.error("Unexpected error in leader thread", e);
        }
    }
}    

logQueue.drainTo(logs, defaultBulkSize - 1); ์—์„œ log๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ๋‚˜์˜ค๋ฉด defaultBulkSize ๋งŒํผ ๋‹ค ์ฐจ์ง€ ์•Š๋”๋ผ๋„ ๋ชจ๋“  ๋กœ๊ทธ๋ฅผ ์ถ”์ถœํ•ด์„œ flush๋ฅผ ํ•œ๋‹ค.

void leaderTask(Consumer<List<Log>> saveFunction) {
    long lastFlushTime = System.currentTimeMillis();

    while (!Thread.currentThread().isInterrupted()) {
        try {
            int size = logQueue.size();

            // ํ˜„์žฌ ์‹œ๊ฐ„ ํ™•์ธ
            long currentTime = System.currentTimeMillis();

            // 2์ดˆ๊ฐ€ ์ง€๋‚ฌ๊ฑฐ๋‚˜, ํ์˜ ํฌ๊ธฐ๊ฐ€ defaultBulkSize ์ด์ƒ์ธ ๊ฒฝ์šฐ flush
            if ((currentTime - lastFlushTime > defaultTimeout) || size >= defaultBulkSize) {
                List<Log> logs = new ArrayList<>();

                // ๋กœ๊ทธ๋ฅผ ์ตœ๋Œ€ defaultBulkSize ๊ฐœ์ˆ˜๋งŒํผ ํ์—์„œ ๊ฐ€์ ธ์˜ด
                logQueue.drainTo(logs, defaultBulkSize);

                if (!logs.isEmpty()) {
                    followerExecutor.execute(() -> saveFunction.accept(logs));
                }
                lastFlushTime = currentTime;
            }
        } catch (Exception e) {
            log.error("Unexpected error in leader thread", e);
        }
    }
}

lastFlushTime ์„ ๊ธฐ๋กํ•ด์„œ ์กฐ๊ฑด์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค์ •ํ•ด์„œ ์ œ๋Œ€๋กœ ๋กœ๊ทธ๊ฐ€ ์Œ“์˜€์„๋•Œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

6. ๋‹ค์‹œ ํ…Œ์ŠคํŠธ

150 TPS๋กœ ๊ณ ์ • ์•ˆ์ •ํ™” ๋จ์„ ํ™•์ธ

๐Ÿงซ ํŒ€ ๋ฌธํ™”

โš™๏ธ ๊ตฌ์„ฑ

๐Ÿ”จ ๊ฐœ๋ฐœ ์œ„ํ‚ค

๐Ÿž Bug Report

๐Ÿงช Test Logs

Clone this wiki locally