<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>보초개발</title>
    <link>https://bocho-developer.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 13 Aug 2026 09:30:11 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>유당불내증이 있는 개발자</managingEditor>
    <image>
      <title>보초개발</title>
      <url>https://tistory1.daumcdn.net/tistory/5927721/attach/c76d28f63d4a43f4910de97da6363989</url>
      <link>https://bocho-developer.tistory.com</link>
    </image>
    <item>
      <title>String, StringBuilder, StringBuffer 성능 비교</title>
      <link>https://bocho-developer.tistory.com/63</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;JSCODE 자바스터디 2주차 공부 중 실습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;String, StringBuilder, StringBuffer&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난번정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bocho-developer.tistory.com/16&quot;&gt;https://bocho-developer.tistory.com/16&lt;/a&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;String&lt;/b&gt;은 불변클래스로 문자열 연산 시 기존 문자열을 수정하는 것이 아니라 새로운 인스턴스를 생성하여 힙 영역에 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런&lt;span&gt; &lt;/span&gt;작업이&lt;span&gt; &lt;/span&gt;반복&lt;span&gt; &lt;/span&gt;수행되면서&lt;span&gt; &lt;/span&gt;메모리를&lt;span&gt; &lt;/span&gt;많이&lt;span&gt; &lt;/span&gt;사용하게&lt;span&gt; &lt;/span&gt;되고&lt;span&gt; &lt;/span&gt;응답&lt;span&gt; &lt;/span&gt;속도에도&lt;span&gt; &lt;/span&gt;많은&lt;span&gt; &lt;/span&gt;영향을&lt;span&gt; &lt;/span&gt;끼치게&lt;span&gt; &lt;/span&gt;된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;StringBuilder&lt;/b&gt;는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;동기화 되어있지 않아 싱글스레드 환경에서 사용&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;StringBuffer&lt;/span&gt;&lt;/b&gt;는 메소드 내부에 synchronized 키워드 설정이 되어있어 멀티스레드 환경에서 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;성능 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-20 오후 10.24.44.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Na16f/btsMRiTT8zz/h4DTYobfX0dpSYnGJzJ9pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Na16f/btsMRiTT8zz/h4DTYobfX0dpSYnGJzJ9pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Na16f/btsMRiTT8zz/h4DTYobfX0dpSYnGJzJ9pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNa16f%2FbtsMRiTT8zz%2Fh4DTYobfX0dpSYnGJzJ9pk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;464&quot; height=&quot;228&quot; data-filename=&quot;스크린샷 2025-03-20 오후 10.24.44.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1742477167035&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static void stringTest() {
        long startTime = System.currentTimeMillis();
        long startMemory = getMemoryUsage();

        String str = &quot;&quot;;
        for (int i = 0; i &amp;lt; 100000; i++) {
            str += &quot;abcd&quot;;
            str += &quot;efgh&quot;;
            str += &quot;ijkl&quot;;
            str += &quot;mnop&quot;;
        }

        long endTime = System.currentTimeMillis();
        long endMemory = getMemoryUsage();


        System.out.println(&quot;string 연산 실행 시간: &quot; + (endTime - startTime) + &quot;ms&quot;);
        System.out.println(&quot;메모리 사용: &quot; + ((endMemory - startMemory) / (1024.0 * 1024.0)) + &quot; MB&quot;);
        System.out.println();
    }
    
    private static void stringBufferTest() {
        long startTime = System.currentTimeMillis();
        long startMemory = getMemoryUsage();

        StringBuffer stringBuffer = new StringBuffer(&quot;&quot;);
        for (int i = 0; i &amp;lt; 100000; i++) {
            stringBuffer.append(&quot;abcd&quot;);
            stringBuffer.append(&quot;efgh&quot;);
            stringBuffer.append(&quot;ijkl&quot;);
            stringBuffer.append(&quot;mnop&quot;);
        }

        long endTime = System.currentTimeMillis();
        long endMemory = getMemoryUsage();


        System.out.println(&quot;stringBuffer 실행 시간: &quot; + (endTime - startTime) + &quot;ms&quot;);
        System.out.println(&quot;메모리 사용: &quot; + ((endMemory - startMemory) / (1024.0 * 1024.0)) + &quot; MB&quot;);
        System.out.println();
    }

    private static void stringBuilderTest() {
        long startTime = System.currentTimeMillis();
        long startMemory = getMemoryUsage();

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i &amp;lt; 100000; i++) {
            stringBuilder.append(&quot;abcd&quot;);
            stringBuilder.append(&quot;efgh&quot;);
            stringBuilder.append(&quot;ijkl&quot;);
            stringBuilder.append(&quot;mnop&quot;);
        }

        long endTime = System.currentTimeMillis();
        long endMemory = getMemoryUsage();


        System.out.println(&quot;stringBuilder 실행 시간: &quot; + (endTime - startTime) + &quot;ms&quot;);
        System.out.println(&quot;메모리 사용: &quot; + ((endMemory - startMemory) / (1024.0 * 1024.0)) + &quot; MB&quot;);
    }

    private static long getMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세가지 메서드다 테스트 방식은 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능을 측정하기 위해 10만번의 루프를 돌며 각각 소요시간과 메모리 사용량을 측정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트 결과&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-20 오후 10.25.33.png&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkRSlU/btsMQEJSsvw/bNLCOFbFEkxk0g4AK6RbWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkRSlU/btsMQEJSsvw/bNLCOFbFEkxk0g4AK6RbWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkRSlU/btsMQEJSsvw/bNLCOFbFEkxk0g4AK6RbWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkRSlU%2FbtsMQEJSsvw%2FbNLCOFbFEkxk0g4AK6RbWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;325&quot; height=&quot;211&quot; data-filename=&quot;스크린샷 2025-03-20 오후 10.25.33.png&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 연산 시 약 14초가 소요되었고 메모리 사용량도 String 연산과 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;StringBuilder 와 Buffer에 비하면 차이가 크다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;생각했던 거보다 꽤나 큰 차이를 보인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;그러나 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;StringBuilder&lt;/span&gt;와 StringBuffer는 실행시간과 메모리 사용량이에서 큰 차이가 보이지는 않았다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;자바 성능 튜닝 이야기 - 조영호 참고&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;StringBuffer는 클래스의 static으로 선언한 문자열을 변경하거나, singleton으로 선언된 클래스에 선언된 문자열일 경우에 사용해야한다.&lt;br /&gt;&lt;br /&gt;StringBuilder의 경우 메서드 내에 변수를 선언했다면 해당 변수는 메서드 내에서만 살아있으므로 StringBuilder를 사용하면 된다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;/div&gt;</description>
      <category>책/자바 성능 튜닝이야기</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/63</guid>
      <comments>https://bocho-developer.tistory.com/63#entry63comment</comments>
      <pubDate>Thu, 20 Mar 2025 19:29:35 +0900</pubDate>
    </item>
    <item>
      <title>중고차를 알아보다 작성하는 조회 성능 개선기 (Redis 캐싱)</title>
      <link>https://bocho-developer.tistory.com/58</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;중고차의 늪&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 중고차에 관심이가 &lt;b&gt;벤츠 인증 중고차&lt;/b&gt; 사이트를 자주 들락날락했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;문제는 사이트에서 차량 조회하면&lt;span&gt; &lt;/span&gt;&lt;span&gt;약 &lt;/span&gt;2초 이상 소요되어 이쁜 자동차들을 빠르게 구경하지 못해 고통받았다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;답답해서 사이트를 금방 탈주하게 되었고 개선이 필요해 보였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-18 오후 9.03.37.png&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;1364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnKTPb/btsMmH75MIP/oVnTNCP20XKUgXllDzkho1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnKTPb/btsMmH75MIP/oVnTNCP20XKUgXllDzkho1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnKTPb/btsMmH75MIP/oVnTNCP20XKUgXllDzkho1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnKTPb%2FbtsMmH75MIP%2FoVnTNCP20XKUgXllDzkho1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3456&quot; height=&quot;1364&quot; data-filename=&quot;스크린샷 2025-02-18 오후 9.03.37.png&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;1364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그에 비해 &lt;b&gt;엔카&lt;/b&gt;는 86.55ms로 아주 훌륭한 조회 성능을 보여준다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;덕분에 엔카에 한번 접속하면 2시간은 순삭이다. 최적의 조회 성능으로 헤어나지 못하게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-18 오후 9.12.04.png&quot; data-origin-width=&quot;3444&quot; data-origin-height=&quot;1090&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byuMzx/btsMnFuSbSj/d9q9Qf2ikdXlcPRDwkoPrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byuMzx/btsMnFuSbSj/d9q9Qf2ikdXlcPRDwkoPrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byuMzx/btsMnFuSbSj/d9q9Qf2ikdXlcPRDwkoPrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyuMzx%2FbtsMnFuSbSj%2Fd9q9Qf2ikdXlcPRDwkoPrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3444&quot; height=&quot;1090&quot; data-filename=&quot;스크린샷 2025-02-18 오후 9.12.04.png&quot; data-origin-width=&quot;3444&quot; data-origin-height=&quot;1090&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 조회 성능은 매우중요하다. 2초 아니 1초만 소요되도 느리다고 생각해 사용자에게 좋지 않은 경험을 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;조회 성능 개선 고민&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 프로젝트에서 100만건의 상품데이터를 관리하며 발생되는 문제 중 상품 검색 조회 같은 경우 Elasticsearch를 적용하여 성능 개선하였고 단건 조회에서의 문제를 찾아봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 PK기반의 단건 조회는 인덱스 설정으로 RDB에서도 100~200ms의 Elasticsearch만큼 빠르지 않지만 양호한 조회 성능을 보여줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 Elasticsearch를 사용 중이라 단건 조회도 함께 처리할 수 있지 않을까 생각했지만 모든 조회를 Elasticsearch로 통합하는 것이 맞을까 고민했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양호한 조회 성능 나오는 단건 조회에서 RDB와 Elasticserach간의 실시간 데이터 동기화 문제, 추가적인 운영 부담을 안고 사용할래? 묻는다면 오버엔지니어링일 수 있다 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 인기상품 같은 경우 사용자의 조회가 많아 성능 문제가 생길거라 생각했고 얼마나 차이가 있을지 트래픽이 몰리는 상황을 만들어 테스트를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인기 상품 조회 성능 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초당 500번의 요청이 발생하는 상황에서의 인기 상품 단건 조회 테스트 진행&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오전 2.58.17.png&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EwYJW/btsMliN2AUd/P8BKpISRAwwrY1ZiohXg91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EwYJW/btsMliN2AUd/P8BKpISRAwwrY1ZiohXg91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EwYJW/btsMliN2AUd/P8BKpISRAwwrY1ZiohXg91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEwYJW%2FbtsMliN2AUd%2FP8BKpISRAwwrY1ZiohXg91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1550&quot; height=&quot;73&quot; data-filename=&quot;스크린샷 2025-02-07 오전 2.58.17.png&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;TPS&lt;/b&gt; 500&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;처리량&lt;/b&gt;: 32.9/sec&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최소 응답 시간&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;: 375ms&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최대 응답 시간&lt;/b&gt;: 14407ms (약 14.4초)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;평균 응답시간:&lt;/b&gt; 3938ms (약 3.9초)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능에 심각한 문제가 보였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회 성능을 위해 이미 인덱스를 적용해 더이상의 성능 개선 효과를 기대하긴 어려웠고 캐싱을 시도했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 상품을 캐싱하기에는 무리가 있었고 트래픽이 몰릴거라 예상되는 인기상품 TOP 10을 정해 캐싱하기로 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Log 작업&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-18 오전 3.58.48.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBium5/btsMmcM34tp/3nKnqYLc126rY4ZhocKkN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBium5/btsMmcM34tp/3nKnqYLc126rY4ZhocKkN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBium5/btsMmcM34tp/3nKnqYLc126rY4ZhocKkN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBium5%2FbtsMmcM34tp%2F3nKnqYLc126rY4ZhocKkN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;526&quot; height=&quot;91&quot; data-filename=&quot;스크린샷 2025-02-18 오전 3.58.48.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상품조회 수치를 집계하기 위해 Logstash 설정 후 상품 단건 조회 시 로그를 저장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캐싱 스케줄러 로직 구현&lt;/h2&gt;
