<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발한다고 호들갑 떠는 사람</title>
    <link>https://kyeum-d.tistory.com/</link>
    <description>대단히 반갑습니다</description>
    <language>ko</language>
    <pubDate>Tue, 2 Jun 2026 09:38:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>동겸동</managingEditor>
    <image>
      <title>개발한다고 호들갑 떠는 사람</title>
      <url>https://tistory1.daumcdn.net/tistory/5512959/attach/9a6b01eb9f8b4c4e92f3eda0ef72e4e7</url>
      <link>https://kyeum-d.tistory.com</link>
    </image>
    <item>
      <title>우리의 MongoDB 의 Rolling Update 는 안전한가</title>
      <link>https://kyeum-d.tistory.com/47</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 &quot;부하가 심한 상황에서 Rolling Update 를 언제 해야 되나&quot;는 이사님의 질문으로부터 시작되어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 테크데이에 발표까지 하게된 Mongo의 Rolling Update에 대해서 다뤄볼까 합니다.&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;MongoDB Atlas 환경에서 예상 가능한 부하를 대비하기 위해 어떤 전략으로 클러스터를 확장할지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게&amp;nbsp;안정적인&amp;nbsp;서비스를&amp;nbsp;제공할&amp;nbsp;것인가에&amp;nbsp;대한&amp;nbsp;고민을 하는&amp;nbsp;분들을&amp;nbsp;위한&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;Rolling Update, 어떻게 진행될까요?&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 문제가 없는 일반적인 상황에서의 Update&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7DWoH/dJMcacb609d/laKzXrYEq4DDbyuiZGiWC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7DWoH/dJMcacb609d/laKzXrYEq4DDbyuiZGiWC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7DWoH/dJMcacb609d/laKzXrYEq4DDbyuiZGiWC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7DWoH%2FdJMcacb609d%2FlaKzXrYEq4DDbyuiZGiWC1%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 Atlas의 클러스터는 1대의 Primary와 2대의 secondary 노드로 구성된 형태를 지닙니다.&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;Mongo DB의 Patch 를 적용해야 하는 상황이 왔습니다.&lt;br /&gt;관리자는&amp;nbsp;Update&amp;nbsp;트리거를&amp;nbsp;동작시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbCzGH/dJMcacb609r/SUdmQH7BPy8IcCVlxHgvRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbCzGH/dJMcacb609r/SUdmQH7BPy8IcCVlxHgvRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbCzGH/dJMcacb609r/SUdmQH7BPy8IcCVlxHgvRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbCzGH%2FdJMcacb609r%2FSUdmQH7BPy8IcCVlxHgvRK%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Secondary 노드 중 한대는 Update 를 진행하고 Primary 와의 연결을 끊습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZF7cy/dJMcacb609f/5TKeEr3ZmjlVtl1pCkAAK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZF7cy/dJMcacb609f/5TKeEr3ZmjlVtl1pCkAAK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZF7cy/dJMcacb609f/5TKeEr3ZmjlVtl1pCkAAK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZF7cy%2FdJMcacb609f%2F5TKeEr3ZmjlVtl1pCkAAK1%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트가 완료된 Secondary 노드는 Primary 노드와 연결되며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 흐름으로 남은 Secondary 노드의 업데이트가 진행됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Wtgw/dJMcacb609o/wjhTh8IkBBYxx7TMVwXra1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Wtgw/dJMcacb609o/wjhTh8IkBBYxx7TMVwXra1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Wtgw/dJMcacb609o/wjhTh8IkBBYxx7TMVwXra1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Wtgw%2FdJMcacb609o%2FwjhTh8IkBBYxx7TMVwXra1%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Secondary 노드의 업데이트가 완료되면 Primary 노드가 업데이트 준비를 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wUlbp/dJMcaaZEWq5/jQ8bdmXYssZK9VpqXKk98K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wUlbp/dJMcaaZEWq5/jQ8bdmXYssZK9VpqXKk98K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wUlbp/dJMcaaZEWq5/jQ8bdmXYssZK9VpqXKk98K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwUlbp%2FdJMcaaZEWq5%2FjQ8bdmXYssZK9VpqXKk98K%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Primary 노드가 down 되면서 선거(election)을 트리거합니다.&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;여기서 선거(election)란, 차기 Primary 를 선출하기 위한 과정입니다.&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;이 선거 트리거를 가장 먼저 받은 Secondary 노드가 선거를 발생시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선거를 결정짓는 요소는 크게 term(임기번호) 와 optime(작업 기록)이 있습니다.&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;term 은 현재 몇대 대통령 선거인지를 나타내는 값이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;optime 은 primary 노드로부터 받은 작업 기록에 대한 값입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(기본적으로 secondary 노드는 쓰기 작업을 할 수 없으므로 primary 의 쓰기 작업에 대한 oplog 를 전달받아 기록합니다.)&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;br /&gt;선거가&amp;nbsp;발생했을&amp;nbsp;때&amp;nbsp;Secondary&amp;nbsp;노드들은&amp;nbsp;이&amp;nbsp;두가지&amp;nbsp;값을&amp;nbsp;기본으로&amp;nbsp;요청받은&amp;nbsp;노드의&amp;nbsp;Primary&amp;nbsp;찬/반&amp;nbsp;여부를&amp;nbsp;선택합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KRKNf/dJMcacb609q/MG2xG4Q7dJcWDZJWwrC9C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KRKNf/dJMcacb609q/MG2xG4Q7dJcWDZJWwrC9C1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KRKNf/dJMcacb609q/MG2xG4Q7dJcWDZJWwrC9C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKRKNf%2FdJMcacb609q%2FMG2xG4Q7dJcWDZJWwrC9C1%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;optime 이 조금 더 빨랐던 한 secondary 노드가 primary 노드가 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선거가 완료되면 term(임기) 값이 증가합니다.&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;secondary 로 강등된 노드는 업데이트를 진행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oGW4i/dJMcaaZEWqV/HyjvL9cutr5hKbxMwoyIz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oGW4i/dJMcaaZEWqV/HyjvL9cutr5hKbxMwoyIz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oGW4i/dJMcaaZEWqV/HyjvL9cutr5hKbxMwoyIz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoGW4i%2FdJMcaaZEWqV%2FHyjvL9cutr5hKbxMwoyIz1%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;1033&quot; height=&quot;708&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트가 완료되면 새롭게 선출된 primary 노드와 통신을 하며 업데이트가 마무리됩니다.&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;진행과정을 보면 아시겠지만 Raft 합의 알고리즘 기반의 동작임을 확인할 수 있습니다.&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. Primary 가 접근이 불가능한 경우 (Failover)&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebRKE7/dJMcacb609h/gKbisSR5WEihALy2j3Kvi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebRKE7/dJMcacb609h/gKbisSR5WEihALy2j3Kvi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebRKE7/dJMcacb609h/gKbisSR5WEihALy2j3Kvi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebRKE7%2FdJMcacb609h%2FgKbisSR5WEihALy2j3Kvi1%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;secondary 노드들은 election timeout 값을 가지고 있습니다.&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;이 timeout 시간이 지나게 되면 secondary 노드들은 선거를 발생시킵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MR5dS/dJMcaaZEWqS/batjWYfkivupmvCoen2Dk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MR5dS/dJMcaaZEWqS/batjWYfkivupmvCoen2Dk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MR5dS/dJMcaaZEWqS/batjWYfkivupmvCoen2Dk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMR5dS%2FdJMcaaZEWqS%2FbatjWYfkivupmvCoen2Dk0%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;primary 노드가 살아있을 때는 주기적으로 secondary 노드들에 heart beat 신호를 보냅니다.&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;heart beat 신호를 받은 secondary 노드들은 이 timeout 시간을 갱신하며 반역(?)을 참습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q2wc5/dJMcaaZEWq1/zK9JHFIime3qbL0eUnY230/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q2wc5/dJMcaaZEWq1/zK9JHFIime3qbL0eUnY230/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q2wc5/dJMcaaZEWq1/zK9JHFIime3qbL0eUnY230/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq2wc5%2FdJMcaaZEWq1%2FzK9JHFIime3qbL0eUnY230%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;979&quot; height=&quot;763&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 primary 가 죽자 더 이상 보낼 heart beat 가 없습니다.&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;여기서 모든 secondary 노드들이 한 번에 선거를 발생시키지 않도록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드별로 랜덤 한 offset 값이 timeout 타임에 추가됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/miKn9/dJMcaaZEWqZ/c8squj3Gf2SlixGAXFmRjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/miKn9/dJMcaaZEWqZ/c8squj3Gf2SlixGAXFmRjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/miKn9/dJMcaaZEWqZ/c8squj3Gf2SlixGAXFmRjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmiKn9%2FdJMcaaZEWqZ%2Fc8squj3Gf2SlixGAXFmRjK%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;offset 시간까지 합친 timeout 시간이 지나면 secondary 노드는 선거를 일으킵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uQeID/dJMcaaZEWq2/nTYhh22F8nCRihopyrMpo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uQeID/dJMcaaZEWq2/nTYhh22F8nCRihopyrMpo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uQeID/dJMcaaZEWq2/nTYhh22F8nCRihopyrMpo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuQeID%2FdJMcaaZEWq2%2FnTYhh22F8nCRihopyrMpo1%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;남은 노드들에 선거를 보내 투표를 획득합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOPs75/dJMcagMoaUp/NMujZHLqtF6IhPwWSwmNIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOPs75/dJMcagMoaUp/NMujZHLqtF6IhPwWSwmNIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOPs75/dJMcagMoaUp/NMujZHLqtF6IhPwWSwmNIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOPs75%2FdJMcagMoaUp%2FNMujZHLqtF6IhPwWSwmNIk%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선거로 새로운 pirmary 가 선출됩니다.&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;그런데 죽어있던 priamry 가 갑자기 눈을 뜬다면?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oUMyM/dJMcagMoaUk/5Vn3z6MPNFJwCg8A3064mK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oUMyM/dJMcagMoaUk/5Vn3z6MPNFJwCg8A3064mK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oUMyM/dJMcagMoaUk/5Vn3z6MPNFJwCg8A3064mK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoUMyM%2FdJMcagMoaUk%2F5Vn3z6MPNFJwCg8A3064mK%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 깨어난 primary 는 자신의 term 과 새로운 primary 의 term 을 비교합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUcSn8/dJMcaaZEWq0/7bRy1KENUxQ5h3cJMIOAf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUcSn8/dJMcaaZEWq0/7bRy1KENUxQ5h3cJMIOAf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUcSn8/dJMcaaZEWq0/7bRy1KENUxQ5h3cJMIOAf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUcSn8%2FdJMcaaZEWq0%2F7bRy1KENUxQ5h3cJMIOAf0%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인이 밀렸다는 사실을 깨달은 primary 노드는 secondary 노드로의 유배를 받아들이고 term 값을 증가시키며 마무리됩니다.&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. 부하가 심한 경우&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n1zR1/dJMcacb609k/wV7tKQQtSDoiNAsFHsnps0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n1zR1/dJMcacb609k/wV7tKQQtSDoiNAsFHsnps0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n1zR1/dJMcacb609k/wV7tKQQtSDoiNAsFHsnps0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn1zR1%2FdJMcacb609k%2FwV7tKQQtSDoiNAsFHsnps0%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스가 흥행하여 secondary 노드들에 CPU 75% 정도의 부하가 발생하고 있다고 가정해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/38ioi/dJMcagMoaUq/FgYPbU5aAFUO9ypRhfbO11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/38ioi/dJMcagMoaUq/FgYPbU5aAFUO9ypRhfbO11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/38ioi/dJMcagMoaUq/FgYPbU5aAFUO9ypRhfbO11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F38ioi%2FdJMcagMoaUq%2FFgYPbU5aAFUO9ypRhfbO11%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자가 이를 발견합니다(!).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF87mH/dJMcagMoaUr/CRgZs2gKCH2FAunKwZ6li1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF87mH/dJMcagMoaUr/CRgZs2gKCH2FAunKwZ6li1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF87mH/dJMcagMoaUr/CRgZs2gKCH2FAunKwZ6li1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF87mH%2FdJMcagMoaUr%2FCRgZs2gKCH2FAunKwZ6li1%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 인지한 관리자는 Mongo Atlas 의 스펙을 올리게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYevx4/dJMcagMoaUs/KRKjAxVC1cPaMfiEG3Z2X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYevx4/dJMcagMoaUs/KRKjAxVC1cPaMfiEG3Z2X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYevx4/dJMcagMoaUs/KRKjAxVC1cPaMfiEG3Z2X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYevx4%2FdJMcagMoaUs%2FKRKjAxVC1cPaMfiEG3Z2X1%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;976&quot; height=&quot;763&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Secondary 한대가 업데이트 모드로 들어가면서 Primary 와의 통신을 끊습니다.&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;그러자 남아있던 Secondary 노드는 모든 부하를 몰아 받습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tWYIf/dJMcaaZEWqY/xucXVf3kyM5ilUCC10k0Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tWYIf/dJMcaaZEWqY/xucXVf3kyM5ilUCC10k0Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tWYIf/dJMcaaZEWqY/xucXVf3kyM5ilUCC10k0Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtWYIf%2FdJMcaaZEWqY%2FxucXVf3kyM5ilUCC10k0Ek%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;976&quot; height=&quot;763&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참다못한 남아있던 Secondary 노드가 죽어버리는 불상사가 일어나게 됩니다.&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;직접 확인해 보자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 3대로 구성된 클러스터를 준비합니다 (M20)&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;rarr; 초당 1천 명 유저 정도의 부하를 줌 (읽기)&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pk8w6/dJMcacb609e/XQitzNR9XnL4wWJTj29G81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pk8w6/dJMcacb609e/XQitzNR9XnL4wWJTj29G81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pk8w6/dJMcacb609e/XQitzNR9XnL4wWJTj29G81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPk8w6%2FdJMcacb609e%2FXQitzNR9XnL4wWJTj29G81%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;1920&quot; height=&quot;333&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;1번부터
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;00-00 클러스터 (S)&lt;/li&gt;
&lt;li&gt;00-01 클러스터 (S)&lt;/li&gt;
&lt;li&gt;00-02 클러스터 (P)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Primary 는 읽기 작업에 대해 손하나 까딱 안 함&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Rolling Update 진행 (M20 &amp;rarr; M30)&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3utjQ/dJMcagMoaUm/RY4po7w6GfQKh1YhX3VGK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3utjQ/dJMcagMoaUm/RY4po7w6GfQKh1YhX3VGK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3utjQ/dJMcagMoaUm/RY4po7w6GfQKh1YhX3VGK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3utjQ%2FdJMcagMoaUm%2FRY4po7w6GfQKh1YhX3VGK0%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;1920&quot; height=&quot;489&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;489&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;01 클러스터가 먼저 Update 됨 &amp;rarr; (Down)&lt;/li&gt;
&lt;li&gt;00 클러스터가 부하를 다 받음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 2번 클러스터 업데이트 완료&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dH6wnV/dJMcacb609j/VulPnHvu8UqUq3vUcaLkHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dH6wnV/dJMcacb609j/VulPnHvu8UqUq3vUcaLkHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dH6wnV/dJMcacb609j/VulPnHvu8UqUq3vUcaLkHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdH6wnV%2FdJMcacb609j%2FVulPnHvu8UqUq3vUcaLkHk%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;1920&quot; height=&quot;532&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;532&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;primary 로 등극&lt;/li&gt;
&lt;li&gt;03 클러스터 강등&lt;/li&gt;
&lt;li&gt;01 클러스터 Update (Down)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 1번 클러스터 업데이트 진행&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uRzfp/dJMcacb609g/K8rjh7MPxdGtoNevDHl5L0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uRzfp/dJMcacb609g/K8rjh7MPxdGtoNevDHl5L0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uRzfp/dJMcacb609g/K8rjh7MPxdGtoNevDHl5L0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuRzfp%2FdJMcacb609g%2FK8rjh7MPxdGtoNevDHl5L0%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;1920&quot; height=&quot;528&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;528&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;01 클러스터는 정지&lt;/li&gt;
&lt;li&gt;primary 에서 강등된 03 클러스터 열일 중&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 3번 클러스터 업데이트까지 진행된 이후 최종 정상화&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ntxPI/dJMcaaZEWqW/VUWBKS3uGdb6Snr2VcykI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ntxPI/dJMcaaZEWqW/VUWBKS3uGdb6Snr2VcykI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ntxPI/dJMcaaZEWqW/VUWBKS3uGdb6Snr2VcykI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FntxPI%2FdJMcaaZEWqW%2FVUWBKS3uGdb6Snr2VcykI0%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;1920&quot; height=&quot;340&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;340&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;03 클러스터의 그래프 부분에 보면 Down time 동안 값이 없는 것을 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;?? Secondary 부터 다 업데이트되고 Primary 가 변경된다면서요?&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;rarr; priority 에 따라 Priority Takeover 가 적용됨&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;priority 란? &amp;rarr; 노드 자체의 우선순위를 말함
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이 우선순위가 높은 노드가 등장하면 강제로 선거가 진행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;160&quot; data-origin-height=&quot;116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPHSun/dJMcagMoaUn/9ZWUaDuQcrNBMYfiU34UP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPHSun/dJMcagMoaUn/9ZWUaDuQcrNBMYfiU34UP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPHSun/dJMcagMoaUn/9ZWUaDuQcrNBMYfiU34UP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPHSun%2FdJMcagMoaUn%2F9ZWUaDuQcrNBMYfiU34UP0%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;261&quot; height=&quot;189&quot; data-origin-width=&quot;160&quot; data-origin-height=&quot;116&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HbsLY/dJMcagMoaUo/uLxJBT9wwhTs4KjRijIdnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HbsLY/dJMcagMoaUo/uLxJBT9wwhTs4KjRijIdnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HbsLY/dJMcagMoaUo/uLxJBT9wwhTs4KjRijIdnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHbsLY%2FdJMcagMoaUo%2FuLxJBT9wwhTs4KjRijIdnK%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;331&quot; height=&quot;267&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;138&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;기본적으로 Region 이 다른 경우 Region을 배치한 순서가 적용된다고 함&lt;/li&gt;
&lt;li&gt;Region 이 같은 경우에는 공식적으로 기준이 문서에 기록되어있지는 않음&lt;/li&gt;
&lt;li&gt;실험 결과로 스펙이 priority 에 영향을 준다고 유추가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Primary 일을 시킬 순 없나요?&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mongo Atlas는 총 5가지의 읽기 모드를 지원하는데&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;모드&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;읽기 대상&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;폴백&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;primary&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Primary만&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;없음 (에러 발생)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;기본값. 가장 강력한 일관성 보장. Primary가 없으면 읽기 실패&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;primaryPreferred&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Primary 우선&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Primary 없으면 Secondary&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;평소엔 Primary에서 읽고, Primary 장애 시 Secondary에서 읽음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;secondary&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Secondary만&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;없음 (에러 발생)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Secondary에서만 읽음. 가용한 Secondary가 없으면 읽기 실패&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;secondaryPreferred&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Secondary 우선&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;모든 Secondary 없으면 Primary&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;평소엔 Secondary에서 읽고, 모든 Secondary가 죽었을 때만 Primary에서 읽음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;nearest&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Primary/Secondary 구분 없음&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;네트워크 지연시간이 가장 짧은 노드에서 읽음. Primary든 Secondary든 무관&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&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;secondaryPreferred&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모드로 살아있는 secondary가 있는 경우 secondary에서 데이터를 읽도록 되어있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;trade-off 를 적절하게 판단하자&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부하가 있는 경우에 secondary 노드들의 CPU 사용량 임계값을 높이고 싶다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 개수를 늘려 Scale-Out 을 고려하거나 primaryPreferred 를 선택해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 다만 이 경우 기본적으로 처리할 수 있는 양이 줄어듦&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;secondaryPreferred 읽기 모드를 기준으로 &lt;br /&gt;클러스터거 N 대인 경우&lt;/li&gt;
&lt;li&gt;안전 CPU 상한(%) = (N - 2) / (N - 1) &amp;times; 100
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;ex)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3대 &amp;rarr; CPU 50%&lt;/li&gt;
&lt;li&gt;5대 &amp;rarr; CPU 75%&lt;/li&gt;
&lt;li&gt;7대 &amp;rarr; CPU 83%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 쓰기 vs 읽기 비율이 1:9 정도로 보기 때문에 scale-out 이 효율이 좋으나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;scalue-out 의 경우 primary 의 성능을 높여줄 수 없기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰기 성능이 중요한 경우 노드 자체의 성능이 올라가기 때문에 scale-up 도 고려할만합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bicfaC/dJMcacb609t/xwVuIoHlzrUG6KEzrwKFc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bicfaC/dJMcacb609t/xwVuIoHlzrUG6KEzrwKFc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bicfaC/dJMcacb609t/xwVuIoHlzrUG6KEzrwKFc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbicfaC%2FdJMcacb609t%2FxwVuIoHlzrUG6KEzrwKFc0%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;856&quot; height=&quot;667&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhITuq/dJMcacb609s/8djtzNTOmkdq577kxeoFK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhITuq/dJMcacb609s/8djtzNTOmkdq577kxeoFK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhITuq/dJMcacb609s/8djtzNTOmkdq577kxeoFK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhITuq%2FdJMcacb609s%2F8djtzNTOmkdq577kxeoFK1%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;856&quot; height=&quot;365&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mongo Atlas 에서 투표 가능한(Electable) 노드의 개수를 늘리는 것은 3, 5, 7 단위의 홀수로 scale-out이 가능합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;근데 스케일 아웃이 왜 홀수 단위로만 되나요?&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Primary 의 장애 상황에서 클러스터가 3대의 노드로 되어있는 경우에도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Primary 가 죽으면 Secondary 2대로도 결국 투표가 가능해서 선거가 가능한데?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ0lxb/dJMcaaZEWq3/1heqpAzpmdaknJjactawh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ0lxb/dJMcaaZEWq3/1heqpAzpmdaknJjactawh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ0lxb/dJMcaaZEWq3/1heqpAzpmdaknJjactawh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ0lxb%2FdJMcaaZEWq3%2F1heqpAzpmdaknJjactawh1%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 사실 반드시 홀수일 필요는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mongo Atlas 에서 홀수로 제한한 것은 &lt;b&gt;효율적인 운영&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;몇 대의 클러스터 &lt;/b&gt;구성에서 &lt;b&gt;몇대의 오류를 허용할 수 있는가&lt;/b&gt;의 관점으로 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bO13cL/dJMcacb609l/Ks9HT3c1POz8HKlrKy3O1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bO13cL/dJMcacb609l/Ks9HT3c1POz8HKlrKy3O1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bO13cL/dJMcacb609l/Ks9HT3c1POz8HKlrKy3O1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO13cL%2FdJMcacb609l%2FKs9HT3c1POz8HKlrKy3O1K%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ytLIE/dJMcaaZEWqU/KCQ7tSZMlosgn8oClkhH9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ytLIE/dJMcaaZEWqU/KCQ7tSZMlosgn8oClkhH9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ytLIE/dJMcaaZEWqU/KCQ7tSZMlosgn8oClkhH9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FytLIE%2FdJMcaaZEWqU%2FKCQ7tSZMlosgn8oClkhH9k%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OKDgI/dJMcacb609i/Hlt8GyQRcl7iViCfwJBLwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OKDgI/dJMcacb609i/Hlt8GyQRcl7iViCfwJBLwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OKDgI/dJMcacb609i/Hlt8GyQRcl7iViCfwJBLwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOKDgI%2FdJMcacb609i%2FHlt8GyQRcl7iViCfwJBLwk%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;허용 장애 수 가 유의미하게 늘어나는 단계가 홀수단위&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;floor(N/2) +1&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 78.1395%; height: 201px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 24.1071%;&quot;&gt;&lt;span&gt;노드 수&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 26.4881%;&quot;&gt;&lt;span&gt;과반수&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 23.3631%;&quot;&gt;&lt;span&gt;허용 장애 수&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 25.8929%;&quot;&gt;&lt;span&gt;비용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 24.1071%;&quot;&gt;&lt;span&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 26.4881%;&quot;&gt;&lt;span&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 23.3631%;&quot;&gt;&lt;span&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 25.8929%;&quot;&gt;&lt;span&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 24.1071%;&quot;&gt;&lt;span&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 26.4881%;&quot;&gt;&lt;span&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 23.3631%;&quot;&gt;&lt;span&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 25.8929%;&quot;&gt;&lt;span&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 24.1071%;&quot;&gt;&lt;span&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 26.4881%;&quot;&gt;&lt;span&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 23.3631%;&quot;&gt;&lt;span&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 25.8929%;&quot;&gt;&lt;span&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 24.1071%;&quot;&gt;&lt;span&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 26.4881%;&quot;&gt;&lt;span&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 23.3631%;&quot;&gt;&lt;span&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 25.8929%;&quot;&gt;&lt;span&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 24.1071%;&quot;&gt;&lt;span&gt;7&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 26.4881%;&quot;&gt;&lt;span&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 23.3631%;&quot;&gt;&lt;span&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 25.8929%;&quot;&gt;&lt;span&gt;7&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 네트워크 파티션이 분리되는 경우도 예상해 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nwBrJ/dJMcacb609p/cYteAJ6Y54dve7l54iltW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nwBrJ/dJMcacb609p/cYteAJ6Y54dve7l54iltW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nwBrJ/dJMcacb609p/cYteAJ6Y54dve7l54iltW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnwBrJ%2FdJMcacb609p%2FcYteAJ6Y54dve7l54iltW0%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBrVLr/dJMcaaZEWqR/Cb4A2zRyz9UKZKqp1SQXIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBrVLr/dJMcaaZEWqR/Cb4A2zRyz9UKZKqp1SQXIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBrVLr/dJMcaaZEWqR/Cb4A2zRyz9UKZKqp1SQXIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBrVLr%2FdJMcaaZEWqR%2FCb4A2zRyz9UKZKqp1SQXIK%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;967&quot; height=&quot;763&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;763&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;마치며&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 Raft 합의 알고리즘을 통한 분산 시스템인 Mongo Atlas 의 클러스터 정책에 대해서 알아봤습니다.&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;과반수 합의&lt;/li&gt;
&lt;li&gt;홀수 구성&lt;/li&gt;
&lt;li&gt;부하 분산 여유 확보&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3가지에 대한 판단 기준만 세울 수 있다면&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;table id=&quot;366c90e0-86d3-8044-930f-e42b72df9ff2&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;366c90e0-86d3-808a-b940-e8f99d8133fb&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Replica Set Elections&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/replica-set-elections/&quot;&gt;Replica Set Elections - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-8003-8b4a-cdc7387249d6&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Retryable Writes&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/retryable-writes/&quot;&gt;Retryable Writes - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-8089-b3b7-f00ab8a2867a&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Retryable Reads&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/retryable-reads/&quot;&gt;Retryable Reads - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-8051-bd57-d7896ccee066&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Rollbacks During Failover&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/replica-set-rollbacks/&quot;&gt;Rollbacks During Replica Set Failover - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-80f2-ab83-cd4f5f1a607b&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Read Preference&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/read-preference/&quot;&gt;Read Preference - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-8069-98ff-c350d0f79b8b&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;maxStalenessSeconds&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/read-preference-staleness/&quot;&gt;Read Preference maxStalenessSeconds - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-80c7-ae80-e15ca90361cf&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Atlas Auto-Scaling&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/cluster-autoscaling/&quot;&gt;Configure Auto-Scaling - Atlas - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-807a-81b9-caeff2b1d64a&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Atlas Maintenance Window&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/tutorial/cluster-maintenance-window/&quot;&gt;Configure Maintenance Window - Atlas - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-8023-8948-c33430b9641b&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Atlas Scalability Guide&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/architecture/current/scalability/&quot;&gt;Guidance for Atlas Scalability - Atlas Architecture Center - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-802e-b5fe-d01192c9f81c&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Atlas High Availability&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/architecture/current/high-availability/&quot;&gt;Guidance for Atlas High Availability - Atlas Architecture Center - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-800b-9c17-cbb9a8b73ecd&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Build a Resilient Application&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/resilient-application/&quot;&gt;Build a Resilient Application with MongoDB Atlas - Atlas - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-801e-b072-c49a7d1e5171&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Cluster Sizing and Tier Selection&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/sizing-tier-selection/&quot;&gt;Atlas Cluster Sizing and Tier Selection - Atlas - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-804d-a3e4-c25fdd03f1b2&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Node Configuration&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/atlas/cluster-config/multi-cloud-distribution/&quot;&gt;Configure High Availability and Workload Isolation - Atlas - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-80c4-b53d-f9d2c44cedc4&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Connection String Options&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/reference/connection-string-options/&quot;&gt;Connection String Options - Database Manual - MongoDB Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-807a-bbb5-f74876a56f49&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Server Selection Spec&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://specifications.readthedocs.io/en/latest/server-selection/server-selection/&quot;&gt;Server Selection - MongoDB Specifications&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-80e2-ba76-fa430edbf9c9&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;Retryable Writes Spec&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://specifications.readthedocs.io/en/latest/retryable-writes/retryable-writes/&quot;&gt;Retryable Writes - MongoDB Specifications&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-80cf-bc2e-eca2c455d065&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;MongoDB 소스 - Election Timeout&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://github.com/mongodb/mongo/blob/master/src/mongo/db/repl/repl_server_parameters.idl&quot;&gt;mongo/src/mongo/db/repl/repl_server_parameters.idl at master &amp;middot; mongodb/mongo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-806d-b8ae-c0ae1f17b564&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;MongoDB 소스 - OpTime 비교&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://github.com/mongodb/mongo/blob/master/src/mongo/db/repl/optime.h&quot;&gt;mongo/src/mongo/db/repl/optime.h at master &amp;middot; mongodb/mongo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;366c90e0-86d3-800c-bdf0-d447e0a77317&quot;&gt;
&lt;td id=&quot;_]?W&quot;&gt;MongoDB 소스 - Heartbeat/Election&lt;/td&gt;
&lt;td id=&quot;Fpzq&quot;&gt;&lt;a href=&quot;https://github.com/mongodb/mongo/blob/master/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp&quot;&gt;mongo/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp at master &amp;middot; mongodb/mongo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>백엔드</category>
      <category>atlas</category>
      <category>MongoDB</category>
      <category>Raft 합의 알고리즘</category>
      <category>Rolling Update</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/47</guid>
      <comments>https://kyeum-d.tistory.com/47#entry47comment</comments>
      <pubDate>Wed, 20 May 2026 21:40:40 +0900</pubDate>
    </item>
    <item>
      <title>하네스 엔지니어링 - 2</title>
      <link>https://kyeum-d.tistory.com/46</link>
      <description>&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://kyeum-d.tistory.com/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kyeum-d.tistory.com/45&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778669401399&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;하네스 엔지니어링 - 1&quot; data-og-description=&quot;들어가며오늘은 핫한(단물 다빠졌는데) 하네스 엔지니어링에 대한 소개를 해보려고 합니다.사내 테크데이에서 발표한 내용에서 조금 더 디테일 한 부분들을 설명하고 싶어서 글을 작성합니다. &quot; data-og-host=&quot;kyeum-d.tistory.com&quot; data-og-source-url=&quot;https://kyeum-d.tistory.com/45&quot; data-og-url=&quot;https://kyeum-d.tistory.com/45&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/r51TI/dJMb84qdvVI/vcY1YFqAsLkj0RU2YX5tIk/img.png?width=800&amp;amp;height=598&amp;amp;face=0_0_800_598,https://scrap.kakaocdn.net/dn/ttwuv/dJMb85WYeLf/gFKctkgyrK66YOb4aSi6K0/img.png?width=800&amp;amp;height=598&amp;amp;face=0_0_800_598,https://scrap.kakaocdn.net/dn/v449t/dJMb9aKJVCN/INkAUXme4ntShDzx3n4Xk0/img.jpg?width=400&amp;amp;height=353&amp;amp;face=0_0_400_353&quot;&gt;&lt;a href=&quot;https://kyeum-d.tistory.com/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kyeum-d.tistory.com/45&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/r51TI/dJMb84qdvVI/vcY1YFqAsLkj0RU2YX5tIk/img.png?width=800&amp;amp;height=598&amp;amp;face=0_0_800_598,https://scrap.kakaocdn.net/dn/ttwuv/dJMb85WYeLf/gFKctkgyrK66YOb4aSi6K0/img.png?width=800&amp;amp;height=598&amp;amp;face=0_0_800_598,https://scrap.kakaocdn.net/dn/v449t/dJMb9aKJVCN/INkAUXme4ntShDzx3n4Xk0/img.jpg?width=400&amp;amp;height=353&amp;amp;face=0_0_400_353');&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;하네스 엔지니어링 - 1&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;kyeum-d.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;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&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;&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;s&gt;(대충 실패한 내용 알려준다는 뜻)&lt;/s&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;우선 직접 구성해보고 느낀 것은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하네스의 제 8원칙(&lt;s&gt;거창하네&lt;/s&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;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;h4 data-ke-size=&quot;size20&quot;&gt;어떻게 정의했는데?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초에는 이렇게 총 6가지의 구성으로 에이전트들을 설계했습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Planner
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기획서를 읽고 계획 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Plan Reviewer
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세운 계획에 대해서 리뷰 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Worker
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업을 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Builder&lt;/span&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Test Writer&lt;/span&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Code Reviewer&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;worker 가 작업한 코드에 대해서 리뷰&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 컨텍스트들은 OpenAI 의 실패사례를 토대로 세부적인 내용을 직접 담지 않고&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;h4 data-ke-size=&quot;size20&quot;&gt;오케스트레이터는 어떻게 구성하지?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*claude code 기준&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;tom 연주.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biogye/dJMb997rBkK/HNRL1Ak4ct8kHIbUUsdOTk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biogye/dJMb997rBkK/HNRL1Ak4ct8kHIbUUsdOTk/img.gif&quot; data-alt=&quot;마! 이게 오케스트레이터다(아님)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biogye/dJMb997rBkK/HNRL1Ak4ct8kHIbUUsdOTk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/biogye/dJMb997rBkK/HNRL1Ak4ct8kHIbUUsdOTk/img.gif&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;394&quot; height=&quot;293&quot; data-filename=&quot;tom 연주.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마! 이게 오케스트레이터다(아님)&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;각 에이전트들을 AGENTS 로 정의하고&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;해당 AGENTS 들을 오케스트레이션 하는 SKILLS 를 생성하였습니다.&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;왜 오케스트레이터는 SKILLS 로 만드나요?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초에 오케스트레이터도 별도 AGENTS로 구성을 할지 SKILLS로 구성을 할지 고민했는데&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;SKILLS로 구성하면 메인 세션에서 클로드와 지속적으로 커뮤니케이션이 가능합니다.&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;하네스 구성 초기 단계인 만큼 수정할 내용이 많다고 생각해서 SKILLS로 구성을 하게 됩니다.&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;구성 끝&lt;/h2&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;h4 data-ke-size=&quot;size20&quot;&gt;이 중에 책임이 과한 에이전트가 있다&lt;/h4&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;계획을 세우는 Planner도 기획서와 구현된 코드를 검토하고 계획을 세우고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계획을 검토하는 Plann Reviewer 도 기획서와 구현된 코드를 검토하고 계획을 리뷰하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업을 진행하는 Worker 도 기획서와 구현된 코드를 확인하고&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;522&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q7zmD/dJMcafzSpZQ/DvVXDyGuyJXjNeVMgYcfKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q7zmD/dJMcafzSpZQ/DvVXDyGuyJXjNeVMgYcfKk/img.png&quot; data-alt=&quot;대충 Planner 와 형제들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q7zmD/dJMcafzSpZQ/DvVXDyGuyJXjNeVMgYcfKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq7zmD%2FdJMcafzSpZQ%2FDvVXDyGuyJXjNeVMgYcfKk%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;394&quot; height=&quot;388&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대충 Planner 와 형제들&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;우선은 Planner가 기획서를 읽고, 분석을 하고, 코드를 보고, 구현 상세 계획까지 세우는 것은 과다한 책임이라 생각하여&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;text-align: start;&quot;&gt;비즈니스 관점에서 &lt;/span&gt;나열하는 적립하도록 변경합니다. (구현 세부 계획 x)&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;또한 Plan Reviewer 도 코드를 읽지 않고 오로지 기획서와 수립된 계획만을 보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 목록을 명확하게 구성했는지 누락된 내용은 없는지 Plan 자체만을 검토하도록 변경합니다.&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;Worker가 고삐가 풀렸다&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현 세부사항에 대한 계획들을 제거했더니 이제 Worker에게 너무 큰 자유가 주어졌습니다.&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;이 큰 자유는 하네스라는 마구가 무색해질 정도로 Worker 가 마음대로 작업을 하게 내버려둡니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmjO2e/dJMcaja3D9g/bTBr68OiDoxJs8gZbBkPOk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmjO2e/dJMcaja3D9g/bTBr68OiDoxJs8gZbBkPOk/img.webp&quot; data-alt=&quot;내가 Worker여&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmjO2e/dJMcaja3D9g/bTBr68OiDoxJs8gZbBkPOk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmjO2e%2FdJMcaja3D9g%2FbTBr68OiDoxJs8gZbBkPOk%2Fimg.webp&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;287&quot; height=&quot;383&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;내가 Worker여&lt;/figcaption&gt;
&lt;/figure&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;이미 존재하는 검증된 코드를 재사용하지 않은 채 전체적인 구조를 무시하고 작업을 진행하였습니다.&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;이런 문제들로 인해 저는 구성 에이전트로 Spec Writer 를 추가하게 됩니다.&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;Worker로 진입하기 전에 현재 아키텍처의 구성이나 도메인을 이루고 있는 레이어들 기본적인 규칙들을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spec Writer가 조금 더 코드 레벨에서 큰 그림을 그리도록 했습니다.&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;이렇게 Worker 까지의 구성은 어느 정도 완성되었는데..&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;Builder? 너 하는 게 뭐야&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Builder의 역할이 굉장히 애매합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr;&amp;nbsp;아무리 모델을 haiku로 돌린다고 하지만 빌더가 굳이 별도 에이전트로 있을 필요는 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worker 에서 작업이 끝나면 빌드를 해서 검증하도록 변경합니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Planner
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기획서를 확인하고 코드를 확인하지 않고 기획서 내용에 대해서만 정리하여 &amp;ldquo;무엇을&amp;rdquo; 만들어야 하는지 계획을 세움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Plan Reviewer
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기획서에 명시된 &amp;ldquo;무엇을&amp;rdquo; 만들어야 하는지에 대한 내용이 전부 계획에 들어가 있는지 검토&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Spec Writer
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;무엇을&amp;rdquo; 만들지에 대한 내용을 확인 후 우리 시스템에 맞춰 &amp;ldquo;어떻게&amp;rdquo; 만들어야 하는지 큰 그림 제시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Worker
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로 코드 작성 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Test Writer
&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;/li&gt;
&lt;li&gt;Code Reviewer (claude 의 /simplify 기능에서 착안하여 구성)&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;simplify 의 3가지 검토 축&amp;nbsp;
&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;li&gt;효율성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;재구성 한 3가지 검토 축
&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;li&gt;재사용성 : DRY 원칙, 공통 컴포넌트 활용, 중복 코드 검출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게&amp;nbsp;각 각 분리된 md 파일로 규약과 명세를 세분화하여&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;하네스 구성을 완료했습니다!&amp;nbsp;&lt;/h4&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;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;네 이렇게 구성하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCw5lK/dJMcadPtZva/2UytG7AkJXgvXiG4PUKF41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCw5lK/dJMcadPtZva/2UytG7AkJXgvXiG4PUKF41/img.png&quot; data-alt=&quot;나약한 개발자여&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCw5lK/dJMcadPtZva/2UytG7AkJXgvXiG4PUKF41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCw5lK%2FdJMcadPtZva%2F2UytG7AkJXgvXiG4PUKF41%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;474&quot; height=&quot;354&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;나약한 개발자여&lt;/figcaption&gt;
&lt;/figure&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;지금까지 구성한 것이 하네스를 이루는 3가지 축 중&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;맞습니다(?). 첫 번째 축은 다들 이미 잘하고 계실 것 같고&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Planner, Plan Reviewer
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;특정 경로(피그마에서 추출한 기획서가 있는 폴더)만 읽을 수 있도록 강제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;특정 경로에만 파일을 Write 할 수 있도록 강제 (계획 작성)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Bash 명령어 차단 등등...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Worker&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;커스텀 린터 / 정적 분석 추가하여 검증&lt;br /&gt;ex) 안티패턴 감지 &amp;rarr; !! 같은 단언 연산자를 쓰거나 Transaction 안에서 외부 API 를 호출하거나 순환 의존성, 패키지 네이밍 규칙, 등등&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;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;작업 완료되면 hook 으로 build 명령어 실행&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;의존성이 추가된 경우 의존성에 대한 검증&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Test Writer&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;작업 완료 후 hook 을 통해 테스트 커버리지를 검사한다던지 @Disabled 가 없는지 검사 등&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;작업이 가능한 폴더는 test 폴더로 제한&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Code Reviewer&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;리뷰어 폴더만 쓰기 권한 부여&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;각 에이전트는 본인의 작업 결과물에 대해서 파일로 상태를 남겨 전달&lt;/span&gt;&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;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;(대표적으로 자꾸 data class 를 계속 필요한 비즈니스 로직이 있는 코드 내부에 추가한다던지 등)&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;&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;지금 생각해 보면 에이전트들에게 제약을 열심히 걸었는데&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;오케스트레이터를 SKILLS 로 작성했고 오케스트레이터에게 별도의 제약을 걸지 않았다는 점입니다.&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;오케스트레이터를 SKILLS 로 작성했을 때의 제가 생각한 장/단점은&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;중간에 사용자가 개입할 수 있음&lt;/li&gt;
&lt;li&gt;오케스트레이션을 함께 관리하여 실패에 대한 컨텍스트를 모두 가지고 있어 빠른 피드백으로 수정 할 수 있음&lt;/li&gt;
&lt;li&gt;수정 대상이 많지 않음&lt;/li&gt;
&lt;/ul&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;컨텍스트 고갈 현상 심함&lt;/li&gt;
&lt;li&gt;세션이 끊기면 재개 불가능 (resume 같은 게 있으니 끊길 일이 없긴 하지만)&lt;/li&gt;
&lt;li&gt;결정론 부족 &amp;rarr; 각 에이전트의 응답을 직접 보고 LLM 이 판단하기 때문에 기계적인 구분이 어려움&lt;/li&gt;
&lt;li&gt;규칙 위반 &amp;rarr; 각 에이전트들이 일을 제대로 못하면 자꾸 직접 개입하려고 하는 현상이 발견됨&lt;/li&gt;
&lt;/ul&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;방법이 없을지 다른 고수들의 레퍼런스를 찾아봤더니 별도의 py 코드로 오케스트레이션을 구성하는 것을 발견했습니다.&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;에이전트 간의 파일 핸드오프와 피드백 루프가 제대로 구축된다면,&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;이런 식으로 2번째 축인 아키텍처 제약을 구성을 완료했습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마지막 엔트로피 관리만 남았나요?&lt;/h2&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;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;h3 data-ke-size=&quot;size23&quot;&gt;1. 데드 코드 및 AI Slop 제거&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더 이상 사용하지 않는 코드 혹은 지정한&amp;nbsp;규칙을 어기는 코드를 찾아서 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 중복 코드 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적으로 코드베이스를 탐색하며 중복되는 유틸리티 함수들이나 퍼져있는 관리 포인트들을 한 곳으로 모음&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 컨텍스트 문서의 부패 관리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예외 사항이나 지속적으로 컨텍스트를 추가하기 시작하면 정리가 안된채로 비대해집니다. &lt;br /&gt;비대해진 컨텍스트 문서는 부패하게 되고 결국 AI 에게 노이즈를 주는 상황이 생길 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 3가지 요소에 대한 관리를 하는 '가비지 컬렉터' 를 별도의 생명주기로 실행하도록 구성하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감지된 코드를 수정 후 PR을 생성하는 등으로 활용해 볼 수 있습니다.&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;br /&gt;지속&amp;nbsp;가능한&amp;nbsp;하네스를&amp;nbsp;구성하기&amp;nbsp;위한&amp;nbsp;가장&amp;nbsp;중요한&amp;nbsp;요소라고&amp;nbsp;생각하는데&lt;br /&gt;&lt;br /&gt;그와&amp;nbsp;동시에&amp;nbsp;가장&amp;nbsp;어렵고&amp;nbsp;까다로운&amp;nbsp;내용이기도&amp;nbsp;하여&amp;nbsp;저도&amp;nbsp;아직&amp;nbsp;구성&amp;nbsp;단계에&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;/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;h3 data-ke-size=&quot;size23&quot;&gt;1. 하네스 변경에 대해 기록한다&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하네스를 추가할 때, 코드를 짜듯 &quot;왜 이 제약을 걸었는지&quot; 명시적으로 기록하고 태깅하는 방법입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADR(Architecture Decision Record) 처럼 기록해 두면 모델이 업데이트되면서 더 잘하게 되었다고 발표하는 내용과&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;h3 data-ke-size=&quot;size23&quot;&gt;2. 하네스 없이 테스팅 해본다&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;한계 돌파 테스트셋 (Limit-break Testset)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적인 기능 테스트(Unit Test)와 별개로, 과거 모델이 실패했던 까다로운 엣지 케이스나 컨텍스트 한계 상황만을 모아둔 전용 평가 데이터셋을 구축&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 피처 플래그를 활용한 모듈형 하네스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하네스를 시스템과 강하게 결합해 두면 떼어내기가 매우 힘듭니다.&lt;br /&gt;&lt;br /&gt;토글(Toggle) 아키텍처&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하네스의 각 축(예: 자가 검증 루프, 컨텍스트 요약기, 강제 JSON 파서 등)을 언제든 껐다 켤 수 있는 플러그인 형태로 설계&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;&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;/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;하지만 컨텍스트 엔지니어링으로 발전했다고 프롬프트 엔지니어링이 사라졌을까요?&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;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;h3 data-ke-size=&quot;size23&quot;&gt;코더에서 개발자로 개발자에서 엔지니어로&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GGIbD/dJMcaak1gwN/saC9kezYPLnZS7Ks8no5V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GGIbD/dJMcaak1gwN/saC9kezYPLnZS7Ks8no5V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GGIbD/dJMcaak1gwN/saC9kezYPLnZS7Ks8no5V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGGIbD%2FdJMcaak1gwN%2FsaC9kezYPLnZS7Ks8no5V0%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;432&quot; height=&quot;648&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&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;저를 포함한 많은 분들이 AI의 발전에 대한 FOMO를 느끼고 미래에 대한 걱정을 하실 것이라 생각됩니다.&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;AI의 변화를 받아들이고 발 빠르게 AI를 다루는 기법들을 적용하고 부딪혀보며 성장해 나가는 것도 좋지 않을까 생각됩니다.&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;&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&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/b32Pip/dJMcajvu2hj/KTsEjjxS8YuqwZJQSDlQ70/%E1%84%92%E1%85%A1%E1%84%82%E1%85%A6%E1%84%89%E1%85%B3%E1%84%8B%E1%85%A6%E1%86%AB%E1%84%8C%E1%85%B5%E1%84%82%E1%85%B5%E1%84%8B%E1%85%A5%E1%84%85%E1%85%B5%E1%86%BC_main%20%281%29.pptx?attach=1&amp;amp;knm=tfile.pptx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;하네스엔지니어링_main (1).pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;12.14MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>백엔드</category>
      <category>하네스 구성</category>
      <category>하네스 실전</category>
      <category>하네스 엔지니어링</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/46</guid>
      <comments>https://kyeum-d.tistory.com/46#entry46comment</comments>
      <pubDate>Sat, 16 May 2026 15:49:32 +0900</pubDate>
    </item>
    <item>
      <title>하네스 엔지니어링 - 1</title>
      <link>https://kyeum-d.tistory.com/45</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 핫한(&lt;s&gt;단물 다빠졌는데&lt;/s&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;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;하는 분들에게 도움이 되고자 작성했습니다.&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;(*AI 생성 글이 아닌 손수 타이핑 한 글입니다.)&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;AI는 빠른속도로 발전하고 있습니다.&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;485&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhnLfu/dJMcadV9QZe/EkmZgngjcvYTOAZFnpBUPK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhnLfu/dJMcadV9QZe/EkmZgngjcvYTOAZFnpBUPK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhnLfu/dJMcadV9QZe/EkmZgngjcvYTOAZFnpBUPK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhnLfu%2FdJMcadV9QZe%2FEkmZgngjcvYTOAZFnpBUPK%2Fimg.jpg&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;378&quot; height=&quot;324&quot; data-origin-width=&quot;485&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;그에 맞추어 이 AI(LLM)를 다루는 엔지니어링 기법도 진화하기 시작했습니다.&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;최초 LLM은 마치 명석한 신입사원과도 같았습니다.&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;p data-ke-size=&quot;size16&quot;&gt;이로 인해 모델에게 &quot;어떻게 잘 물어볼 것인가&quot;에 대해 고민했습니다.&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;프롬프트 엔지니어링&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;AI에게 페르소나 같은 가면을 씌워 최면을 걸기도 하고,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxSMV/dJMcaja0kVz/aFkB6JhknnjOBDAr9BFy9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxSMV/dJMcaja0kVz/aFkB6JhknnjOBDAr9BFy9K/img.png&quot; data-alt=&quot;너는 10년차 노련한 서버 개발자다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxSMV/dJMcaja0kVz/aFkB6JhknnjOBDAr9BFy9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxSMV%2FdJMcaja0kVz%2FaFkB6JhknnjOBDAr9BFy9K%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;341&quot; height=&quot;283&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;너는 10년차 노련한 서버 개발자다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단계별로&amp;nbsp;차근차근&amp;nbsp;생각하게&amp;nbsp;만드는&amp;nbsp;CoT,&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;예시를&amp;nbsp;쥐여주는&amp;nbsp;Few-shot&amp;nbsp;등&lt;br /&gt;&lt;br /&gt;다양한&amp;nbsp;기법들이&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;br /&gt;&lt;br /&gt;이제는&amp;nbsp;질문의&amp;nbsp;의도를&amp;nbsp;잘&amp;nbsp;파악하고&amp;nbsp;작업을&amp;nbsp;이행하는&amp;nbsp;'주임'&amp;nbsp;급이&amp;nbsp;되었습니다.&lt;br /&gt;&lt;br /&gt;그런데&amp;nbsp;아직&amp;nbsp;회사&amp;nbsp;내규에는&amp;nbsp;익숙하지&amp;nbsp;않습니다.&lt;br /&gt;회사의 기존 규칙이나 관례는 무시한 채, 지시받은 내용 자체에만 집중해서 작업을 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/93GT0/dJMcaf0KP4K/KMTVjH1KXftv92kBCD9Ag1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/93GT0/dJMcaf0KP4K/KMTVjH1KXftv92kBCD9Ag1/img.png&quot; data-alt=&quot;일단 열심히 하자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/93GT0/dJMcaf0KP4K/KMTVjH1KXftv92kBCD9Ag1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F93GT0%2FdJMcaf0KP4K%2FKMTVjH1KXftv92kBCD9Ag1%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;316&quot; height=&quot;328&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;일단 열심히 하자&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;작업 레퍼런스를 AI에게 어떻게 넘겨줄지 고민하게 됩니다.&lt;br /&gt;&lt;br /&gt;이때&amp;nbsp;나온&amp;nbsp;기법이&amp;nbsp;바로&amp;nbsp;&lt;b&gt;컨텍스트&amp;nbsp;엔지니어링&lt;/b&gt;입니다.&lt;br /&gt;&lt;br /&gt;우리가&amp;nbsp;가진&amp;nbsp;컨텍스트를&amp;nbsp;효율적이고&amp;nbsp;정확하게&amp;nbsp;전달할&amp;nbsp;방법들을&amp;nbsp;찾았고,&lt;br /&gt;&lt;br /&gt;RAG, MCP, SKILLS 등 다양한 방법들이 등장하게 됩니다.&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;모델은&amp;nbsp;또&amp;nbsp;한&amp;nbsp;번&amp;nbsp;발전합니다.&lt;br /&gt;&lt;br /&gt;이제는&amp;nbsp;질문&amp;nbsp;내용도&amp;nbsp;잘&amp;nbsp;이해하고&amp;nbsp;회사&amp;nbsp;내규도&amp;nbsp;꿰뚫고&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;그런데&amp;nbsp;자신이&amp;nbsp;다&amp;nbsp;안다고&amp;nbsp;생각하니,&amp;nbsp;오히려&amp;nbsp;일을&amp;nbsp;자기&amp;nbsp;마음대로&amp;nbsp;처리하기&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;734&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Qsp3/dJMcahddUYp/G4auLxB3mZcOeok9y0d9D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Qsp3/dJMcahddUYp/G4auLxB3mZcOeok9y0d9D0/img.png&quot; data-alt=&quot;개발자보다 강해진&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Qsp3/dJMcahddUYp/G4auLxB3mZcOeok9y0d9D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Qsp3%2FdJMcahddUYp%2FG4auLxB3mZcOeok9y0d9D0%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;372&quot; height=&quot;278&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개발자보다 강해진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자보다 자율성이 강해진 AI는&lt;br /&gt;프롬프트나&amp;nbsp;컨텍스트&amp;nbsp;같은&amp;nbsp;부드러운&amp;nbsp;'부탁'&amp;nbsp;정도로는&amp;nbsp;말을&amp;nbsp;듣지&amp;nbsp;않게&amp;nbsp;되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;결국 시스템으로, 기계적으로 이를 제어할 방법들이 필요해지기 시작합니다.&lt;br /&gt;&lt;br /&gt;Linter,&amp;nbsp;Hooks,&amp;nbsp;파이프라인&amp;nbsp;등을&amp;nbsp;도입하여&amp;nbsp;말이죠.&lt;br /&gt;&lt;br /&gt;우리는 이처럼 LLM을 제어하는 시스템적 요소들을 구성하고 발전시키는 기법을&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;그래서... 하네스 엔지니어링이란 뭘까요?&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;하네스(Harness)란&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;blob&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TWhjI/dJMcahK4z3g/J9gmWN45tSqzjlnHBSmPMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TWhjI/dJMcahK4z3g/J9gmWN45tSqzjlnHBSmPMK/img.png&quot; data-alt=&quot;얘는 나보다 훨씬 잘생겼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TWhjI/dJMcahK4z3g/J9gmWN45tSqzjlnHBSmPMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTWhjI%2FdJMcahK4z3g%2FJ9gmWN45tSqzjlnHBSmPMK%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;300&quot; height=&quot;356&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;얘는 나보다 훨씬 잘생겼&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;.&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;그건 바로 말을 잘 달리게 하기 위해서 입니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;192&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bClkER/dJMcadu3ALz/qFpFjKnRglw7MPljZR2YA1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bClkER/dJMcadu3ALz/qFpFjKnRglw7MPljZR2YA1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bClkER/dJMcadu3ALz/qFpFjKnRglw7MPljZR2YA1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbClkER%2FdJMcadu3ALz%2FqFpFjKnRglw7MPljZR2YA1%2Fimg.jpg&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;192&quot; height=&quot;230&quot; data-origin-width=&quot;192&quot; data-origin-height=&quot;230&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;s&gt;이상 하네스 엔지니어링에 대해서 알아봤&lt;/s&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;잘 달리는 말&lt;/b&gt;이란, 빠르기만 한 말을 의미하는 것이 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간의 &lt;b&gt;의도대로 정확한 방향으로 달리는가&lt;/b&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;하네스&amp;nbsp;엔지니어링은,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;거대한&amp;nbsp;AI&amp;nbsp;시대에서&amp;nbsp;'AI'라는&amp;nbsp;말이&amp;nbsp;인간의&amp;nbsp;의도대로&amp;nbsp;정확하고&amp;nbsp;빠르게&amp;nbsp;달릴&amp;nbsp;수&amp;nbsp;있도록&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;h3 data-ke-size=&quot;size23&quot;&gt;하네스... 어디서 들어 봤는데??&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맞습니다(?) 개발바닥에서는 1970년대부터 쓰여왔던 &quot;테스트 하네스&quot;가 존재합니다.&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;p data-ke-size=&quot;size16&quot;&gt;전통적인 소프트웨어 개발은 &lt;b&gt;예측이 가능&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 정해진 공식이 아니라,&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;이로 인해 결과 값을 100% 예측할 수 없는 특성을 지녔고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 공학에서는 이를 '비결정적(Non-deterministic)&amp;nbsp;동작'이라고&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;400&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clDE91/dJMcagyA94B/b8w3IBI7kry2wpC0E9N5qk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clDE91/dJMcagyA94B/b8w3IBI7kry2wpC0E9N5qk/img.webp&quot; data-alt=&quot;예상했습니까 휴먼?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clDE91/dJMcagyA94B/b8w3IBI7kry2wpC0E9N5qk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclDE91%2FdJMcagyA94B%2Fb8w3IBI7kry2wpC0E9N5qk%2Fimg.webp&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;400&quot; height=&quot;240&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예상했습니까 휴먼?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리가 코드를 작성하고 개발을 하면서 LLM을 활용 할 때,&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;p data-ke-size=&quot;size16&quot;&gt;그래서 이 하네스 엔지니어링을 보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM의 작업물에 &lt;b&gt;멱등성&lt;/b&gt;을 부여해주는 기법이라고 보는 경우도 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금부터는 하네스의 개념적인 부분인 3가지 핵심 축과, 9가지 원칙에 대해서 알아보겠습니다.&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;하네스의 3가지 축&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하네스는 크게 3가지 축으로 이루어져 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컨텍스트 엔지니어링&amp;nbsp;&lt;/li&gt;
&lt;li&gt;아키텍쳐 제약&lt;/li&gt;
&lt;li&gt;엔트로피 관리&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3130&quot; data-origin-height=&quot;1730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FmrYy/dJMcafmbYZ5/yoYahDEeeKXr7PFls5jn20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FmrYy/dJMcafmbYZ5/yoYahDEeeKXr7PFls5jn20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FmrYy/dJMcafmbYZ5/yoYahDEeeKXr7PFls5jn20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFmrYy%2FdJMcafmbYZ5%2FyoYahDEeeKXr7PFls5jn20%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;3130&quot; height=&quot;1730&quot; data-origin-width=&quot;3130&quot; data-origin-height=&quot;1730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;여기에는 대표적으로&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에이전트 가이드 파일,&amp;nbsp;docs/, skills/&lt;/li&gt;
&lt;li&gt;프로젝트 기술 스택, 코딩 규칙, 금지사항&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;등이 들어갈 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;최근 OpenAI의 하네스 엔지니어링에서는&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이러한 컨텍스트 엔지니어링을 적용하며 겪은 실패 사례들을 공유했는데, 주요 내용은 다음과 같습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;Context is a scarce resource&quot; : 거대 지시 파일이 태스크&amp;middot;코드&amp;middot;관련 문서를 밀어냄 &lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;rarr; 에이전트가 핵심 제약을 놓치거나 엉뚱한 걸 최적화&lt;/li&gt;
&lt;li&gt;&quot;Too much guidance becomes non-guidance&quot; : 모든 게 중요하면 아무것도 중요하지 않다&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;rarr; 에이전트가 의도적 탐색 대신 로컬 패턴 매칭으로 빠짐&lt;/li&gt;
&lt;li&gt;&quot;It rots instantly&quot; : 모놀리식 매뉴얼은 낡은 규칙들의 무덤이 된다.&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;rarr; 뭐가 현재에도 유효한지 에이전트도 사람도 모름&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;OpenAI는&amp;nbsp;이러한&amp;nbsp;실패&amp;nbsp;사례들을&amp;nbsp;교훈&amp;nbsp;삼아&amp;nbsp;컨텍스트&amp;nbsp;구조를&amp;nbsp;개선했습니다.&lt;br /&gt;&lt;br /&gt;각&amp;nbsp;항목과&amp;nbsp;원칙에&amp;nbsp;대한&amp;nbsp;상세&amp;nbsp;내용은&amp;nbsp;개별적으로&amp;nbsp;분리하고,&lt;br /&gt;&lt;br /&gt;항상&amp;nbsp;로드되는&amp;nbsp;'루트&amp;nbsp;컨텍스트(Root&amp;nbsp;Context)'에는&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;에이전트가 필요할 때 해당 내용을 스스로 찾아갈 수 있도록&lt;/p&gt;
&lt;p style=&quot;text-align: left;&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-origin-width=&quot;400&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNbWvK/dJMcahROkyu/tBDcn7T7wtCCgWqyoMrK50/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNbWvK/dJMcahROkyu/tBDcn7T7wtCCgWqyoMrK50/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNbWvK/dJMcahROkyu/tBDcn7T7wtCCgWqyoMrK50/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNbWvK%2FdJMcahROkyu%2FtBDcn7T7wtCCgWqyoMrK50%2Fimg.jpg&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;400&quot; height=&quot;353&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;두번째 축으로, 하네스를 구성하는 핵심적인 요소인 아키텍쳐 제약 축이 있습니다.&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;기계적으로 LLM의 행동에 제약을 주는 것입니다.&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;기계적 제약에는 크게 2가지 관점이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Guides : 사전 제어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 린터, 타입체커, 코드모드, 훅&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sensors : 사후 제어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 구조 테스트. 정적 분석, 로그, 리뷰&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;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 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;마지막 축으로, 하네스를 구성함에 있어 가장 어렵고 까다로운 요소인 엔트로피 관리 축이 있습니다.&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;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;LLM 이 작업한 코드도 결국 증가하는 엔트로피를 피할 수는 없습니다.&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;482&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Mq22/dJMcadu3QwO/Q3X9Kv1qJxO3l0yVrCK98k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Mq22/dJMcadu3QwO/Q3X9Kv1qJxO3l0yVrCK98k/img.jpg&quot; data-alt=&quot;무질서를 먹고 자라는 엔트로피&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Mq22/dJMcadu3QwO/Q3X9Kv1qJxO3l0yVrCK98k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Mq22%2FdJMcadu3QwO%2FQ3X9Kv1qJxO3l0yVrCK98k%2Fimg.jpg&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;416&quot; height=&quot;360&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무질서를 먹고 자라는 엔트로피&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;LLM은 구린 코드를 보고 레퍼런스를 삼아 구린 코드를 만들기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주기적으로 코드를 바로잡는 역할의 클리너가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(세운 규칙들을 제대로 지키고 있는지 전수 검사를 하고 잘못된 부분을 수정해서 PR 을 올리는 등)&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;그런데 사실 말이 쉽지 정량적인 평가가 어려운 LLM 작업 결과물에 있어&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;p data-ke-size=&quot;size16&quot;&gt;이 3가지 축에 추가로 피드백 루프 까지 4가지로 보는 관점도 있습니다만,&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;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;하네스의 핵심 9가지 원칙&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;에이전트의 상태를 컨텍스트가 아닌 파일로(디스크에) 상태 관리 한다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;휘발되는 컨텍스트에 저장하면 상태 관리가 어려움&lt;/span&gt;&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;&amp;nbsp;LLM도 인간처럼 본인의 작업 결과물에 대해서 관대하게 평가함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;이전 세션에서의 문제가 남아 있을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;빠른 피드백 루프를 연결&amp;nbsp;
&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;/li&gt;
&lt;li&gt;레파지토리가 유일한 진실의 원천이다&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;in-context 로 즉, 파일로 접근 할 수 없는 내용은 존재하지 않는 것과 같다&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;사람이 직접 작업하지 않는다&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;한번에 완벽하게 구성하려 하지말고 계속 고쳐나가야함&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;하네스는 현재 모델이 못하는 것에 대한 가정&lt;/li&gt;
&lt;li&gt;모델이 업그레이드 되면 해당 가정이 낡음 &amp;rarr; 낡은 가정은 제거해야함&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;자 이렇게 하여 하네스가 어떻게 구성되어야 하는지&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;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;s&gt;원래 글 하나에 다 담으려고 했는데 쓸데없는 말 하다보니 길어져서 다음화에 계속&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N2iqH/dJMcabRBzxT/TYHXcTURlOxN9w6OvqhYu0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N2iqH/dJMcabRBzxT/TYHXcTURlOxN9w6OvqhYu0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N2iqH/dJMcabRBzxT/TYHXcTURlOxN9w6OvqhYu0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN2iqH%2FdJMcabRBzxT%2FTYHXcTURlOxN9w6OvqhYu0%2Fimg.jpg&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;439&quot; height=&quot;439&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&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;</description>
      <category>백엔드</category>
      <category>하네스</category>
      <category>하네스 엔지니어링</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/45</guid>
      <comments>https://kyeum-d.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 4 May 2026 17:14:19 +0900</pubDate>
    </item>
    <item>
      <title>다사다난 했던 이직기를 돌아보며...</title>
      <link>https://kyeum-d.tistory.com/40</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며...&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 다사다난한 2024년 한해 중 저에게 있어 가장 큰 이벤트였던 이직기를 다뤄보고자 합니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;저와 비슷한 고민을 하고 있거나 이 시기에 이직을 고려하는 3~4년차 개발자들에게 저의 경험이 조금이나마 도움이 되었으면 좋겠다는 마음에 글을 작성하게 되었습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;(*이제부터는 제 경험을 좀 더 생생하게 전달하기 위해 &lt;s&gt;반말&lt;/s&gt; 구어체로 진행하겠습니다.)&lt;br /&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;개발자 붐이 일고서부터 3년정도가 지났을까.. 그 당시부터 개발자를 준비하던 수 많은 개발자 지망생들이 쏟아져 나옴과 동시에&lt;br /&gt;&amp;nbsp;&lt;br /&gt;휘청거리는 경제를 입증이라도 하듯 개발자를 비롯한 취업 시장의 한파가 찾아왔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQFP6T/btsLEfDGenN/KGqRfEwKcxnUGdO6RmYkTK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQFP6T/btsLEfDGenN/KGqRfEwKcxnUGdO6RmYkTK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQFP6T/btsLEfDGenN/KGqRfEwKcxnUGdO6RmYkTK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQFP6T%2FbtsLEfDGenN%2FKGqRfEwKcxnUGdO6RmYkTK%2Fimg.jpg&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;458&quot; height=&quot;263&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;하지만 직장을 다니고 있던 나로써는 이 말이 크게 와 닿지 않았고 1년이 지난 시점에서 이직을 결심하게 된다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;환경을 바꾸는 저마다 이유가 있겠지만 결국엔 두가지 중 하나 일 것이다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;새로운 길을 찾아 나서거나&lt;br /&gt;&amp;nbsp;&lt;br /&gt;현재의 만족스럽지 않은 상황을 바꿔보기 위해서이거나&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;본인의 경우는 두번째가 좀 더 컸을 것이다. (후술하겠지만 이 사유를 객관화 하여 바라봐야한다.)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;와닿지 않은 취업시장의 한파를 우습게 봤던 것일까 그 추위를 몸소 체험해보고 싶었던 것일까&lt;br /&gt;&amp;nbsp;&lt;br /&gt;선 퇴사 후 이직 이라는 이직러로써의 최악의 결정을 내리게 된다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;당연하게도 이 결정은 모든 주위 사람들의 반대와 염려를 자아냈다. 반대하는 이들의 대부분이 이미 그런 과정을 겪고서&lt;br /&gt;&amp;nbsp;&lt;br /&gt;어려웠던 상황을 마주해 본 이들이였으므로, 충분히 설득력 있는 반대였을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2NSQS/btsLD2kjQVv/lNeLlkgjFxXJbQZPKQSXkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2NSQS/btsLD2kjQVv/lNeLlkgjFxXJbQZPKQSXkK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2NSQS/btsLD2kjQVv/lNeLlkgjFxXJbQZPKQSXkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2NSQS%2FbtsLD2kjQVv%2FlNeLlkgjFxXJbQZPKQSXkK%2Fimg.jpg&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;420&quot; height=&quot;235&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;하지만 인간이란 얼마나 이기적이고 오만한 존재인가... 본인이 겪지 않고서는 정확히 이해를 할 수 없는 족속일 것이다.(&lt;s&gt;너만 그런거야&lt;/s&gt;)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;일이 재밌어서 회사를 다니는 나에게 있어, 회사를 '버티기' 시작하면 그 시간들이 너무 괴로워져서, 사실 선택지란 존재하지 않았을 것이다.&lt;br /&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;그렇게 모두의 염려를 뒤로한 채 11월 초 퇴사를 하고 취업시장에 뛰어들게 된다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;1년 아주 열심히 달려왔지만, 퇴사의 해방감과 함께 은연 중의 불안감이 함께 엄습한다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;패기롭게 퇴사 했지만 본인도 알고 있을 것이다. 막연함의 무서움과 끝이 정해지지 않은 자유로움의 대가를&lt;br /&gt;&amp;nbsp;&lt;br /&gt;지금 생각해보면 별도의 쉬는 기간 없이 바로 구직 활동에 임했던 점은&lt;br /&gt;선퇴사 후이직 이라는 최악의 선택 이후에 있어 가장 최고의 선택이였지 않았을까 싶다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;서론이 길었지만 본론으로 들어가자면 &lt;br /&gt;이번 이직 준비 과정에서 느꼈던 점들과 미리 준비했으면 좋았을 내용들에 대해서 다뤄보고자 한다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;본격적인 보금자리 찾기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이력서 관리는 평소에&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 이직 과정에서 가장 절실하게 느낀 점은 이력서를 평소에 꾸준히 다듬어 놓아야 한다는 것이었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;물론 기존에도 &quot;평소에 이력서를 업데이트 해야한다.&quot; 라는 얘기를 꾸준히 들었던 입장에서, 이 조언을 잊지 않았기에&lt;br /&gt;주도적으로 진행했던 업무들에 대해서 틈틈히 기록을 해놨었다.(나중에 이력서에 작성하기 위한)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;그런데 여기서 간과했던 점이 있었는데 바로 업무 그 자체에 대해서만 기록을 해놨던 점이다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;해당 업무를 왜 진행했고 어떤 배경이 있었으며, 어떤 과정과 고민을 거쳐 어떤 결과가 나왔는지에 대한&amp;nbsp;&lt;br /&gt;그 당시의 생생한 기록이 중요한 것인데&lt;br /&gt;&amp;nbsp;&lt;br /&gt;나의 기록(업무 자체에 대한 기록)만으로는 그 당시의 나의 선택의 근거를 기억해내기에는 역부족이였으리라&lt;br /&gt;&amp;nbsp;&lt;br /&gt;주니어 개발자들은 경험 자체 뿐 아니라 내가 어떻게 일을 하는지를 보여주는 것 또한 중요한데&lt;br /&gt;이러한 점들이 기억이 나도록 깊이 생각하고 진행했던 내역을 최대한 자세하게 기록해두는 것이 필요할 것이다.&lt;br /&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;개발자 채용 과정은 크게 3가지 정도가 있다.&lt;/p&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;과제 전형이 추가된 과정&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적인 과정이 없는 전형은 서류 전형이 빡세고&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;코딩테스트는 평소에 준비를 해야하며&lt;br /&gt;&amp;nbsp;&lt;br /&gt;과제전형은 준비 시간은 필요 없지만 전형 자체의 리소스가 가장 많이 필요하다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;목표로 하고 있는 회사의 채용 과정을 미리 준비하거나&lt;br /&gt;목표로 하고 있는 회사는 따로 없다면 본인의 준비된 상황을 고려하여 타겟을 설정하면 좋을 것이다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;본인의 경우에는&lt;br /&gt;퇴사 후 시간이 많은 상황이였기에 과제전형을 진행하는 회사들을 선택하여 준비했다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;과제전형의 좋은 점은 과제전형에서 떨어진다 하더라도 토이프로젝트로 전환해서 그대로 포트폴리오로 써먹을 수 있다는 점인데&lt;br /&gt;(물론 특정 회사의 채용 과제 내용이 드러나지 않도록 변형이 필요하지만)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;마침 특별히 진행하는 사이드 프로젝트도 없었으므로 겸사겸사 쉬는 기간동안 코드도 작성할 겸 과제전형이 있는 회사들에 지원하게 되었다.&lt;br /&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oIUZQ/btsLE33STGz/sOGVKLmjYxuejG3Ezhff51/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oIUZQ/btsLE33STGz/sOGVKLmjYxuejG3Ezhff51/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oIUZQ/btsLE33STGz/sOGVKLmjYxuejG3Ezhff51/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoIUZQ%2FbtsLE33STGz%2FsOGVKLmjYxuejG3Ezhff51%2Fimg.jpg&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;499&quot; height=&quot;349&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;컨텐츠의 즐거움이 주는 힘과 내가 하는 일들이 누군가에게 즐거움을 주기 위해서라는 점이 굉장히 낭만적이고 매력적이라고 생각되어 지원하게 되었고&lt;br /&gt;&amp;nbsp;&lt;br /&gt;블로그 글들을 좋게 봐주신 덕인지 서류 전형을 통과하고 과제 전형을 진행할 수 있게 되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이후로도 다양한 회사들의 과제전형을 진행했지만, 확실히 회사마다 차이가 있었는데&lt;br /&gt;&amp;nbsp;&lt;br /&gt;크게는 두가지 부류로 나뉘는 듯 했다.&lt;/p&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 data-ke-size=&quot;size16&quot;&gt;레진코믹스의 경우는 두번째에 해당했는데 확실히 본인의 생각을 녹여야 하는 부류가 생각할 시간도 더 많이 필요하고 어렵다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;지원자들도 기업의 채용 절차들을 겪으면서 기업을 평가하는데&lt;br /&gt;개인적으로 자유로움 속에서의 본인의 생각을 담을 수 있는 레진코믹스의 과제 전형이 가장 마음에 들었고 자연스럽게 가장 심혈을 기울여 진행한 과제가 되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;일주일 정도의 기간동안 코드를 작성해 갔으며 주어진 도전 과제들을 성공적으로 수행하기 위해 수 많은 수정 작업을 거쳤다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;수정 작업들은 선택(기술의 선택 혹은 구조의 선택)의 연속이었다. 선택에는 항상 명확한 근거와 이유가 존재해야 했고 실제로도 효율적이여야만 했다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;자유로운 과제는 아마도 지원자들이 주도적으로 고민하고 깊이 생각할 줄 아는 사람인지를 확인하려는 것이였으리라&lt;br /&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;노력에 보답이라도 하듯 과제전형에 합격 했고 1차 면접을 준비하게 되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;1차 면접은 내가 작성한 코드를 화면에 띄우고 제출한 Read.me를 읽으며 시작되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;먼저 이 과제의 목적과 프로젝트 전체적인 구조와 요구사항에 기반한 프로젝트 주요 관심사에 대해서 설명했다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이후, 주어진 챌린지를 해결하기 위해 시도한 다양한 접근들 중 성공한 시도와 실패한 시도를 구분하여 서술했다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이에 따라 자연스럽게 기술적인 질문과 대화들이 오갔으며, 모르는 점들에 대해서는 솔직하게 잘 모르겠다고 답변했다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;기술적인 대화가 오갈 때는 정확하게 모르는 기술에 대해서는 아는 듯이 대답하는 것은 오히려 독이 될 것이다.&lt;br /&gt;지난 회사에서 면접관으로 참관했던 경험을 미루어 보아, 이런 점들은 금방 드러나고 부정적인 요소로 작용한다.&lt;br /&gt;&lt;br /&gt;이러한 점들 때문에 오히려 기술자들에게 1차 면접이란 더 마음이 편한 것이지 않을까&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2차 면접으로 ...&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 생각들을 솔직하게 말한 점들이 높은 점수를 샀던걸까&lt;br /&gt;1차 면접에 합격했다는 통보를 받았고 2차 면접을 준비하게 되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;지난 회사를 오퍼를 받아 따로 채용 절차를 까다롭게 거치지 않았던 나에게 있어 2차 면접이란 미지의 영역 그 자체였다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;그렇기에 다양한 정보들을 수집하고 보편적인 질문들에 대해서 준비를 했다.(왜 이직하게 되었나, 왜 지원하게 되었나 등)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;2차 면접에는 CTO님이 한 분 들어오셨고 우려와 달리 편안한 분위기에서 진행되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;예상했던 질문들도 있었고 예상하지 못한 질문들도 있었는데 정말 대화하듯이 자연스럽게 나의 모습을 보여주었던 것 같다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;마지막으로는 어떤 인재를 원하는지 회사 및 면접관님의 인재상에 대해서 물어봤고 스스로도 그런 인재와 부합하는지 생각하게 되었다.&lt;br /&gt;(인재상에 나를 맞춘다기 보단 서로가 핏에 맞는지를 검증하는)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;결국 회사와 지원자는 갑과 을의 수직적인 관계 보다는 내가 일하는 곳 같은 배를 탄 동료라고 생각하기 때문에 서로가 잘 맞는지 검증하는 것도 필수적일 것이다.&lt;br /&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;처음 지원으로 부터 1달여간의 여정이었을까 최종합격 통보를 받게 되었고 무사히 레진코믹스에 합류하게 되었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이제서야 마음 놓고 2주간을 편하게 쉬면서 &lt;s&gt;이게 인생이지&lt;/s&gt; 평소에 보고 싶었던 드라마나 영화들을 몰아봤다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이 길다면 긴 여정에서 느낀 점은 퇴사를 하고 이직을 하면 멘탈 관리가 어렵다는 점이다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;여기서 말하는 멘탈 관리는 피말리는 결과들의 기다림과  기다림의  기간 동안 다른 일들을 찾아서 하는 것이 생각보다 굉장히 어려운 일이라는 것&lt;br /&gt;&amp;nbsp;&lt;br /&gt;월급의 공백보다도 이러한 점들 때문에 이직을 할 때 환승 이직을 해야하지 않나 싶다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이번에는 운 좋게도 원하던 회사에 무사히 이륙 할 수 있었지만 다음에는 이런 패기로운 선택을 다시 할 수 있을까? 생각하며&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이번 이직기를 마무리 하려고 한다.&lt;br /&gt;&amp;nbsp;&lt;br /&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;br /&gt;&amp;nbsp;&lt;/p&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;본인의 강점을 이해하고 채용 프로세스를 선택하여 집중하자&lt;/li&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;&amp;nbsp;&lt;br /&gt;긴 글 읽어주셔서 감사합니다.&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;구직활동하는 모든 취준생들 화이팅!!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B3r6u/btsLCD0iAgm/4EZZOEh4srTgVJMSMjGDW1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B3r6u/btsLCD0iAgm/4EZZOEh4srTgVJMSMjGDW1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B3r6u/btsLCD0iAgm/4EZZOEh4srTgVJMSMjGDW1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB3r6u%2FbtsLCD0iAgm%2F4EZZOEh4srTgVJMSMjGDW1%2Fimg.jpg&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;225&quot; height=&quot;224&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;224&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;</description>
      <category>기록</category>
      <category>레진코믹스</category>
      <category>이직</category>
      <category>주니어 개발자</category>
      <category>취뽀</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/40</guid>
      <comments>https://kyeum-d.tistory.com/40#entry40comment</comments>
      <pubDate>Sun, 5 Jan 2025 14:23:14 +0900</pubDate>
    </item>
    <item>
      <title>[GC] 나야 메모리, 근데 이제 누수를 곁들인</title>
      <link>https://kyeum-d.tistory.com/39</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbpEdq/btsKeGCrHcw/kVPK73EY9fBbECqen7iOPK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbpEdq/btsKeGCrHcw/kVPK73EY9fBbECqen7iOPK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbpEdq/btsKeGCrHcw/kVPK73EY9fBbECqen7iOPK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbpEdq%2FbtsKeGCrHcw%2FkVPK73EY9fBbECqen7iOPK%2Fimg.jpg&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;300&quot; height=&quot;168&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&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;이번 글은 메모리 관련 이슈의 정의와 해결 과정을 공유하여, 유사한 문제를 겪는 개발자분들께 도움이 되고자 작성했습니다.&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;또한, GC 동작 원리를 심도 있게 탐구함으로써 이해도를 높이고, 문제 해결 과정에서 발생했던 몇 가지 오해를 바로잡아 추후 유사한 문제를 예방하는 것을 목표로 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;* 본 글은 Java8 버젼 JVM의 CMSGC에 대한 내용입니다.&lt;/i&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;APM을 모니터링 하던 중 이상현상을 보이는 지표를 발견했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3260&quot; data-origin-height=&quot;1592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/REDSV/btsKeSh4NXM/GkZXE05i9RIH7wkx1QiTGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/REDSV/btsKeSh4NXM/GkZXE05i9RIH7wkx1QiTGk/img.png&quot; data-alt=&quot;이거완전 럭키메모리 자나?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/REDSV/btsKeSh4NXM/GkZXE05i9RIH7wkx1QiTGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FREDSV%2FbtsKeSh4NXM%2FGkZXE05i9RIH7wkx1QiTGk%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;686&quot; height=&quot;335&quot; data-origin-width=&quot;3260&quot; data-origin-height=&quot;1592&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이거완전 럭키메모리 자나?&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WKErT/btsKcUWm3Ox/aZI0KDwAJL9LvdPCRuPEG1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WKErT/btsKcUWm3Ox/aZI0KDwAJL9LvdPCRuPEG1/img.jpg&quot; data-alt=&quot;출처 : 몽글이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WKErT/btsKcUWm3Ox/aZI0KDwAJL9LvdPCRuPEG1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWKErT%2FbtsKcUWm3Ox%2FaZI0KDwAJL9LvdPCRuPEG1%2Fimg.jpg&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;380&quot; height=&quot;380&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1500&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 몽글이&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;s&gt;왜 나 대신 니가 성장을&lt;/s&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;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;증거를 수집하자 - Heap Dump&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Dump를 생성해보자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 누수가 의심 되는 상황에서 할 수 있는 가장 첫번째 작업은 Heap Dump를 생성하는 것입니다.&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;jmap 명령어를 사용하여 간편하게 Dump 를 생성 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729497266845&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jmap -dump:file=heapdump.hprof &amp;lt;pid&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*주의 : 따라하지 마시오 (후술 하겠지만 여기서 첫번째 실수가 생겼습니다. )&lt;/b&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;명령의 결과로 3GB 남짓의 Dump 파일이 생성되었습니다.&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;Dump 를 분석해보자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원하는 기능이 많고 간편하게 사용 할 수 있는 Eclipse Memory Analyzer 툴을 사용해서 분석했습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2462&quot; data-origin-height=&quot;886&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zqGZn/btsKdEFt6fZ/FQ1Nck9XKhZfsrhGkEFeX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zqGZn/btsKdEFt6fZ/FQ1Nck9XKhZfsrhGkEFeX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zqGZn/btsKdEFt6fZ/FQ1Nck9XKhZfsrhGkEFeX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzqGZn%2FbtsKdEFt6fZ%2FFQ1Nck9XKhZfsrhGkEFeX1%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;2462&quot; height=&quot;886&quot; data-origin-width=&quot;2462&quot; data-origin-height=&quot;886&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;분석 결과를 마주했을 때 첫번째로 당황했던 부분은 3GB 남짓의 덤프 파일에서 분석 한 내용이 194MB? 라는 점이였습니다.&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;관련 내용을 찾아보니 Memory Analyzer 에서 기본적으로 GC 수집 대상으로 낙인이 찍힌 객체들은(미사용 객체) 분석 결과에서 제외되도록 설정이 되어있었습니다.&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;1054&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qFC7c/btsKeF4D73i/Y7Fd1NHm6iWf7yCyNp9cU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qFC7c/btsKeF4D73i/Y7Fd1NHm6iWf7yCyNp9cU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qFC7c/btsKeF4D73i/Y7Fd1NHm6iWf7yCyNp9cU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqFC7c%2FbtsKeF4D73i%2FY7Fd1NHm6iWf7yCyNp9cU0%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;369&quot; height=&quot;119&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2460&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lpcXd/btsKdCU9643/aT0OpBgfkVeokheDVmgDU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lpcXd/btsKdCU9643/aT0OpBgfkVeokheDVmgDU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lpcXd/btsKdCU9643/aT0OpBgfkVeokheDVmgDU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlpcXd%2FbtsKdCU9643%2FaT0OpBgfkVeokheDVmgDU1%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;2460&quot; height=&quot;920&quot; data-origin-width=&quot;2460&quot; data-origin-height=&quot;920&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;관련 설정을 켜주고 Dump를 다시 분석하니 맞게 나오는 것을 확인 할 수 있습니다. (Details 부분을 보시면 첫번째 분석에서는 Unreachable Object에 대해 볼 수 있는 Histogram 을 별도로 제공)&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;하지만, 저희에게 필요한 것은 누수가 일어나고 있는 객체의 분석, 즉 GC 수집 대상으로 낙인 찍히지 않은 객체들이기 때문에&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;Memory Analyzer에서는 분석 결과 이런 유형의 객체들을 찾아주는 Leak Suspects 항목을 제공합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2450&quot; data-origin-height=&quot;1210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7aacC/btsKdO88IdK/6vNLkGDVvD4GCQrmhHlsx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7aacC/btsKdO88IdK/6vNLkGDVvD4GCQrmhHlsx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7aacC/btsKdO88IdK/6vNLkGDVvD4GCQrmhHlsx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7aacC%2FbtsKdO88IdK%2F6vNLkGDVvD4GCQrmhHlsx0%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;2450&quot; height=&quot;1210&quot; data-origin-width=&quot;2450&quot; data-origin-height=&quot;1210&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;Leak Suspects 버튼을 눌러 분석을 요청합니다.&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;1766&quot; data-origin-height=&quot;2188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLWZEO/btsKcTJ25AM/9LcSzXKUAZSYjYKY0kbTKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLWZEO/btsKcTJ25AM/9LcSzXKUAZSYjYKY0kbTKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLWZEO/btsKcTJ25AM/9LcSzXKUAZSYjYKY0kbTKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLWZEO%2FbtsKcTJ25AM%2F9LcSzXKUAZSYjYKY0kbTKk%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;530&quot; height=&quot;657&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;2188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누수로 의심되는 객체 분석 결과 ClassLoader 종류의 객체가 두가지가 나왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClassLoader 에서 메모리 누수가..? 여기서 부터 뭔가 이상함을 감지했지만 분석 결과를 조금 더 파악해보기로 했습니다.&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;dominator_tree&lt;/b&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-origin-width=&quot;1656&quot; data-origin-height=&quot;2042&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhIuUX/btsKeJlt9Ah/XGne5fsSC3BzwbSVu0ObQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhIuUX/btsKeJlt9Ah/XGne5fsSC3BzwbSVu0ObQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhIuUX/btsKeJlt9Ah/XGne5fsSC3BzwbSVu0ObQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhIuUX%2FbtsKeJlt9Ah%2FXGne5fsSC3BzwbSVu0ObQ1%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;649&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;2042&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;Shallow Heap
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 객체 자체가 차지하는 메모리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Retained Heap&lt;br /&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Class Loader... 너 맞아?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class Loader 관련 메모리 누수에 대한 내용을 열심히 찾아보니...&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Tomcat  재기동 하지 않은채로 배포하는 방식을 채택하게 되면 동적 클래스 로딩으로 인한 ClassLoader가 해제되지 않고 메모리에 남아있으면서 누수가 발생&lt;/li&gt;
&lt;li&gt;ThreadLocal에서 ClassLoader 를 참조하면서 스레드 풀의 스레드가 반환되지 않아 누수가 발생&lt;/li&gt;
&lt;/ol&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;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;의심 할 수 있는 것들을 전부 의심하기 시작했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Stream을 열고 close 하지 않아 생기는 메모리 누수&lt;/li&gt;
&lt;li&gt;static으로 선언된 변수의 Map, HashMap에 적재되고 사용되지 않는 객체들&lt;/li&gt;
&lt;li&gt;JDBC Connection 관련 connection을 맺고 close 하지 않는 경우&lt;/li&gt;
&lt;li&gt;완료되지 않은 Future와 ExecutorService&lt;/li&gt;
&lt;/ul&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;이 중에서 가장 빈번하게 발생하는 부분인 Stream resource의 미반환 상황을 찾아봤습니다.&lt;/p&gt;
&lt;p 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;InputStream 너 범인해라&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oKvgp/btsKc1gRuQl/4TKGDoSZ4TdIOwMrll1yV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oKvgp/btsKc1gRuQl/4TKGDoSZ4TdIOwMrll1yV0/img.jpg&quot; data-alt=&quot;영화 부당거래&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oKvgp/btsKc1gRuQl/4TKGDoSZ4TdIOwMrll1yV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoKvgp%2FbtsKc1gRuQl%2F4TKGDoSZ4TdIOwMrll1yV0%2Fimg.jpg&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;506&quot; height=&quot;285&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;영화 부당거래&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stream을 획득하고 close 하지 않는 부분을 발견하고 &quot;이거다&quot; 싶은 마음에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Visual VM, JProfiler 를 총 동원하여 local 환경을 모니터링 하고&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;NGrinder를 통해 의심되는 코드를 사용하는 api에 5천건 정도의 호출을 보냈습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2551&quot; data-origin-height=&quot;1397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UC3kU/btsKeN9oEdE/nR0JpxPuwKxrFNUyDlRw00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UC3kU/btsKeN9oEdE/nR0JpxPuwKxrFNUyDlRw00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UC3kU/btsKeN9oEdE/nR0JpxPuwKxrFNUyDlRw00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUC3kU%2FbtsKeN9oEdE%2FnR0JpxPuwKxrFNUyDlRw00%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;2551&quot; height=&quot;1397&quot; data-origin-width=&quot;2551&quot; data-origin-height=&quot;1397&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;하지만 base line은 높아지지 않았고... 성급하게 판단하고 결론지은 결과의 쓴 맛을 보게됐습니다.&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;수 많은 삽질을 거치고 나서야 GC 의 동작에 대해서 다시 자세하게 살펴볼 생각이 들었습니다.&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;GC 를 파헤쳐 보자(CMSGC)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 기술은 기술의 탄생 배경을 살펴보면 해당 기술의 핵심 가치에 접근하기 쉬워진다고 생각하기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMSGC의 탄생 배경에 대해서 먼저 알아보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 도입되었을까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMSGC(Concurrent Mark Sweep)는 약어에서도 힌트를 얻으셨을 수 있듯, 동시성을 유지하기 위해 등장했습니다.&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;기존의 Parallel GC와 Serial GC 에서의 너무 긴 STW(Stop-the-World) 가 문제가 됐습니다.&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;p data-ke-size=&quot;size16&quot;&gt;이름 그대로 Concurrent(동시에) Marking(마킹) 함으로써  STW 시간을 최대한 짧게 가져가서 높은 응답속도를 낼 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 총 5가지의 단계를 거칩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Initial Mark &lt;/span&gt;(짧은 STW 발생) - 루트 객체에서 직접 참조되는 객체만 마킹&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Concurrent Marking - Initial Mark에서 마킹된 객체를 기반으로 모든 연결된 객체를 마킹 (어플리케이션 실행과 동시에 실행)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Remark (STW 발생) - 병렬 마킹 도중 누락된 객체가 있는지 확인하고 최종 마킹 수행&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Concurrent Sweep - 마킹된 객체가 아닌 모든 객체의 메모리 해제 (어플리케이션과 병렬 실행)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Resetting - 다음 GC 주기를 준비하기 위해 데이터 구조를 초기화&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;CMS GC가 어떻게 처리되는지에 대해 전체적인 흐름을 이해했으니,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 단계가 내부적으로 어떤 구조&lt;/b&gt;와 메커니즘을 통해 작동하는지 살펴보겠습니다.&lt;span&gt;&amp;nbsp;&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-origin-width=&quot;556&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1C1p3/btsKfzvYhQn/9IlQzvopl1fE12ojkkkzG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1C1p3/btsKfzvYhQn/9IlQzvopl1fE12ojkkkzG1/img.png&quot; data-alt=&quot;출처 : https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1C1p3/btsKfzvYhQn/9IlQzvopl1fE12ojkkkzG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1C1p3%2FbtsKfzvYhQn%2F9IlQzvopl1fE12ojkkkzG1%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;327&quot; height=&quot;405&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html&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;Heap 내부 구조는 다음과 같은 4개의 영역으로 구분됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Eden&lt;/li&gt;
&lt;li&gt;Survivors 0&lt;/li&gt;
&lt;li&gt;Survivors 1&lt;/li&gt;
&lt;li&gt;Old Generation&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Edne, S0, S1은 Young Generation 에 속합니다.&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;최초 객체가 생성되면 Eden 영역에 저장됩니다. Eden 공간이 가득차게 되면 &lt;b&gt;Minor GC&lt;/b&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;Minor GC&lt;/b&gt;는 총 3가지 작업을 진행합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;u&gt;Eden 영역&lt;/u&gt;에서 살아 남은 객체를 현재&amp;nbsp;&lt;u&gt;비활성화 Survivors &lt;/u&gt;영역으로 이동&lt;/li&gt;
&lt;li&gt;현재 &lt;u&gt;활성화 Survivors&lt;/u&gt; 영역에서 살아남은 객체를 &lt;u&gt;비활성화 Survivors&lt;/u&gt; 영역으로 이동하면서 생존 횟수 카운팅&lt;/li&gt;
&lt;li&gt;생존 횟수가 임계값에 도달한 살아남은 객체를 &lt;u&gt;Old Generation&lt;/u&gt;으로 승격&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ea0MHX/btsKeVTOXAp/LnGM1a6l85uUyNwfTPL6Vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ea0MHX/btsKeVTOXAp/LnGM1a6l85uUyNwfTPL6Vk/img.png&quot; data-alt=&quot;출처 : https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ea0MHX/btsKeVTOXAp/LnGM1a6l85uUyNwfTPL6Vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fea0MHX%2FbtsKeVTOXAp%2FLnGM1a6l85uUyNwfTPL6Vk%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;566&quot; height=&quot;383&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;752&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html&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;* 여기서 S0과 S1는 번갈아가면서 한쪽만 사용이 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  왜 Survivors 영역은 한쪽만 사용될까?&lt;br /&gt;- 생존과 이동의 관리를 효율적으로 하기 위함&lt;br /&gt;- Minor GC가 수행 될 때마다 다른 Survivors 영역을 사용함으로써 메모리 파편화를 방지 할 수 있음&lt;br /&gt;- 사용된 영역을 초기화 하고 새로운 영역에 새롭게 적재하는 것이기에&lt;br /&gt;- Survivors 영역을 교차하며 이동하는 횟수를 가지고 카운팅을 하는 방식을 사용하기 위해&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;이렇게 실행되는 &lt;b&gt;Minor GC&lt;/b&gt;는 STW 이벤트가 발생하며 빠르고 주기적으로 실행됩니다.&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;이 과정을 반복하다보면 Old Generation의 영역에 객체를 담을 수 없는 상황이 옵니다.&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;Major GC&lt;/b&gt;(Full GC)가 발생합니다. Major GC는 Heap 영역의 모든 미사용 객체를 메모리에서 해제합니다.&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&gt; &lt;b&gt;Major&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&amp;nbsp;GC&lt;/b&gt;는 STW 이벤트가 발생하며 느리고 긴 주기를 가지고 실행됩니다.&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;이제 CMSGC 의 동작 방식에 대해서도 정확히 알아봤으니 다시 범인을 찾기위해 단서를 수집해야 합니다.&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;한번 더 Dump를 생성해보자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누수된 객체를 찾기위해서는 일정 간격을 두고 Dump를 생성해서 비교해봐야 한다는 조언을 듣게되고&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;다시 한번 Dump를 생성하기로 합니다.&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;여기서 최초에 Dump 생성 시 실수했던 부분을 바로잡게됩니다.&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;바로 live 옵션을 주지 않고 dump를 생성했던 것인데&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;live 옵션을 주고 dump를 생성해야 FullGC를 수행한 후 dump를 생성해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FullGC가 돌았음에도 해제되지 않은 객체들을 식별해서 분석하기가 용이합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729567295511&quot; class=&quot;tcl&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jmap -dump:live,format=b,file=heapdump.hprof &amp;lt;pid&amp;gt;&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;live 옵션을 주고 dump를 생성합니다.&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;메모리.. 다 비었는데요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dump를 생성하자 FullGC가 돌면서 메모리 사용률이 급격히 떨어지는 것을 확인 할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2546&quot; data-origin-height=&quot;1310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bb0Iz/btsKdScPJoh/cI18uaKYjEzKl1T4MlujFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bb0Iz/btsKdScPJoh/cI18uaKYjEzKl1T4MlujFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bb0Iz/btsKdScPJoh/cI18uaKYjEzKl1T4MlujFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBb0Iz%2FbtsKdScPJoh%2FcI18uaKYjEzKl1T4MlujFK%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;527&quot; height=&quot;271&quot; data-origin-width=&quot;2546&quot; data-origin-height=&quot;1310&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;여기서부터 아차 싶었습니다. 여태 FullGC가 동작하지 않고 Minor GC만 수행됐던게 아닐까..?&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;떨리는 마음으로 확인결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4058&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnr8CT/btsKeHhlruV/cxVQf78KEWUlHuZbLMDaBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnr8CT/btsKeHhlruV/cxVQf78KEWUlHuZbLMDaBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnr8CT/btsKeHhlruV/cxVQf78KEWUlHuZbLMDaBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnr8CT%2FbtsKeHhlruV%2FcxVQf78KEWUlHuZbLMDaBK%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;4058&quot; height=&quot;212&quot; data-origin-width=&quot;4058&quot; data-origin-height=&quot;212&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;Heap Dump 요청에 의한 Full GC 동작과 Full GC 동작 이후에 싹 정리가 된 메모리 들을 확인 할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상했던 상황을 사실로 만들어줄만한 증거가 나온겁니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;근데 왜 Full GC가 안돌지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 든 의문점은 그럼 언제 FullGC가 동작하는가? 였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Old Generation의 threshold 를 넘긴 순간인 것을 확인 했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 설정 값을 확인했지만 따로 설정되어 있지 않아 기본 값을 따르는 것으로 보였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729566244073&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-XX:CMSInitiatingOccupancyFraction&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;Oracle 공식문서에 따르면 threshold 기본 값은 92%입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2510&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F8Ue4/btsKeyEVXci/kT4kLqjuS6WwIVZd8uAKf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F8Ue4/btsKeyEVXci/kT4kLqjuS6WwIVZd8uAKf0/img.png&quot; data-alt=&quot;출처 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_sweep_cms_collector&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F8Ue4/btsKeyEVXci/kT4kLqjuS6WwIVZd8uAKf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF8Ue4%2FbtsKeyEVXci%2FkT4kLqjuS6WwIVZd8uAKf0%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;2510&quot; height=&quot;434&quot; data-origin-width=&quot;2510&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_sweep_cms_collector&lt;/figcaption&gt;
&lt;/figure&gt;
&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;그럼 Old Gen의 영역은 전체 메모리의 어느정도를 차지하는거지?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 실제로 Old Generation의 영역은 얼마나 차지하고 있고 그 영역의 92%는 전체 메모리의 어느정도 인가를 알아보기위해&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;Young Gen과 Old Gen의 비율에 대한 설정 값을 찾아봤습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729566497923&quot; class=&quot;bash&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;-XX:NewRatio&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;&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;1206&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfakuY/btsKeAvZOdy/2Tm90RhbcEttiV2oL7Qoq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfakuY/btsKeAvZOdy/2Tm90RhbcEttiV2oL7Qoq0/img.png&quot; data-alt=&quot;출처 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/sizing.html#sizing_generations&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfakuY/btsKeAvZOdy/2Tm90RhbcEttiV2oL7Qoq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfakuY%2FbtsKeAvZOdy%2F2Tm90RhbcEttiV2oL7Qoq0%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;656&quot; height=&quot;288&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/sizing.html#sizing_generations&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1:2 비율 즉 1/3 의 YoungGen 과 2/3의 OldGen 으로 구성된다고 볼 수 있습니다.&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;그럼 FullGC가 돌아야지!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상했습니다. APM에서의 메모리 사용률은 Heap에 전체 크기에 대한 사용률입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이 수치가 80%에 육박했다는 것은 2/3 영역을 차지하는 OldGen 이 92% 이상 찼다는 것을 의미할겁니다.&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;그렇다면 지금 APM과 GC Log 중에서 누군가 거짓말을 하고 있는것으로 보였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;APM에서 메모리 점유율이 80%를 육박하는 시점에 GC Log를 살펴보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2676&quot; data-origin-height=&quot;790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmHfJn/btsKfa4iiAN/bevLOWjx62NVfdUuBaFsxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmHfJn/btsKfa4iiAN/bevLOWjx62NVfdUuBaFsxK/img.png&quot; data-alt=&quot;전부 Minor GC만 수행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmHfJn/btsKfa4iiAN/bevLOWjx62NVfdUuBaFsxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmHfJn%2FbtsKfa4iiAN%2FbevLOWjx62NVfdUuBaFsxK%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;2676&quot; height=&quot;790&quot; data-origin-width=&quot;2676&quot; data-origin-height=&quot;790&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전부 Minor GC만 수행&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PSYoungGen 의 GC를 수행시켜 용량을 줄이고 (괄호 안의 용량은 총 용량) 최종적으로 전체 메모리에서 해당 수치만큼 정리가 된 것을 확인 할 수 있었습니다.&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;그런데 APM에서 80%를 육박하는 시점에 실제로는 전체 메모리 사용률이 50%인거 보니 보여주는 지표에 대해서 정확하게 파악 할 필요가 생겼습니다.&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;APM 개발사에 문의했더니 부하를 줄이기 위해 5분 단위로 평균 값을 지표에 나타낸다고 하더군요&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&gt; &lt;/span&gt;사건의&lt;span&gt; &lt;/span&gt;전말은&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;nbsp;YoungGen 영역이 빠르게 차고 소멸되면서 OldGen 영역이 누적되고 Old + Young 의 평균 값이 80% 정도 되는 지표를 보이고 있었음&lt;/li&gt;
&lt;li&gt;APM을 보다가 80%를 넘어가자 불안한 마음에 서버를 재기동&lt;/li&gt;
&lt;li&gt;다시 정상화 되어 MinorGC 만 수행되며 1번 상황을 반복&lt;/li&gt;
&lt;/ol&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2092&quot; data-origin-height=&quot;1210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2IVc/btsKeBbdH00/1z5Hj1KGguHsI4KkPnt8H0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2IVc/btsKeBbdH00/1z5Hj1KGguHsI4KkPnt8H0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2IVc/btsKeBbdH00/1z5Hj1KGguHsI4KkPnt8H0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2IVc%2FbtsKeBbdH00%2F1z5Hj1KGguHsI4KkPnt8H0%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;2092&quot; height=&quot;1210&quot; data-origin-width=&quot;2092&quot; data-origin-height=&quot;1210&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;현 시점에서도 지표상 70~80%에 육박하는 사용률을 보여주는 인스턴스에 접속해서&lt;/p&gt;
&lt;pre id=&quot;code_1729575528169&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jstat -gc &amp;lt;pid&amp;gt; &amp;lt;주기&amp;gt;&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;jstat 명령어를 통해 모니터링을 수행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;914&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbZAcK/btsKdRetccU/80gb0nVuaw7SamhfQzPMyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbZAcK/btsKdRetccU/80gb0nVuaw7SamhfQzPMyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbZAcK/btsKdRetccU/80gb0nVuaw7SamhfQzPMyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbZAcK%2FbtsKdRetccU%2F80gb0nVuaw7SamhfQzPMyk%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;2466&quot; height=&quot;914&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;914&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C는 해당 영역의 총 크기를 의미하고 U는 영역 사용량을 의미합니다. (*MB단위, 기본적으로는 Byte 단위지만 awk 명령어를 추가해 보기좋게 만들었습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 좌측부터 S0의 크기, S1의 크기, S0 사용량, S1 사용량, Eden 크기, Eden 사용량 OldGen 크기, OldGen 사용량&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;OldGen 영역의 크기에 비례한 사용량을 보면 알 수 있 듯, 실제로는 50~60% 정도의 Old 영역이 찬것으로 확인됩니다.&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;즉, APM 성능으로 인해 집계하는 과정에서 즉각적인 데이터를 보여주기 어려움으로 인한 것이였습니다.&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;다른 서비스보다 사용량이 많고 반영이 자주 있지 않은 APP 이다 보니 이것이 좀 더 부각되어 나타났던 것이고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1994&quot; data-origin-height=&quot;774&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W6DCl/btsKeb4RAlv/a1I5mMppKOs0jRVwB1fvs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W6DCl/btsKeb4RAlv/a1I5mMppKOs0jRVwB1fvs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W6DCl/btsKeb4RAlv/a1I5mMppKOs0jRVwB1fvs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW6DCl%2FbtsKeb4RAlv%2Fa1I5mMppKOs0jRVwB1fvs0%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;1994&quot; height=&quot;774&quot; data-origin-width=&quot;1994&quot; data-origin-height=&quot;774&quot;/&gt;&lt;/span&gt;&lt;/figure&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;(메모리 사이즈 자체가 크고 반영이 자주 있어서 80~90% 까지 가지 않았을 뿐)&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;/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;830&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1RmN6/btsKfNVCr5Q/93mtGnmSvCCeKFKTpwahU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1RmN6/btsKfNVCr5Q/93mtGnmSvCCeKFKTpwahU1/img.png&quot; data-alt=&quot;메모리는 이상이 없었고.. 나는 삽질을 했을 뿐이고...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1RmN6/btsKfNVCr5Q/93mtGnmSvCCeKFKTpwahU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1RmN6%2FbtsKfNVCr5Q%2F93mtGnmSvCCeKFKTpwahU1%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;633&quot; height=&quot;279&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메모리는 이상이 없었고.. 나는 삽질을 했을 뿐이고...&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;이번 기회를 통해 모니터링 시스템에서 데이터를 수집하는 방식이 다양하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직관적인 내용 뿐 아니라 모니터링 시스템에서 성능 상 빈틈이 생기는 부분들을 이해하고 지표를 봐야한다는 것을 이해하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(GC에 대한 자세한 동작 과정을 얻은것은 덤)&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;FullGC가 실행된 시점 이후에도 baseline이 높아지는지 꼭 확인하고 세부적인 내용을 확인하시면 좋을듯 합니다.&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;실제로 메모리가 누수되는 상황이였다면 몇가지 튜닝 포인트로 영역 비율 조정 및 영역 크기, metaspace 크기 조정 등이 있습니다만.. 일반적으로는 기본 값을 사용하는게 좋을듯 합니다. (&lt;s&gt;그냥 스케일 업을&lt;/s&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;CMSGC에서는 FullGC가 일어나면서 Old Generation 영역을 정리하는데 여기서 메모리 파편화가 발생하는 문제가 있고&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;병렬로 어플리케이션 동작과 동시에 GC 작업을 수행하기 때문에 CPU 자원을 많이 소모한다는 단점이 존재합니다.&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;이런 CMSGC의 단점을 해결하기 위해서 Java9 부터는 G1 GC가 채택되었는데 다음 시간에는 이 G1 GC에 대해서 깊게 알아보는 시간을 가져볼까 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고 : Java9 부터 CMSGC는 deprecated 되었으며, Java14 부터는 Drop 되었습니다.)&lt;/p&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;G1 GC의 동작 원리&lt;/li&gt;
&lt;li&gt;어떻게 G1 GC는 CMSGC의 한계를 극복했을까&lt;/li&gt;
&lt;li&gt;G1 GC 다음 세대인 ZGC&lt;/li&gt;
&lt;li&gt;ZGC와 Java21의 Virtual Thread&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #777777; text-align: center;&quot;&gt;GC 튜닝에 대한 공식 문서&lt;/span&gt;&lt;/a&gt;&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;담고 싶은 내용이 많다보니 생각보다 길어져서 글이 좀 길어졌네요 긴 글 읽어주셔서 감사드립니다! &lt;s&gt;도움이 되셨다면 구독 좋아요 알림설정까지(?)&lt;/s&gt;&lt;/p&gt;</description>
      <category>백엔드</category>
      <category>cmsgc</category>
      <category>gc</category>
      <category>gc 동작 원리</category>
      <category>java8</category>
      <category>가비지 컬렉션</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/39</guid>
      <comments>https://kyeum-d.tistory.com/39#entry39comment</comments>
      <pubDate>Tue, 22 Oct 2024 15:14:47 +0900</pubDate>
    </item>
    <item>
      <title>[Base64] 빼앗긴 Parameter 찾습니다.</title>
      <link>https://kyeum-d.tistory.com/38</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;Base64 인코딩과 디코딩에 대한 이해 부족으로 인해 문제를 해결하는 과정에서 어려움을 겪었던 경험을 바탕으로 이 글을 작성하게 되었습니다.&lt;br&gt;Base64에 대해 저와 비슷한 고민을 하신 분들, 혹은 개념은 알고 있지만 막연하게 이해하고 계신 분들에게 도움이 되고자 글을 작성했습니다.&lt;br&gt;이번 글에서는 Base64가 무엇인지, 왜 사용하는지, 어떤 특징이 있는지를 살펴보고, 그와 관련된 몇 가지 오해와 사실에 대해 이야기해 보겠습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;Parameter 를 빼앗겼습니다.&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;기프티콘 API 발송 작업 진행 중 기프티콘 쿠폰 코드가 화면에서 넘어오지 않는 현상이 발생했습니다.&lt;br&gt;개발자 도구로 Network를 확인 한 결과 &lt;i&gt;&lt;b&gt;클라이언트 에서는 정상적으로 전달&lt;/b&gt;&lt;/i&gt;&amp;nbsp;한 것으로 나오는 상황이였습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;Payload : 전 분명 전달했습니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGIluT/btsJZ79dPpj/cUsqp5TKtg5WUXwLoay2k1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGIluT/btsJZ79dPpj/cUsqp5TKtg5WUXwLoay2k1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGIluT/btsJZ79dPpj/cUsqp5TKtg5WUXwLoay2k1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGIluT%2FbtsJZ79dPpj%2FcUsqp5TKtg5WUXwLoay2k1%2Fimg.jpg&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;664&quot; height=&quot;301&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 빼앗겼습니다(?)&lt;br&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;로컬에서 디버깅 해 본 결과 특정 모바일 쿠폰 코드가 Controller 쪽으로 넘어오지 않는 것을 확인 할 수 있었습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt; 어디서 사라진걸까요?&lt;br&gt;Controller 에 값이 넘어오지 않는다면 Spring Framework 를 쓰는 사용자 입장에서는&amp;nbsp;&lt;br&gt;대표적으로 두가지를 먼저 확인하게 됩니다.&amp;nbsp;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;Dispatcher Servlet 의 prehandler&lt;/li&gt;&lt;li&gt;Filter Chain 의 Custom Filter&lt;/li&gt;&lt;/ol&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;확인 결과 Custom Filter 에서문제가 발생했습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;&lt;b&gt;Custom Filter&lt;/b&gt;를 하나 생성하고 해당&amp;nbsp;Filter&amp;nbsp;에서&lt;/li&gt;&lt;li&gt;&lt;b&gt;HttpServletRequestWrapper&lt;/b&gt;&amp;nbsp;를 상속받은&amp;nbsp;&lt;b&gt;Custom Request Wrapper&lt;/b&gt;&amp;nbsp;를 구현,&lt;/li&gt;&lt;li&gt;구현체에서 Paramter 를 가져오는 함수들을&amp;nbsp;&lt;b&gt;overriding&lt;/b&gt;&amp;nbsp;하고&amp;nbsp;&lt;/li&gt;&lt;li&gt;다음 Filter 를 호출 할 때 넘겨주는 request 를 Custom Request Wrapper 로 넘겨준 것&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;어떻게 사라진거죠?&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;overriding한 메서드에서 파라미터를 가져올 때 모든 파리미터 항목에 대해서&amp;nbsp;&lt;br&gt;Base64 디코딩 후 복호화를 진행하는데&amp;nbsp;&lt;br&gt;특이한 점은 디코딩 -&amp;gt; 복호화 를 진행하는 코드가 try 문으로 감싸져있었고 실패하는 순간&lt;br&gt;logging 만 처리하고 파라미터 값을 그대로 쓰던 상황이였습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;보안 상 회사 코드의 자세한 내부 로직이나 코드를 게시할 수는 없지만,,&lt;br&gt;&amp;nbsp;&lt;br&gt;결과적으로 base64 인코딩 하지 않은 내용을 디코딩한 후 복호화 하려고 했고&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;디코딩 된 바이트 배열을 복사하는 과정에서 특정 자릿수의 값이 문제가 생기는 상황이였습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;여기서 특정 자릿수에 문제가 있다는 것을 파악하기 위해 base64의 인코딩/디코딩 구조에 대해서 학습 할 필요가 생겼습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;base64.. 그냥 64진법인줄...&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 단축 URL 토이 프로젝트를 진행한적이 있었는데 해당 프로젝트에서 base64 인코딩 기법을 활용하여 단축 URL을 생성했었습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그때 간단하게 DB에 auto increment 되는 ID 값을 두고 해당 ID 값을 base64로 인코딩하여 단축된 URL 을 사용했었죠&lt;br&gt;그렇다보니 저에게 있어 base64는 그냥 64진법이구나 긴 값을 짧게 줄여주는구나 정도로 인식을 했습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;그런데 base64 의 실체&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 base64는 실제로는 문자를 각 8비트 단위(바이트) 배열로 만들고 그 비트들을 이어붙인 후 6비트 단위로 쪼개서 6비트 단위로 재구성하여 해당 비트별 base64의 문자에 대응하는 구조였습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;이해를 돕기위해 예시를 들어보겠습니다. LDK 라는 문자열에 대해서 각 문자를 바이트 배열로 생성합니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;이 때, ASCII 코드표를 기반으로 변환됩니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;998&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W2yZz/btsJ0U2WHJ1/4chNBta7KBOIv2DqXCoDMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W2yZz/btsJ0U2WHJ1/4chNBta7KBOIv2DqXCoDMk/img.png&quot; data-alt=&quot;출처 : 나무위키&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W2yZz/btsJ0U2WHJ1/4chNBta7KBOIv2DqXCoDMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW2yZz%2FbtsJ0U2WHJ1%2F4chNBta7KBOIv2DqXCoDMk%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;639&quot; height=&quot;433&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;998&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 나무위키&lt;/figcaption&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; style=&quot;text-align: left;&quot;&gt;&lt;u&gt;&lt;b&gt;L&lt;/b&gt;&lt;/u&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;u&gt;&lt;b&gt;D&lt;/b&gt;&lt;/u&gt;&lt;b&gt; &lt;/b&gt;&lt;u&gt;&lt;b&gt;K&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;L : 76&amp;nbsp; -&amp;gt; 0100 1100&lt;/li&gt;&lt;li&gt;D : 68 -&amp;gt; 0100 0100&lt;/li&gt;&lt;li&gt;K : 75 -&amp;gt; 0100 1011&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 변환 된 값을 이어붙입니다&lt;br&gt;0100 1100 0100 0100 0100 1011&lt;br&gt;&amp;nbsp;&lt;br&gt;이렇게 붙인 값에서 6자리씩 구분을 짓습니다.&amp;nbsp;&lt;br&gt;0100 11&lt;b&gt;/&lt;/b&gt;00&amp;nbsp;0100&lt;b&gt;/&lt;/b&gt; 0100&amp;nbsp;01&lt;b&gt;/&lt;/b&gt;00 1011&lt;b&gt;/&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;이렇게 구분된 6자리의 비트로 base64 인코딩을 진행합니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;1158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnuQl7/btsJ2vU30yX/6SxJSc4BNOMoYs9E2iEkXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnuQl7/btsJ2vU30yX/6SxJSc4BNOMoYs9E2iEkXk/img.png&quot; data-alt=&quot;출처 : 나무위키&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnuQl7/btsJ2vU30yX/6SxJSc4BNOMoYs9E2iEkXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnuQl7%2FbtsJ2vU30yX%2F6SxJSc4BNOMoYs9E2iEkXk%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;388&quot; height=&quot;505&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;1158&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 나무위키&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;19 / 4 / 17 / 11 값은&lt;br&gt;결국 T E R L&amp;nbsp; 로 치환됩니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;따라서, LDK 를 base64로 인코딩하면 TERL 이라는 결과가 나오게 됩니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;a href=&quot;https://www.base64encode.org/&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.base64encode.org/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;Base64 Encode and Decode - Online&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;Encode to Base64 format or decode from it with various advanced options. Our site has an easy to use online tool to convert your data.&quot; data-og-host=&quot;www.base64encode.org&quot; data-og-source-url=&quot;https://www.base64encode.org/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bBnpLL/hyXhOGPj7H/Xy24rGBn2gu4dgDx6xGCLK/img.png?width=600&amp;amp;height=315&amp;amp;face=9_266_548_299&quot; data-og-url=&quot;https://www.base64encode.org/&quot;&gt;&lt;a href=&quot;https://www.base64encode.org/&quot; target=&quot;_blank&quot; data-source-url=&quot;https://www.base64encode.org/&quot;&gt;&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bBnpLL/hyXhOGPj7H/Xy24rGBn2gu4dgDx6xGCLK/img.png?width=600&amp;amp;height=315&amp;amp;face=9_266_548_299')&quot;&gt; &lt;/div&gt;&lt;div class=&quot;og-text&quot;&gt;&lt;p class=&quot;og-title&quot;&gt;Base64 Encode and Decode - Online&lt;/p&gt;&lt;p class=&quot;og-desc&quot;&gt;Encode to Base64 format or decode from it with various advanced options. Our site has an easy to use online tool to convert your data.&lt;/p&gt;&lt;p class=&quot;og-host&quot;&gt;www.base64encode.org&lt;/p&gt;&lt;/div&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;온라인 base64 사이트에서 간단하게 검증 할 수 있습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫번째 의문, 항상 6자리로 나눠지나요?&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 변환을 보고나면 저와 같은 의문을 가지는 분이 있으실겁니다.&lt;br&gt;결론부터 말하자면 항상 6으로 나눠지지 않습니다. 당연한 결과죠 문자열 하나당 8비트씩 차지하는데 이게 6비트와 정확히 일치하려면&amp;nbsp;&lt;br&gt;원본 문자열이 3의배수여야만 합니다.(최소공배수 24)&lt;br&gt;&amp;nbsp;&lt;br&gt;base64 기법에서는 이와같은 상황을 해결하기 위해 padding 기법을 사용합니다. 의미를 지니지 않는 약속된 문자(&quot;=&quot;)를 추가해서 = 문자 하나당 2비트씩 추가된 비트가 있다고 명시하는 것이죠.&lt;br&gt;&amp;nbsp;&lt;br&gt;이전 예시에서 마지막 문자에 L을 추가해서 LDKL 을 인코딩 한다고 해봅시다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;u&gt;&lt;b&gt;L&lt;/b&gt;&lt;/u&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;u&gt;&lt;b&gt;D&lt;/b&gt;&lt;/u&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;u&gt;&lt;b&gt;K&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;L : 76&amp;nbsp; -&amp;gt; 0100 1100&lt;/li&gt;&lt;li&gt;D : 68 -&amp;gt; 0100 0100&lt;/li&gt;&lt;li&gt;K : 75 -&amp;gt; 0100 1011&lt;/li&gt;&lt;li&gt;L : 76&amp;nbsp; -&amp;gt; 0100 1100&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;0100 11&lt;b&gt;/&lt;/b&gt;00&amp;nbsp;0100&lt;b&gt;/&lt;/b&gt;&amp;nbsp;0100&amp;nbsp;01&lt;b&gt;/&lt;/b&gt;00 1011&lt;b&gt;/ &lt;/b&gt;0100 11&lt;b&gt;/&lt;/b&gt;00&amp;nbsp;&lt;b&gt;+ 0000&lt;/b&gt;&lt;br&gt;19 / 4 / 17 / 11 / 19 / 0 값은&lt;br&gt;&amp;nbsp;T E R L T A 로 치환되고 추가로 붙은 4비트를 명시하기 위해 =을 두개 붙여&lt;br&gt;결과적으로 TERLTA== 으로 생성이 됩니다.&lt;br&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;br&gt;왜냐하면 실제로 패딩이 없는 데이터를 가지고도 충분히 디코딩을 할 수 있기 때문입니다.&lt;br&gt;각 문자열을 비트로 변환하고 8비트로 구분 했을 때 남는 값을 그냥 버리면 되는거 아닌가 라는 생각이 들었습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;이에 대한 답변은 &quot;이러한 약속을 base64 인코딩의 표준으로 정했고, 좀 더 효율적인 계산을 위함&quot;이라는 것이였습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;실제로 java 라이브러리의 Base64 클래스를 살펴보면&lt;/p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTLsKO/btsJ0CIelnU/31WYdmSAnkkhL1rNQeZ5o1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTLsKO/btsJ0CIelnU/31WYdmSAnkkhL1rNQeZ5o1/img.png&quot; data-alt=&quot;java8 Base64.java&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTLsKO/btsJ0CIelnU/31WYdmSAnkkhL1rNQeZ5o1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTLsKO%2FbtsJ0CIelnU%2F31WYdmSAnkkhL1rNQeZ5o1%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;1444&quot; height=&quot;1802&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1802&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;java8 Base64.java&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;padding 값인 &quot;=&quot; 이 있다면 명시적으로 추가하고 없다면 직접 padding 값을 계산합니다.&lt;br&gt;&amp;nbsp;&lt;br&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;맞습니다. 그도 그런것이 한 문자당 8비트 길이를 6비트로 구분한다는 얘기는 당연히 결과 문자열이 늘어나는 것을 의미합니다.&lt;br&gt;일반적으로는 전송되는 데이터를 어떻게든 줄이기 위해 용을 쓰는데 base64는 그렇지 않습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;제가 오해했던 부분도 이 내용과 관련있습니다.&lt;br&gt;단축 URL에서 사용한 인코딩은 정수값 자체를 base64 인코딩 하면서 값이 짧아지는 효과를 가져왔었기 때문입니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 데이터를 늘리면서까지 base64 인코딩을 할까요?&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 base64를 쓰는 근본적인 이유가 밝혀집니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;결과적으로 base64는 데이터의 안전한 전송과 저장을 목적으로 사용됩니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;가장 주로 사용되는 목적은&lt;br&gt;&lt;u&gt;&lt;b&gt;바이너리 데이터를 텍스트로 표현하기 위함입니다.&lt;/b&gt;&lt;/u&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;다양한 시스템과 프로토콜(HTTP 통신, 이메일, HTML)들은 텍스트 데이터만 처리할 수 있는 경우가 많습니다.&lt;br&gt;이미지 같은 데이터를 안전하고 효율적으로 보내기 위해서 이렇게 base64로 문자열로 전부 치환하여 보내는 것입니다.&lt;br&gt;특수문자 같은 데이터들을 그대로 사용할 수 없는 URL 생성에서도 많이 사용됩니다.(단축URL과 다른 개념)&lt;br&gt;&amp;nbsp;&lt;br&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;이번 글에서는 사라진 파라미터를 찾기 위한 험난한 여정과 그 과정에서 저를 혼란스럽게 했던 base64에 대해 다루어 보았습니다. &lt;br&gt;평소 base64로 인코딩된 URL을 자주 사용하면서도 왜 사용하는지, 마지막에 붙는 패딩 문자열에 대해 깊이 고민해본 적이 없었지만, 이번 기회를 통해 그 의미와 필요성을 이해하게 되었습니다. &lt;br&gt;덕분에 앞으로 관련 장애나 오류가 발생했을 때 더욱 빠르게 문제를 해결할 수 있는 시야를 가지게 되었습니다. &lt;br&gt;&lt;br&gt;긴 글 읽어주셔서 감사드리며, 이 글이 비슷한 상황에 있는 분들에게 조금이나마 도움이 되기를 바랍니다.&lt;br&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;.&lt;br&gt;.&lt;br&gt;.&lt;br&gt;&amp;nbsp;&lt;br&gt;추가로 알아보면 좋은 자료들&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
 &lt;li&gt;Base64 외에도 바이너리 데이터를 텍스트로 변환하는 다른 방법들 
  &lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li&gt;Hexadecimal(Base16) 인코딩이나 Base85 인코딩&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;JWT(JSON Web Token)에서의 Base64의 역할&lt;/li&gt; 
 &lt;li&gt;Base64 class 에도 나와있던MIME(Multipurpose Internet Mail Extensions)&lt;/li&gt; 
&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백엔드</category>
      <category>BASE64</category>
      <category>인코딩</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/38</guid>
      <comments>https://kyeum-d.tistory.com/38#entry38comment</comments>
      <pubDate>Fri, 11 Oct 2024 14:05:52 +0900</pubDate>
    </item>
    <item>
      <title>나는 어떻게 이런 장점을 가지게 되었지? - 인생지도</title>
      <link>https://kyeum-d.tistory.com/37</link>
      <description>&lt;h3 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;p data-ke-size=&quot;size16&quot;&gt;글또라는 모임을 알 수 있게 좋은 정보를 공유해주신 회사 동료 Finn에게 감사드립니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 사람(동료)을 만나는 것만큼 좋은 운은 없는것 같습니다. (&lt;s&gt;쓰다보니 기술 책의 감사의 글처럼 된거 같은... 왜 쓰는지 이제 이해가 가네요&lt;/s&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;h3 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;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;h3 data-ke-size=&quot;size23&quot;&gt;나서기를 좋아하던 친구&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;빠르게 바뀌는 환경에서도 제가 놓치지&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;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;span style=&quot;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;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;저는 흔히 말하는 중2병(14살에 찾아오는) 시절은 없었습니다. 고등학교에 진입 할 때까지만 해도 부모님 말을 잘 듣는 학생이였죠. 그런데 이게 쌓였던게 한번에 터지면서 역풍이 되어 돌아오게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 시기인 고2에서 고3으로 넘어가는 시점에 늦풍노도가 찾아온거죠&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;h3 data-ke-size=&quot;size23&quot;&gt;인생의 첫번째 터닝포인트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 첫 학기에서 올F 를 맞고 학사 경고를 맞게됩니다. 그 때 문득 이런생각이 들더군요. &quot;아, 이렇게 살면 진짜 답이 없겠다.&quot;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 생각이 들고서 다시 진학준비를 시작했습니다. 진학에 있어서 가장 중요한 시기들을 놓치고 허투로 보낸 시간들에 대한 업보가 돌아와 반년 정도 준비한다고 좋은 대학에 진학을 하진 못했지만, 제가 항상 원하던 컴공과에는 진학에 성공합니다. 그 때 들었던 생각은 &quot;어디를 가서든 내가 열심히 하면 된다&quot; 였고 실제로 열심히 한 결과 4년동안 전액 장학금을 받으면서 학교생활을 하게됩니다.&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;첫번째 회사에 취직을 하고 본격적인 개발 시작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;교수님의 소개로 금융 SI 기업에 들어가게 됩니다. 그때는 몰랐지만 이후에 들어보니 금융 SI는 신입 개발자들의 무덤이라고도 불린다고 하더라구요. 그 때까지도 생각은 같았습니다. 어디를 가서든 내가 열심히 해서 다음 스텝을 밟아야지, 우선 실무를 시작해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 조금 아쉬운 선택을 했던거 같아요. 처음 얘기했던 환경에 쉽게 녹아든다는 점이 여기서는 단점으로 작용했습니다. 저 자신을 잘 몰랐던거죠. 의욕이 넘치고 개발에 대한 욕심이 있었던 저와 다르게 회사의 동료들의 분위기는 그렇지 않았습니다. 개발을 일이라고 생각을 하고 그 이상으로는 생각하지 않았습니다. 그리고 SI 특성 상 본사 사무실에서 일을 보는 일이 거의 없고 고객사에 나가서 일을 하기 때문에 같이 일하는 사람이 항상 바뀌고, 동기 개발자들과는 거의 마주할 수 없는 상태였습니다.&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;여기서 저는 환경을 바꿔보기 위해서 2가지 노력을 했습니다. 동기 개발자들과 함께 토이 프로젝트를 하자고 제안하고 선배 개발자에게 찾아가서 Spring에 대해서 알려달라고 하는 등..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이게 앞서 얘기했던 파견 업무의 특성상 지역과 동료가 계속 바뀌니까 &lt;span style=&quot;text-align: start;&quot;&gt;점점 &lt;/span&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;h3 data-ke-size=&quot;size23&quot;&gt;두번째 터닝 포인트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경에 스며들고 시간이 흐르면서 다시 이런생각이 들었습니다. &quot;이건 내가 원하던 개발이 아닌데.. 이대로 가면 영영 내가 원하던 개발자가 될 수 없겠다.&quot; 이렇게 생각이 들고 바로 내가 처한 환경 자체를 바꿔야 겠다는 생각이 들더군요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 f-lab 이라는 멘토링 프로그램을 접하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kyeum-d.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kyeum-d.tistory.com/34&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726889914454&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;F-lab 자바 백엔드 6개월 수료 후기&quot; data-og-description=&quot;4월에 시작한 F-lab 멘토링이 벌써 끝맺음을 맺게 되었다. 회고를 시작하며 6개월간의 어떤 성장이 있었는지 돌이켜보기 위해 최초 나의 커리어를 돌이켜 본다. 2년 반이라는 시간동안 일명 '신입 &quot; data-og-host=&quot;kyeum-d.tistory.com&quot; data-og-source-url=&quot;https://kyeum-d.tistory.com/34&quot; data-og-url=&quot;https://kyeum-d.tistory.com/34&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bIjZrw/hyW2WNMHSi/kvmdtERotsvIe8pij3SQI0/img.png?width=800&amp;amp;height=455&amp;amp;face=0_0_800_455,https://scrap.kakaocdn.net/dn/biA4g4/hyW6INTPAI/hB3rY1eKH79fBO6nrHNbN1/img.png?width=800&amp;amp;height=455&amp;amp;face=0_0_800_455,https://scrap.kakaocdn.net/dn/Wk5pQ/hyW22N1d0P/s7uyKoCQzF2pHdE0mZBuO0/img.png?width=1724&amp;amp;height=981&amp;amp;face=0_0_1724_981&quot;&gt;&lt;a href=&quot;https://kyeum-d.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kyeum-d.tistory.com/34&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bIjZrw/hyW2WNMHSi/kvmdtERotsvIe8pij3SQI0/img.png?width=800&amp;amp;height=455&amp;amp;face=0_0_800_455,https://scrap.kakaocdn.net/dn/biA4g4/hyW6INTPAI/hB3rY1eKH79fBO6nrHNbN1/img.png?width=800&amp;amp;height=455&amp;amp;face=0_0_800_455,https://scrap.kakaocdn.net/dn/Wk5pQ/hyW22N1d0P/s7uyKoCQzF2pHdE0mZBuO0/img.png?width=1724&amp;amp;height=981&amp;amp;face=0_0_1724_981');&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;F-lab 자바 백엔드 6개월 수료 후기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4월에 시작한 F-lab 멘토링이 벌써 끝맺음을 맺게 되었다. 회고를 시작하며 6개월간의 어떤 성장이 있었는지 돌이켜보기 위해 최초 나의 커리어를 돌이켜 본다. 2년 반이라는 시간동안 일명 '신입&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kyeum-d.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;
&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;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;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;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;최근에는 밤에 학습이 잘 안되는 듯 하여 방법을 찾다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미라클 모닝을 실천하려 회사에 2시간씩 일찍 나가서 책을 읽는 챌린지를 한달 째 진행하고 있네요.&lt;s&gt;(이거 진짜 좋아요 추천드립니다)&lt;/s&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;h3 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;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;</description>
      <category>기록</category>
      <category>글또</category>
      <category>글또 10기</category>
      <category>인생지도</category>
      <category>인생회고</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/37</guid>
      <comments>https://kyeum-d.tistory.com/37#entry37comment</comments>
      <pubDate>Sat, 21 Sep 2024 12:57:04 +0900</pubDate>
    </item>
    <item>
      <title>[Transactional] 거래가 왜 없었을까요?</title>
      <link>https://kyeum-d.tistory.com/36</link>
      <description>&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://kyeum-d.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kyeum-d.tistory.com/35&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723956132263&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;[Transactional] 거래가 있었는데요.. 없었습니다&quot; data-og-description=&quot;거래내역의 실종입사하자마자 흥미로운 주제의 CS가 들어왔습니다.&amp;nbsp;몇달 동안 지속적으로 유입되던 문의였습니다. 내용은&amp;nbsp;&amp;quot;거래를 분명히 했고 잘 됐다고 떳는데요..&amp;quot;&amp;nbsp;&amp;quot;거래내역에 제 거래가 &quot; data-og-host=&quot;kyeum-d.tistory.com&quot; data-og-source-url=&quot;https://kyeum-d.tistory.com/35&quot; data-og-url=&quot;https://kyeum-d.tistory.com/35&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qY6tj/hyWScg6prB/19uTr8Z3UHYvvZxBVGK5Ek/img.png?width=253&amp;amp;height=558&amp;amp;face=0_0_253_558,https://scrap.kakaocdn.net/dn/O4XmY/hyWSiIoBrm/1CXekAByuXYnb2Wtipj7J0/img.png?width=253&amp;amp;height=558&amp;amp;face=0_0_253_558,https://scrap.kakaocdn.net/dn/L6dZv/hyWSmcXLFF/sfSjLkdI8hdW3E2uc7m9BK/img.png?width=1194&amp;amp;height=490&amp;amp;face=0_0_1194_490&quot;&gt;&lt;a href=&quot;https://kyeum-d.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kyeum-d.tistory.com/35&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qY6tj/hyWScg6prB/19uTr8Z3UHYvvZxBVGK5Ek/img.png?width=253&amp;amp;height=558&amp;amp;face=0_0_253_558,https://scrap.kakaocdn.net/dn/O4XmY/hyWSiIoBrm/1CXekAByuXYnb2Wtipj7J0/img.png?width=253&amp;amp;height=558&amp;amp;face=0_0_253_558,https://scrap.kakaocdn.net/dn/L6dZv/hyWSmcXLFF/sfSjLkdI8hdW3E2uc7m9BK/img.png?width=1194&amp;amp;height=490&amp;amp;face=0_0_1194_490');&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;[Transactional] 거래가 있었는데요.. 없었습니다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;거래내역의 실종입사하자마자 흥미로운 주제의 CS가 들어왔습니다.&amp;nbsp;몇달 동안 지속적으로 유입되던 문의였습니다. 내용은&amp;nbsp;&quot;거래를 분명히 했고 잘 됐다고 떳는데요..&quot;&amp;nbsp;&quot;거래내역에 제 거래가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kyeum-d.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;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스팅에서 @Transactional 이 붙어있음에도 DB Stored Procedure 의 Rollback 을 감지하지 못하고&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;이번 포스팅에서는 Transactional 이 어떻게 동작하는지 이해하고 왜 이런 현상이 발생했는지 분석하는 시간을 가져보겠습니다.&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;i&gt;* 이번 포스팅은 TransactionManager의 구현체로 JPA와 MSSQL 기준으로 작성 된 글입니다.&lt;/i&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;@Transactional 너 어떻게 동작하는거지?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transactional은 기본적으로 관심사의 분리로 인해 AOP로 동작합니다. 이 것을 Spring이 굉장히 단순화 시켜서 사용자들에게 추상화된 레벨의 어노테이션으로 기능을 제공하고 있습니다.&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;br /&gt;Transacional의 주요 동작이 일어나는 Manager 에서의 동작을 살펴보겠습니다. (동기화 부분은 이번 파트에서 제외)&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 의 핵심적인 가치와 걸맞게 이 Transaction을 관리하는 Manager 또한 추상화 되어있습니다.&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;text-align: start;&quot;&gt;PlatformTransactionManager 를 통해 추상화 하고 각 기술 별로 Manager를 구현하여 사용하는 구조로 이루어져있습니다.&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;text-align: start;&quot;&gt;JPA에서는 JpaTransactionManager 가 이 &lt;span style=&quot;text-align: start;&quot;&gt;PlatformTransactionManager를 구현하여 트랜잭션을 관리합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsq90W/btsI7IBn3dA/eOmKp4mq1xudc1T1ikKq3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsq90W/btsI7IBn3dA/eOmKp4mq1xudc1T1ikKq3k/img.png&quot; data-alt=&quot;AbstractPlatformTransactionManager 는 PlatformTransactionManager 의 추상화 클래스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsq90W/btsI7IBn3dA/eOmKp4mq1xudc1T1ikKq3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsq90W%2FbtsI7IBn3dA%2FeOmKp4mq1xudc1T1ikKq3k%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;1338&quot; height=&quot;64&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AbstractPlatformTransactionManager 는 PlatformTransactionManager 의 추상화 클래스&lt;/figcaption&gt;
&lt;/figure&gt;
&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동작은 크게&lt;/span&gt;&lt;/h4&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;text-align: start;&quot;&gt;1. Transaction 을 시작하는 doGetTrasnaction()&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m0WZS/btsI6N4ODuu/obIiUQE7U7Ho6K1vkWYkK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m0WZS/btsI6N4ODuu/obIiUQE7U7Ho6K1vkWYkK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m0WZS/btsI6N4ODuu/obIiUQE7U7Ho6K1vkWYkK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm0WZS%2FbtsI6N4ODuu%2FobIiUQE7U7Ho6K1vkWYkK0%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;708&quot; height=&quot;68&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;2. Transaction을 commit하는 doCommit()&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZrl81/btsI7c36Ed9/BIXWwtkNjFl08UYvA7K4Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZrl81/btsI7c36Ed9/BIXWwtkNjFl08UYvA7K4Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZrl81/btsI7c36Ed9/BIXWwtkNjFl08UYvA7K4Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZrl81%2FbtsI7c36Ed9%2FBIXWwtkNjFl08UYvA7K4Tk%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;980&quot; height=&quot;60&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;60&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;3. Transaction을 rollback하는 rollback()&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MjWBi/btsI79ZJ5Ld/JDTKx8wfQx3elobKP2lWLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MjWBi/btsI79ZJ5Ld/JDTKx8wfQx3elobKP2lWLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MjWBi/btsI79ZJ5Ld/JDTKx8wfQx3elobKP2lWLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMjWBi%2FbtsI79ZJ5Ld%2FJDTKx8wfQx3elobKP2lWLK%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;1012&quot; height=&quot;58&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;3가지로 이루어져있습니다.&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;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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;doGetTransaction()&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;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;text-align: start;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;AbstractPlatformTransactionManager &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;클래스의 getTransaction() 으로부터 시작합니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2760&quot; data-origin-height=&quot;1344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJparx/btsI6L0dcPv/yZRK9lif3O07TTayEQ7Zu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJparx/btsI6L0dcPv/yZRK9lif3O07TTayEQ7Zu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJparx/btsI6L0dcPv/yZRK9lif3O07TTayEQ7Zu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJparx%2FbtsI6L0dcPv%2FyZRK9lif3O07TTayEQ7Zu0%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;2760&quot; height=&quot;1344&quot; data-origin-width=&quot;2760&quot; data-origin-height=&quot;1344&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;해당 메서드 2번째 라인에서 구현체의 doGetTransaction()을 호출하는 부분이 보입니다.&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;아래 분기문에서 Transaction이 이미 존재하는 경우와 아닌 경우를 구분해서 판단 하는 것을 알 수 있습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2604&quot; data-origin-height=&quot;906&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rU4bM/btsI7syItnI/ljT07kpW2nvXX7aZ8s8Uzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rU4bM/btsI7syItnI/ljT07kpW2nvXX7aZ8s8Uzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rU4bM/btsI7syItnI/ljT07kpW2nvXX7aZ8s8Uzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrU4bM%2FbtsI7syItnI%2FljT07kpW2nvXX7aZ8s8Uzk%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;2604&quot; height=&quot;906&quot; data-origin-width=&quot;2604&quot; data-origin-height=&quot;906&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this.startTransaction 메서드를 실행하는 것을 확인 할 수 있습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2738&quot; data-origin-height=&quot;1102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F4q3O/btsI6M5Ts5k/EjL0wTNVtSwLMfq7q6oKq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F4q3O/btsI6M5Ts5k/EjL0wTNVtSwLMfq7q6oKq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F4q3O/btsI6M5Ts5k/EjL0wTNVtSwLMfq7q6oKq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF4q3O%2FbtsI6M5Ts5k%2FEjL0wTNVtSwLMfq7q6oKq0%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;2738&quot; height=&quot;1102&quot; data-origin-width=&quot;2738&quot; data-origin-height=&quot;1102&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;startTransaction 에서는 다시 doBegin 메서드를 호출하는 모습&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;여기서 this.doBegin 은 JPA TransactionManager구현체의 doBegin을 실행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2598&quot; data-origin-height=&quot;1196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGxbJ/btsI6uEpwot/15LMoxQ8qDH6ShwguIBkVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGxbJ/btsI6uEpwot/15LMoxQ8qDH6ShwguIBkVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGxbJ/btsI6uEpwot/15LMoxQ8qDH6ShwguIBkVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGxbJ%2FbtsI6uEpwot%2F15LMoxQ8qDH6ShwguIBkVk%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;2598&quot; height=&quot;1196&quot; data-origin-width=&quot;2598&quot; data-origin-height=&quot;1196&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2832&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0L71m/btsI7nYCYHy/5gmluYqk8QR7jPgQogsIqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0L71m/btsI7nYCYHy/5gmluYqk8QR7jPgQogsIqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0L71m/btsI7nYCYHy/5gmluYqk8QR7jPgQogsIqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0L71m%2FbtsI7nYCYHy%2F5gmluYqk8QR7jPgQogsIqk%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;2832&quot; height=&quot;1150&quot; data-origin-width=&quot;2832&quot; data-origin-height=&quot;1150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;doBegin에서는 여러 설정들을 하며 this.getJpaDialect().beginTransaction 으로 Transaction을 시작합니다.&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;여기서 JpaDialect의 구현체는 HibernateDialect의 begin() 을 실행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0ojEv/btsI7IOYl9u/fn4vLaJMQDuDv2WukxXRv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0ojEv/btsI7IOYl9u/fn4vLaJMQDuDv2WukxXRv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0ojEv/btsI7IOYl9u/fn4vLaJMQDuDv2WukxXRv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0ojEv%2FbtsI7IOYl9u%2Ffn4vLaJMQDuDv2WukxXRv0%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;1784&quot; height=&quot;728&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setAutoCommit을 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;HikariProxyConnection에서 setAutoCommit 을 실행&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8ptRx/btsI6vcb1yd/dkIKAX93r8LuIFKlIYGem0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8ptRx/btsI6vcb1yd/dkIKAX93r8LuIFKlIYGem0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8ptRx/btsI6vcb1yd/dkIKAX93r8LuIFKlIYGem0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8ptRx%2FbtsI6vcb1yd%2FdkIKAX93r8LuIFKlIYGem0%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;1504&quot; height=&quot;414&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;414&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2340&quot; data-origin-height=&quot;1258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nOEPe/btsI6iqFKve/WvYKkRYA9vOHYl2iKtge80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nOEPe/btsI6iqFKve/WvYKkRYA9vOHYl2iKtge80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nOEPe/btsI6iqFKve/WvYKkRYA9vOHYl2iKtge80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnOEPe%2FbtsI6iqFKve%2FWvYKkRYA9vOHYl2iKtge80%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;2340&quot; height=&quot;1258&quot; data-origin-width=&quot;2340&quot; data-origin-height=&quot;1258&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setAutoCommit에서는 connectionCommand 를 통해 sql 문을 실행합니다.&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;여기서 생성된 sql문은&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KdPum/btsI7j24F5o/fburliZVchtGqeGGBqDQvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KdPum/btsI7j24F5o/fburliZVchtGqeGGBqDQvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KdPum/btsI7j24F5o/fburliZVchtGqeGGBqDQvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKdPum%2FbtsI7j24F5o%2FfburliZVchtGqeGGBqDQvk%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;1610&quot; height=&quot;190&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;set implicit_transactions on&quot; 으로&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;MSSQL에서 implicit_transactions 를 on 으로 하겠다는 의미는&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;데이터 변경을 일으킬 수 있는 다음과 같은 SQL 명령어를 실행할 때마다 트랜잭션이 자동으로 시작된다는 것을 의미합니다.&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&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;INSERT&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;UPDATE&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;DELETE&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;MERGE&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;CREATE&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;DROP&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;ALTER&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&gt;COMMIT&lt;/span&gt;이나 &lt;span&gt;ROLLBACK&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;많이 돌아왔지만 결국 transaction을 시작 하는 것은 set implicit_transactions on 처리를 하기 위함이였음이 밝혀졌습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EwzUB/btsI8kmqs5h/9Zve47Qki6skqf8W12k69K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EwzUB/btsI8kmqs5h/9Zve47Qki6skqf8W12k69K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EwzUB/btsI8kmqs5h/9Zve47Qki6skqf8W12k69K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEwzUB%2FbtsI8kmqs5h%2F9Zve47Qki6skqf8W12k69K%2Fimg.jpg&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;250&quot; height=&quot;309&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;374&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;제 어렴풋한 예상으로는 db transaction을 시작시키고 현재 transaciton id 를 가지고 있다가 이 id가 변경되거나 했을 때(SP에서 rollback) 변경도 감지 할 수 있을 것으로 예상 했으나&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;이런 방식의 동작이라면 SP에서 rollback 을 충분히 감지하지 못할 것으로  판단이 되었습니다.&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;그렇다면 rollback은 어떻게 일어나는 것일까요?&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;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;doRollback()&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsqXsx/btsI7IVIMB9/orgGFdUilBBmDickqB3kcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsqXsx/btsI7IVIMB9/orgGFdUilBBmDickqB3kcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsqXsx/btsI7IVIMB9/orgGFdUilBBmDickqB3kcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsqXsx%2FbtsI7IVIMB9%2ForgGFdUilBBmDickqB3kcK%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;1562&quot; height=&quot;610&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TransactionAspectSupport 클래스에서 Exception 처리에 대해 AfterThrowing을 실행시키고&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lLljz/btsI8gxGIKV/KcIYomRl7gUu7Jt1yyyhq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lLljz/btsI8gxGIKV/KcIYomRl7gUu7Jt1yyyhq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lLljz/btsI8gxGIKV/KcIYomRl7gUu7Jt1yyyhq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlLljz%2FbtsI8gxGIKV%2FKcIYomRl7gUu7Jt1yyyhq0%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;1834&quot; height=&quot;674&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;completeTransactionAfterThrowing 에서 rollback 메서드를 실행하는 것을 확인 할 수 있습니다.&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;doGetTransaction과 동일하게 추적 한 결과&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2804&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xkeIF/btsI7kgASxo/UyGaSXjOzf7eqUvMAiH5Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xkeIF/btsI7kgASxo/UyGaSXjOzf7eqUvMAiH5Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xkeIF/btsI7kgASxo/UyGaSXjOzf7eqUvMAiH5Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxkeIF%2FbtsI7kgASxo%2FUyGaSXjOzf7eqUvMAiH5Yk%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;2804&quot; height=&quot;684&quot; data-origin-width=&quot;2804&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;IF @@TRANCOUNT &amp;gt; 0 ROLLBACK TRAN&quot;&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;b&gt;@@TRANCOUNT 으로&amp;nbsp;&lt;/b&gt;현재 활성화 된 Transaction 이 있는지 확인하고 있다면 ROLLBACK 시키는 것을 의미합니다.&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;결국 트랜잭션이 필요한 동작이 있을 때 Transaction을 새로 생성하고 Exception이 나는 경우 현재 생성된 트랜잭션이 있는지 파악하고 ROLLBACK 시키는 역할을 해주는 것입니다.&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;따라서, 현재 상황을 종합 해 봤을 때 SP에서 일어나는 Exception은 당연히 Application에 전파되지 않고 &lt;br /&gt;SP에서 ROLLBACK 명령어는 실행했기 때문에 DB에서는 현재 트랜잭션을 ROLLBACK 시켰고&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;Application 에서는 다음 프로세스를 시작 할 때 다시 트랜잭션을 생성해서 나머지 작업을 진행 한 것으로 보이는 상황입니다.&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;그렇다면, 새로운 Transaction을 생성하는지 비교해보자&lt;/h2&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;li&gt;쿠폰 내역 정보 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;li&gt;쿠폰 내역 정보 저장&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;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;쿠폰 내역 정보 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하기 작전에 doGetTransaction을 살펴보고 어떤 차이가 있는지 확인해보겠습니다.&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWKqN8/btsI7jWihWC/ciii0sdXRgfROkN4UkJZm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWKqN8/btsI7jWihWC/ciii0sdXRgfROkN4UkJZm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWKqN8/btsI7jWihWC/ciii0sdXRgfROkN4UkJZm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWKqN8%2FbtsI7jWihWC%2Fciii0sdXRgfROkN4UkJZm0%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;1188&quot; height=&quot;426&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2416&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcde0F/btsI7K6VBsF/ckCMsD0xqjdpaokrPWqkzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcde0F/btsI7K6VBsF/ckCMsD0xqjdpaokrPWqkzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcde0F/btsI7K6VBsF/ckCMsD0xqjdpaokrPWqkzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcde0F%2FbtsI7K6VBsF%2FckCMsD0xqjdpaokrPWqkzk%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;2416&quot; height=&quot;440&quot; data-origin-width=&quot;2416&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상 했던 대로 isExistingTransaction 을 통과하여 이미 존재하는 Transaction에 합류합니다.&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;두번째 상황 (롤백)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MCufw/btsI6hrIsY2/yHR3qE1KKjhNlanprrmEQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MCufw/btsI6hrIsY2/yHR3qE1KKjhNlanprrmEQ0/img.png&quot; data-alt=&quot;userId 22인 경우 rollback 하도록 sp 작성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MCufw/btsI6hrIsY2/yHR3qE1KKjhNlanprrmEQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMCufw%2FbtsI6hrIsY2%2FyHR3qE1KKjhNlanprrmEQ0%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;1196&quot; height=&quot;474&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;userId 22인 경우 rollback 하도록 sp 작성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8zPH4/btsI76BUGUL/MxYCanpckBk9xYc2cTukkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8zPH4/btsI76BUGUL/MxYCanpckBk9xYc2cTukkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8zPH4/btsI76BUGUL/MxYCanpckBk9xYc2cTukkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8zPH4%2FbtsI76BUGUL%2FMxYCanpckBk9xYc2cTukkk%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;2634&quot; height=&quot;680&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;680&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;예상과는 달리 isExistingTransaction을 통과하고 합류하는 것을 확인 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvpC1j/btsI6R61bM3/yBWtYw2xwf8JiLzpazmcc1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvpC1j/btsI6R61bM3/yBWtYw2xwf8JiLzpazmcc1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvpC1j/btsI6R61bM3/yBWtYw2xwf8JiLzpazmcc1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvpC1j%2FbtsI6R61bM3%2FyBWtYw2xwf8JiLzpazmcc1%2Fimg.jpg&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;296&quot; height=&quot;170&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그렇다면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 기준으로 ExistingTransaction을 하는지 확인해봐야합니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkxWea/btsI7enht7c/e0L7Q3mrbv1mGUBMLzGPSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkxWea/btsI7enht7c/e0L7Q3mrbv1mGUBMLzGPSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkxWea/btsI7enht7c/e0L7Q3mrbv1mGUBMLzGPSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkxWea%2FbtsI7enht7c%2Fe0L7Q3mrbv1mGUBMLzGPSK%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;2228&quot; height=&quot;176&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hasTransaction() 메서드를 통해 판단하고 있고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3oPP1/btsI7iwlaoj/CoaZbgoRDKyMqi4WlgElD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3oPP1/btsI7iwlaoj/CoaZbgoRDKyMqi4WlgElD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3oPP1/btsI7iwlaoj/CoaZbgoRDKyMqi4WlgElD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3oPP1%2FbtsI7iwlaoj%2FCoaZbgoRDKyMqi4WlgElD0%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;1654&quot; height=&quot;184&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hasTransaction 은 isTransactionActive() 메서드를 통해 판단하고 있습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UO9Hm/btsI6uRW2PJ/ZKakjymUC6nSWjbvyG0Rg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UO9Hm/btsI6uRW2PJ/ZKakjymUC6nSWjbvyG0Rg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UO9Hm/btsI6uRW2PJ/ZKakjymUC6nSWjbvyG0Rg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUO9Hm%2FbtsI6uRW2PJ%2FZKakjymUC6nSWjbvyG0Rg0%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;1186&quot; height=&quot;182&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국엔 EntityManagerHolder의 transactionActive 필드의 true/false 여부로 판단하고 있는 것을 확인 할 수 있습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjnZvZ/btsI5OQMAkX/5WS6lEinUArI4RsadOhcnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjnZvZ/btsI5OQMAkX/5WS6lEinUArI4RsadOhcnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjnZvZ/btsI5OQMAkX/5WS6lEinUArI4RsadOhcnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjnZvZ%2FbtsI5OQMAkX%2F5WS6lEinUArI4RsadOhcnK%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;1282&quot; height=&quot;330&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;330&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;/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;그렇습니다. SP에서는 EntityManagerHolder의 transactionActive 값을 변경 해 줄 수 없고 &lt;br /&gt;그렇다고 EntityManagerHolder가 DB에서 rollback 되었는지 여부를 알 수도 없으니 당연한 결과였습니다..&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;결국 예상과는 다르게 SP에서 일어난 모든 동작에 대해 Application에서는 알 수단도 방법도 없었으며&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;s&gt;&lt;i&gt;용빼는 재주가 없음&lt;/i&gt;&lt;/s&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;최초 set implicit_transactions on 처리 해 둔 것으로 미루어보아&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;다시 transaction이 필요한 작업 실행 시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에서 새롭게 transaction 생성하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application에서 exception 난 경우에만 rollback 명령어를 실행하는 구조였던 것이였습니다.&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;/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;이번 기회를 통해 Transaction 에 대한 환상이 깨졌으며 &lt;s&gt;용 빼는 재주는 없구나&lt;/s&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSrnsb/btsI7s6xa9d/n9mbWNek1ThA13YNoaMowk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSrnsb/btsI7s6xa9d/n9mbWNek1ThA13YNoaMowk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSrnsb/btsI7s6xa9d/n9mbWNek1ThA13YNoaMowk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bSrnsb/btsI7s6xa9d/n9mbWNek1ThA13YNoaMowk/img.gif&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;360&quot; height=&quot;264&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>백엔드</category>
      <category>Java</category>
      <category>JPA</category>
      <category>rollback</category>
      <category>SP</category>
      <category>storedproceduer</category>
      <category>TRANSACTIONAL</category>
      <category>내부동작</category>
      <category>트랜잭션</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/36</guid>
      <comments>https://kyeum-d.tistory.com/36#entry36comment</comments>
      <pubDate>Sun, 18 Aug 2024 15:36:59 +0900</pubDate>
    </item>
    <item>
      <title>[Transactional] 거래가 있었는데요.. 없었습니다</title>
      <link>https://kyeum-d.tistory.com/35</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;거래내역의 실종&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입사하자마자 흥미로운 주제의 CS가 들어왔습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d81hZ9/btsHuQ1YgLZ/Rs88TDiUzY9yAjvXE7KnxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d81hZ9/btsHuQ1YgLZ/Rs88TDiUzY9yAjvXE7KnxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d81hZ9/btsHuQ1YgLZ/Rs88TDiUzY9yAjvXE7KnxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd81hZ9%2FbtsHuQ1YgLZ%2FRs88TDiUzY9yAjvXE7KnxK%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;253&quot; height=&quot;558&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;558&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;/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;&quot;거래를 분명히 했고 잘 됐다고 떳는데요..&quot;&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;&quot;거래내역에 제 거래가 없는데요?&quot;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;150&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwQCOA/btsHtGTOSSt/lYeu1IKlPeQCKkkS79GNTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwQCOA/btsHtGTOSSt/lYeu1IKlPeQCKkkS79GNTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwQCOA/btsHtGTOSSt/lYeu1IKlPeQCKkkS79GNTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwQCOA%2FbtsHtGTOSSt%2FlYeu1IKlPeQCKkkS79GNTk%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;150&quot; height=&quot;293&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;150&quot; data-origin-height=&quot;293&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;가장 먼저 확인했던 것은 메서드에 @Transactional 이 걸려있는가 였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bszmy2/btsHvxASe3B/SOwUzQnIMAksxgHJgongOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bszmy2/btsHvxASe3B/SOwUzQnIMAksxgHJgongOK/img.png&quot; data-alt=&quot;문제의 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bszmy2/btsHvxASe3B/SOwUzQnIMAksxgHJgongOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbszmy2%2FbtsHvxASe3B%2FSOwUzQnIMAksxgHJgongOK%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;521&quot; height=&quot;93&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;93&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;문제의 메서드&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;문제 없이 걸려있던 점을 확인했고 그렇다면 어딘가 Exception 이 발생하여 Rollback 된 것으로 보였습니다.&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;@Transactional 이 적용된 메서드에서&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;당연히 checked Exception 을 catch 로 잡은게 아닐까 생각했지만.. 아쉽게도 그런 로직은 없었고&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;SP(Stored Procedure)에서 아마 잘못 됐을 가능성이 크다는 조언이였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  SP란?&lt;br /&gt;- Stored Procedure 의 약자로 DB 에서 제공하는 프로그래밍 기능이다.&lt;br /&gt;- 쉽게 말해서 DB가 어느정도 롤을 가져가고 인터페이스를 제공하는 것이라고 볼 수 있다.&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;현재 거래 프로세스에서 사용되는 프로시저가 몇가지 있었는데 이 프로시저들을 중점적으로 살펴보기로 했습니다.&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;경계 포인트를 찾자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 롤백되는 경계지점을 찾아 범인을 잡는 것을 목표로 했습니다.&lt;/p&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;그 사이 실행된 프로시저 확인&lt;/li&gt;
&lt;/ol&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;p data-ke-size=&quot;size16&quot;&gt;의심되는 프로시저에서 validating을 통해 롤백 되는 몇가지 포인트를 발견했고&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;상황을 재현해보자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재현해야 하는 상황은 다음과 같습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;거래내역 저장&amp;nbsp;&lt;/li&gt;
&lt;li&gt;문제 프로시저 실행 ( 여기서 강제 롤백 처리 )&lt;/li&gt;
&lt;li&gt;쿠폰, 포인트 사용 내역 저장&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1666&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oew6t/btsI7lsKHwx/6pTb6Mquvb3tSGoNoWo6bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oew6t/btsI7lsKHwx/6pTb6Mquvb3tSGoNoWo6bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oew6t/btsI7lsKHwx/6pTb6Mquvb3tSGoNoWo6bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOew6t%2FbtsI7lsKHwx%2F6pTb6Mquvb3tSGoNoWo6bk%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;1666&quot; height=&quot;726&quot; data-origin-width=&quot;1666&quot; data-origin-height=&quot;726&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;간단하게 Order 와 Coupon 정보를 저장하는 프로세스를 구현하고&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpJTPX/btsI6dP2X53/3r1pwSEr2fbPeViNhb3QEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpJTPX/btsI6dP2X53/3r1pwSEr2fbPeViNhb3QEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpJTPX/btsI6dP2X53/3r1pwSEr2fbPeViNhb3QEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpJTPX%2FbtsI6dP2X53%2F3r1pwSEr2fbPeViNhb3QEK%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;1194&quot; height=&quot;490&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;490&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2926&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cohPTg/btsI7HWCpHm/J5BXnszndA2sD15X3DjY50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cohPTg/btsI7HWCpHm/J5BXnszndA2sD15X3DjY50/img.png&quot; data-alt=&quot;CouponHistory&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cohPTg/btsI7HWCpHm/J5BXnszndA2sD15X3DjY50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcohPTg%2FbtsI7HWCpHm%2FJ5BXnszndA2sD15X3DjY50%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;2926&quot; height=&quot;160&quot; data-origin-width=&quot;2926&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CouponHistory&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2826&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxxjEY/btsI6P8YO1C/2r7uqLRtp7Ph3QHLzurti0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxxjEY/btsI6P8YO1C/2r7uqLRtp7Ph3QHLzurti0/img.png&quot; data-alt=&quot;OrderHIstory&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxxjEY/btsI6P8YO1C/2r7uqLRtp7Ph3QHLzurti0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxxjEY%2FbtsI6P8YO1C%2F2r7uqLRtp7Ph3QHLzurti0%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;2826&quot; height=&quot;178&quot; data-origin-width=&quot;2826&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;OrderHIstory&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;&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;1228&quot; data-origin-height=&quot;1214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOUttP/btsI5zlKO5Z/Yb67BZjCDuNQsomOvjbKd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOUttP/btsI5zlKO5Z/Yb67BZjCDuNQsomOvjbKd0/img.png&quot; data-alt=&quot;중략..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOUttP/btsI5zlKO5Z/Yb67BZjCDuNQsomOvjbKd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOUttP%2FbtsI5zlKO5Z%2FYb67BZjCDuNQsomOvjbKd0%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;419&quot; height=&quot;414&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;1214&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중략..&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;간단하게 userId가 22가 들어오면 에러를 반환하고 catch 에서 현재 트랜잭션을 rollback 하도록 구현하였습니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1ofSB/btsI7IuszLL/RnQl0cg1kNS5lWO4TcmL0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1ofSB/btsI7IuszLL/RnQl0cg1kNS5lWO4TcmL0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1ofSB/btsI7IuszLL/RnQl0cg1kNS5lWO4TcmL0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1ofSB%2FbtsI7IuszLL%2FRnQl0cg1kNS5lWO4TcmL0K%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;1612&quot; height=&quot;354&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;354&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzSaA3/btsI5UXGEKV/7q0C1QaW8arXgmsDl6kBJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzSaA3/btsI5UXGEKV/7q0C1QaW8arXgmsDl6kBJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzSaA3/btsI5UXGEKV/7q0C1QaW8arXgmsDl6kBJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzSaA3%2FbtsI5UXGEKV%2F7q0C1QaW8arXgmsDl6kBJ1%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;1124&quot; height=&quot;384&quot; data-origin-width=&quot;1124&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;333으로 다시 실행해봅니다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2776&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBIPp9/btsI6f8bNk7/QCeZJXNsAHATQn35WSoUGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBIPp9/btsI6f8bNk7/QCeZJXNsAHATQn35WSoUGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBIPp9/btsI6f8bNk7/QCeZJXNsAHATQn35WSoUGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBIPp9%2FbtsI6f8bNk7%2FQCeZJXNsAHATQn35WSoUGk%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;2776&quot; height=&quot;174&quot; data-origin-width=&quot;2776&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2880&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAm79/btsI5WuqNeN/mRV7R8Rwa6cMLRu1P1yovK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAm79/btsI5WuqNeN/mRV7R8Rwa6cMLRu1P1yovK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAm79/btsI5WuqNeN/mRV7R8Rwa6cMLRu1P1yovK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAm79%2FbtsI5WuqNeN%2FmRV7R8Rwa6cMLRu1P1yovK%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;2880&quot; height=&quot;148&quot; data-origin-width=&quot;2880&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;잘 저장된 것을 확인 할 수 있습니다.&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;userId 22로 저장을 시도해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9ObH2/btsI7iQr4UO/6FCsfQeldrfkgTNLzt3kPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9ObH2/btsI7iQr4UO/6FCsfQeldrfkgTNLzt3kPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9ObH2/btsI7iQr4UO/6FCsfQeldrfkgTNLzt3kPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9ObH2%2FbtsI7iQr4UO%2F6FCsfQeldrfkgTNLzt3kPK%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;1136&quot; height=&quot;392&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2872&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s08XH/btsI5vjoUlg/Hwz4aH2A3EtjjTeaZirZa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s08XH/btsI5vjoUlg/Hwz4aH2A3EtjjTeaZirZa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s08XH/btsI5vjoUlg/Hwz4aH2A3EtjjTeaZirZa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs08XH%2FbtsI5vjoUlg%2FHwz4aH2A3EtjjTeaZirZa0%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;2872&quot; height=&quot;236&quot; data-origin-width=&quot;2872&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2858&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2zlN/btsI6SdzxfQ/WtKCOR283QKANy7c5QvsIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2zlN/btsI6SdzxfQ/WtKCOR283QKANy7c5QvsIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2zlN/btsI6SdzxfQ/WtKCOR283QKANy7c5QvsIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2zlN%2FbtsI6SdzxfQ%2FWtKCOR283QKANy7c5QvsIk%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;2858&quot; height=&quot;286&quot; data-origin-width=&quot;2858&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eh9q76/btsI7jogcEi/OE7q6mbXDImlDah9EkHdTK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eh9q76/btsI7jogcEi/OE7q6mbXDImlDah9EkHdTK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eh9q76/btsI7jogcEi/OE7q6mbXDImlDah9EkHdTK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feh9q76%2FbtsI7jogcEi%2FOE7q6mbXDImlDah9EkHdTK%2Fimg.jpg&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;225&quot; height=&quot;225&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&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;실제로 프로시저에서 rollback을 해서 order 내역에 대한 정보는 rollback 되었지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application 에서는 이를 감지하지 못하고 성공했다고 판단을 하고 이후 로직을 실행 한 것이였습니다..!&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;/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;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;데이터 정합성을 맞추고 추가적인 상황이 발생하지 않도록 조치하는 것으로 마무리 되었습니다.&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;왜 이런일이 발생하는 것일까요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 Transaction 어노테이션이 Spring의 관점지향 프로그래밍인 AOP 로 동작 한다는 것을 알고있습니다.&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;그런데  이 정도 추상화 된 내용으로 이해하고 있고 어떻게 Transaction을 맺고&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;이 Transaction 을 어떻게 관리하는지에 대한 지식이 없어&amp;nbsp;이런 오류에 즉각적인 반응이 어려웠습니다.&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;따라서 다음 포스팅에서는 이 AOP에서 실제로 어떻게 Transaction을 관리하고 있기에 SP에서 실패한 로직을 파악 할 수 없었던 것인지&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;h4 data-ke-size=&quot;size20&quot;&gt;다음 이야기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kyeum-d.tistory.com/36&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kyeum-d.tistory.com/36&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723963229241&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;[Transactional] 거래가 왜 없었을까요?&quot; data-og-description=&quot;지난글...https://kyeum-d.tistory.com/35&amp;nbsp;[Transactional] 거래가 있었는데요.. 없었습니다거래내역의 실종입사하자마자 흥미로운 주제의 CS가 들어왔습니다.&amp;nbsp;몇달 동안 지속적으로 유입되던 문의였습니다.&quot; data-og-host=&quot;kyeum-d.tistory.com&quot; data-og-source-url=&quot;https://kyeum-d.tistory.com/36&quot; data-og-url=&quot;https://kyeum-d.tistory.com/36&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dYUeP7/hyWScVIvb2/KWLfujrmKxjCAkxTQdBY50/img.png?width=800&amp;amp;height=38&amp;amp;face=0_0_800_38,https://scrap.kakaocdn.net/dn/cMMGWP/hyWOoDxq79/w5dV0rkl08PrA0TuKENBVk/img.png?width=800&amp;amp;height=38&amp;amp;face=0_0_800_38,https://scrap.kakaocdn.net/dn/rLTLh/hyWOnxQwN9/eUK0jsKTeN9MUruWduRZ9K/img.png?width=2760&amp;amp;height=1344&amp;amp;face=0_0_2760_1344&quot;&gt;&lt;a href=&quot;https://kyeum-d.tistory.com/36&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kyeum-d.tistory.com/36&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dYUeP7/hyWScVIvb2/KWLfujrmKxjCAkxTQdBY50/img.png?width=800&amp;amp;height=38&amp;amp;face=0_0_800_38,https://scrap.kakaocdn.net/dn/cMMGWP/hyWOoDxq79/w5dV0rkl08PrA0TuKENBVk/img.png?width=800&amp;amp;height=38&amp;amp;face=0_0_800_38,https://scrap.kakaocdn.net/dn/rLTLh/hyWOnxQwN9/eUK0jsKTeN9MUruWduRZ9K/img.png?width=2760&amp;amp;height=1344&amp;amp;face=0_0_2760_1344');&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;[Transactional] 거래가 왜 없었을까요?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;지난글...https://kyeum-d.tistory.com/35&amp;nbsp;[Transactional] 거래가 있었는데요.. 없었습니다거래내역의 실종입사하자마자 흥미로운 주제의 CS가 들어왔습니다.&amp;nbsp;몇달 동안 지속적으로 유입되던 문의였습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kyeum-d.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>
      <category>백엔드</category>
      <category>AOP</category>
      <category>Java</category>
      <category>Spring</category>
      <category>trasnactional</category>
      <category>거래가 없어졌다</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/35</guid>
      <comments>https://kyeum-d.tistory.com/35#entry35comment</comments>
      <pubDate>Sat, 17 Aug 2024 16:23:39 +0900</pubDate>
    </item>
    <item>
      <title>F-lab 자바 백엔드 6개월 수료 후기</title>
      <link>https://kyeum-d.tistory.com/34</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;4월에 시작한&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F-lab 멘토링이 벌써 끝맺음을 맺게 되었다.&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;회고를 시작하며 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;2년 반이라는 시간동안 일명 '신입 개발자의 무덤'이라고도 불리는 금융 SI 업체에서 근무했고&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;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;초기 개발만 해주고 운영에 대한 경험을 쌓을 수 없는 SI의 특성&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;p data-ke-size=&quot;size16&quot;&gt;퇴사를 결심했고, 그 과정에서 F-lab을 알게되었다.&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;내가 F-lab을 처음 마주하고 느낀 F-lab의 모토는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;문제를 스스로 해결할 수 있는 능력을 길러줍니다.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;답을 알려주지 않습니다. 답을 알려가는 길을 알려드립니다.&quot;&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;p data-ke-size=&quot;size16&quot;&gt;나태했던 지난 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;하지만 결국 내가 하기에 달려있음이라는 걸 깨닫고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고싶은건 많고 의욕은 넘치는데 어떻게 뭘 해야할지를 모르겠는 막막한 나의 상황에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 길을 알려줄 누군가가 필요하다고 판단했기에 F-lab 멘토링을 진행하고자 마음을 먹었다.&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;/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;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;Spring을 깊게 보면서 Dispatcher Servlet 의 존재도 처음 알게 되었고,&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;이런 이론적인 기술 지식의 습득이나, 코드레벨의 확인, 기술의 존재 의의 등을 알아가는 것도 좋았지만&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;나에게 배정된 멘토님은 내가 먼 미래 시니어가 되었을 때 가장 되고싶은 이상향에 가까웠다.&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;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;li&gt;비개발자 직군과의 커뮤니케이션&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;이 3가지였는데 이 3가지 모두 멘토님께 배울점이 굉장히 많았다. (CTO쯤 되는 시니어분들의 강연 및 강의를 들어보니 사실 다 그런분들이기도 하지만, 반대로 그런 분들만 CTO가 될 수 있는거 같기도 하다는 생각도 했다)&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;지금 돌이켜보면 6개월간 배운 것이 회사 일을 하던 2년 반보다 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;최초 2~3개월 정도는 이론 공부에만 몰두한다.&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;3~4개월차에는 같이 멘토링을 듣는 멘티와 함께 할 프로젝트를 정하고&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;마지막 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;(물론 이러한 일련의 과정은 멘토님 스타일마다 다르기 때문에 획일화 된것은 아니지만)&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;1724&quot; data-origin-height=&quot;981&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bycWQn/btsz93Vyftt/xP5x0s1fIfhyTaJIxRV520/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bycWQn/btsz93Vyftt/xP5x0s1fIfhyTaJIxRV520/img.png&quot; data-alt=&quot;멘토링 시간에 스레드 덤프를 확인하는 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bycWQn/btsz93Vyftt/xP5x0s1fIfhyTaJIxRV520/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbycWQn%2Fbtsz93Vyftt%2FxP5x0s1fIfhyTaJIxRV520%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;1724&quot; height=&quot;981&quot; data-origin-width=&quot;1724&quot; data-origin-height=&quot;981&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;멘토링 시간에 스레드 덤프를 확인하는 화면&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;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;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 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;그 이후로는 이론공부에 힘을 더 쏟았는데, 이 조절이 조금 극단적으로 된 것 같았다.&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;그리고 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;이런 부분들을 간과하고 그냥 무작정 열심히 하면 뭐라도 되겠지 했던 것이 패착이 되었던 것 같다.&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;이 이력서를 처음 쓰기 시작할 때가 가장 많이 힘들었는데 지난 5개월간 분명 열심히 한 시간이 더 많았음에도, 열심히 하지 않은 일말의 순간들이 모두 기억을 스쳐가며 그 순간 또한 열심히 했어야한다 라는 좌절감과 후회가 밀려왔다.&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;&quot;제어할 수 있는 것과 제어할 수 없는 것을 구분하고 제어할 수 있는 것에 집중하자&quot;&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;제어할 수 없는 것 = 지난 5개월간의 공부&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;이 두가지로 구분하고 지난 5개월간의 공부를 후회하고 좌절해봐야 지금 바꿀 수 있는 것은 아무것도 없다는 것을 깨달았고, 이번에 느낀것을 토대로 앞으로의 방향성을 찾는 것에 몰두했다.&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;내가 어떤 부분을 어필 할 수 있고 어떤 부분들을 성장할지 구체적으로 작성해보는 것이 많이 도움이 될 것 같다.&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;짧다면&lt;/span&gt; 짧고 길다면 긴 6개월이라는 시간동안&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;결국 6개월간의 가르침을 받고&lt;/h2&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;특별히 긴장되는 것도 없었고 꼬리를 물고 들어오는 기술 질문이 오히려 멘토링 시간에 진행했던 내용보다 짧다고 느껴졌다.(멘토링 시간이였으면 여기서 더 꼬리를 물리겠다 싶었던 내용들이..)&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;멘토링 진행 중에 오피스 투어 갔던 곳의 CTO님이 해주신 얘기가 있었는데 &quot;입사할 때 퇴사를 생각하라&quot; 라는 얘기였다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기록</category>
      <category>F-Lab</category>
      <category>에프랩 회고</category>
      <category>에프랩 후기</category>
      <author>동겸동</author>
      <guid isPermaLink="true">https://kyeum-d.tistory.com/34</guid>
      <comments>https://kyeum-d.tistory.com/34#entry34comment</comments>
      <pubDate>Sun, 15 Oct 2023 10:33:45 +0900</pubDate>
    </item>
  </channel>
</rss>