&lt;pre id=&quot;code_1739818902289&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @Transactional
  public void refreshPopularProductsCache() {
    TimeRange timeRangeForCache = schedulerUtil.getTimeRangeForCache();

    List&amp;lt;LogDetails&amp;gt; logDetailsList = getLogsInTimeRange(timeRangeForCache);

    Map&amp;lt;String, Integer&amp;gt; productIdAndViewCount = calculateProductViewCounts(logDetailsList);

    saveCacheProduct(productIdAndViewCount);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 현재 시간부터 1시간 전 TimeRange 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Logstash에서 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;TimeRange 시간대에 맞는&lt;/span&gt;&amp;nbsp;로그 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 조회된 로그 값에서 상품 아이디, 조회 수 계산&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 인기 상품 Redis 캐싱&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상품 단건 조회 캐시 적용&lt;/h2&gt;
&lt;pre id=&quot;code_1739863079813&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  public ProductDetails findById(String productPublicId) {
    log.info(&quot;publicId = {}&quot;, productPublicId);

    ProductDetails cachedProduct = productOperations.get(&quot;getProduct:&quot; + productPublicId);
    if (cachedProduct != null) {
      return cachedProduct;
    }

    return productRepository.findByProductAndCurrentPrice(productPublicId)
        .orElseThrow(() -&amp;gt; new ProductException(
            ErrorCode.PRODUCT_NOT_FOUND));
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 캐시에서 데이터 확인 후 있으면 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 없으면 DB 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Look Aside 전략과는 비슷하지만 조금 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시에 데이터가 없다면 DB에서 조회 후 캐시 데이터를 저장 하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인기상품 캐싱 후 부하테스트&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오전 3.12.42.png&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NYToR/btsMnri2kRZ/qKaDtiyzYAIwKbIlvgqZZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NYToR/btsMnri2kRZ/qKaDtiyzYAIwKbIlvgqZZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NYToR/btsMnri2kRZ/qKaDtiyzYAIwKbIlvgqZZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNYToR%2FbtsMnri2kRZ%2FqKaDtiyzYAIwKbIlvgqZZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1558&quot; height=&quot;91&quot; data-filename=&quot;스크린샷 2025-02-07 오전 3.12.42.png&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;TPS:500&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;처리량&lt;/b&gt;: 238.1/sec&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최소 응답 시간&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;: 44ms&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최대 응답 시간&lt;/b&gt;: 1719ms (약 1.7초)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;평균 응답시간:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;346.85ms (약 0.35초)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;인기 상품 캐싱 전 후 비교&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;평균 응답시간이 3938ms -&amp;gt; 346.85ms&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;약 11.2배 상승했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전체 처리 소요시간은 15.2s -&amp;gt; 2.4s&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;약 6배 단축되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>이슈</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/58</guid>
      <comments>https://bocho-developer.tistory.com/58#entry58comment</comments>
      <pubDate>Fri, 14 Feb 2025 03:46:45 +0900</pubDate>
    </item>
    <item>
      <title>EXPLAIN 발표</title>
      <link>https://bocho-developer.tistory.com/57</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스파르타 단기심화반에서 전체 발표 할 수 있는 기회가 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인생은 도전이고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;드디어 때가 왔다.&lt;/span&gt;. 기회 생기면 다 해보자라는 마음으로 사는중이라 내심 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;나는 EXPLAIN에 대해서 준비하며&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;전 회사에서 겪었던 성능 개선 과정에 대해 문제점들을 있다 생각했고 발표를 통해 공유하고 싶었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;EXPLAIN 키워드를 알고 있다면 문제해결 방법에서 느낌이 아닌 데이터로 판단하는 개발을 할 수 있을 거라 생각한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;그래서 많은 내용보다는 발표를 보는 사람들이 이 키워드에 대해서 인식할 수 있다면 반은 성공이다.. 라는 마음으로 발표 자료를 준비했다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Group 1000006360.png&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btGlOb/btsL4n9kV3w/JNoPezYbHLWpWP3i9ETl51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btGlOb/btsL4n9kV3w/JNoPezYbHLWpWP3i9ETl51/img.png&quot; data-alt=&quot;이렇게 홍보사진도 만들어주셔서 너무 감사하다.. (많은 사람들이 집중했으면 좋겠어서 사진으로 어그로를 끌어봤다...)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btGlOb/btsL4n9kV3w/JNoPezYbHLWpWP3i9ETl51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtGlOb%2FbtsL4n9kV3w%2FJNoPezYbHLWpWP3i9ETl51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;317&quot; height=&quot;96&quot; data-filename=&quot;Group 1000006360.png&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이렇게 홍보사진도 만들어주셔서 너무 감사하다.. (많은 사람들이 집중했으면 좋겠어서 사진으로 어그로를 끌어봤다...)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;발표 자료 및 영상&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자료는 노션으로 준비했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용을 정리하며 편리했지만 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이번에&lt;span&gt; 발표해보니&amp;nbsp;&lt;/span&gt;&lt;/span&gt;PPT로 준비하는게 집중하기 더 좋을거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;발표 링크&quot; href=&quot;https://dorian-hub-840.notion.site/EXPLAIN-18ff3adef064804aacb2f86350a5bf3d&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dorian-hub-840.notion.site/EXPLAIN-18ff3adef064804aacb2f86350a5bf3d&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1742302828841&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;EXPLAIN (쿼리 실행 계획)  | Notion&quot; data-og-description=&quot; &amp;nbsp;발표영상 00:20 ~ 12:50&quot; data-og-host=&quot;dorian-hub-840.notion.site&quot; data-og-source-url=&quot;https://dorian-hub-840.notion.site/EXPLAIN-18ff3adef064804aacb2f86350a5bf3d&quot; data-og-url=&quot;https://dorian-hub-840.notion.site/EXPLAIN-18ff3adef064804aacb2f86350a5bf3d&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bNl3Ug/hyYvsCuk6K/90yslIPad3cJhs6y4ahEZK/img.png?width=537&amp;amp;height=127&amp;amp;face=0_0_537_127,https://scrap.kakaocdn.net/dn/bUhKPv/hyYvu1m0pn/NUmymKERXmJsCxKDrFjhkk/img.png?width=537&amp;amp;height=127&amp;amp;face=0_0_537_127&quot;&gt;&lt;a href=&quot;https://dorian-hub-840.notion.site/EXPLAIN-18ff3adef064804aacb2f86350a5bf3d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dorian-hub-840.notion.site/EXPLAIN-18ff3adef064804aacb2f86350a5bf3d&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bNl3Ug/hyYvsCuk6K/90yslIPad3cJhs6y4ahEZK/img.png?width=537&amp;amp;height=127&amp;amp;face=0_0_537_127,https://scrap.kakaocdn.net/dn/bUhKPv/hyYvu1m0pn/NUmymKERXmJsCxKDrFjhkk/img.png?width=537&amp;amp;height=127&amp;amp;face=0_0_537_127');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;EXPLAIN (쿼리 실행 계획) | Notion&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;발표영상 00:20 ~ 12:50&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dorian-hub-840.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;발표 영상을 다시 보니 아쉬움이 많이 남는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;그동안 살면서 더 긴장되고 많은 일들을 있었다고 생각하며 준비도 여러 번 했지만 막상 발표하니 많이 떨렸다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;영상을 보니 목소리 톤이 루즈해지는 느낌이 들어 전달력이 떨어지는 거 같다. 어려운 내용은 아니라 생각했지만 전달하려는 바가 잘 됐을까&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #222225; text-align: start;&quot;&gt;다음번에 기회가 생긴다면 더 잘 준비해서 다시 발표해 보고 싶다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>db</category>
      <category>explain</category>
      <category>MySQL</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/57</guid>
      <comments>https://bocho-developer.tistory.com/57#entry57comment</comments>
      <pubDate>Sat, 1 Feb 2025 17:57:49 +0900</pubDate>
    </item>
    <item>
      <title>상품 재고 관리 - 비관적 락 vs 분산 락 적용 사례</title>
      <link>https://bocho-developer.tistory.com/56</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;재고 차감 동시성 문제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;  &lt;/span&gt;주문-상품 서비스간 2PC 방식 구현 중 동일 상품에 대한 동시 주문 발생 시 재고 수량 데이터 불일치 문제 발견&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JMeter 테스트 상품 재고 100개, 200번의 동시 요청&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트 요청 수 - 200건&lt;/li&gt;
&lt;li&gt;성공 응답 수 - 200건&lt;/li&gt;
&lt;li&gt;오류율 - 0%&lt;/li&gt;
&lt;li&gt;평균 처리 시간 - 167.8/sec&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오후 3.51.47.png&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l0oLN/btsL24oBYeX/Kw2dlugGko0Fq00OlFqa8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l0oLN/btsL24oBYeX/Kw2dlugGko0Fq00OlFqa8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l0oLN/btsL24oBYeX/Kw2dlugGko0Fq00OlFqa8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl0oLN%2FbtsL24oBYeX%2FKw2dlugGko0Fq00OlFqa8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1556&quot; height=&quot;99&quot; data-filename=&quot;스크린샷 2025-01-12 오후 3.51.47.png&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 요청을 성공으로 응답했으나 데이터베이스의 실제 데이터와 불일치가 발생&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재고 차감 이력 테이블 : 200건 기록&lt;/li&gt;
&lt;li&gt;실제 상품 재고: 79개 (21개 차감)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오후 3.51.32.png&quot; data-origin-width=&quot;1663&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctVNnq/btsL3gCiXgT/arUt50vCqTXtqYRekHm0xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctVNnq/btsL3gCiXgT/arUt50vCqTXtqYRekHm0xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctVNnq/btsL3gCiXgT/arUt50vCqTXtqYRekHm0xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctVNnq%2FbtsL3gCiXgT%2FarUt50vCqTXtqYRekHm0xK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1663&quot; height=&quot;448&quot; data-filename=&quot;스크린샷 2025-01-12 오후 3.51.32.png&quot; data-origin-width=&quot;1663&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 방안 고민&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;❓분산락 적용 안한 이유&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;분산락은 전체 프로세스에 락을 걸어 동시성을 제어&lt;/li&gt;
&lt;li&gt;상품 재고 차감은 DB에 단일 리소스 업데이트 하는 과정으로 전체 프로세스에 락을 걸 필요X&lt;/li&gt;
&lt;li&gt;여러 DB서버가 존재하는게 아니고 현재 단일 DB서버 사용중&lt;/li&gt;
&lt;li&gt;지금 같은 상황에서 분산락을 적용한다면 오버스팩이라고 생각&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;❓낙관적 락 적용 안한 이유&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;롤백 재시도 로직 구현하기 번거롭고 작성한 로직에서 추가적인 문제 발생할 수 있다&lt;/li&gt;
&lt;li&gt;인기상품 구매로 동시요청이 많아질 경우 계속 충돌 발생하면서 부하발생&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관적락 적용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오후 4.08.49 (1).png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3DlyN/btsL2PxWFUe/qBTuSz5m8DYCit7sh0PWWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3DlyN/btsL2PxWFUe/qBTuSz5m8DYCit7sh0PWWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3DlyN/btsL2PxWFUe/qBTuSz5m8DYCit7sh0PWWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3DlyN%2FbtsL2PxWFUe%2FqBTuSz5m8DYCit7sh0PWWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;156&quot; data-filename=&quot;스크린샷 2025-01-12 오후 4.08.49 (1).png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JMeter 테스트 상품 재고 100개, 200번의 동시 요청&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트 요청 수 - 200건&lt;/li&gt;
&lt;li&gt;성공 응답 수 - 100건&lt;/li&gt;
&lt;li&gt;오류율 - 50%&lt;/li&gt;
&lt;li&gt;평균 처리 시간 - 143.9/sec&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오후 4.12.17.png&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddfnaS/btsL2dMPtVB/kLFc7QKeKK4zqmNEsZoa30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddfnaS/btsL2dMPtVB/kLFc7QKeKK4zqmNEsZoa30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddfnaS/btsL2dMPtVB/kLFc7QKeKK4zqmNEsZoa30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddfnaS%2FbtsL2dMPtVB%2FkLFc7QKeKK4zqmNEsZoa30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1552&quot; height=&quot;94&quot; data-filename=&quot;스크린샷 2025-01-12 오후 4.12.17.png&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 결과와 데이터베이스의 정합성 보장&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재고 차감 이력 테이블 - 100건 기록&lt;/li&gt;
&lt;li&gt;실제 상품 재고 - 0개 (초기 100개에서 모두 차감)&lt;/li&gt;
&lt;li&gt;실패한 요청 - 100건 (재고 부족으로 인한 에러)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오후 4.18.57.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCtKCx/btsL3A8lMfB/5YDkTKiEsLJTmpO0o62L10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCtKCx/btsL3A8lMfB/5YDkTKiEsLJTmpO0o62L10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCtKCx/btsL3A8lMfB/5YDkTKiEsLJTmpO0o62L10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCtKCx%2FbtsL3A8lMfB%2F5YDkTKiEsLJTmpO0o62L10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1206&quot; height=&quot;319&quot; data-filename=&quot;스크린샷 2025-01-12 오후 4.18.57.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;재고 롤백 스케줄러 &amp;nbsp;분산락 적용&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;문제 상황&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;여러 인스턴스 환경에서 상품 재고 롤백 스케줄러 실행 시 중복 증가 문제 발생&lt;/p&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42;&quot;&gt;&lt;code&gt;[서버 A]
1. 조회: 재고 차감 이력 테이블(stock_decrease_history)에서 재고 차감 후 커밋되지 않은 이력 조회
2. 처리: 상품 재고 테이블(top_size_stock) 재고 증가 

[서버 B]
1. 조회: 재고차감 이력 테이블(stock_decrease_history)에서 서버 A와 같은 중복 데이터 조회
2. 처리: 상품 재고 테이블(top_size_stock) 재고 증가 (이미 처리된 건에 대해서도 재고 증가 발생)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-11 오후 11.54.19.png&quot; data-origin-width=&quot;2479&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5B73/btsL3nBnRTZ/YnmkacplTvu0QDGjsMR6Zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5B73/btsL3nBnRTZ/YnmkacplTvu0QDGjsMR6Zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5B73/btsL3nBnRTZ/YnmkacplTvu0QDGjsMR6Zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5B73%2FbtsL3nBnRTZ%2FYnmkacplTvu0QDGjsMR6Zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2479&quot; height=&quot;469&quot; data-filename=&quot;스크린샷 2025-01-11 오후 11.54.19.png&quot; data-origin-width=&quot;2479&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;해결방안&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;❓비관적 락 적용 안한 이유&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;두 테이블 간의 데이터 정합성 문제 (재고 차감 이력 테이블, 상품 재고테이블)&lt;/li&gt;
&lt;li&gt;비관적 락 은 해당 테이블(상품 재고) 특정 로우에만 락을 걸어 순차적인 재고 증가 문제는 해결 가능&lt;/li&gt;
&lt;li&gt;하지만 재고 차감 이력 테이블(stock_decrease_history)에서 중복 데이터가 먼저 조회문제는 비관적락과 상관 X&lt;/li&gt;
&lt;li&gt;두 테이블 간 조회 및 처리에 대한 작업을 비관적락으로는 해결 불가&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;분산락 적용&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;분산락 획득&lt;/li&gt;
&lt;li&gt;트랜잭션 시작&amp;nbsp;&lt;/li&gt;
&lt;li&gt;rollback 메서드 실행 (커밋되지 않은 이력 조회 후 재고 증가)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;트랜잭션 종료&amp;nbsp;&lt;/li&gt;
&lt;li&gt;분산락 해제&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 락을 획득한 하나의 서버만 전체 프로세스 실행&lt;/li&gt;
&lt;li&gt;다음 서버가 락 획득 후 프로세스 실행으로 불필요한 중복 데이터 조회 및 처리 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오전 12.16.43.png&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbBFoj/btsL1i9dKCq/iPiWF9zgTePFZitn4Ikaq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbBFoj/btsL1i9dKCq/iPiWF9zgTePFZitn4Ikaq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbBFoj/btsL1i9dKCq/iPiWF9zgTePFZitn4Ikaq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbBFoj%2FbtsL1i9dKCq%2FiPiWF9zgTePFZitn4Ikaq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;765&quot; height=&quot;462&quot; data-filename=&quot;스크린샷 2025-01-12 오전 12.16.43.png&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;처음과 같이 중복 실행되지 않고 하나의 인스턴스에서만 롤백스케줄러를 실행하는것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-12 오전 12.14.08.png&quot; data-origin-width=&quot;2503&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvQ95m/btsL3jeHawX/CzMHXYDKBmhQKrHChRmMTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvQ95m/btsL3jeHawX/CzMHXYDKBmhQKrHChRmMTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvQ95m/btsL3jeHawX/CzMHXYDKBmhQKrHChRmMTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvQ95m%2FbtsL3jeHawX%2FCzMHXYDKBmhQKrHChRmMTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2503&quot; height=&quot;476&quot; data-filename=&quot;스크린샷 2025-01-12 오전 12.14.08.png&quot; data-origin-width=&quot;2503&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;</description>
      <category>이슈</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/56</guid>
      <comments>https://bocho-developer.tistory.com/56#entry56comment</comments>
      <pubDate>Fri, 31 Jan 2025 02:30:20 +0900</pubDate>
    </item>
    <item>
      <title>RDB vs Elasticsearch 검색 성능 비교</title>
      <link>https://bocho-developer.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;상품 조회 시 트래픽 증가로 성능 저하문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상품데이터는 100만건, 상품 검색 조회 시 JPA QueryDsl을 사용하여 검색 조회를 하였고 소요시간은 꽤나 걸렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. RDB 상품 검색 목록 조회 평균 응답시간&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.32.41.png&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVWOey/btsL3Xb7o3M/c5IUHrUm0KasMkkUfUtTsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVWOey/btsL3Xb7o3M/c5IUHrUm0KasMkkUfUtTsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVWOey/btsL3Xb7o3M/c5IUHrUm0KasMkkUfUtTsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVWOey%2FbtsL3Xb7o3M%2Fc5IUHrUm0KasMkkUfUtTsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;781&quot; height=&quot;388&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.32.41.png&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.28.16.png&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bztEPM/btsL46sgT0t/Yb9Zui0qOky9fkPi3a3Rh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bztEPM/btsL46sgT0t/Yb9Zui0qOky9fkPi3a3Rh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bztEPM/btsL46sgT0t/Yb9Zui0qOky9fkPi3a3Rh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbztEPM%2FbtsL46sgT0t%2FYb9Zui0qOky9fkPi3a3Rh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;349&quot; height=&quot;337&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.28.16.png&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RDB 정상 범위 데이터 4건의 평균 소요 시간
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2897 + 2639 + 2663 + 2624&amp;nbsp; = 10823&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;평균 소요 시간
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;10,823&amp;nbsp;&amp;divide; 4건&amp;nbsp;&lt;/li&gt;
&lt;li&gt;약 2.7초&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 Full-Text Index 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Full-Text Index를 적용하고 기존 Like 문을 변경했다.&lt;/p&gt;
&lt;pre id=&quot;code_1738392985970&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WHERE  	 P.NAME LIKE '%니트%'&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738392972970&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WHERE  MATCH(P.NAME) AGAINST ('니트');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-01 오후 3.59.30.png&quot; data-origin-width=&quot;2266&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHvskI/btsL31liLvq/SVgUBzumzkvj0RnFYGEqF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHvskI/btsL31liLvq/SVgUBzumzkvj0RnFYGEqF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHvskI/btsL31liLvq/SVgUBzumzkvj0RnFYGEqF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHvskI%2FbtsL31liLvq%2FSVgUBzumzkvj0RnFYGEqF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2266&quot; height=&quot;382&quot; data-filename=&quot;스크린샷 2025-02-01 오후 3.59.30.png&quot; data-origin-width=&quot;2266&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXPLAIN ANALYZE를 실행해보니 예상대로 Full-text index가 성공적으로 적용되어 소요시간이 줄어든것을 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 조회되는 rows=0&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무슨 문제일까 알아보니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 MySQL은 3글자 미만의 단어는 인덱싱하지 않아서 한글의 경우 2바이트 문자이므로 이 설정의 영향을 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-01 오후 4.02.14.png&quot; data-origin-width=&quot;2272&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wQNN7/btsL4OyEf9Z/W2T1yxy00INT20UpmzeEMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wQNN7/btsL4OyEf9Z/W2T1yxy00INT20UpmzeEMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wQNN7/btsL4OyEf9Z/W2T1yxy00INT20UpmzeEMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwQNN7%2FbtsL4OyEf9Z%2FW2T1yxy00INT20UpmzeEMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2272&quot; height=&quot;384&quot; data-filename=&quot;스크린샷 2025-02-01 오후 4.02.14.png&quot; data-origin-width=&quot;2272&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색조건을 니트 -&amp;gt; 알파카 3글자로 변경하니 잘 반환된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 한글을 무조건 3글자 이상 검색하지는 않을것이다. 다른 방법을 적용해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 엘라스틱서치 적용&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2.1 데이터 동기화 방법 고민&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;동기 처리&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 하나의 트랜잭션안에서 DB와 엘라스틱 저장해서 실시간으로 데이터 저장&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;동기 처리 고민&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 브랜드에서 상품 등록 시 얼마나 트래픽이 발생할까?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 실시간으로 처리가 필요한가?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 엘라스틱서치 동기화 장애로 인해 상품노출이 누락된어 보여지지 않고 있다면? 차라리 동기식으로 처리하여 등록 시 오류가 있다는걸 알면 좋지 않을까 -&amp;gt; 빠르게 문의가능&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;비동기 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. logstash 사용하여 주기적으로 엘라스틱서치에 데이터 동기화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. DB저장 후 이벤트 발행&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;비동기 처리 고민&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 브랜드에서 대량의 상품을 한번에 등록하는 경우가 많다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 또 이미지와 상세설명 등 데이터가 크다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 등록 즉시 검색될 필요는 있으나 약간의 지연은 큰 문제가 아닐 수 있다?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4. 대부분 logstash 사용하여 주기적으로 DB와 엘라스틱서치 데이터 동기화를 하는것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결론&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보편적으로 많이 사용하는 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Logstash 파이프라인 방식으로 데이터 동기화 진행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;상품검색시 조회되는 쿼리 데이터를 엘라스틱서치 index로 설정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;동기화 문제 해결&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Logstash와 MySQL이 서로 다른 도커 컨테이너에서 실행 되어 Logstash가 MySQL 주소 찾지 못하는 문제
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;하나의 docker-compose.yml에서 실행으로 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RDB와 엘라스틱서치 중복 데이터 제거
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Logstash 파이프라인에서 document_id =&amp;gt; &quot;%{product_id}&quot; 추가하여 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;sql_last_value를 활용한 데이터 변경 추적
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Logstash 파이프라인의 sql_last_value값을 created_at, updated_at과 비교하여 생성, 수정된 데이터 변경 감지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 Elasticsearch 상품 검색 목록 조회 평균 응답시간&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.33.12.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDtw4D/btsL4RITnwW/1uQz2t84mfw76h9EM4dceK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDtw4D/btsL4RITnwW/1uQz2t84mfw76h9EM4dceK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDtw4D/btsL4RITnwW/1uQz2t84mfw76h9EM4dceK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDtw4D%2FbtsL4RITnwW%2F1uQz2t84mfw76h9EM4dceK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;803&quot; height=&quot;416&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.33.12.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.32.21.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNX1zv/btsL4bBdzTi/Cm99VmAMJbDRhawZk9qNK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNX1zv/btsL4bBdzTi/Cm99VmAMJbDRhawZk9qNK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNX1zv/btsL4bBdzTi/Cm99VmAMJbDRhawZk9qNK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNX1zv%2FbtsL4bBdzTi%2FCm99VmAMJbDRhawZk9qNK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;158&quot; data-filename=&quot;스크린샷 2025-01-23 오후 4.32.21.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Elasticsearch 정상 범위 데이터 4건의 평균 소요 시간&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;100 + 58 + 47 + 49 = 254 ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;평균 소요 시간
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;254 &amp;divide; 4건&lt;/li&gt;
&lt;li&gt;약 0.06초 (63.5ms)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 검색 성능 개선 결과&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;RDB vs Elasticsearch&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RDB: 약 2.7초 (2,705ms)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Elasticsearch: 약 0.06초 (63.5ms)&lt;/li&gt;
&lt;li&gt;Elasticsearch가 RDB보다 약 42.6배 더 빠른 검색 속도를 보여줌&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>이슈</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/55</guid>
      <comments>https://bocho-developer.tistory.com/55#entry55comment</comments>
      <pubDate>Fri, 10 Jan 2025 00:28:54 +0900</pubDate>
    </item>
    <item>
      <title>24년 회고</title>
      <link>https://bocho-developer.tistory.com/54</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;취업 그리고 퇴사&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;24년 1월부터 다니던 회사를 8월말에 퇴사하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;입사 후 얼마 지나지 않아 &lt;/span&gt;선임 개발자들의 퇴사로 인해 입사 동기와 둘이서 백엔드 업무를 진행하게 되는데 그때부터 뭔가 잘못돼감을 느꼈다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 당시에는 '기회다 오히려 좋아. 이참에 나의 기술적 역량을 높이며 실무에 적용해 보자' 라는 부푼 마음을 가지고 임했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각했던 것보다 작은 서비스라도 신입 둘이서 운영하기에 많은 어려움이 있었고 개인의 기술 역량, 문제 해결능력의 중요성을 느꼈다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느정도 시간이 지났고 회사에서 원하는 더 이상의 기능개발은 없었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 월급이 들어오지 않았고 며칠 뒤 회사 경영난으로 인해 권고사직을 권유하는 메일을 받았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 당시에는 막막함도 있었지만 '드디어 각잡고 공부할 때가 왔다. 초심으로 돌아가자' 라는 생각을 했기 때문에 마냥 아쉽지만은 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 두달 치 월급을 받지 못한채 개발팀 대부분의 사람들이 퇴사를 하였다. 그렇게 작은회사는 아니라고 생각했는데 이렇게 갑자기 회사가 망할 줄은 몰랐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴사하니 그때 왜 더 아득바득 공부해서 여러 가지 시도를 해보지 못했을까 하는 아쉬움이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;떼인 돈 받기&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴사 후 밀린 월급을 받기 위해 회사와의 연락, 고용노동부 방문을 하며 그렇게 두달정도를 보냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 회사는 협조에 저조했고 약속했던 실업급여를 받기까지도 꽤 오랜시간이 걸렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세상의 쓴맛을 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이바닥도 쉽지 않구나.. 스트레스도 상당했고 무언가 손에 잡히지 않았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 인생경험이라 생각했고 하나씩 해결해가며 어느정도 마무리 되었다. (아직 못 받은 돈이 조금 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴때가 아니다 다시 공부를 시작하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스파르타 코딩클럽&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F-LAB 멘토링 과정을 고민하던 중 스파르타 코딩클럽 단기심화 과정을 보게 되었고 대용량 트래픽 처리, MSA 키워드에 꽂혀 과정을 진행하게 되었다. 사실 국비 심화과정이라 무료였던 점도 컸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국비학원 출신으로서 국비, 부트캠프를 그렇게 신뢰하지는 않는다. 교육기관에 무언가 크게 바라지 않았고 공부하는 기간중 하나의 과정이라 생각하고 임했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 생각했던 것보다 좋다. (너무 다행이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3번의 프로젝트를 진행하게된다. 뛰어난 팀원들도 만났고&lt;span&gt; &lt;/span&gt;&lt;/span&gt;담당 튜터님은 그동안 만나본 개발자 중에서도 선한 인성과 비례되는 좋은 실력을 가지셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두가지 충족되는 개발자들은 잘 보지 못했는데 이게 가능한거였구나 싶다. 나의 롤모델 리스트중 한분이 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모의면접을 통한 기본기, 팀원들의 트러블 슈팅, 튜터님 특강 등 혼자 공부했다면 경험해 보지 못했을 거 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 현타를 많이 느껴 감정의 변화가 자주 생긴다. 덕분에 공부에 집중을 못 할 때도 있지만 정해진 스케줄 안에서 팀원들과 이야기 나누며 지루하지 않게 공부하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오래 앉아있지만 다 습득하진 못한거 같아 아쉬움은 크다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;끝으로&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년은 다사다난한 해였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴사를 하고 공부를 하니 다시 개발에 재미를 느끼고 있는 중이다.&amp;nbsp;나는 아니라 생각했지만 환경에 영향을 많이 받는 사람이라 느꼈고 뭔가 진거 같아서 아쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;25년은 개발 오타쿠로 살아가 보려한다. 좋은 개발자로 성장할 수 있기를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/54</guid>
      <comments>https://bocho-developer.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 1 Jan 2025 02:57:10 +0900</pubDate>
    </item>
    <item>
      <title>try-with-resources</title>
      <link>https://bocho-developer.tistory.com/52</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;try-finally 문제점&lt;/h2&gt;
&lt;pre id=&quot;code_1735059181843&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package exam;

public class TryFinally {
    public static void main(String[] args) throws Exception {
        TestResource testResource = new TestResource();
        try {
            testResource.firstMethod();
        } finally {
            testResource.close();
        }
    }


    static class TestResource implements AutoCloseable {
        public void firstMethod() {
            System.out.println(&quot;firstMethod() 실행 &quot;);
            throw new RuntimeException(&quot;첫번째 에러 발생&quot;);
        }

        @Override
        public void close() throws Exception {
            System.out.println(&quot;close() 실행 &quot;);
            throw new RuntimeException(&quot;두번째 에러 발생&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 첫번째 메서드에서 에러가 발생했고 close()메서드를 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.만약 finally 에서 에러가 발생한다면 첫번째 메서드의 에러는 두번째 에러에 가려지게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.처음 오류가 발생 근원지를 찾을 수 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-25 오전 2.02.14.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l1Zlq/btsLwqNb9J9/96yxmmn2D0YUcQpEn41yI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l1Zlq/btsLwqNb9J9/96yxmmn2D0YUcQpEn41yI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l1Zlq/btsLwqNb9J9/96yxmmn2D0YUcQpEn41yI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl1Zlq%2FbtsLwqNb9J9%2F96yxmmn2D0YUcQpEn41yI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1592&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2024-12-25 오전 2.02.14.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735059762899&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/Users/dongpillson/Library/Java/JavaVirtualMachines/corretto-17.0.9/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=50215:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/dongpillson/study/TIL/out/production/TIL exam.TryFinally
firstMethod() 실행 
close() 실행 
Exception in thread &quot;main&quot; java.lang.RuntimeException: 두번째 에러 발생
	at exam.TryFinally$TestResource.close(TryFinally.java:23)
	at exam.TryFinally.main(TryFinally.java:9)

Process finished with exit code 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;try-with-resources 적용&lt;/h2&gt;
&lt;pre id=&quot;code_1735059805854&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package exam;

public class TryWithResources {
    public static void main(String[] args) throws Exception {
        try (TestResource testResource = new TestResource();) {
            testResource.firstMethod();
        }
    }


    static class TestResource implements AutoCloseable {
        public void firstMethod() {
            System.out.println(&quot;firstMethod() 실행 &quot;);
            throw new RuntimeException(&quot;첫번째 에러 발생&quot;);
        }

        @Override
        public void close() throws Exception {
            System.out.println(&quot;close() 실행 &quot;);
            throw new RuntimeException(&quot;두번째 에러 발생&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두개의 에러가 발생하는것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-25 오전 2.03.56.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JfBzi/btsLxZAHa6C/Pc8aRRf9EzlFOIdbKAK4U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JfBzi/btsLxZAHa6C/Pc8aRRf9EzlFOIdbKAK4U1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JfBzi/btsLxZAHa6C/Pc8aRRf9EzlFOIdbKAK4U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJfBzi%2FbtsLxZAHa6C%2FPc8aRRf9EzlFOIdbKAK4U1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1358&quot; height=&quot;447&quot; data-filename=&quot;스크린샷 2024-12-25 오전 2.03.56.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>책/이펙티브 자바</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/52</guid>
      <comments>https://bocho-developer.tistory.com/52#entry52comment</comments>
      <pubDate>Wed, 25 Dec 2024 02:20:41 +0900</pubDate>
    </item>
    <item>
      <title>Kafka, Redis를 활용한 이벤트 중복 처리 방지</title>
      <link>https://bocho-developer.tistory.com/51</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2차 팀프로젝트 회고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_image (3).png&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYZpQ/btsLpbve00o/CP8uvbQBLFNwG05Mk9kkkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYZpQ/btsLpbve00o/CP8uvbQBLFNwG05Mk9kkkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYZpQ/btsLpbve00o/CP8uvbQBLFNwG05Mk9kkkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYZpQ%2FbtsLpbve00o%2FCP8uvbQBLFNwG05Mk9kkkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;456&quot; data-filename=&quot;edited_image (3).png&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문 서비스와 배송 서비스 간 Kafka 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 지연, 시스템 장애 등으로 인한 메시지 중복 전송이나 순서 보장 문제가 발생할 수 있는 문제에 대한 고민&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구성&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;-&amp;nbsp;메시지&amp;nbsp;큐:&amp;nbsp;Kafka&lt;br /&gt;-&amp;nbsp;중복&amp;nbsp;처리&amp;nbsp;방지:&amp;nbsp;Redis&lt;br /&gt;-&amp;nbsp;이벤트&amp;nbsp;타입:&amp;nbsp;OrderCreateEvent&amp;nbsp;(주문&amp;nbsp;생성&amp;nbsp;이벤트)&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;1. 이벤트 중복 처리 방지&lt;/h3&gt;
&lt;pre id=&quot;code_1734536312318&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@KafkaListener(
            topics = &quot;${spring.kafka.consumer.topic.order.create}&quot;, // OrderCreateEvent
            groupId = &quot;${spring.kafka.consumer.group-id}&quot;, // group-delivery
            containerFactory = &quot;orderCreateEventListener&quot;
    )
    public void consumeOrderCreateEvent(DomainEventEnvelop&amp;lt;OrderCreateEvent&amp;gt; eventEnvelop) {
        OrderCreateEvent orderCreateEvent = eventEnvelop.getEvent();
        Long orderId = orderCreateEvent.getOrderId();
        LocalDateTime createdAt = eventEnvelop.getCreatedAt();
        String eventKey = EVENT_KEY_PREFIX + orderId;

        // 현재 이벤트가 기존 이벤트보다 과거이거나 같은 시간이면 무시
        String existingEventTimestamp = redisTemplate.opsForValue().get(eventKey);
        if (existingEventTimestamp != null) {
            LocalDateTime existingCreatedAt = LocalDateTime.parse(existingEventTimestamp);
            if (!createdAt.isAfter(existingCreatedAt)) {
                log.warn(&quot;과거 이벤트 발생 [orderId: {}, currentEventTimestamp: {}, existingEventTimestamp: {}&quot; , orderId, createdAt, existingCreatedAt);
                return;
            }
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis를 활용하여 주문아이디와 이벤트의 타임스탬프 정보를 저장하였고 동일한 주문 아이디에 대해 이전 이벤트보다 과거의 이벤트가 들어오면 무시&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 이벤트 정보 저장&lt;/h3&gt;
&lt;pre id=&quot;code_1734620218309&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;redisTemplate.opsForValue().set(eventKey, createdAt.toString(), Duration.ofDays(1));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 정보를 Redis에 1일간 보관, TTL설정을 어떻게 하면 좋을지 판단이 안되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 배송 생성&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1734620309627&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
    deliveryService.createDelivery(DeliveryCreateRequestDto.from(orderCreateEvent));
} catch (Exception e) {
    log.error(&quot;Failed to process OrderCreateEvent - orderId: {}, error: {}&quot;,
            orderCreateEvent.getOrderId(), e.getMessage(), e);
    throw new RuntimeException(e);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효한 이벤트에 대해 배송 생성 하며 예외 발생 시 로그 기록&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터베이스 기반 중복 처리 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 이벤트 발생되는 로그를 테이블에 저장 후 값을 읽어와도 될 거같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 부하 증가, 이벤트 처리 지연 시간 증가의 문제가 있다는것을 예상은 하지만 트래픽이 얼만큼 발생되느냐에 따라 다를거같다. 또 아직 그만큼의 트래픽은 경험해보지 못해서 이번에 비교 성능테스트를 하지못한 점은 아쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 발생 정보를 레디스로 저장 후 휘발 시킬것인가? 로그까지 저장할 것인가에 대한 고민은 해결되지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-20 오전 12.17.22.png&quot; data-origin-width=&quot;1297&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkOpwn/btsLpBUGZaZ/MKonMArpUqpEzycBYqxHh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkOpwn/btsLpBUGZaZ/MKonMArpUqpEzycBYqxHh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkOpwn/btsLpBUGZaZ/MKonMArpUqpEzycBYqxHh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkOpwn%2FbtsLpBUGZaZ%2FMKonMArpUqpEzycBYqxHh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1297&quot; height=&quot;838&quot; data-filename=&quot;스크린샷 2024-12-20 오전 12.17.22.png&quot; data-origin-width=&quot;1297&quot; data-origin-height=&quot;838&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>이슈</category>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/51</guid>
      <comments>https://bocho-developer.tistory.com/51#entry51comment</comments>
      <pubDate>Thu, 19 Dec 2024 00:31:45 +0900</pubDate>
    </item>
    <item>
      <title>Ch.2 대규모 AI 시스템 설계 프로젝트 S.A</title>
      <link>https://bocho-developer.tistory.com/50</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;API 명세서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.notion.so/teamsparta/API-4919a95833be44d2bf9228a1c9b5e1b9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.notion.so/teamsparta/API-4919a95833be44d2bf9228a1c9b5e1b9&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1733711173361&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;API 명세서 | Notion&quot; data-og-description=&quot;  Basic Response 구조&quot; data-og-host=&quot;teamsparta.notion.site&quot; data-og-source-url=&quot;https://www.notion.so/teamsparta/API-4919a95833be44d2bf9228a1c9b5e1b9&quot; data-og-url=&quot;https://teamsparta.notion.site/API-4919a95833be44d2bf9228a1c9b5e1b9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qRqMj/hyXGMjudJG/WhyEgPlGTclwHZaeXKzmD0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/QoWxX/hyXGNbE95d/QxbKTQtkuHlKK1PvkYhjck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.notion.so/teamsparta/API-4919a95833be44d2bf9228a1c9b5e1b9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.notion.so/teamsparta/API-4919a95833be44d2bf9228a1c9b5e1b9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qRqMj/hyXGMjudJG/WhyEgPlGTclwHZaeXKzmD0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/QoWxX/hyXGNbE95d/QxbKTQtkuHlKK1PvkYhjck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;API 명세서 | Notion&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Basic Response 구조&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;teamsparta.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1311&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEIMev/btsLbQYB5rd/KTHACYiKkVynOXoax7bXM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEIMev/btsLbQYB5rd/KTHACYiKkVynOXoax7bXM0/img.png&quot; data-alt=&quot;Auth(회원) API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEIMev/btsLbQYB5rd/KTHACYiKkVynOXoax7bXM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEIMev%2FbtsLbQYB5rd%2FKTHACYiKkVynOXoax7bXM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;266&quot; data-origin-width=&quot;1311&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Auth(회원) API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oFsUD/btsLbvf3cr9/2WXIByjo22vjqbEVeNkeq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oFsUD/btsLbvf3cr9/2WXIByjo22vjqbEVeNkeq1/img.png&quot; data-alt=&quot;주문 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oFsUD/btsLbvf3cr9/2WXIByjo22vjqbEVeNkeq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoFsUD%2FbtsLbvf3cr9%2F2WXIByjo22vjqbEVeNkeq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;265&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주문 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FiiOw/btsLa9K7xAk/dAERiIGnbwjQtqrwSZU8kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FiiOw/btsLa9K7xAk/dAERiIGnbwjQtqrwSZU8kK/img.png&quot; data-alt=&quot;상품 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FiiOw/btsLa9K7xAk/dAERiIGnbwjQtqrwSZU8kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFiiOw%2FbtsLa9K7xAk%2FdAERiIGnbwjQtqrwSZU8kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;867&quot; height=&quot;378&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상품 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tyK2B/btsLcHs8yR2/Ri9bASLHRwpOq7C8xZ5kYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tyK2B/btsLcHs8yR2/Ri9bASLHRwpOq7C8xZ5kYk/img.png&quot; data-alt=&quot;배송 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tyK2B/btsLcHs8yR2/Ri9bASLHRwpOq7C8xZ5kYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtyK2B%2FbtsLcHs8yR2%2FRi9bASLHRwpOq7C8xZ5kYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;278&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배송 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Au8Fl/btsLaLqtMfD/F6SYCDt5ZhOB0E8drKLdJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Au8Fl/btsLaLqtMfD/F6SYCDt5ZhOB0E8drKLdJ0/img.png&quot; data-alt=&quot;배송 경로 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Au8Fl/btsLaLqtMfD/F6SYCDt5ZhOB0E8drKLdJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAu8Fl%2FbtsLaLqtMfD%2FF6SYCDt5ZhOB0E8drKLdJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;287&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배송 경로 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY0Yn4/btsLb001kbu/6xuTEhoBhkxQzP3IGZNQ50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY0Yn4/btsLb001kbu/6xuTEhoBhkxQzP3IGZNQ50/img.png&quot; data-alt=&quot;배송 담당자 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY0Yn4/btsLb001kbu/6xuTEhoBhkxQzP3IGZNQ50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY0Yn4%2FbtsLb001kbu%2F6xuTEhoBhkxQzP3IGZNQ50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;285&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배송 담당자 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJcZRY/btsLcJ5yGQ8/wiekYvT7COfXZ035VR27CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJcZRY/btsLcJ5yGQ8/wiekYvT7COfXZ035VR27CK/img.png&quot; data-alt=&quot;허브 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJcZRY/btsLcJ5yGQ8/wiekYvT7COfXZ035VR27CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJcZRY%2FbtsLcJ5yGQ8%2FwiekYvT7COfXZ035VR27CK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;268&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;허브 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CiSfJ/btsLbYoxfy2/ROHale7t40SPq6kEyb1FD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CiSfJ/btsLbYoxfy2/ROHale7t40SPq6kEyb1FD0/img.png&quot; data-alt=&quot;허브 경로 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CiSfJ/btsLbYoxfy2/ROHale7t40SPq6kEyb1FD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCiSfJ%2FbtsLbYoxfy2%2FROHale7t40SPq6kEyb1FD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;295&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;허브 경로 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pq7yp/btsLcxc9QWF/feMV6xVaXLjsLWocWBdNnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pq7yp/btsLcxc9QWF/feMV6xVaXLjsLWocWBdNnK/img.png&quot; data-alt=&quot;업체 API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pq7yp/btsLcxc9QWF/feMV6xVaXLjsLWocWBdNnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpq7yp%2FbtsLcxc9QWF%2FfeMV6xVaXLjsLWocWBdNnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;287&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;업체 API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkw9kP/btsLaYJPbiG/InrSkzbKEIfRNZkPkqLoCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkw9kP/btsLaYJPbiG/InrSkzbKEIfRNZkPkqLoCK/img.png&quot; data-alt=&quot;SNS, AI API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkw9kP/btsLaYJPbiG/InrSkzbKEIfRNZkPkqLoCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdkw9kP%2FbtsLaYJPbiG%2FInrSkzbKEIfRNZkPkqLoCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;431&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SNS, AI API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테이블 명세서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.notion.so/teamsparta/DB-2f6f5a7373bf4fd0bed1e5f573d04f1e&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.notion.so/teamsparta/DB-2f6f5a7373bf4fd0bed1e5f573d04f1e&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1733709894170&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;DB 설계 | Notion&quot; data-og-description=&quot;  테이블 명세&quot; data-og-host=&quot;teamsparta.notion.site&quot; data-og-source-url=&quot;https://www.notion.so/teamsparta/DB-2f6f5a7373bf4fd0bed1e5f573d04f1e&quot; data-og-url=&quot;https://teamsparta.notion.site/DB-2f6f5a7373bf4fd0bed1e5f573d04f1e&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sclev/hyXGAQVpFN/JD66O6FyItVkOkgDgp37F1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.notion.so/teamsparta/DB-2f6f5a7373bf4fd0bed1e5f573d04f1e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.notion.so/teamsparta/DB-2f6f5a7373bf4fd0bed1e5f573d04f1e&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sclev/hyXGAQVpFN/JD66O6FyItVkOkgDgp37F1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DB 설계 | Notion&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  테이블 명세&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;teamsparta.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;ERD&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baN7FK/btsLbuIaWYz/S2KlIXFEKlHRZGkF3FA4vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baN7FK/btsLbuIaWYz/S2KlIXFEKlHRZGkF3FA4vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baN7FK/btsLbuIaWYz/S2KlIXFEKlHRZGkF3FA4vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaN7FK%2FbtsLbuIaWYz%2FS2KlIXFEKlHRZGkF3FA4vK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1350&quot; height=&quot;733&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인프라 설계서&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image (3).png&quot; data-origin-width=&quot;3036&quot; data-origin-height=&quot;1648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YsjHT/btsLpOsK36N/jpRCGD8eXYfX4H623QEXWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YsjHT/btsLpOsK36N/jpRCGD8eXYfX4H623QEXWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YsjHT/btsLpOsK36N/jpRCGD8eXYfX4H623QEXWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYsjHT%2FbtsLpOsK36N%2FjpRCGD8eXYfX4H623QEXWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3036&quot; height=&quot;1648&quot; data-filename=&quot;image (3).png&quot; data-origin-width=&quot;3036&quot; data-origin-height=&quot;1648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/50</guid>
      <comments>https://bocho-developer.tistory.com/50#entry50comment</comments>
      <pubDate>Mon, 9 Dec 2024 11:26:34 +0900</pubDate>
    </item>
    <item>
      <title>OSIV (Open Session In View)</title>
      <link>https://bocho-developer.tistory.com/48</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSIV (Open Session In View)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트를 HTTP 요청 시작부터 응답까지 유지하는 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서  View라는 개념이 어떤건지 궁금했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REST API 등 View가 없는 서비스에서도 이 용어를 그대로 사용한다고 한다&lt;/li&gt;
&lt;li&gt;View라기보다는 클라이언트에 대한 응답이 완료되는 시점을 의미&lt;/li&gt;
&lt;li&gt;HTTP&amp;nbsp;응답이 끝날 때까지 영속성 컨텍스트를 유지하는 개념으로 확장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSIV의 View는 역사적인 용어이며 현재는 클라이언트에 대한 응답 완료 시점으로 이해하면 된다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;spring.jpa.open-in-view=?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA를 사용하면 yml에서 위의 값을 true,false로 설정할 수 있다. 기본 설정값은 true이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;spring.jpa.open-in-view=true&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 설정이 true 라면 http 요청 시작부터 끝까지 DB커넥션을 가져와 영속성 컨텍스트를 유지한다. (영속성 컨텍스트는 기본적으로 커넥션을 유지)&lt;/li&gt;
&lt;li&gt;트랜잭션 범위가 아닌 곳에서도 사용할 수 있다는 것인데 예를들면 controller단에서의 엔티티 조회시 Lazy loading으로 조회가 가능하다.&lt;/li&gt;
&lt;li&gt;커넥션을 오래 가지고 있게되어 성능에 문제가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;spring.jpa.open-in-view=false&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Transactional 이 붙은 service 쪽에서만 영속성 컨텍스트를 유지한다.&lt;/li&gt;
&lt;li&gt;만약 다른곳에서 사용하고 싶다면 DTO 클래스를 만들어 반환하여 구성&lt;/li&gt;
&lt;li&gt;오래 DB커넥션을 가지고 있지않아 대용량 트래픽 상황에서 커넥션 관리에 용이하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring.jpa.open-in-view=true 설정했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;별문제없이 Lazy Loading이 동작한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.07.51.png&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CfKIZ/btsK1LduUNj/VRkiWcVtk54QD9JYfuLJNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CfKIZ/btsK1LduUNj/VRkiWcVtk54QD9JYfuLJNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CfKIZ/btsK1LduUNj/VRkiWcVtk54QD9JYfuLJNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCfKIZ%2FbtsK1LduUNj%2FVRkiWcVtk54QD9JYfuLJNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;809&quot; height=&quot;173&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.07.51.png&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.08.47.png&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p8U40/btsK1P1kodM/3qdwL3HrUhpUxiKuTVidGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p8U40/btsK1P1kodM/3qdwL3HrUhpUxiKuTVidGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p8U40/btsK1P1kodM/3qdwL3HrUhpUxiKuTVidGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp8U40%2FbtsK1P1kodM%2F3qdwL3HrUhpUxiKuTVidGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1454&quot; height=&quot;148&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.08.47.png&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 spring.jpa.open-in-view=false&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LazyInitializationException이 발생한다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.07.59.png&quot; data-origin-width=&quot;2448&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv9F7D/btsK14RsJGg/zGukBP9GWkpAcZGo1qzAbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv9F7D/btsK14RsJGg/zGukBP9GWkpAcZGo1qzAbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv9F7D/btsK14RsJGg/zGukBP9GWkpAcZGo1qzAbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv9F7D%2FbtsK14RsJGg%2FzGukBP9GWkpAcZGo1qzAbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2448&quot; height=&quot;250&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.07.59.png&quot; data-origin-width=&quot;2448&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 service단에서도 @Transactional을 붙이지 않으면 LazyInitializationException이 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.20.38.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzF5sy/btsK17f8s4F/crLMj1iHHWiFiUwrYkX4Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzF5sy/btsK17f8s4F/crLMj1iHHWiFiUwrYkX4Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzF5sy/btsK17f8s4F/crLMj1iHHWiFiUwrYkX4Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzF5sy%2FbtsK17f8s4F%2FcrLMj1iHHWiFiUwrYkX4Ek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;791&quot; height=&quot;271&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.20.38.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.20.44.png&quot; data-origin-width=&quot;2402&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci0Pgg/btsK3PZkwok/bNwEU5Ji57tW5grcWBqiHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci0Pgg/btsK3PZkwok/bNwEU5Ji57tW5grcWBqiHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci0Pgg/btsK3PZkwok/bNwEU5Ji57tW5grcWBqiHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci0Pgg%2FbtsK3PZkwok%2FbNwEU5Ji57tW5grcWBqiHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1158&quot; height=&quot;101&quot; data-filename=&quot;스크린샷 2024-11-30 오전 1.20.44.png&quot; data-origin-width=&quot;2402&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service를 제외하고는 엔티티를 직접적으로 사용하지 않게 코드를 작성해왔다 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 spring.jpa.open-in-view=true 기본설정값으로 인해 @Transactional 없는곳에서 동작했던 부분에 대해&amp;nbsp; 직접 오류를 겪어보지 못했던거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도 Service쪽이 아닌 View 즉, 다른곳에서는 엔티티를 직접 호출하지 않을 것 같지만 Lazy Loading 관련해 동작원리에 대해 다시 되짚어보게 되는 시간이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 DB 커넥션을 HTTP 요청 시점부터 계속 잡고 응답 시에 반환하는 것은 대규모 트래픽에서 커넥션 풀 문제가 발생할 수 있다는 점을 이번에 새로 알게되었고 트래픽 상황에 고려해 설정값을 false로 두어야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 :Claud, ChatGPT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ykh6242.tistory.com/entry/JPA-OSIVOpen-Session-In-View%EC%99%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ykh6242.tistory.com/entry/JPA-OSIVOpen-Session-In-View%EC%99%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732982216949&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JPA - OSIV(Open Session In View) 정리&quot; data-og-description=&quot;OSIV(Open Session In View) OSIV(Open Session In View)는 영속성 컨텍스트를 뷰까지 열어두는 기능이다. 영속성 컨텍스트가 유지되면 엔티티도 영속 상태로 유지된다. 뷰까지 영속성 컨텍스트가 살아있다면 &quot; data-og-host=&quot;ykh6242.tistory.com&quot; data-og-source-url=&quot;https://ykh6242.tistory.com/entry/JPA-OSIVOpen-Session-In-View%EC%99%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94&quot; data-og-url=&quot;https://ykh6242.tistory.com/entry/JPA-OSIVOpen-Session-In-View%EC%99%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d68si6/hyXGLDgCy1/R7Bh3iP4D8KK38m9Fkv9PK/img.png?width=800&amp;amp;height=324&amp;amp;face=0_0_800_324,https://scrap.kakaocdn.net/dn/bBzKGd/hyXGHAQktZ/qCHm8bnn25JUXuHH71pMV0/img.png?width=800&amp;amp;height=324&amp;amp;face=0_0_800_324,https://scrap.kakaocdn.net/dn/ArONy/hyXDmFasjs/tKp5AeeKAby2s32lvUcyoK/img.png?width=906&amp;amp;height=368&amp;amp;face=0_0_906_368&quot;&gt;&lt;a href=&quot;https://ykh6242.tistory.com/entry/JPA-OSIVOpen-Session-In-View%EC%99%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ykh6242.tistory.com/entry/JPA-OSIVOpen-Session-In-View%EC%99%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d68si6/hyXGLDgCy1/R7Bh3iP4D8KK38m9Fkv9PK/img.png?width=800&amp;amp;height=324&amp;amp;face=0_0_800_324,https://scrap.kakaocdn.net/dn/bBzKGd/hyXGHAQktZ/qCHm8bnn25JUXuHH71pMV0/img.png?width=800&amp;amp;height=324&amp;amp;face=0_0_800_324,https://scrap.kakaocdn.net/dn/ArONy/hyXDmFasjs/tKp5AeeKAby2s32lvUcyoK/img.png?width=906&amp;amp;height=368&amp;amp;face=0_0_906_368');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JPA - OSIV(Open Session In View) 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;OSIV(Open Session In View) OSIV(Open Session In View)는 영속성 컨텍스트를 뷰까지 열어두는 기능이다. 영속성 컨텍스트가 유지되면 엔티티도 영속 상태로 유지된다. 뷰까지 영속성 컨텍스트가 살아있다면&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ykh6242.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>유당불내증이 있는 개발자</author>
      <guid isPermaLink="true">https://bocho-developer.tistory.com/48</guid>
      <comments>https://bocho-developer.tistory.com/48#entry48comment</comments>
      <pubDate>Sun, 1 Dec 2024 01:12:49 +0900</pubDate>
    </item>
  </channel>
</rss>