<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>블로그으으</title>
    <link>https://rangerang.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 20 May 2026 08:39:18 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>rangrangerang</managingEditor>
    <image>
      <title>블로그으으</title>
      <url>https://tistory1.daumcdn.net/tistory/3173848/attach/65a59e2a24cb4cbb9fac041084d20061</url>
      <link>https://rangerang.tistory.com</link>
    </image>
    <item>
      <title>[cursor] 갑자기 spring boot 실행 안될 때(기본 클래스를 찾거나 로드할 수 없습니다. ClassNotFound)</title>
      <link>https://rangerang.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;종종 cursor 에서 스프링 부트가 돌지 않는 경우가 생기는데 그때마다 시간을 많이 쓰는 것 같아 기록으로 남겨둔다&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;오류 상황들&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행(f5)을 했을 때 아래와 같이 터미널에 오류 메세지가 뜨면서 실행이 안된다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1747795003941&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;오류: 기본 클래스 src.main.java.com.xxx.XXX (를) 찾거나 로드할 수 없습니다.
원인: java.lang.ClassNotFoundException: src.main.java.com.xxx.XXX&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Boot Dashboard에 프로젝트가 안 뜸&lt;br /&gt;프로젝트를 열었는데 &lt;b&gt;Spring Boot Dashboard&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;에서 프로젝트가 보이지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2bPP3/btsN423WPGS/r6kV2n0q3h6U8j8Ki0zdu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2bPP3/btsN423WPGS/r6kV2n0q3h6U8j8Ki0zdu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2bPP3/btsN423WPGS/r6kV2n0q3h6U8j8Ki0zdu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2bPP3%2FbtsN423WPGS%2Fr6kV2n0q3h6U8j8Ki0zdu0%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;407&quot; height=&quot;371&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;371&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;Run and Debug&amp;nbsp;에서 실행(F5) 을 해보지만 아래 오류가 발생하며 안된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VaqoS/btsN47w3cNs/IIwlwYVnmQXsQkEquWxFHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VaqoS/btsN47w3cNs/IIwlwYVnmQXsQkEquWxFHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VaqoS/btsN47w3cNs/IIwlwYVnmQXsQkEquWxFHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVaqoS%2FbtsN47w3cNs%2FIIwlwYVnmQXsQkEquWxFHk%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;404&quot; height=&quot;101&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;101&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;❗해결 방법&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;clean java&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ctrl + + shift + p 를 눌러 &lt;b&gt;Java: Clean Java Language Server Workspace &lt;/b&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;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crxGQt/btsN61oOu0a/F5a9UVIoFgoLaaWaZINDGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crxGQt/btsN61oOu0a/F5a9UVIoFgoLaaWaZINDGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crxGQt/btsN61oOu0a/F5a9UVIoFgoLaaWaZINDGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrxGQt%2FbtsN61oOu0a%2FF5a9UVIoFgoLaaWaZINDGk%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;734&quot; height=&quot;92&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌하단에 아래와 같은 경고 메세지가 뜨는데 &lt;b&gt;Reload and delete&lt;/b&gt; 를 해준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;422&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ztHkk/btsN4L18sG8/uygYLG8rAHWXdwdoJyzou1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ztHkk/btsN4L18sG8/uygYLG8rAHWXdwdoJyzou1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ztHkk/btsN4L18sG8/uygYLG8rAHWXdwdoJyzou1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FztHkk%2FbtsN4L18sG8%2FuygYLG8rAHWXdwdoJyzou1%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;422&quot; height=&quot;282&quot; data-origin-width=&quot;422&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;816&quot; data-start=&quot;750&quot; data-ke-size=&quot;size18&quot;&gt;jdk 경로 설정&lt;/p&gt;
&lt;p data-end=&quot;816&quot; data-start=&quot;750&quot; data-ke-size=&quot;size16&quot;&gt;settings.json 에 jdk 경로가 잘 설정되어 있는지 확인 해보자&lt;/p&gt;
&lt;pre id=&quot;code_1747803970237&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;spring-boot.ls.java.home&quot;: &quot;C:\\Users\\xxx\\.jdks\\azul-11.0.24&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;816&quot; data-start=&quot;750&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;816&quot; data-start=&quot;750&quot; 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;cursor 재시작&lt;/li&gt;
&lt;li&gt;Spring Boot Dashboard&amp;nbsp;재설치&lt;/li&gt;
&lt;li&gt;launch.json 삭제&amp;nbsp;&lt;/li&gt;
&lt;li&gt;clean &amp;amp; build&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;935&quot; data-start=&quot;926&quot; data-ke-size=&quot;size26&quot;&gt;최후의 수단&lt;/h2&gt;
&lt;p data-end=&quot;987&quot; data-start=&quot;937&quot; data-ke-size=&quot;size16&quot;&gt;정 안 되면 그냥 프로젝트를 새로 clone 받아서 열자. 그게 제일 빠를 수도 있다&lt;/p&gt;</description>
      <category>classnotfound</category>
      <category>CURSOR</category>
      <category>spring boot</category>
      <category>기본클래스를 찾거나 로드할 수 없습니다</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/91</guid>
      <comments>https://rangerang.tistory.com/91#entry91comment</comments>
      <pubDate>Wed, 21 May 2025 13:24:47 +0900</pubDate>
    </item>
    <item>
      <title>cursor 에 postgres MCP 연동하기(대화로 쿼리 날려보기!)</title>
      <link>https://rangerang.tistory.com/90</link>
      <description>&lt;p data-end=&quot;236&quot; data-start=&quot;121&quot; data-ke-size=&quot;size16&quot;&gt;요즘은 Intellij 대신 &lt;a href=&quot;https://www.cursor.so/&quot; data-end=&quot;157&quot; data-start=&quot;125&quot;&gt;Cursor&lt;/a&gt;를 사용해보는 중인데, 오늘은 여기에 &lt;b&gt;PostgreSQL MCP&lt;/b&gt;를 붙여서 AI와 &lt;b&gt;채팅으로 DB 쿼리를 날려보는 작업&lt;/b&gt;을 해봤다.&lt;/p&gt;
&lt;h2 data-end=&quot;278&quot; data-start=&quot;243&quot; data-ke-size=&quot;size26&quot;&gt;  MCP(Model Context Protocol)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MCP(Model Context Protocol)&lt;/b&gt;는 AI 모델이 외부 시스템(예: GitHub, Notion, SQL DB 등)과 쉽게 통신할 수 있도록 만들어진 &lt;b&gt;오픈소스 표준 프로토콜&lt;/b&gt;이다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;쉽게 말하면, &lt;/span&gt;&lt;b&gt;AI 모델과 외부 시스템 간의 연결 방식과 데이터 형식을 USB-C처럼 표준화한 규격&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이 영상을 한번 보자! 짧고 쉽게 설명해준다 &amp;rarr; &lt;a href=&quot;https://www.youtube.com/watch?v=-b0IEN4JAGE&quot;&gt;https://www.youtube.com/watch?v=-b0IEN4JAGE&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❓ Cursor란?&lt;/h3&gt;
&lt;p data-end=&quot;694&quot; data-start=&quot;580&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;VS Code 기반의 AI 개발 환경&lt;/b&gt;이다.&lt;br /&gt;GitHub Copilot보다 더 깊은 코드 컨텍스트를 이해하고, 자연어로 코드 수정&amp;middot;리팩토링&amp;middot;디버깅 요청을 할 수 있다.&lt;/p&gt;
&lt;blockquote data-end=&quot;746&quot; data-start=&quot;696&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;746&quot; data-start=&quot;698&quot; data-ke-size=&quot;size16&quot;&gt;Copilot이 자동완성이라면, Cursor는 진짜 AI 개발 도우미에 가까움!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; ️ Postgres MCP 붙이기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0. node, npm을 설치한다 &lt;br /&gt;설치&amp;nbsp;안&amp;nbsp;되어&amp;nbsp;있다면&amp;nbsp;&lt;a href=&quot;https://nodejs.org/ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Node.js 공식 사이트&lt;/a&gt;를 참고하자&lt;/p&gt;
&lt;pre id=&quot;code_1747273187005&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node -v
npm -v&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Cursor에서 MCP 서버 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cursor Settings &amp;gt; MCP &amp;gt; Add new global MCP server 을 클릭한다&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;text-align: center; caret-color: transparent; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/bDiDai/btsNX4NDy7I/MhsxmzFUnyRw67832BS4qK/img.png&quot; data-origin-width=&quot;2543&quot; data-origin-height=&quot;686&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. mcp.json 설정 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 PostgreSQL MCP 서버를 등록한다.&lt;/p&gt;
&lt;pre id=&quot;code_1747271771655&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;postgres&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [
        &quot;-y&quot;,
        &quot;@modelcontextprotocol/server-postgres&quot;,
        &quot;postgresql://{username}:{password}@{host}:{port}/{database}&quot;
      ]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;1273&quot; data-end=&quot;1300&quot;&gt;{} 부분은 본인의 DB 정보로 채워준다.&lt;/li&gt;
&lt;li data-start=&quot;1301&quot; data-end=&quot;1351&quot;&gt;예: postgresql://admin:1234@localhost:5432/mydb&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. MCP 탭에서 Postgres 활성화 확인 &lt;br /&gt;&lt;b&gt;MCP 탭&lt;/b&gt;을 열면 postgres가 보일 것이다.&lt;br /&gt;왼쪽에 &lt;b&gt;초록색 불이 들어와 있으면 연결 성공!&lt;/b&gt; &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;2542&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWfAg/btsNWkYstTa/l6xpniwwsV2u9flMGBfCVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWfAg/btsNWkYstTa/l6xpniwwsV2u9flMGBfCVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWfAg/btsNWkYstTa/l6xpniwwsV2u9flMGBfCVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWfAg%2FbtsNWkYstTa%2Fl6xpniwwsV2u9flMGBfCVK%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;2542&quot; height=&quot;507&quot; data-origin-width=&quot;2542&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;1. Cursor 우측 챗 영역을 &lt;b&gt;Agent&lt;/b&gt; 모드로 바꿔준다. 쿼리로 확인해야할 내용을 작성해보자.&lt;/p&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;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/whHjU/btsNWRnY5dM/zaAAmFkfKvNXFeqlL411q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/whHjU/btsNWRnY5dM/zaAAmFkfKvNXFeqlL411q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/whHjU/btsNWRnY5dM/zaAAmFkfKvNXFeqlL411q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwhHjU%2FbtsNWRnY5dM%2FzaAAmFkfKvNXFeqlL411q0%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;193&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 그러면 MCP가 자동으로 쿼리를 생성해준다. 확인해보고 맞다면 Run tool 을 클릭해준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TqWWr/btsNYEt57WH/lZLhyKmOK4m7HWG3knELQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TqWWr/btsNYEt57WH/lZLhyKmOK4m7HWG3knELQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TqWWr/btsNYEt57WH/lZLhyKmOK4m7HWG3knELQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTqWWr%2FbtsNYEt57WH%2FlZLhyKmOK4m7HWG3knELQK%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;681&quot; height=&quot;291&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 그럼 아래와 같이 실행 결과를 보여준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnjOI5/btsNYUQZKYb/WsoWRsLEizx7xhCgM5lhM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnjOI5/btsNYUQZKYb/WsoWRsLEizx7xhCgM5lhM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnjOI5/btsNYUQZKYb/WsoWRsLEizx7xhCgM5lhM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnjOI5%2FbtsNYUQZKYb%2FWsoWRsLEizx7xhCgM5lhM0%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;690&quot; height=&quot;425&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로만 듣던 MCP를 실제로 써보니까, 진짜 잘만 쓰면 할 수 있는 게 무궁무진 할 것 같다는 생각이 들었다. 나중엔 진짜로 AI한테 &quot;피그마 기획부터 프론트, API, DB까지 다 해줘&quot; 하면, 말만으로 개발이 끝나는 시대가 올지도 모를 것 같다. 요즘 이런 도구들 잘 써먹는 게 결국 진짜 개발 생산성으로 이어지는 것 같아 더 공부해봐야 겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Ai</category>
      <category>CURSOR</category>
      <category>cursor ai</category>
      <category>cursor mcp</category>
      <category>MCP</category>
      <category>postgres</category>
      <category>PostgreSQL</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/90</guid>
      <comments>https://rangerang.tistory.com/90#entry90comment</comments>
      <pubDate>Thu, 15 May 2025 10:43:07 +0900</pubDate>
    </item>
    <item>
      <title>같은 쿼리인데 결과가 다르게 나온다면? &amp;ndash; MyBatis 1차 캐시</title>
      <link>https://rangerang.tistory.com/89</link>
      <description>&lt;p data-end=&quot;261&quot; data-start=&quot;110&quot; data-ke-size=&quot;size16&quot;&gt;이번에 꽤 흥미로운 이슈를 하나 겪었다. 동일한 쿼리, 동일한 파라미터로 MyBatis 쿼리를 두 번 실행했는데, 첫 번째 쿼리의 결과와 두 번째 쿼리의 결과가 달랐다. (p6spy를 통해 확인했을 때 두 번째 쿼리는 로그조차 안 찍힘)&lt;/p&gt;
&lt;p data-end=&quot;307&quot; data-start=&quot;263&quot; data-ke-size=&quot;size16&quot;&gt;결론부터 얘기하자면, &lt;b&gt;MyBatis의 1차 캐시&lt;/b&gt; 때문에 발생한 문제였다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;959&quot; data-start=&quot;944&quot; data-ke-size=&quot;size26&quot;&gt;트랜잭션과 1차 캐시&lt;/h2&gt;
&lt;p data-end=&quot;1192&quot; data-start=&quot;961&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;트랜잭션 내에서 1차 캐시가 동작&lt;/b&gt;한다는 점을 이해하는 것이 중요하다. MyBatis에서 1차 캐시는 SqlSession 단위로 관리되며, &lt;b&gt;하나의 트랜잭션 내에서 같은 SqlSession을 사용&lt;/b&gt;하기 때문에 &lt;b&gt;트랜잭션 동안 캐시된 데이터는 계속 유지&lt;/b&gt;된다. 이 말은 트랜잭션 내에서 &lt;b&gt;같은 쿼리와 파라미터로 데이터 조회 시, 쿼리가 실행되지 않고 1차 캐시에서 결과를 가져온다는 의미&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;1394&quot; data-start=&quot;1194&quot; data-ke-size=&quot;size16&quot;&gt;따라서 트랜잭션 내에서 같은 데이터를 여러 번 조회하는 경우, &lt;b&gt;1차 캐시로 인해 의도치 않은 데이터 오염&lt;/b&gt;이 발생할 수 있다. 예를 들어, 위의 경우에서는 &lt;b&gt;빈 리스트&lt;/b&gt;를 처음 조회하고, 그 리스트를 수정했는데, &lt;b&gt;다시 조회 시 1차 캐시에서 수정된 리스트를 그대로 가져와&lt;/b&gt; DB에는 없는 데이터가 포함된 리스트를 반환하게 되는 상황이 발생했다.&lt;/p&gt;
&lt;p data-end=&quot;1394&quot; data-start=&quot;1194&quot; data-ke-size=&quot;size16&quot;&gt;참고로 Mybatis에는 1차 캐시와 2차 캐시가 있다(&lt;a href=&quot;https://codingdreamtree.tistory.com/92&quot;&gt;https://codingdreamtree.tistory.com/92&lt;/a&gt;)&lt;/p&gt;
&lt;p data-end=&quot;307&quot; data-start=&quot;263&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;307&quot; data-start=&quot;263&quot; data-ke-size=&quot;size26&quot;&gt;상황 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;케이스를 간단히 요약해보면 아래와 같다&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. mapper를 통해 name=aaa인 데이터를 가지고 온다 -&amp;gt; &lt;b&gt;결과없음(0개)&lt;/b&gt;&lt;br /&gt;2. 1을 통해 가지고 온 데이터를 리턴하고 이후 로직에서 1에서 리턴한 객체에 add 한다&lt;br /&gt;3. aaa 유저를 다시 mapper를 통해 가지고 온다 -&amp;gt; &lt;b&gt;쿼리 로그 찍히지 않음&lt;/b&gt;, &lt;b&gt;결과는 1개&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-end=&quot;628&quot; data-start=&quot;480&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 이게 뭔가 싶었는데, 알고 보니 MyBatis는 동일한 쿼리와 동일한 파라미터로 요청이 들어오면 1차 캐시(Local Cache)에서 결과를 꺼내 반환하기 때문에 생긴 현상이었다.&amp;nbsp;문제는 1차 조회 결과(빈 리스트)를 그대로 반환해서, 이후 로직에서 그 리스트를 수정했다는 거다.&lt;/p&gt;
&lt;p data-end=&quot;736&quot; data-start=&quot;630&quot; data-ke-size=&quot;size16&quot;&gt;결국 3번 조회 시에는 쿼리를 날리지도 않고, &lt;b&gt;캐시에 있던 조작된 리스트&lt;/b&gt;를 그대로 반환해버린 것이다.&lt;br /&gt;당연히 DB에는 없는 데이터인데도, 있는 것처럼 처리되는 상황이 되어버린 셈이다.&lt;/p&gt;
&lt;p data-end=&quot;736&quot; data-start=&quot;630&quot; data-ke-size=&quot;size16&quot;&gt;아래는 상황을 코드로 간략하게 재현해본 코드이다:&lt;/p&gt;
&lt;pre id=&quot;code_1744529278665&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    public void testFirstLevelCacheIssueWithLoop() {
        String notExistUser = &quot;notExistUser&quot;;

        for (int i = 0; i &amp;lt; 2; i++) {
            List&amp;lt;User&amp;gt; users = getUserListAndModify(notExistUser);
            System.out.println(&quot;Loop &quot; + i + &quot; - users.size() = &quot; + users.size());
            users.add(new User()); //  add() 수행
        }
    }

    /**
     * 유저 데이터를 조회하고, 내부에서 add() 수행
     * 동일 쿼리와 파라미터 사용 시 1차 캐시 영향 받음
     */
    private List&amp;lt;User&amp;gt; getUserListAndModify(String name) {
        List&amp;lt;User&amp;gt; users = userMapper.getUserByName(name); // 1차 캐시 대상
        return users;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 확인해보면, 3번 쿼리는 아예 실행조차 되지 않는다.&lt;br /&gt;1차 캐시에 의해 생략됐기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, users 리스트는 같은 객체고, add가 누적되면서 사이즈가 계속 증가한다.&lt;br /&gt;실제로 DB엔 아무것도 없지만, 코드상에선 계속 유저가 생겨나는 상황이 된 것이다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mxgnt/btsNjDwu52j/aMEVXO8C9OaSIxlaaNXox0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mxgnt/btsNjDwu52j/aMEVXO8C9OaSIxlaaNXox0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mxgnt/btsNjDwu52j/aMEVXO8C9OaSIxlaaNXox0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmxgnt%2FbtsNjDwu52j%2FaMEVXO8C9OaSIxlaaNXox0%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;545&quot; height=&quot;226&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;226&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;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 1차 캐시를 끈다(비추)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;MyBatis에서는 SqlSession 단위로 1차 캐시를 사용한다.&lt;br /&gt;&lt;/span&gt;필요하다면 아래처럼 캐시를 직접 초기화할 수도 있다:&lt;/p&gt;
&lt;pre id=&quot;code_1744530639970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sqlSession.clearCache();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1532&quot; data-start=&quot;1507&quot; data-ke-size=&quot;size16&quot;&gt;아니면 설정에서 캐시 범위를 좁힐 수도 있다:&lt;/p&gt;
&lt;pre id=&quot;code_1744530684929&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;settings&amp;gt;
  &amp;lt;setting name=&quot;localCacheScope&quot; value=&quot;STATEMENT&quot;/&amp;gt;
&amp;lt;/settings&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1669&quot; data-start=&quot;1623&quot; data-ke-size=&quot;size16&quot;&gt;아니면 해당 쿼리에서만 캐싱을 하지 않을수도 있다:&lt;/p&gt;
&lt;pre id=&quot;code_1744533268431&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;select id=&quot;selectUser&quot; parameterType=&quot;int&quot; resultType=&quot;User&quot; flushCache=&quot;true&quot;&amp;gt;
    &amp;lt;!-- Your SQL statement here --&amp;gt;
&amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1669&quot; data-start=&quot;1623&quot; data-ke-size=&quot;size16&quot;&gt;하지만 이건 근본적인 해결책이라기보다는, &lt;b&gt;그때그때 문제점만 막는 것&lt;/b&gt;에 가깝고, 이로인해 어떤 사이드 이팩트가 발생할지 모른다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 조회한 데이터를 직접 수정하지 않도록 한다(추천 )&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;1805&quot; data-start=&quot;1708&quot; data-ke-size=&quot;size16&quot;&gt;내가 겪은 이슈의 핵심은 &quot;조회한 데이터를 로직에서 수정했다&quot;는 데 있다.&lt;br /&gt;1차 캐시는 동일한 객체를 리턴하기 때문에, 해당 객체를 수정하면 &lt;b&gt;캐시도 같이 오염된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1862&quot; data-start=&quot;1807&quot; data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 가장 깔끔한 방법은, &lt;b&gt;조회한 데이터를 DTO 등으로 변환해서 리턴하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1744530787806&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private List&amp;lt;User&amp;gt; getUserListAndModifySafely(String name) {
    List&amp;lt;User&amp;gt; users = new ArrayList&amp;lt;&amp;gt;(userMapper.getUserByName(name)); // 복사본 생성
    return users;
}&lt;/code&gt;&lt;/pre&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;274&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nvp27/btsNjie3b63/5s8rY3qr7Gy9v0PUnoUPWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nvp27/btsNjie3b63/5s8rY3qr7Gy9v0PUnoUPWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nvp27/btsNjie3b63/5s8rY3qr7Gy9v0PUnoUPWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnvp27%2FbtsNjie3b63%2F5s8rY3qr7Gy9v0PUnoUPWk%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;274&quot; height=&quot;205&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;205&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;사실 이 코드도 문제가 있다 만약 users 의 결과가 있고, 그 데이터를 리스트에서 가져다 수정한다면 캐시에 있는 데이터는 또 오염될 것이다!&lt;br /&gt;따라서 user도 deepcopy를 해야한다&lt;/p&gt;
&lt;pre id=&quot;code_1744531639265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private List&amp;lt;User&amp;gt; getDeepCopiedUsers(String name) {
    return userMapper.getUserByName(name).stream()
            .map(user -&amp;gt; new User(user)) // 복사 생성자
            .collect(Collectors.toList());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;2384&quot; data-start=&quot;2170&quot; data-ke-size=&quot;size16&quot;&gt;최근엔 JPA로 개발을 진행하다 보니 MyBatis 쓸 일이 줄어들고 있다. 신입 친구들 중에는 MyBatis 한 번도 안 써봤다는 경우도 있어서 놀랐던 적도 있다. 내가 개발 중인 서비스는 오래된 MyBatis 기반의 코드와 새로 작성한 JPA 기반 코드가 공존하고 있는데, JPA에선 익숙했던 캐시 개념이 MyBatis에도 있다는 걸 새삼스럽게 다시 알게 된 계기였다.&lt;/p&gt;
&lt;p data-end=&quot;2500&quot; data-start=&quot;2386&quot; data-ke-size=&quot;size16&quot;&gt;실제 운영 중인 서비스에서 이런 캐시 오염 문제가 발생하면 꽤 위험할 수 있기 때문에, 조회한 데이터를 왠만하면 복사해서 리턴하는게 좋다는 교훈을 얻은 경험이었다.&lt;/p&gt;</description>
      <category>ㄴspring boot</category>
      <category>1차캐시</category>
      <category>cache</category>
      <category>myabatis</category>
      <category>캐시</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/89</guid>
      <comments>https://rangerang.tistory.com/89#entry89comment</comments>
      <pubDate>Sun, 13 Apr 2025 17:12:39 +0900</pubDate>
    </item>
    <item>
      <title>JPA @Transactional 과 1차 캐시</title>
      <link>https://rangerang.tistory.com/88</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #404040; text-align: start;&quot;&gt;문제&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #404040; text-align: start;&quot;&gt;JPA에서는 1차 캐시를 사용하기 때문에 같은 엔티티에 대해서는 동일성(주소값이 같음)을 만족한다고 알고 사용해왔다. &lt;/span&gt;&lt;span&gt;그래서 나는 객체를 비교할 때 id가 아닌 객체 그 자체로 비교해 왔다. 그런데 어느 날 id로 가지고 온 객체를 이용해 fetch join을 통해 가지고 온 객체 중 하나를 찾는 로직을 작성했는데, 하나도 못 찾는 문제가 발생했다. 확인해보니 id를 통해 가지고 온 객체와 fetch join을 통해 가지고 온 객체의 주소값이 달랐다. 결론부터 말하자면 원인은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;@Transactional&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 붙이지 않아 발생했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;테스트1. @Transactional 없이 조회&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아래 코드는 테스트를 위해 작성한 코드로, &lt;/span&gt;&lt;span&gt;findByIdPerson&lt;/span&gt;&lt;span&gt;은 &lt;/span&gt;&lt;span&gt;personRepository&lt;/span&gt;&lt;span&gt;에서 id를 이용해 &lt;/span&gt;&lt;span&gt;person&lt;/span&gt;&lt;span&gt;을 가지고 왔고, &lt;/span&gt;&lt;span&gt;entityGraphPerson&lt;/span&gt;&lt;span&gt; 객체는 &lt;/span&gt;&lt;span&gt;team&lt;/span&gt;&lt;span&gt;을 가져올 때 fetch join으로 거기에 속한 멤버도 함께 가져오도록 해서 &lt;/span&gt;&lt;span&gt;person&lt;/span&gt;&lt;span&gt; 객체를 조회했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738490890880&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    public void jpaFirstCacheTransactionalTest() {
        // id 로 사람 조회
        Member findByIdMember = personRepository.findById(1L).get();

        // team과 사람 한번에 조회(패치 조인)
        Team teamWithMember = teamRepository.findWithPersonById(1L).get();
        Member entityGraphMember = teamWithMember.getMembers().get(0);

        assertEquals(findByIdMember.getId(), entityGraphMember.getId(), &quot;id가 다릅니다&quot;);
        assertEquals(findByIdMember, entityGraphMember, &quot;주소값이 다릅니다&quot;);
    }&lt;/code&gt;&lt;/pre&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;178&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bin4kF/btsL46F3Eih/xNuwK39nB1qbGcKAA1QEI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bin4kF/btsL46F3Eih/xNuwK39nB1qbGcKAA1QEI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bin4kF/btsL46F3Eih/xNuwK39nB1qbGcKAA1QEI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbin4kF%2FbtsL46F3Eih%2FxNuwK39nB1qbGcKAA1QEI1%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;178&quot; height=&quot;216&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;216&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-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 테스트인 id 값 비교는 성공하지만, 두 번째 테스트인 주소값 비교는 실패한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFB69m/btsL4nuWW9q/d2YGsWDczfzjbx5WZsfENk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFB69m/btsL4nuWW9q/d2YGsWDczfzjbx5WZsfENk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFB69m/btsL4nuWW9q/d2YGsWDczfzjbx5WZsfENk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFB69m%2FbtsL4nuWW9q%2Fd2YGsWDczfzjbx5WZsfENk%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;624&quot; height=&quot;221&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;221&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;테스트2. @Transactional 추가 후 조회&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그럼 이번에는 &lt;/span&gt;&lt;span&gt;@Transactional&lt;/span&gt;&lt;span&gt;을 추가해서 테스트해보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738491754284&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    @Transactional	// 추가**
    public void jpaFirstCacheTransactionalTest() {
        // id 로 사람 조회
        Member findByIdMember = personRepository.findById(1L).get();

        // team과 사람 한번에 조회(패치 조인)
        Team teamWithMember = teamRepository.findWithPersonById(1L).get();
        Member entityGraphMember = teamWithMember.getMembers().get(0);

        assertEquals(findByIdMember.getId(), entityGraphMember.getId(), &quot;id가 다릅니다&quot;);
        assertEquals(findByIdMember, entityGraphMember, &quot;주소값이 다릅니다&quot;);
    }&lt;/code&gt;&lt;/pre&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;253&quot; data-origin-height=&quot;32&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V9wd6/btsL3qlAIcy/PKMKaOprfFAzkqB1hVhzW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V9wd6/btsL3qlAIcy/PKMKaOprfFAzkqB1hVhzW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V9wd6/btsL3qlAIcy/PKMKaOprfFAzkqB1hVhzW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV9wd6%2FbtsL3qlAIcy%2FPKMKaOprfFAzkqB1hVhzW1%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;67&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;32&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JPA 1차 캐시 조건&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA 의 1차 캐시의 조건에는 아래와 같은 내용이 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. 트랜잭션이 종료되거나, flush()될 경우 캐시는 초기화&lt;br /&gt;2. 캐시에서 값을 가져오는건 PK를 기반으로한 find (entity manager를 쓸때 find() 메서드 혹은 data-jpa의 findById)에서만 동작&lt;br /&gt;3. EntityManager 단위에서 1차 캐시가 관리됨&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 테스트해본 문제는 1번 조건이 적용되지 않아 동일 트랜잭션이 아니었던 조회에서 1차 캐시가 공유되지 않았고, 그래서 엔티티의 동일성이 보장되지 않았던 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;테스트3. id로 조회후 name으로 조회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 2번의 경우 쿼리가 몇번 날라가는지 테스트를 해보자. 만약 id로 조회한 후 name로 조회하면 쿼리는 몇 번 실행될까?&lt;/p&gt;
&lt;pre id=&quot;code_1738494543426&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    @Transactional
    public void jpaFirstCacheOrderTest() {
        // id 로 사람 조회
        Member findByIdMember = personRepository.findById(1L).get();

        // name으로 동일한 사람 조회
        Member findByNameMember = personRepository.findByName(&quot;YR&quot;).get();

        assertEquals(findByIdMember.getId(), findByNameMember.getId(), &quot;id가 다릅니다&quot;);
        assertEquals(findByIdMember, findByNameMember, &quot;주소값이 다릅니다&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 테스트는 성공하지만 중요한건 쿼리가 2번 나간다. 어떻게 동작하는지 생각해보면 첫번째 id로 조회했을 때 1차 캐시에 아래와 같이 데이터가 저장됐을 것이다. 하지만 name으로 조회할 땐 2번 조건에 따라 1차 캐시가 아닌 db에서 다시 가지고 오기 때문에 쿼리가 한번 더 나간다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 27.5581%; height: 70px;&quot; border=&quot;1&quot; data-ke-style=&quot;style4&quot; data-ke-align=&quot;alignCenter&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot; colspan=&quot;2&quot;&gt;1차 캐시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;@Id&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Entity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Member(YR)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blhayX/btsL4psLtbQ/iPeKAgL2RoWMRksjuTuzKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blhayX/btsL4psLtbQ/iPeKAgL2RoWMRksjuTuzKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blhayX/btsL4psLtbQ/iPeKAgL2RoWMRksjuTuzKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblhayX%2FbtsL4psLtbQ%2FiPeKAgL2RoWMRksjuTuzKk%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;628&quot; height=&quot;526&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;526&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;테스트4. name으로 조회 후 id로 조회&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 name으로 먼저 조회하고 id 로 조회해보자&lt;/p&gt;
&lt;pre id=&quot;code_1738494728474&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    @Transactional
    public void jpaFirstCacheOrderTest() {
        // name으로 동일한 사람 조회
        Member findByNameMember = personRepository.findByName(&quot;YR&quot;).get();
        
        // id 로 사람 조회
        Member findByIdMember = personRepository.findById(1L).get();
        
        assertEquals(findByIdMember.getId(), findByNameMember.getId(), &quot;id가 다릅니다&quot;);
        assertEquals(findByIdMember, findByNameMember, &quot;주소값이 다릅니다&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 쿼리가 한번만 나갔다. 첫번째 name으로 조회했을 때 첫번째 테스트에서와 마찬가지로 1차 캐시에 아래와 같이 데이터가 저장됐을 것이다 그 이후에 pk 로 조회했을 때 1차 캐시에서 id로 1번 데이터를 찾았을 거고, 첫번째 조회에서 저장된 엔티티가 있으니 쿼리는 날라가지 않은 것이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 27.5581%; height: 70px;&quot; border=&quot;1&quot; data-ke-style=&quot;style4&quot; data-ke-align=&quot;alignCenter&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot; colspan=&quot;2&quot;&gt;1차 캐시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;@Id&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Entity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Member(YR)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: center;&quot; 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;701&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4M4zm/btsL2PMItkA/n7fyL3yUp1rqhTUKGRrZEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4M4zm/btsL2PMItkA/n7fyL3yUp1rqhTUKGRrZEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4M4zm/btsL2PMItkA/n7fyL3yUp1rqhTUKGRrZEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4M4zm%2FbtsL2PMItkA%2Fn7fyL3yUp1rqhTUKGRrZEK%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;701&quot; height=&quot;379&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #404040; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 문제를 통해 JPA에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;@Transactional의 중요성을 다시 한번 깨달았다. 보통 나는 service 단에 @Transactional(readOnly=true) 를 붙여놓고 데이터 저장,수정,삭제 등이 필요한 메서드에만 @Transactional 를 따로 붙여주는데 이 서비스는 기존에 있던 서비스에 내용을 추가하다보니 놓친 것 같다.. 앞으로는 간단한 내용만 추가한다고 해도 서비스를 꼼꼼히 살펴보고 추가하는게 좋을 것 같다.&lt;/p&gt;</description>
      <category>웹개발</category>
      <category>1차캐시</category>
      <category>@Transactional</category>
      <category>JPA</category>
      <category>jpa 1차 캐시</category>
      <category>spring boot</category>
      <category>조건</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/88</guid>
      <comments>https://rangerang.tistory.com/88#entry88comment</comments>
      <pubDate>Sun, 2 Feb 2025 20:26:38 +0900</pubDate>
    </item>
    <item>
      <title>스레드 동기화와 volatile, synchronized 키워드</title>
      <link>https://rangerang.tistory.com/87</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리 팀에서는 사용자의 조작에 따라 카프카의 특정 토픽을 구독하거나 구독 취소하는 기능을 구현하고 있다. 이 과정에서 topicList라는 리스트를 통해 구독할 토픽을 관리하고, 해당 리스트의 사이즈를 체크하여 구독할 대상이 있는 경우에만 로직을 실행하도록 개발했다. 그런데 topicList에 데이터가 하나도 없을 때 무한루프에 빠져 새로운 토픽이 추가되어도 무한루프를 빠져나오지 못하는 현상이 발생했다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;문제의 원인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 대략적인 코드이다. 코드를 살펴보면, topicList의 사이즈가 0일 때 while문 안에서 continue가 호출되어 무한루프에 빠지는 것을 알 수 있다. 사실 이 코드는 애초에 잘못 짜여진 코드이다. 토픽이 없는 경우에도 무한루프에 빠지가 코드를 짜면 안된다. 하지만 그렇다고 하더라도 사용자가 새로운 토픽을 추가하면 이 조건을 통과해 다음 로직을 실행해야 할 것 같은데, 실제로는 그렇지 않았다.&lt;/p&gt;
&lt;pre id=&quot;code_1731328569970&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Log4j2
public class TestConsumer implements Runnable {

    private List&amp;lt;String&amp;gt; topicList = new ArrayList&amp;lt;&amp;gt;();

    @Override
    public void run() {
        log.info(&quot;[{}] start consumer!!&quot;, Thread.currentThread().getName());
        while (true) {
            if (topicList.size() == 0) {
                continue;
            }

            log.info(&quot;[{}] ======= topicList is not null! logic start! size:{} =======&quot;, Thread.currentThread().getName(), topicList.size());
            try {
                Thread.sleep(1000 * 10L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void addTopic(String topic) {
        topicList.add(topic);
        log.info(&quot;[{}] add topic : {}&quot;, Thread.currentThread().getName(), topicList);
    }
}&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;아래의 메인 코드를 실행해보자. topic_init을 우선 추가 후 5초 이후 topic_new를 추가하는 코드이다.&lt;/p&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;public class Main {

    public static void main(String[] args) throws InterruptedException {
        TestConsumer testConsumer = new TestConsumer();
        testConsumer.addTopic(&quot;topic_init&quot;);
        Thread thread = new Thread(testConsumer, &quot;testConsumer&quot;);
        thread.start();

        // 사용자가 topic을 추가.
        Thread.sleep(1000 * 5L);
        testConsumer.addTopic(&quot;topic_new&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;topicList 에 topic_init 이라는 토픽이 이미 존재하는 경우 실행된 로그를 확인해보면 정상적으로 이후 로직이 실행되는 것을 확인해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4YmXO/btsJ3adzFcu/20htQAHggszYl0otmJDJg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4YmXO/btsJ3adzFcu/20htQAHggszYl0otmJDJg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4YmXO/btsJ3adzFcu/20htQAHggszYl0otmJDJg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4YmXO%2FbtsJ3adzFcu%2F20htQAHggszYl0otmJDJg1%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;1006&quot; height=&quot;138&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;138&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;pre id=&quot;code_1731328569973&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;public class Main {

    public static void main(String[] args) throws InterruptedException {
        TestConsumer testConsumer = new TestConsumer();
//        testConsumer.addTopic(&quot;topic_init&quot;);
        Thread thread = new Thread(testConsumer, &quot;testConsumer&quot;);
        thread.start();

        // 사용자가 topic을 추가.
        Thread.sleep(1000 * 5L);
        testConsumer.addTopic(&quot;topic_new&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토픽 추가를 해도 이를 인지하지 못하고, 이후 로직이 실행되지 않는다. topicList에 topic_new 라는 토픽을 추가해줬지만 여전히 topicList 의 사이즈는 0이라고 인식하고 있는 거다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;50&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRR2v/btsJ3gxPPzt/zHHDaEaQFY8cyvJ1fZ8fkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRR2v/btsJ3gxPPzt/zHHDaEaQFY8cyvJ1fZ8fkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRR2v/btsJ3gxPPzt/zHHDaEaQFY8cyvJ1fZ8fkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRR2v%2FbtsJ3gxPPzt%2FzHHDaEaQFY8cyvJ1fZ8fkk%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;663&quot; height=&quot;50&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;50&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드 덤프를 떠보면 더 확실히 확인할 수 있는데 토픽이 추가된 이후인데도 여전히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;if(topicList.sizer() == 0)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&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;1180&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lsd5J/btsJ4ey32pM/xquJZdaxD6Ji1zQWwDqvI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lsd5J/btsJ4ey32pM/xquJZdaxD6Ji1zQWwDqvI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lsd5J/btsJ4ey32pM/xquJZdaxD6Ji1zQWwDqvI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLsd5J%2FbtsJ4ey32pM%2FxquJZdaxD6Ji1zQWwDqvI0%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;1180&quot; height=&quot;676&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;CPU 캐시&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;457&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kKuG8/btsJ3HaUXr8/Ks3Jxo2QPoi8qksWRiRQFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kKuG8/btsJ3HaUXr8/Ks3Jxo2QPoi8qksWRiRQFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kKuG8/btsJ3HaUXr8/Ks3Jxo2QPoi8qksWRiRQFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkKuG8%2FbtsJ3HaUXr8%2FKs3Jxo2QPoi8qksWRiRQFk%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;532&quot; height=&quot;457&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;457&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 현상이 나타나는 원인을 알기 위해서는 cpu캐시에 대해 알아야 한다. JVM에서는 스레드는 실행되고 있는 CPU 메모리 영역에 데이터를 캐싱 한다. (CPU Cache) 따라서 멀티 코어 프로세서에서 다수의 스레드가 변수를 공유하더라도 캐싱 된 시점에 따라 데이터가 다를 수 있으며, 서로 다른 코어의 스레드는 데이터 값이 불일치하는 문제가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임의로 데이터를 갱신해 주지 않는 이상&lt;span&gt;&amp;nbsp;&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1115&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eKylkm/btsKDO2wD1f/EXbKT9KU5wvlU4eKfsivTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eKylkm/btsKDO2wD1f/EXbKT9KU5wvlU4eKfsivTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eKylkm/btsKDO2wD1f/EXbKT9KU5wvlU4eKfsivTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeKylkm%2FbtsKDO2wD1f%2FEXbKT9KU5wvlU4eKfsivTK%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;1115&quot; height=&quot;686&quot; data-origin-width=&quot;1115&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, topicList에 새로운 토픽이 추가되더라도, 추가한 스레드의 캐시와 메인 메모리는 업데이트 되지만, 기존 스레드가 가지고 있는 캐시된 데이터가 업데이트되지 않을 수 있어 무한루프에 빠지게 되는 것이다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;해결 방법 : volatile 키워드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우&amp;nbsp;&lt;b&gt;volatile&amp;nbsp;&lt;/b&gt;키워드를 사용하여 CPU 메모리 영역에 캐싱 된 값이 아니라&amp;nbsp;&lt;b&gt;항상 최신의 값을 가지도록 메인 메모리 영역에서 값을 참조하도록 할 수 있다.&lt;/b&gt;&amp;nbsp;&lt;br /&gt;-&amp;gt; 즉, 동일 시점에 모든 스레드가 동일한 값을 가지도록 동기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;쓰레드가 변경한 값이 아직 메인 메모리에 기록되지 않았기 때문에 다른 쓰레드가 변수의 최신 값을 볼 수 없는 문제를 &quot;가시성&quot; 문제라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 topicList에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;volatile&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드를 추가 후 테스트해보자&lt;/p&gt;
&lt;pre id=&quot;code_1731328569974&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Log4j2
public class TestConsumer implements Runnable {
    // volatile 키워드 추가
    private volatile List&amp;lt;String&amp;gt; topicList = new ArrayList&amp;lt;&amp;gt;();

    @Override
    public void run() {
        log.info(&quot;[{}] start consumer!!&quot;, Thread.currentThread().getName());
        while (true) {
            if (topicList.size() == 0) {
                continue;
            }

            log.info(&quot;[{}] ======= topicList is not null! logic start! size:{} =======&quot;, Thread.currentThread().getName(), topicList.size());
            try {
                Thread.sleep(1000 * 10L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void addTopic(String topic) {
        topicList.add(topic);
        log.info(&quot;[{}] add topic : {}&quot;, Thread.currentThread().getName(), topicList);
    }
}&lt;/code&gt;&lt;/pre&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNCwPH/btsJ4e6OBGE/ifogAr8Jqwl36skgLI3CG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNCwPH/btsJ4e6OBGE/ifogAr8Jqwl36skgLI3CG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNCwPH/btsJ4e6OBGE/ifogAr8Jqwl36skgLI3CG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNCwPH%2FbtsJ4e6OBGE%2FifogAr8Jqwl36skgLI3CG0%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;870&quot; height=&quot;97&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;synchronized 키워드&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;하지만 volatile 을 붙여주더라도 문제가 생길 여지는 있다 바로 여러 스레드에서 한번에 해당 리스트에 topic을 추가하는 경우이다. 사실 우리 서비스는 해당 영역을 개발자 혹은 담당자 한명 정도만 만지기 때문에 동시에 동일한 토픽에 대한 수정을 할 일은 극히 적지만, 만약 동시에 토픽을 수정한다고 하면 이상한 결과가 나올수도 있다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;이런경우 synchronized 키워드를 사용해주면 문제는 해결된다&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;그럼 그냥 모든 공유 변수에 synchronized를 사용하면 되지 않을까?&lt;br /&gt;-&amp;gt; synchronized 는 volatile 보다 성능이 좋지 않다(락을 획득해야 하기 때문)&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;✔ 결론 : 여러 쓰레드에서 참조하는 변수의 경우 volatile 키워드를 붙여주자.&lt;br /&gt;만약 여러 쓰레드에서 해당 값을 수정한다면 synchronized 키워드를 붙여주자.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;참고&lt;br /&gt;&lt;a href=&quot;https://rachel0115.tistory.com/entry/Java-%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88%EC%99%80-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&quot;&gt;https://rachel0115.tistory.com/entry/Java-%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88%EC%99%80-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://programmer-chocho.tistory.com/82&quot;&gt;https://programmer-chocho.tistory.com/82&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>synchronized</category>
      <category>volatile</category>
      <category>멀티스레드</category>
      <category>스레드 동기화</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/87</guid>
      <comments>https://rangerang.tistory.com/87#entry87comment</comments>
      <pubDate>Mon, 11 Nov 2024 21:38:03 +0900</pubDate>
    </item>
    <item>
      <title>GitHub pull request 발생 시  Mattermost 에 메세지 전송하기(AWS lambda, api gateway)</title>
      <link>https://rangerang.tistory.com/85</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체적인 로직&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브에서 &lt;b&gt;pull request&lt;/b&gt; 를 만들면 &lt;b&gt;api gateway&lt;/b&gt;로 요청을 보낸다 &lt;b&gt;api gateway&lt;/b&gt; 는 &lt;b&gt;lambda&lt;/b&gt;의 함수를 호출하고 &lt;b&gt;lambda&lt;/b&gt; 의 함수 로직에서 &lt;b&gt;mattermost&lt;/b&gt;를에 메세지를 전송한다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;api gateway : API 만들어주는 친구. 외부 클라이언트로부터 요청을 받아 람다 함수로 연결해줌&lt;/li&gt;
&lt;li&gt;lambda : 서버리스 컴퓨팅 플랫폼(메서드만 작성해서 실행시킬 수 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEUoxB/btsH5YsOyoV/FpongvFYeykhXNr7JKL9O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEUoxB/btsH5YsOyoV/FpongvFYeykhXNr7JKL9O1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEUoxB/btsH5YsOyoV/FpongvFYeykhXNr7JKL9O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEUoxB%2FbtsH5YsOyoV%2FFpongvFYeykhXNr7JKL9O1%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;453&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Mattermost에 webhook 추가하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 mattermost에 외부 메세지를 받을 수 있도록 webhook을 추가해 준다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좌상단 &amp;gt; 통합&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5doA4/btsH6ObWSDw/xj36Ls3GN3QBmN09M9yXf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5doA4/btsH6ObWSDw/xj36Ls3GN3QBmN09M9yXf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5doA4/btsH6ObWSDw/xj36Ls3GN3QBmN09M9yXf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5doA4%2FbtsH6ObWSDw%2Fxj36Ls3GN3QBmN09M9yXf1%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;1280&quot; height=&quot;690&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;전체 Incoming Webhook&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CXvtX/btsH7ylT7o3/RJCvzK5Dv3d5ZKuwS6k6PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CXvtX/btsH7ylT7o3/RJCvzK5Dv3d5ZKuwS6k6PK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CXvtX/btsH7ylT7o3/RJCvzK5Dv3d5ZKuwS6k6PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCXvtX%2FbtsH7ylT7o3%2FRJCvzK5Dv3d5ZKuwS6k6PK%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;1280&quot; height=&quot;693&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;Incoming Webhook 추가하기 &lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;691&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGKJLy/btsH7FSSnWd/2P31Cjq18rJydbTKOssLvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGKJLy/btsH7FSSnWd/2P31Cjq18rJydbTKOssLvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGKJLy/btsH7FSSnWd/2P31Cjq18rJydbTKOssLvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGKJLy%2FbtsH7FSSnWd%2F2P31Cjq18rJydbTKOssLvk%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;1280&quot; height=&quot;691&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;691&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;내용 입력 &lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1042&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x7ngS/btsH5XObwUY/U36muvYqgXIA2ZFBJ30SV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x7ngS/btsH5XObwUY/U36muvYqgXIA2ZFBJ30SV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x7ngS/btsH5XObwUY/U36muvYqgXIA2ZFBJ30SV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx7ngS%2FbtsH5XObwUY%2FU36muvYqgXIA2ZFBJ30SV1%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;1280&quot; height=&quot;1042&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1042&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;생성된 URL &amp;rarr; 람다에서 메세지 전송할 &lt;b&gt;&lt;span style=&quot;color: #eb5757;&quot; data-token-index=&quot;1&quot;&gt;URL&lt;/span&gt; &lt;/b&gt;로 사용&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tvYWt/btsH5BESRx9/oEbC7Teq7jY0A9FUOL1Vh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tvYWt/btsH5BESRx9/oEbC7Teq7jY0A9FUOL1Vh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tvYWt/btsH5BESRx9/oEbC7Teq7jY0A9FUOL1Vh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtvYWt%2FbtsH5BESRx9%2FoEbC7Teq7jY0A9FUOL1Vh1%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;1280&quot; height=&quot;693&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. aws lambda 함수 만들기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. 함수 생성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;aws lambda &amp;gt; 함수 생성&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwOme7/btsH6LM3ogu/iD0SFyHOPEVHWdKY5KZIH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwOme7/btsH6LM3ogu/iD0SFyHOPEVHWdKY5KZIH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwOme7/btsH6LM3ogu/iD0SFyHOPEVHWdKY5KZIH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwOme7%2FbtsH6LM3ogu%2FiD0SFyHOPEVHWdKY5KZIH1%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;1280&quot; height=&quot;622&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;622&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;언어는 python 3.11 사용&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바의 경우 코드 수정 시 로컬에서 빌드 후 jar 업로드 필요&lt;/li&gt;
&lt;li&gt;파이썬의 경우 aws 웹에서 바로 수정&amp;amp;배포&amp;amp;테스트가 가능함&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eZTm1M/btsH6OwiYVO/qC4JdOAPUKFF31y8dZjeo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eZTm1M/btsH6OwiYVO/qC4JdOAPUKFF31y8dZjeo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eZTm1M/btsH6OwiYVO/qC4JdOAPUKFF31y8dZjeo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeZTm1M%2FbtsH6OwiYVO%2FqC4JdOAPUKFF31y8dZjeo0%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;1280&quot; height=&quot;584&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2. 코드 &amp;gt; 코드 작성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;github json을 받아 원하는 데이터 추출&lt;/li&gt;
&lt;li&gt;해당 데이터를 Mattermost에 보낼 형식에 맞게 변환&lt;/li&gt;
&lt;li&gt;1에서 생성한 Mattermost url로 전송&lt;/li&gt;
&lt;li&gt;Mattermost 전송 형식 참고 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developers.mattermost.com/integrate/reference/message-attachments/&quot;&gt;https://developers.mattermost.com/integrate/reference/message-attachments/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7hxku/btsH7AD1JvI/o47UhuBuKcrD6kc2dEDNQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7hxku/btsH7AD1JvI/o47UhuBuKcrD6kc2dEDNQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7hxku/btsH7AD1JvI/o47UhuBuKcrD6kc2dEDNQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7hxku%2FbtsH7AD1JvI%2Fo47UhuBuKcrD6kc2dEDNQ1%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;1280&quot; height=&quot;636&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1718892308962&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import requests
import json

def lambda_handler(event, context):
    try:
        # Slack 메시지 전송
        send_slack_message(event)
        
        return {
            'statusCode': 200,
            'body': json.dumps('send message mm')
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps(f'error : {str(e)}')
        }
    
    
def send_slack_message(event):
    # mm url : 메터모스트 webhook url
    url = 'https://~~~~~'
    
    # github json 에서 필요 데이터 추출
    title = event[&quot;pull_request&quot;][&quot;title&quot;]
    pr_url = event[&quot;pull_request&quot;][&quot;html_url&quot;]
    user_id = event[&quot;pull_request&quot;][&quot;user&quot;][&quot;login&quot;]
    branch = event[&quot;pull_request&quot;][&quot;head&quot;][&quot;ref&quot;]
    task_url = f'https://app.clickup.com/t/25540965/{branch}'
    
    
    # 메세지 형식 지정
    text = f'Task: {title}\nMR: {pr_url}\nTASK: {task_url}\nUSER: {user_id}\n'
    message = {
        # &quot;text&quot;: title,
        &quot;attachments&quot;: [
            {
                # &quot;pretext&quot;: &quot;test&quot;,
                &quot;text&quot;:text
            }
        ]
    }
    
    # mm 에 메세지 전송
    headers = {'Content-Type': 'text/plain'}
    payload = {&quot;text&quot; : message}
    response = requests.post(url, headers=headers, data=json.dumps(message))
    
    # 응답 확인
    print('Response:', response.status_code)
    print(response.text)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-3. requests 계층 추가&lt;/h4&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;amp; 세팅 : &lt;a href=&quot;https://ottl-seo.tistory.com/181&quot;&gt;https://ottl-seo.tistory.com/181&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-4. 배포&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Deploy 버튼 클릭&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqo061/btsH7AjIQPB/TVpniJjiH8Kr4hTQsLPwLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqo061/btsH7AjIQPB/TVpniJjiH8Kr4hTQsLPwLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqo061/btsH7AjIQPB/TVpniJjiH8Kr4hTQsLPwLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdqo061%2FbtsH7AjIQPB%2FTVpniJjiH8Kr4hTQsLPwLk%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;1280&quot; height=&quot;639&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-5. (참고) 테스트&lt;/h4&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;Test &amp;gt; Configure test event&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lg9DM/btsH5AlGlG4/zKhAKEXDDBxqWSRzdx6xSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lg9DM/btsH5AlGlG4/zKhAKEXDDBxqWSRzdx6xSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lg9DM/btsH5AlGlG4/zKhAKEXDDBxqWSRzdx6xSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLg9DM%2FbtsH5AlGlG4%2FzKhAKEXDDBxqWSRzdx6xSK%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;1280&quot; height=&quot;643&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;이벤트 JSON에 github 결과 예시 추가 및 저장&lt;/li&gt;
&lt;li&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;테스트 데이터 가지고 오는 법 &lt;br /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 webhook 데이터를 긁어오거나 람다에서 event를 print 해서 사용해도 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 내용은 기존 webhook 데이터 긁어오는 방법&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;github의 Settings &amp;gt; Webhooks &amp;gt; 이미 만들어져 있던 webhook 클릭&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vx9wE/btsH7C2Txpa/Z9jD9bstMwZdOAEDJU0LZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vx9wE/btsH7C2Txpa/Z9jD9bstMwZdOAEDJU0LZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vx9wE/btsH7C2Txpa/Z9jD9bstMwZdOAEDJU0LZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVx9wE%2FbtsH7C2Txpa%2FZ9jD9bstMwZdOAEDJU0LZK%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;1280&quot; height=&quot;635&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;635&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;Content type 이 application/json 인 webhook 선택 필요&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;629&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lV8JE/btsH6AkFS20/kT6Qe4CWQOB7ktXyaxTVN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lV8JE/btsH6AkFS20/kT6Qe4CWQOB7ktXyaxTVN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lV8JE/btsH6AkFS20/kT6Qe4CWQOB7ktXyaxTVN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlV8JE%2FbtsH6AkFS20%2FkT6Qe4CWQOB7ktXyaxTVN1%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;1280&quot; height=&quot;629&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;629&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;우리가 원하는 pull request 관련 데이터의 Payload 복사&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y9xf1/btsH50KVJwF/qdCHYG52ofw0m6IuxY9IbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y9xf1/btsH50KVJwF/qdCHYG52ofw0m6IuxY9IbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y9xf1/btsH50KVJwF/qdCHYG52ofw0m6IuxY9IbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY9xf1%2FbtsH50KVJwF%2FqdCHYG52ofw0m6IuxY9IbK%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;1280&quot; height=&quot;640&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dETkYd/btsH65xJ2C2/aSoRtMnkXyq6SLRfrIHSa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dETkYd/btsH65xJ2C2/aSoRtMnkXyq6SLRfrIHSa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dETkYd/btsH65xJ2C2/aSoRtMnkXyq6SLRfrIHSa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdETkYd%2FbtsH65xJ2C2%2FaSoRtMnkXyq6SLRfrIHSa0%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;1280&quot; height=&quot;637&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Api Gateway API 생성&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. API 생성(API base url을 만드는 작업)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;aws api gateway &amp;gt; API 생성&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuq2Qh/btsH5IcG18z/jQRA8US0tnm0JW8qKyctGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuq2Qh/btsH5IcG18z/jQRA8US0tnm0JW8qKyctGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuq2Qh/btsH5IcG18z/jQRA8US0tnm0JW8qKyctGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcuq2Qh%2FbtsH5IcG18z%2FjQRA8US0tnm0JW8qKyctGk%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;1280&quot; height=&quot;619&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;REST&amp;nbsp;API&amp;nbsp;&amp;gt;&amp;nbsp;구축&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5i6yr/btsH7gsgVb6/CnPiztcD2KkhLYp8r5daE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5i6yr/btsH7gsgVb6/CnPiztcD2KkhLYp8r5daE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5i6yr/btsH7gsgVb6/CnPiztcD2KkhLYp8r5daE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5i6yr%2FbtsH7gsgVb6%2FCnPiztcD2KkhLYp8r5daE1%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;1280&quot; height=&quot;640&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;API 이름 작성 후 API 생성&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmnxcl/btsH6t0bQml/kpyHySIccHkJyYjJkxlMM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmnxcl/btsH6t0bQml/kpyHySIccHkJyYjJkxlMM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmnxcl/btsH6t0bQml/kpyHySIccHkJyYjJkxlMM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmnxcl%2FbtsH6t0bQml%2FkpyHySIccHkJyYjJkxlMM1%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;1280&quot; height=&quot;615&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. 리소스 생성(API 상세 url을 만드는 작업)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5G7l1/btsH6SSYoxK/pjERhTyd8DqVqMofCzqqX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5G7l1/btsH6SSYoxK/pjERhTyd8DqVqMofCzqqX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5G7l1/btsH6SSYoxK/pjERhTyd8DqVqMofCzqqX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5G7l1%2FbtsH6SSYoxK%2FpjERhTyd8DqVqMofCzqqX1%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;1280&quot; height=&quot;617&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;617&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스 이름 작성 후 리소스 생성 &lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2envj/btsH6Nxmfvg/kfaE5Gk1mOGEqseVWqDSlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2envj/btsH6Nxmfvg/kfaE5Gk1mOGEqseVWqDSlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2envj/btsH6Nxmfvg/kfaE5Gk1mOGEqseVWqDSlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2envj%2FbtsH6Nxmfvg%2FkfaE5Gk1mOGEqseVWqDSlK%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;1280&quot; height=&quot;615&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-3. 메서드 생성(GET, POST 등을 결정)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드 생성&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbuAEV/btsH7ndSCix/fvdWQlOuKHq5Av4fzbsXfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbuAEV/btsH7ndSCix/fvdWQlOuKHq5Av4fzbsXfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbuAEV/btsH7ndSCix/fvdWQlOuKHq5Av4fzbsXfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbuAEV%2FbtsH7ndSCix%2FfvdWQlOuKHq5Av4fzbsXfK%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;1280&quot; height=&quot;618&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;/figure&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;메서드 유형 : POST(github에서 POST 로 전송해줌)&lt;/li&gt;
&lt;li&gt;통합 유형 : Lambda 함수&lt;/li&gt;
&lt;li&gt;Lambda 함수 : 2에서 생성한 lambda 함수 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;메서드 생성 버튼 클릭&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wT2ic/btsH5Oqus6d/5DBVsncxkNWTUPnKb7POmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wT2ic/btsH5Oqus6d/5DBVsncxkNWTUPnKb7POmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wT2ic/btsH5Oqus6d/5DBVsncxkNWTUPnKb7POmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwT2ic%2FbtsH5Oqus6d%2F5DBVsncxkNWTUPnKb7POmk%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;1280&quot; height=&quot;634&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-4. 외부에서 접근 가능하도록 API 배포&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 배포&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blYFvN/btsH5A0hM4C/uTal6MtmiTFpfurKWQUKr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blYFvN/btsH5A0hM4C/uTal6MtmiTFpfurKWQUKr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blYFvN/btsH5A0hM4C/uTal6MtmiTFpfurKWQUKr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYFvN%2FbtsH5A0hM4C%2FuTal6MtmiTFpfurKWQUKr0%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;1280&quot; height=&quot;638&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;스테이지 : prod(보통은 개발은 dev, 운영은 prod를 사용함 여기서는 운영 개발 상관없기 때문에 그냥 prod로 함)&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beoFsP/btsH6Bw7tUB/yMLDaAHubGEyIEwdkmGFCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beoFsP/btsH6Bw7tUB/yMLDaAHubGEyIEwdkmGFCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beoFsP/btsH6Bw7tUB/yMLDaAHubGEyIEwdkmGFCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeoFsP%2FbtsH6Bw7tUB%2FyMLDaAHubGEyIEwdkmGFCk%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;1280&quot; height=&quot;639&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;URL 호출 : pull reqeust 발생 시 github 에서 호출하는 api&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uWsz8/btsH7BQskSo/cI1VFDIEv3sMkjmh2LvaWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uWsz8/btsH7BQskSo/cI1VFDIEv3sMkjmh2LvaWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uWsz8/btsH7BQskSo/cI1VFDIEv3sMkjmh2LvaWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuWsz8%2FbtsH7BQskSo%2FcI1VFDIEv3sMkjmh2LvaWk%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;1280&quot; height=&quot;635&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;635&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(참고) 로그 확인 방법&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;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI6E9U/btsH5VCTaZD/QEoq3L6j1RP6pGMkQKGUGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI6E9U/btsH5VCTaZD/QEoq3L6j1RP6pGMkQKGUGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI6E9U/btsH5VCTaZD/QEoq3L6j1RP6pGMkQKGUGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI6E9U%2FbtsH5VCTaZD%2FQEoq3L6j1RP6pGMkQKGUGK%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;1280&quot; height=&quot;636&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;하단 CloudWatch Logs &amp;gt; Recentinvocations &lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;629&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0nuJR/btsH6CbNEg5/m84dfjZuI3PgCDDhFdFEG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0nuJR/btsH6CbNEg5/m84dfjZuI3PgCDDhFdFEG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0nuJR/btsH6CbNEg5/m84dfjZuI3PgCDDhFdFEG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0nuJR%2FbtsH6CbNEg5%2Fm84dfjZuI3PgCDDhFdFEG0%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;1280&quot; height=&quot;629&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;629&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;예시 &lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;611&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB8FOm/btsH6AdX2IG/XFmskXvzKqLRGMqcxc0ng0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB8FOm/btsH6AdX2IG/XFmskXvzKqLRGMqcxc0ng0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB8FOm/btsH6AdX2IG/XFmskXvzKqLRGMqcxc0ng0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB8FOm%2FbtsH6AdX2IG%2FXFmskXvzKqLRGMqcxc0ng0%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;1280&quot; height=&quot;611&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;611&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. github Webhooks 추가&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Settings &amp;gt; Webhooks &amp;gt; Add webhook&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQAatA/btsH6vwVH2E/xYgiyiFCtVZQkaFy67DvV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQAatA/btsH6vwVH2E/xYgiyiFCtVZQkaFy67DvV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQAatA/btsH6vwVH2E/xYgiyiFCtVZQkaFy67DvV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQAatA%2FbtsH6vwVH2E%2FxYgiyiFCtVZQkaFy67DvV1%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;1280&quot; height=&quot;638&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;API Gateway에서 생성한 api url을 입력 &amp;amp; &lt;b&gt;&lt;span style=&quot;color: #eb5757;&quot; data-token-index=&quot;1&quot;&gt;Content type : application/json&lt;/span&gt; &lt;/b&gt;선택&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bspmw1/btsH5Nyhi6v/hjKqaRBVdyt0FnZiOOV8Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bspmw1/btsH5Nyhi6v/hjKqaRBVdyt0FnZiOOV8Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bspmw1/btsH5Nyhi6v/hjKqaRBVdyt0FnZiOOV8Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbspmw1%2FbtsH5Nyhi6v%2FhjKqaRBVdyt0FnZiOOV8Ek%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;1280&quot; height=&quot;639&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Which events would you like to trigger this webhook? &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; Let me select individual events. 선택&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하위 내용에서 Pull Requests 선택(pull request 관련 작업이 있을 때만 알람을 전송)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하단 Add webhook 클릭&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1ZAVD/btsH51bZ7hb/9CvF76qEKwzEv5Y9rKiXLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1ZAVD/btsH51bZ7hb/9CvF76qEKwzEv5Y9rKiXLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1ZAVD/btsH51bZ7hb/9CvF76qEKwzEv5Y9rKiXLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1ZAVD%2FbtsH51bZ7hb%2F9CvF76qEKwzEv5Y9rKiXLk%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;1280&quot; height=&quot;636&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&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;1280&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b15WIK/btsH7El6ZoI/rY9nXlOW9hzqVkAeGejGLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b15WIK/btsH7El6ZoI/rY9nXlOW9hzqVkAeGejGLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b15WIK/btsH7El6ZoI/rY9nXlOW9hzqVkAeGejGLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb15WIK%2FbtsH7El6ZoI%2FrY9nXlOW9hzqVkAeGejGLK%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;1280&quot; height=&quot;636&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;636&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;1280&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPvv3Z/btsH7BXeQ0P/pe847XAvUzj6KVGvkDRAQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPvv3Z/btsH7BXeQ0P/pe847XAvUzj6KVGvkDRAQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPvv3Z/btsH7BXeQ0P/pe847XAvUzj6KVGvkDRAQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPvv3Z%2FbtsH7BXeQ0P%2Fpe847XAvUzj6KVGvkDRAQk%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;1280&quot; height=&quot;638&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;정상적으로 생성 시 아래와 같이 pull_request 만 대상임을 알 수 있음 &lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xzAba/btsH7AKOyOa/0LW4sKJ5TbjnuPsymOP83K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xzAba/btsH7AKOyOa/0LW4sKJ5TbjnuPsymOP83K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xzAba/btsH7AKOyOa/0LW4sKJ5TbjnuPsymOP83K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxzAba%2FbtsH7AKOyOa%2F0LW4sKJ5TbjnuPsymOP83K%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;1280&quot; height=&quot;634&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;실제로 전송한 데이터와 결과를 &lt;b&gt;&lt;span style=&quot;color: #eb5757;&quot; data-token-index=&quot;1&quot;&gt;Recent Deliveries에서&lt;/span&gt; &lt;/b&gt; 확인 가능&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pQ1ut/btsH7f7Zu41/x0bZ00XKiqHb7KohKpbtQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pQ1ut/btsH7f7Zu41/x0bZ00XKiqHb7KohKpbtQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pQ1ut/btsH7f7Zu41/x0bZ00XKiqHb7KohKpbtQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpQ1ut%2FbtsH7f7Zu41%2Fx0bZ00XKiqHb7KohKpbtQk%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;1280&quot; height=&quot;634&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태가 open 인 경우 초록, closed 인 경우 보라&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd7eDd/btsH6fOCMvZ/ge4Vitpu3B4UT338KbTOJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd7eDd/btsH6fOCMvZ/ge4Vitpu3B4UT338KbTOJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd7eDd/btsH6fOCMvZ/ge4Vitpu3B4UT338KbTOJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd7eDd%2FbtsH6fOCMvZ%2Fge4Vitpu3B4UT338KbTOJK%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;1280&quot; height=&quot;659&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;참고&lt;br /&gt;&lt;br /&gt;https://velog.io/@parksangwon0610/Slack-Github-Webhook을-이용한-슬랙-PR-자동-Mention#api-gateway-를-사용하여-람다-호출&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>API Gateway</category>
      <category>AWS</category>
      <category>github</category>
      <category>mattermost</category>
      <category>PR</category>
      <category>pull request</category>
      <category>알림</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/85</guid>
      <comments>https://rangerang.tistory.com/85#entry85comment</comments>
      <pubDate>Thu, 20 Jun 2024 23:30:13 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Boot] Multiple Datasource with Clickhouse</title>
      <link>https://rangerang.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt; 최근에 DL(Data Lake) 데이터 저장소를 Logpresso에서 ClickHouse(+Nifi)로 전환하는 작업을 진행했다. 이에 따라 API 서버(Spring Boot)에서도 Logpresso에서 가지고 오던 데이터를 ClickHouse에서 가져오도록 전환을 진행했다. 이를 위해 하나의 프로젝트에 다중 데이터소스(pg, ClickHouse)를 연결해야 했다. 이 글은 그 내용을 다룬다. &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. build.gradle 에 clickhouse jdbc 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClickHouse JDBC를 사용하기 위해 &lt;b&gt;build.gradle&lt;/b&gt;에 의존성을 추가해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnsBLX/btsH0jRlaFb/6TjK35h0TTX8UyiTmbr7Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnsBLX/btsH0jRlaFb/6TjK35h0TTX8UyiTmbr7Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnsBLX/btsH0jRlaFb/6TjK35h0TTX8UyiTmbr7Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnsBLX%2FbtsH0jRlaFb%2F6TjK35h0TTX8UyiTmbr7Tk%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;2000&quot; height=&quot;239&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. yml 에 clickhouse 접속 정보 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.yml 파일에 ClickHouse 접속 정보를 추가해준다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;datasource 위의 postgres depth 추가&lt;/li&gt;
&lt;li&gt;clickhouse 접속 정보 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSM5Sr/btsHZXOE6bN/ZrkzpX4z7k5IeKL72zk8Gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSM5Sr/btsHZXOE6bN/ZrkzpX4z7k5IeKL72zk8Gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSM5Sr/btsHZXOE6bN/ZrkzpX4z7k5IeKL72zk8Gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSM5Sr%2FbtsHZXOE6bN%2FZrkzpX4z7k5IeKL72zk8Gk%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;2000&quot; height=&quot;1488&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Configuration 파일 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 데이터베이스를 연결하기 위한 설정 파일을 작성해준다. 데이터베이스가 하나일 때는 Spring Boot에서 자동으로 설정해주지만, 두 개 이상일 때부터는 수동 설정이 필요하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. Postgres Configuration&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 기존에 사용하던 Postgres의 설정부터 해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우리는 디폴트로 Postgres를 사용하기 때문에 @Primary 어노테이션을 붙여줬다.&lt;/li&gt;
&lt;li&gt;Postgres는 MyBatis와 JPA를 같이 사용하고 있기 때문에 두 설정을 모두 해줘야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클래스 어노테이션 설정&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; @EnableJpaRepositories&lt;/b&gt;: JPA 리포지토리를 스캔하고 Spring 컨텍스트에 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;basePackages&lt;/b&gt;: JPA 리포지토리 인터페이스가 위치한 패키지를 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;entityManagerFactoryRef&lt;/b&gt;: 사용할 EntityManagerFactory의 빈 이름을 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;transactionManagerRef&lt;/b&gt;: 사용할 TransactionManager의 빈 이름을 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt; @MapperScan&lt;/b&gt;: MyBatis 매퍼 인터페이스를 스캔하고 Spring 컨텍스트에 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;sqlSessionFactoryRef&lt;/b&gt;: 사용할 SqlSessionFactory의 빈 이름을 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;basePackages&lt;/b&gt;: MyBatis &lt;b&gt;매퍼 인터페이스&lt;/b&gt;가 위치한 패키지를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1718547890386&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableJpaAuditing
@EnableJpaRepositories( // jpa
        // repository 위치
        basePackages = {&quot;repository 위치&quot;, &quot;여러개를&quot;, &quot;적을수도&quot;, &quot;있음&quot;},
        entityManagerFactoryRef = &quot;pgEntityManagerFactory&quot;,	// entityManagerFactory의 이름
        transactionManagerRef = &quot;pgTransactionManager&quot;		// transactionManager의 이름
)
@MapperScan(    // mybatis
        sqlSessionFactoryRef = &quot;sqlSessionFactory&quot;,
        // mapper 클래스 위치
        basePackages = {&quot;mapper 클래스 위치&quot;, &quot;여러개를&quot;, &quot;적을수도&quot;, &quot;있음&quot;}   
)
public class PostgresDataSourceConfiguration {&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;2. 데이터 소스 설정&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;dataSourceProperties()&lt;/b&gt;: DataSourceProperties 빈을 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;spring.postgres.datasource&lt;/b&gt;로 시작하는 설정을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dataSource()&lt;/b&gt;: HikariDataSource 빈을 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;spring.postgres.datasource.hikari&lt;/b&gt;로 시작하는 설정을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1718547958565&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Primary
    @Bean
    @ConfigurationProperties(&quot;spring.postgres.datasource&quot;)
    public DataSourceProperties dataSourceProperties() {    // datasource 관련 설정
        return new DataSourceProperties();
    }

    @Primary
    @Bean
    @ConfigurationProperties(&quot;spring.postgres.datasource.hikari&quot;)
    public HikariDataSource dataSource(DataSourceProperties properties) {   // hikari 커넥션 풀 관련 설정
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }&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;3. JPA 설정&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;pgEntityManagerFactory()&lt;/b&gt;: JPA 엔티티 매니저 팩토리 빈을 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;packages: &lt;b&gt;JPA 엔티티&lt;/b&gt; 클래스가 위치한 패키지를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pgTransactionManager()&lt;/b&gt;: JPA 트랜잭션 매니저 빈을 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1718547995902&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Primary
    @Bean(name = &quot;pgEntityManagerFactory&quot;)
    public LocalContainerEntityManagerFactoryBean pgEntityManagerFactory(EntityManagerFactoryBuilder builder,
                                                                         DataSource dataSource,
                                                                         HibernateProperties hibernateProperties,
                                                                         ConfigurableListableBeanFactory beanFactory) {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = builder
                .dataSource(dataSource)
                .packages(&quot;entity 위치&quot; // entity 위치
                        , &quot;여러개&quot;
                        , &quot;작성&quot;
                        , &quot;가능&quot;)
                .properties(hibernateProperties.determineHibernateProperties(
                        new HashMap&amp;lt;&amp;gt;(),
                        new HibernateSettings()))
                .build();
        entityManagerFactoryBean.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
        return entityManagerFactoryBean;
    }

    @Primary
    @Bean(name = &quot;pgTransactionManager&quot;)
    public PlatformTransactionManager pgTransactionManager(EntityManagerFactory pgEntityManagerFactory) {
        return new JpaTransactionManager(pgEntityManagerFactory);
    }&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;4. MyBatis 설정&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;sqlSessionFactory()&lt;/b&gt;: MyBatis SQL 세션 팩토리 빈을 생성&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;setMapperLocations&lt;/b&gt;: MyBatis 매퍼 XML 파일의 위치를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;sqlSessionTemplate()&lt;/b&gt;: MyBatis SQL 세션 템플릿 빈을 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1718548013745&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Primary
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setMapperLocations(applicationContext.getResources(&quot;classpath:mybatis/postgres/**/*.xml&quot;));	// xml 위치
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Primary
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);

    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 코드는 아래와 같다&lt;/p&gt;
&lt;pre id=&quot;code_1718546495909&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableJpaAuditing
@EnableJpaRepositories( // jpa
        // repository 위치
        basePackages = {&quot;repository 위치&quot;, &quot;여러개를&quot;, &quot;적을수도&quot;, &quot;있음&quot;},
        entityManagerFactoryRef = &quot;pgEntityManagerFactory&quot;,	// entityManagerFactory의 이름
        transactionManagerRef = &quot;pgTransactionManager&quot;		// transactionManager의 이름
)
@MapperScan(    // mybatis
        sqlSessionFactoryRef = &quot;sqlSessionFactory&quot;,
        // mapper 클래스 위치
        basePackages = {&quot;mapper 클래스 위치&quot;, &quot;여러개를&quot;, &quot;적을수도&quot;, &quot;있음&quot;}   
)
public class PostgresDataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(&quot;spring.postgres.datasource&quot;)
    public DataSourceProperties dataSourceProperties() {    // datasource 관련 설정
        return new DataSourceProperties();
    }

    @Primary
    @Bean
    @ConfigurationProperties(&quot;spring.postgres.datasource.hikari&quot;)
    public HikariDataSource dataSource(DataSourceProperties properties) {   // hikari 커넥션 풀 관련 설정
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }


    /////////////////////// jpa ///////////////////////
    @Primary
    @Bean(name = &quot;pgEntityManagerFactory&quot;)
    public LocalContainerEntityManagerFactoryBean pgEntityManagerFactory(EntityManagerFactoryBuilder builder,
                                                                         DataSource dataSource,
                                                                         HibernateProperties hibernateProperties,
                                                                         ConfigurableListableBeanFactory beanFactory) {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = builder
                .dataSource(dataSource)
                .packages(&quot;entity 위치&quot; // entity 위치
                        , &quot;여러개&quot;
                        , &quot;작성&quot;
                        , &quot;가능&quot;)
                .properties(hibernateProperties.determineHibernateProperties(
                        new HashMap&amp;lt;&amp;gt;(),
                        new HibernateSettings()))
                .build();
        entityManagerFactoryBean.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
        return entityManagerFactoryBean;
    }

    @Primary
    @Bean(name = &quot;pgTransactionManager&quot;)
    public PlatformTransactionManager pgTransactionManager(EntityManagerFactory pgEntityManagerFactory) {
        return new JpaTransactionManager(pgEntityManagerFactory);
    }

    /////////////////////// mybatis ///////////////////////
    @Primary
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setMapperLocations(applicationContext.getResources(&quot;classpath:mybatis/postgres/**/*.xml&quot;));	// xml 위치
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Primary
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);

    }

}&lt;/code&gt;&lt;/pre&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 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3-2. Clickhouse Configuration&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postgres 수동 설정이 정상적으로 끝났다면 이제 ClickHouse 설정을 해보자. ClickHouse에서는 JPA를 사용하지 않기 때문에 MyBatis에 대한 설정만 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 설정이 Postgres 설정과 같고, 자바 클래스에서는 카멜케이스를 사용하고 있어 아래 설정을 추가해줬다. &lt;br /&gt;&lt;b&gt; configuration.setMapUnderscoreToCamelCase(true) : &lt;/b&gt;데이터베이스의 언더스코어(_)가 포함된 컬럼명을 자바의 카멜 케이스(camelCase) 필드명으로 자동 변환하도록 설정.&lt;/p&gt;
&lt;pre id=&quot;code_1718548099396&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@MapperScan(
        sqlSessionFactoryRef = &quot;chSqlSessionFactory&quot;,
        basePackages = {&quot;com.company.mapper.clickhouse&quot;}   // mapper 클래스 위치
)
public class ClickhouseDataSource {

    @Bean(name = &quot;chDataSourceProperties&quot;)
    @ConfigurationProperties(&quot;spring.clickhouse.datasource&quot;)
    public DataSourceProperties chDataSourceProperties() {    // datasource 관련 설정
        return new DataSourceProperties();
    }

    @Bean(name = &quot;chDataSource&quot;)
    @ConfigurationProperties(&quot;spring.clickhouse.datasource.hikari&quot;)
    public HikariDataSource chDataSource(@Qualifier(&quot;chDataSourceProperties&quot;) DataSourceProperties properties) {   // hikari 커넥션 풀 관련 설정
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    /////////////////////// mybatis ///////////////////////
    @Bean(name = &quot;chSqlSessionFactory&quot;)
    public SqlSessionFactory sessionFactory(@Qualifier(&quot;chDataSource&quot;) DataSource datasource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setMapperLocations(applicationContext.getResources(&quot;classpath:mybatis/clickhouse/**/*.xml&quot;));  // xml 위치 설정
        bean.setDataSource(datasource);

        // MyBatis Configuration 생성
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true); // underscore를 camelCase로 변환 설정
        bean.setConfiguration(configuration); // 설정 적용

        return bean.getObject();
    }

    @Bean(name = &quot;chSessionTemplate&quot;)
    public SqlSessionTemplate secondSqlSessionTemplate(@Qualifier(&quot;chSqlSessionFactory&quot;) SqlSessionFactory chSqlSessionFactory) {
        return new SqlSessionTemplate(chSqlSessionFactory);
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; 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;4. clickhouse 쿼리 실행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 설정이 끝났다면 거의 다 끝이다! 이제 쿼리를 직접 날려보자. 사용 방법은 기존 MyBatis 사용 방법과 동일하고, 인터페이스와 XML의 위치만 Configuration에서 설정해준 위치로 맞춰주면 된다.&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-filename=&quot;blob&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3HLjt/btsH0zTMZOh/eDLLSjYiSwSWG9fu9RF4KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3HLjt/btsH0zTMZOh/eDLLSjYiSwSWG9fu9RF4KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3HLjt/btsH0zTMZOh/eDLLSjYiSwSWG9fu9RF4KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3HLjt%2FbtsH0zTMZOh%2FeDLLSjYiSwSWG9fu9RF4KK%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;2000&quot; height=&quot;1450&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1040&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sbRjs/btsH0CbXkg4/TXv48Golpbg9mccxKwdZq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sbRjs/btsH0CbXkg4/TXv48Golpbg9mccxKwdZq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sbRjs/btsH0CbXkg4/TXv48Golpbg9mccxKwdZq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsbRjs%2FbtsH0CbXkg4%2FTXv48Golpbg9mccxKwdZq0%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;2000&quot; height=&quot;1040&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1040&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설정하면서 잘 안됐던 부분&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 문제 1. clickhouse mybatis mapper 를 못찾는 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 잘못된 설정(Postgres)을 연결하고 있었다. ClickHouse 설정의 경우 아래와 같이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Qualifier&lt;/b&gt;&lt;/span&gt; 키워드로 명시적으로 어떤 빈을 주입받을지 설정해줬다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bem1DE/btsHZVKb6eK/x0WimvdOPnwX2K5u6kLQyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bem1DE/btsHZVKb6eK/x0WimvdOPnwX2K5u6kLQyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bem1DE/btsHZVKb6eK/x0WimvdOPnwX2K5u6kLQyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbem1DE%2FbtsHZVKb6eK%2Fx0WimvdOPnwX2K5u6kLQyk%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;2000&quot; height=&quot;1383&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1383&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. yml 에 설정한 커넥션 풀 개수가 적용되지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 URL 관련 설정만 있는 &lt;b&gt;dataSourceProperties()&lt;/b&gt;만 정의했었다. 쿼리의 실행은 정상적으로 됐는데 문제는 yml에 설정한 커넥션 풀 개수가 제대로 적용되지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인해보니 &lt;b&gt;dataSourceProperties()&lt;/b&gt; 설정은 &lt;b&gt;spring.postgres.datasource&lt;/b&gt;에 있는 설정만 가지고 와서 그 하위에 있는 &lt;b&gt;spring.postgres.datasource.&lt;span style=&quot;color: #ee2323;&quot;&gt;hikari&lt;/span&gt;&lt;/b&gt; 설정은 불러오지 못한 것이었다. 그래서 데이터소스 설정을 먼저 한 후 그 설정을 받아 추가로 Hikari에 대한 설정을 해주는 방식으로 해결했다.&lt;/p&gt;
&lt;pre id=&quot;code_1718549284721&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// as-is
//    @Primary
//    @Bean
//    @ConfigurationProperties(prefix = &quot;spring.postgres.datasource&quot;) 	// application.properties에서 사용한 이름
//    public DataSource dataSource() {
//        return DataSourceBuilder.create().build();
//    }

// to-be
    @Bean
    @Primary
    @ConfigurationProperties(&quot;spring.postgres.datasource&quot;)
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean
    @ConfigurationProperties(&quot;spring.postgres.datasource.hikari&quot;)
    public HikariDataSource dataSource(DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;div&gt;
&lt;div data-message-id=&quot;f37fd116-d785-4950-befa-81611b808810&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이전에 멀티 데이터소스 설정 내용을 포스팅한 적이 있는데, 그때는 스프링을 해본 지 한 달도 안 된 때여서 깊이 이해하지 못했던 것 같다. 이번 기회에 다시 설정해보면서 조금 더 이해할 수 있었다. 3년 전과 지금을 비교해보면 당시에는 MyBatis의 비중이 컸지만, 이제는 대부분의 쿼리를 JPA로 전환 완료했다. 또한, JPA 엔티티의 위치도 중구난방이었는데 하나의 패키지로 정리했고, 멀티 프로젝트를 도입하는 등 그때보다 우리 프로젝트가 많이 성장한 것 같아 뿌듯하다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rangerang.tistory.com/70&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://rangerang.tistory.com/70&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1718545872454&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;[spring boot] mybatis + jpa multi datasource 설정하기&quot; data-og-description=&quot;스프링 부트 프로젝트를 개발하며 2개의 데이터베이스를 연결해야하는 이슈가 생겼다. 기존 프로젝트는 mybatis와 jpa를 섞어서 사용하는 구조이고, multi datasource를 설정하기 위해서는 수동설정이 &quot; data-og-host=&quot;rangerang.tistory.com&quot; data-og-source-url=&quot;https://rangerang.tistory.com/70&quot; data-og-url=&quot;https://rangerang.tistory.com/70&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dduIOR/hyWlmzjomK/z62iMJO2QuM7LKkfGQmre0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cHM8ql/hyWoJTU2IX/cuvml8gKJzjPZyxZOSKtt0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://rangerang.tistory.com/70&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://rangerang.tistory.com/70&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dduIOR/hyWlmzjomK/z62iMJO2QuM7LKkfGQmre0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cHM8ql/hyWoJTU2IX/cuvml8gKJzjPZyxZOSKtt0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;[spring boot] mybatis + jpa multi datasource 설정하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스프링 부트 프로젝트를 개발하며 2개의 데이터베이스를 연결해야하는 이슈가 생겼다. 기존 프로젝트는 mybatis와 jpa를 섞어서 사용하는 구조이고, multi datasource를 설정하기 위해서는 수동설정이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;rangerang.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;참고&lt;br /&gt;&lt;br /&gt;https://clickhouse.com/docs/en/integrations/java&lt;br /&gt;https://jsijsi99.tistory.com/9&lt;br /&gt;https://velog.io/@ghkvud2/Multiple-DataSource-적용하기&lt;br /&gt;https://velog.io/@dongvelop/Spring-Boot-Hikari-CP-커스텀으로-성능-최적화하기&lt;br /&gt;https://github.com/ClickHouse/clickhouse-java&lt;br /&gt;https://github.com/lewis-ing/clickhouse-native/tree/master/src&lt;br /&gt;https://clickhouse.com/docs/en/interfaces/jdbc&lt;/blockquote&gt;</description>
      <category>ㄴspring boot</category>
      <category>db 두개</category>
      <category>Multi Datasource</category>
      <category>multiple datasource</category>
      <category>spring boot</category>
      <category>다중 데이터소스</category>
      <category>스프링 부트</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/83</guid>
      <comments>https://rangerang.tistory.com/83#entry83comment</comments>
      <pubDate>Mon, 17 Jun 2024 00:03:05 +0900</pubDate>
    </item>
    <item>
      <title>nexus3 파일 보관 주기 설정</title>
      <link>https://rangerang.tistory.com/82</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리 팀에서는 브랜치에 push 될 때 마다 jar를 넥서스에 올려놓는 형식으로 사용중이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넥서스를 설치한 이후 보관주기를 설정한적이 없어 서버용량의 99% 를 사용중이었고 nexus 의 기능을 이용해 cleanup 설정을 걸어줬다&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. Cleanup Policies 설정&lt;/h3&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;Nexus Repository Manager에 로그인한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Administration &amp;gt; Repository &amp;gt; Cleanup Policies&lt;/b&gt;로 이동한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1IsLg/btsH0ijTXXq/kwAJCKkTfVMo1yIL0VOhyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1IsLg/btsH0ijTXXq/kwAJCKkTfVMo1yIL0VOhyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1IsLg/btsH0ijTXXq/kwAJCKkTfVMo1yIL0VOhyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1IsLg%2FbtsH0ijTXXq%2FkwAJCKkTfVMo1yIL0VOhyK%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;1919&quot; height=&quot;926&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;926&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;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적인 정보들을 적어준다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;919&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n4GCb/btsH0C974vv/Ixyvi8Q7VnyMhrshqxSzu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n4GCb/btsH0C974vv/Ixyvi8Q7VnyMhrshqxSzu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n4GCb/btsH0C974vv/Ixyvi8Q7VnyMhrshqxSzu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn4GCb%2FbtsH0C974vv%2FIxyvi8Q7VnyMhrshqxSzu0%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;1918&quot; height=&quot;919&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;919&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Cleanup Criteria 설정&lt;/b&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;b&gt;Component Age&lt;/b&gt;: 게시일로부터 설정한 날짜가 지났을 경우&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Component Usage&lt;/b&gt;: 설정한 날짜 동안 다운로드되지 않았을 경우&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Asset Name Matcher&lt;/b&gt;: 삭제할 대상 이름의 정규식 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AnJos/btsH0A5Hntw/UurkwVhJk0X3kCj4dSmwh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AnJos/btsH0A5Hntw/UurkwVhJk0X3kCj4dSmwh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AnJos/btsH0A5Hntw/UurkwVhJk0X3kCj4dSmwh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAnJos%2FbtsH0A5Hntw%2FUurkwVhJk0X3kCj4dSmwh1%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;892&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;892&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;b&gt;Preview&lt;/b&gt;를 클릭하여 삭제 대상 파일을 확인한다&lt;br /&gt;대상이 맞다면 &lt;b&gt;Save&lt;/b&gt;를 눌러 저장한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;923&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDKkuj/btsH0mzP05B/KiDkVjNeT0CaFLEW2aqVjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDKkuj/btsH0mzP05B/KiDkVjNeT0CaFLEW2aqVjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDKkuj/btsH0mzP05B/KiDkVjNeT0CaFLEW2aqVjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDKkuj%2FbtsH0mzP05B%2FKiDkVjNeT0CaFLEW2aqVjk%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;1915&quot; height=&quot;923&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;923&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 정책을 레포지토리에 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Repositories 에 들어가 원하는 레포지토리를 선택해준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tfyl6/btsH0zln1kU/Mhiw3jbt5PwD3HVuRCcc6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tfyl6/btsH0zln1kU/Mhiw3jbt5PwD3HVuRCcc6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tfyl6/btsH0zln1kU/Mhiw3jbt5PwD3HVuRCcc6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTfyl6%2FbtsH0zln1kU%2FMhiw3jbt5PwD3HVuRCcc6K%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;456&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;456&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;b&gt;Cleanup Policies&lt;/b&gt;를 선택하여 원하는 정책을 설정하고 저장한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCWZqF/btsHZ6KUw8p/SGgjdAKZMkuK6NfB54vlZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCWZqF/btsHZ6KUw8p/SGgjdAKZMkuK6NfB54vlZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCWZqF/btsHZ6KUw8p/SGgjdAKZMkuK6NfB54vlZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCWZqF%2FbtsHZ6KUw8p%2FSGgjdAKZMkuK6NfB54vlZ1%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;1918&quot; height=&quot;920&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1918&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;여기까지 설정하면 내부에서 자동으로 스케쥴링이 돌면서 대상들을 정리한다&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. Cleanup Policies 수동 실행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 용량이 99%인 상황에서는 설정한 정책이 실행되길 기다릴수가 없었다 바로 실행하는 방법을 알아보자&lt;br /&gt;System &amp;gt; Tasks 에 들어가 Cleanup Service 를 선택해준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;916&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beDuUO/btsHZxh2Q0q/aEbrkrLxS6yUvCcVjemYv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beDuUO/btsHZxh2Q0q/aEbrkrLxS6yUvCcVjemYv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beDuUO/btsHZxh2Q0q/aEbrkrLxS6yUvCcVjemYv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeDuUO%2FbtsHZxh2Q0q%2FaEbrkrLxS6yUvCcVjemYv1%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;916&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;916&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;상단의 &lt;b&gt;Run&lt;/b&gt; 버튼을 눌러 바로 실행한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;919&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UYoQV/btsHZyOIMmx/i5XzPgNRj7hG7oECQ0EI61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UYoQV/btsHZyOIMmx/i5XzPgNRj7hG7oECQ0EI61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UYoQV/btsHZyOIMmx/i5XzPgNRj7hG7oECQ0EI61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUYoQV%2FbtsHZyOIMmx%2Fi5XzPgNRj7hG7oECQ0EI61%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;919&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;919&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3k109/btsH079Lugu/wzlBTOLqHczYmjbElBIC9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3k109/btsH079Lugu/wzlBTOLqHczYmjbElBIC9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3k109/btsH079Lugu/wzlBTOLqHczYmjbElBIC9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3k109%2FbtsH079Lugu%2FwzlBTOLqHczYmjbElBIC9K%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;1915&quot; height=&quot;559&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;559&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;실제로 실행된 로그는 Support &amp;gt; _Logs 에서 확인할 수 있다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4c35m/btsH0vKdKXL/VzX7ZVpM8YQnNzsLzBrMH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4c35m/btsH0vKdKXL/VzX7ZVpM8YQnNzsLzBrMH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4c35m/btsH0vKdKXL/VzX7ZVpM8YQnNzsLzBrMH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4c35m%2FbtsH0vKdKXL%2FVzX7ZVpM8YQnNzsLzBrMH1%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;912&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;912&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wsry9/btsH1iQTEEF/L2wJKywlimvGKpdp2thKV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wsry9/btsH1iQTEEF/L2wJKywlimvGKpdp2thKV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wsry9/btsH1iQTEEF/L2wJKywlimvGKpdp2thKV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWsry9%2FbtsH1iQTEEF%2FL2wJKywlimvGKpdp2thKV0%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;884&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;884&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7evu7/btsH0hZJELQ/TGRZoBlNmLnnXkXkHE0wG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7evu7/btsH0hZJELQ/TGRZoBlNmLnnXkXkHE0wG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7evu7/btsH0hZJELQ/TGRZoBlNmLnnXkXkHE0wG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7evu7%2FbtsH0hZJELQ%2FTGRZoBlNmLnnXkXkHE0wG1%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;812&quot; height=&quot;410&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 찾아봤더니 공식 문서에 아래와 같은 내용이 있다&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;You can create cleanup policies and assign them to one or more repositories so that a scheduled cleanup task (Admin - Cleanup repositories using their associated policies) will automatically soft delete artifacts from the repository. A soft delete means that artifacts are only marked for removal and not yet deleted from the disk. Disk space is not reclaimed until the Admin - Compact blob store task runs.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 내용을 보면 cleanup policies 는 단지 어떤 파일이 삭제될 지 표시만하고(soft delete) 실제로는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Compact blob store task&lt;/b&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;4. Compact Blob Store Task 실행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 Compact blob store 하는 방법을 알아보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Tasks &amp;gt; Create Task&lt;/b&gt; 로 태스크를 생성해주자(사진에는 이미 생성된 태스크가 있는데 무시하자..)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;919&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dt9mcI/btsH0ObGysA/FM9kyIzlR5yqiXKNPSzg2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dt9mcI/btsH0ObGysA/FM9kyIzlR5yqiXKNPSzg2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dt9mcI/btsH0ObGysA/FM9kyIzlR5yqiXKNPSzg2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdt9mcI%2FbtsH0ObGysA%2FFM9kyIzlR5yqiXKNPSzg2K%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;919&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;919&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;compact&lt;/b&gt; 라고 검색하면 &lt;b&gt;Admin-Compact blob store&lt;/b&gt; 태스크가 검색된다&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;1916&quot; data-origin-height=&quot;918&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckP2Nr/btsH0M51ciu/I1pMCAzD0BGnI9a7FUSVD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckP2Nr/btsH0M51ciu/I1pMCAzD0BGnI9a7FUSVD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckP2Nr/btsH0M51ciu/I1pMCAzD0BGnI9a7FUSVD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckP2Nr%2FbtsH0M51ciu%2FI1pMCAzD0BGnI9a7FUSVD1%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;1916&quot; height=&quot;918&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;918&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;아래 내용을 채워주고 Create task 해주자!&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;Task name&lt;/b&gt;: 태스크 이름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Notification email&lt;/b&gt;: 실패 또는 성공/실패 시 메일을 보낼 이메일&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Send Notification on&lt;/b&gt;: 메일을 실패 시 보낼지 성공/실패 시 보낼지 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Blob Store&lt;/b&gt;: 정리할 레포지토리 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Task Frequency&lt;/b&gt;: 태스크 실행 주기 설정 (매일, 매주, 매달 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/snOcc/btsHZURxTdu/b8qtgSkn8qF70IU2tuHQ51/img.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;914&quot; data-is-animation=&quot;false&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;b&gt;Run&lt;/b&gt;을 클릭해 실행시킨다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;907&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XRvnA/btsH1kVuoEh/k1dG94VE0aHgck7ykRK9L0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XRvnA/btsH1kVuoEh/k1dG94VE0aHgck7ykRK9L0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XRvnA/btsH1kVuoEh/k1dG94VE0aHgck7ykRK9L0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXRvnA%2FbtsH1kVuoEh%2Fk1dG94VE0aHgck7ykRK9L0%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;1919&quot; height=&quot;907&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;907&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;b&gt;cleanup&lt;/b&gt; 과 마찬가지로 &lt;b&gt;logs&lt;/b&gt; 에서 확인할 수 있다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OWyVn/btsHZvEsuEd/ozRQKHW4TXTmowf7VZdSlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OWyVn/btsHZvEsuEd/ozRQKHW4TXTmowf7VZdSlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OWyVn/btsHZvEsuEd/ozRQKHW4TXTmowf7VZdSlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOWyVn%2FbtsHZvEsuEd%2FozRQKHW4TXTmowf7VZdSlK%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;807&quot; data-filename=&quot;nexus.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;807&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;서버를 확인해보면 /data 의 용량이 99% -&amp;gt; 64% 로 줄어든 것을 확인할 수 있다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rdwUl/btsHZKuIE6r/xWDuei75QKQSUdZ73KtYL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rdwUl/btsHZKuIE6r/xWDuei75QKQSUdZ73KtYL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rdwUl/btsHZKuIE6r/xWDuei75QKQSUdZ73KtYL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrdwUl%2FbtsHZKuIE6r%2FxWDuei75QKQSUdZ73KtYL1%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;795&quot; height=&quot;269&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;269&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://help.sonatype.com/en/cleanup-policies.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://help.sonatype.com/en/cleanup-policies.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1718379295819&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Cleanup Policies&quot; data-og-description=&quot;NoteImportant Impact for Those Migrating to H2 or PostgreSQLIn OrientDB environments, the Asset Name Matcher uses Lucene regular expressions; in H2 or PostgreSQL environments, it uses Java regular expressions. The major difference is that the Lucene regula&quot; data-og-host=&quot;help.sonatype.com&quot; data-og-source-url=&quot;https://help.sonatype.com/en/cleanup-policies.html&quot; data-og-url=&quot;https://help.sonatype.com/en/cleanup-policies.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b8AzT0/hyWljPIQii/K0uEVsZank3pBn1PWZ27r0/img.png?width=1580&amp;amp;height=1600&amp;amp;face=0_0_1580_1600,https://scrap.kakaocdn.net/dn/bK0HpV/hyWlcC0W7O/bEkTXfekttkjSZXKOzh9nk/img.png?width=1644&amp;amp;height=1474&amp;amp;face=0_0_1644_1474&quot;&gt;&lt;a href=&quot;https://help.sonatype.com/en/cleanup-policies.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://help.sonatype.com/en/cleanup-policies.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b8AzT0/hyWljPIQii/K0uEVsZank3pBn1PWZ27r0/img.png?width=1580&amp;amp;height=1600&amp;amp;face=0_0_1580_1600,https://scrap.kakaocdn.net/dn/bK0HpV/hyWlcC0W7O/bEkTXfekttkjSZXKOzh9nk/img.png?width=1644&amp;amp;height=1474&amp;amp;face=0_0_1644_1474');&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;Cleanup Policies&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;NoteImportant Impact for Those Migrating to H2 or PostgreSQLIn OrientDB environments, the Asset Name Matcher uses Lucene regular expressions; in H2 or PostgreSQL environments, it uses Java regular expressions. The major difference is that the Lucene regula&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;help.sonatype.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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>blob</category>
      <category>cleanup</category>
      <category>cleanup policies</category>
      <category>cleanup policy</category>
      <category>NEXUS</category>
      <category>nexus3</category>
      <category>넥서스</category>
      <category>넥서스 보관주기</category>
      <category>넥서스 파일 보관주기</category>
      <category>보관주기</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/82</guid>
      <comments>https://rangerang.tistory.com/82#entry82comment</comments>
      <pubDate>Sun, 16 Jun 2024 00:00:12 +0900</pubDate>
    </item>
    <item>
      <title>CentOS7에 Jeus8 설치 및 실행</title>
      <link>https://rangerang.tistory.com/81</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;✔ 목표 : centOS7에 제우스8 설치하고 띄워보자&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;0. 설치 파일 다운로드 - 아래 링크에서 진행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://technet.tmax.co.kr/ko/front/download/findDownloadList.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://technet.tmax.co.kr/ko/front/download/findDownloadList.do&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707664902937&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;TmaxSoft Technical Network [technet-01]&quot; data-og-description=&quot;데모라이선스 신청 데모라이선스는 제품구입 전 테스트 및 검토를 위하여 제한 된 기간 동안 발급받아 사용가능한 라이선스 입니다.&quot; data-og-host=&quot;technet.tmax.co.kr&quot; data-og-source-url=&quot;https://technet.tmax.co.kr/ko/front/download/findDownloadList.do&quot; data-og-url=&quot;https://technet.tmax.co.kr/ko/front/download/findDownloadList.do&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://technet.tmax.co.kr/ko/front/download/findDownloadList.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://technet.tmax.co.kr/ko/front/download/findDownloadList.do&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;TmaxSoft Technical Network [technet-01]&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;technet.tmax.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XEK7n/btsEE1zMZ0B/fV4XMYNMNAwOlwJ7KSkEn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XEK7n/btsEE1zMZ0B/fV4XMYNMNAwOlwJ7KSkEn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XEK7n/btsEE1zMZ0B/fV4XMYNMNAwOlwJ7KSkEn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXEK7n%2FbtsEE1zMZ0B%2FfV4XMYNMNAwOlwJ7KSkEn1%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;838&quot; height=&quot;164&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;164&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;231&quot; data-origin-height=&quot;27&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2xzSH/btsEMZz3aqq/hli6Qvs6PZkIctKtcY3NY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2xzSH/btsEMZz3aqq/hli6Qvs6PZkIctKtcY3NY1/img.png&quot; data-alt=&quot;다운로드 된 제우스 설치파일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2xzSH/btsEMZz3aqq/hli6Qvs6PZkIctKtcY3NY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2xzSH%2FbtsEMZz3aqq%2Fhli6Qvs6PZkIctKtcY3NY1%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;231&quot; height=&quot;27&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;27&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;다운로드 된 제우스 설치파일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;jeus8500_unix_generic_ko.bin&lt;/b&gt; 파일이 위치한 디렉터리로 이동 후 설치 파일을 실행&lt;/h3&gt;
&lt;pre id=&quot;code_1707665115737&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./jeus8500_unix_generic_ko.bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1)소개&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAh87Y/btsEMXWwVIh/KKoQpi7goRd6kB5Q236OM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAh87Y/btsEMXWwVIh/KKoQpi7goRd6kB5Q236OM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAh87Y/btsEMXWwVIh/KKoQpi7goRd6kB5Q236OM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAh87Y%2FbtsEMXWwVIh%2FKKoQpi7goRd6kB5Q236OM0%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;2000&quot; height=&quot;754&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 라이센스&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PcKbH/btsEGj0Ld52/wv3hQKSzk738zacmr94HK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PcKbH/btsEGj0Ld52/wv3hQKSzk738zacmr94HK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PcKbH/btsEGj0Ld52/wv3hQKSzk738zacmr94HK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPcKbH%2FbtsEGj0Ld52%2Fwv3hQKSzk738zacmr94HK0%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;2000&quot; height=&quot;1618&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1618&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&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;2000&quot; data-origin-height=&quot;1109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qweRq/btsEGNUUFPM/QABeg33OIFBvCPSKLteZHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qweRq/btsEGNUUFPM/QABeg33OIFBvCPSKLteZHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qweRq/btsEGNUUFPM/QABeg33OIFBvCPSKLteZHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqweRq%2FbtsEGNUUFPM%2FQABeg33OIFBvCPSKLteZHK%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;2000&quot; height=&quot;1109&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1109&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kHWIR/btsEEGpfhL6/eoRnTVAxirJDKSwKcL7kVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kHWIR/btsEEGpfhL6/eoRnTVAxirJDKSwKcL7kVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kHWIR/btsEEGpfhL6/eoRnTVAxirJDKSwKcL7kVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkHWIR%2FbtsEEGpfhL6%2FeoRnTVAxirJDKSwKcL7kVk%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;2000&quot; height=&quot;150&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 플랫폼 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k35rr/btsEEESug6k/UCVHuwFvSoCsbWm1R6jG0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k35rr/btsEEESug6k/UCVHuwFvSoCsbWm1R6jG0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k35rr/btsEEESug6k/UCVHuwFvSoCsbWm1R6jG0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk35rr%2FbtsEEESug6k%2FUCVHuwFvSoCsbWm1R6jG0K%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;2000&quot; height=&quot;920&quot; data-origin-width=&quot;2000&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;gt; (우리는 리눅스 64비트를 사용하므로) 9 혹은 그냥 ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4)&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;1834&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n8fbR/btsEEWk0dIt/QmotZfpQcQK7bL3ObO7KyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n8fbR/btsEEWk0dIt/QmotZfpQcQK7bL3ObO7KyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n8fbR/btsEEWk0dIt/QmotZfpQcQK7bL3ObO7KyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn8fbR%2FbtsEEWk0dIt%2FQmotZfpQcQK7bL3ObO7KyK%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;478&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 설치하고 싶은 위치를 적어준다 디폴트 설치위치가 마음에 들면 그냥 ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) JDK 위치 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8qeuA/btsEGh9Jmx0/VONJt12ZmNvEU34TrXUJd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8qeuA/btsEGh9Jmx0/VONJt12ZmNvEU34TrXUJd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8qeuA/btsEGh9Jmx0/VONJt12ZmNvEU34TrXUJd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8qeuA%2FbtsEGh9Jmx0%2FVONJt12ZmNvEU34TrXUJd1%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;2000&quot; height=&quot;421&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 디폴트 설정이 맞게 되어 있으므로 ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) 설치 타입&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UjMrk/btsEFcOHbqs/cRHwAI3ly6Qk29kogt0q21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UjMrk/btsEFcOHbqs/cRHwAI3ly6Qk29kogt0q21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UjMrk/btsEFcOHbqs/cRHwAI3ly6Qk29kogt0q21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUjMrk%2FbtsEFcOHbqs%2FcRHwAI3ly6Qk29kogt0q21%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;2000&quot; height=&quot;554&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7) 설치 모드&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yzfJy/btsEMXIZU9J/x9xsoEChdJKVI3Bo9LsQUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yzfJy/btsEMXIZU9J/x9xsoEChdJKVI3Bo9LsQUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yzfJy/btsEMXIZU9J/x9xsoEChdJKVI3Bo9LsQUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyzfJy%2FbtsEMXIZU9J%2Fx9xsoEChdJKVI3Bo9LsQUK%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;2000&quot; height=&quot;1014&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1014&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8) 제우스 도메인 이름&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csAixO/btsEEJ7cP82/BVfJxMcHzNZXbcwvyZCKE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csAixO/btsEEJ7cP82/BVfJxMcHzNZXbcwvyZCKE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csAixO/btsEEJ7cP82/BVfJxMcHzNZXbcwvyZCKE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsAixO%2FbtsEEJ7cP82%2FBVfJxMcHzNZXbcwvyZCKE0%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;2000&quot; height=&quot;489&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;489&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER ( 디폴트 값인 jeus_domain 사용)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9) DAS 서버 이름&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k07br/btsEIN7ZEsN/bN73PvslyLs1J1gwqRE2kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k07br/btsEIN7ZEsN/bN73PvslyLs1J1gwqRE2kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k07br/btsEIN7ZEsN/bN73PvslyLs1J1gwqRE2kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk07br%2FbtsEIN7ZEsN%2FbN73PvslyLs1J1gwqRE2kK%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;2000&quot; height=&quot;466&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER(디폴트 값인 adminServer 사용)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10) 포트&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daR5L6/btsEGLW8ft1/TrCEHXpTnV94cHxBnJJmKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daR5L6/btsEGLW8ft1/TrCEHXpTnV94cHxBnJJmKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daR5L6/btsEGLW8ft1/TrCEHXpTnV94cHxBnJJmKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaR5L6%2FbtsEGLW8ft1%2FTrCEHXpTnV94cHxBnJJmKk%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;2000&quot; height=&quot;495&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER(디폴트 값인 9736 사용)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11) admin 유저명&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnrI8a/btsEF6UJz8o/Mp4RXo4MApVMc1wSQdktD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnrI8a/btsEF6UJz8o/Mp4RXo4MApVMc1wSQdktD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnrI8a/btsEF6UJz8o/Mp4RXo4MApVMc1wSQdktD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnrI8a%2FbtsEF6UJz8o%2FMp4RXo4MApVMc1wSQdktD0%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;2000&quot; height=&quot;476&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER(디폴트 값인 administrator 사용)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12) 패스워드 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;441&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oPbq1/btsEMYOFTe6/KC1zSI6UqcQCqb3UH38R6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oPbq1/btsEMYOFTe6/KC1zSI6UqcQCqb3UH38R6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oPbq1/btsEMYOFTe6/KC1zSI6UqcQCqb3UH38R6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoPbq1%2FbtsEMYOFTe6%2FKC1zSI6UqcQCqb3UH38R6k%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;2000&quot; height=&quot;441&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;441&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 원하는 패스워드 작성 후 엔터&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;13) 노드 매니저 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMzaM1/btsEGhWcn65/W2lxQEGMgrkdS9FMnxCNx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMzaM1/btsEGhWcn65/W2lxQEGMgrkdS9FMnxCNx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMzaM1/btsEGhWcn65/W2lxQEGMgrkdS9FMnxCNx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMzaM1%2FbtsEGhWcn65%2FW2lxQEGMgrkdS9FMnxCNx1%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;2000&quot; height=&quot;589&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER(디폴트 값으로 설정)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;14) 샘플 디렉토리&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sweub/btsEHGA96dr/IQRYLwUKiNlOKdE1L2uWa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sweub/btsEHGA96dr/IQRYLwUKiNlOKdE1L2uWa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sweub/btsEHGA96dr/IQRYLwUKiNlOKdE1L2uWa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsweub%2FbtsEHGA96dr%2FIQRYLwUKiNlOKdE1L2uWa1%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;2000&quot; height=&quot;613&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER(샘플디렉토리 만듦 사실 별로 필요는 없는데 나중에 필요없으면 지우면 됨)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;15) 설치 요약&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wINyE/btsEE1Gwdbz/qHgkSAQTBKXJerKWRgsWx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wINyE/btsEE1Gwdbz/qHgkSAQTBKXJerKWRgsWx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wINyE/btsEE1Gwdbz/qHgkSAQTBKXJerKWRgsWx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwINyE%2FbtsEE1Gwdbz%2FqHgkSAQTBKXJerKWRgsWx0%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;1840&quot; height=&quot;904&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;904&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 확인 후 ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;16) 설치 완료&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1811&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJUo9p/btsELrDuVoP/3DDqQQntRwCkdZemWprJek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJUo9p/btsELrDuVoP/3DDqQQntRwCkdZemWprJek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJUo9p/btsELrDuVoP/3DDqQQntRwCkdZemWprJek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJUo9p%2FbtsELrDuVoP%2F3DDqQQntRwCkdZemWprJek%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;1811&quot; height=&quot;435&quot; data-origin-width=&quot;1811&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ENTER&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;17) 쉘에서 bash_profile 수정&lt;/p&gt;
&lt;pre id=&quot;code_1707666049669&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vi ~/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1771&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dG3vpV/btsEFd7UCoz/xMkxWZBlWukKKwA9BKOld1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dG3vpV/btsEFd7UCoz/xMkxWZBlWukKKwA9BKOld1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dG3vpV/btsEFd7UCoz/xMkxWZBlWukKKwA9BKOld1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdG3vpV%2FbtsEFd7UCoz%2FxMkxWZBlWukKKwA9BKOld1%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;1771&quot; height=&quot;936&quot; data-origin-width=&quot;1771&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제우스 8_5의 홈이 안잡혀있으면 잡아주고, 두번째 체크된 내용이 잘 들어가 있는지 확인한다(정상적으로 깔렸다면 자동으로 들어가있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;18) bash_profile 수정 후 적용&lt;/p&gt;
&lt;pre id=&quot;code_1707666374817&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;source ~/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인&lt;/p&gt;
&lt;pre id=&quot;code_1707666424193&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo $JEUS_HOME
&amp;gt;&amp;gt;&amp;gt; /home/p/jeus8_5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제우스 설치 완료!&lt;/b&gt;&lt;/span&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;3. 제우스 8.5 실행&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DAS(Domain Admin Server)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; Jeus Webadmin에 접속하기 위한 관리자용 서버 ( 이 서버는 죽더라도 MS만 멀쩡하면 서비스에는 지장이 없다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Domain Admin Server(DAS)를 시작한다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;startDomainAdminServer -u administrator -p {비밀번호}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;nbsp;&lt;u&gt;http://{서버ip}:9736/webadmin/login&lt;/u&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O8lmR/btsELo7Plbn/uKKLku7ZsKFvPsESMZZmy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O8lmR/btsELo7Plbn/uKKLku7ZsKFvPsESMZZmy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O8lmR/btsELo7Plbn/uKKLku7ZsKFvPsESMZZmy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO8lmR%2FbtsELo7Plbn%2FuKKLku7ZsKFvPsESMZZmy1%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;2000&quot; height=&quot;956&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NM(NodeManager)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; DAS 가 MS 를 관리하기 위해 사용하는 프로세스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NM을 시작한다&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;nohup startNodeManager &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인&amp;nbsp;&lt;u&gt;http://{서버ip}/webadmin/login &lt;/u&gt;에&amp;nbsp;접속&amp;nbsp;후&amp;nbsp;Node&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;2000&quot; data-origin-height=&quot;1357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/smdl6/btsEFfxU6Ci/w8xKpmTHghMamzc1DHpNp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/smdl6/btsEFfxU6Ci/w8xKpmTHghMamzc1DHpNp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/smdl6/btsEFfxU6Ci/w8xKpmTHghMamzc1DHpNp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsmdl6%2FbtsEFfxU6Ci%2Fw8xKpmTHghMamzc1DHpNp1%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;2000&quot; height=&quot;1357&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1357&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;Under Control 이 &lt;span data-token-index=&quot;1&quot;&gt;Y&lt;/span&gt; 면 정상&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1851&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/molxQ/btsEF3ReNvm/gwKFkSArlKA9xdKc5JnOx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/molxQ/btsEF3ReNvm/gwKFkSArlKA9xdKc5JnOx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/molxQ/btsEF3ReNvm/gwKFkSArlKA9xdKc5JnOx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmolxQ%2FbtsEF3ReNvm%2FgwKFkSArlKA9xdKc5JnOx0%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;1851&quot; height=&quot;639&quot; data-origin-width=&quot;1851&quot; data-origin-height=&quot;639&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고1) 제우스 주요 명령어&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;### das
# start
startDomainAdminServer -domain jeus_domain -u administrator -p {비밀번호}
# stop
stopServer -host 127.0.0.1:9736 -u administrator -p {비밀번호}

### nm
# start
nohup startNodeManager &amp;amp;
# stop
stopNodeManager -host 127.0.0.1 -port 7730

### ms
# start
startManagedServer -dasurl 127.0.0.1:9736 -domain jeus_domain -server server4  -u administrator -p {비밀번호}
# stop 포트는 http 포트
stopServer -host 127.0.0.1:9748 -u administrator -p {비밀번호}&lt;/code&gt;&lt;/pre&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nodeManager 로그&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;$JEUS_HOME/nodemanager/logs/JeusNodeManager.log
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 로그 &amp;rarr; 위치 조금 다를수도..?&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$JEUS_HOME/domains/jeus_domain/servers/{서버이름}/logs/JeusServer.log&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;war 위치 &amp;rarr; 조금씩 다를수도..&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$JEUS_HOME/domains/jeus_domain/.applications/{어플리케이션이름}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>제우스</category>
      <category>Das</category>
      <category>JEUS</category>
      <category>jeus 로그</category>
      <category>jeus8</category>
      <category>jeus8.5</category>
      <category>NM</category>
      <category>제우스</category>
      <category>제우스 로그</category>
      <category>제우스8</category>
      <category>제우스8.5</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/81</guid>
      <comments>https://rangerang.tistory.com/81#entry81comment</comments>
      <pubDate>Mon, 12 Feb 2024 01:07:50 +0900</pubDate>
    </item>
    <item>
      <title>ThreadPoolExecutor RejectedExecutionException 오류 - SynchronousQueue</title>
      <link>https://rangerang.tistory.com/80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리 프로젝트에서는 여러개의 쓰레드를 이용하여 작업을 실행하기 위해 ThreadPoolExecutor를 이용하고 있다 쓰레드 풀의 개수는 고정적으로 사용하고 있으며, 해당 쓰레드를 실행하는 부분에서 쓰레드의 개수를 관리하며 쓰레드 풀 이상의 요청은 하지 않기 때문에 이론적으로는 쓰레드 풀이 터지는 경우는 없어야 했다. 하지만 여러 프로젝트를 진행하며 종종 쓰레드 풀이 터지곤 했는데 이번에 조금 더 깊이 파봤다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발생한 오류 는 아래와 같다&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;RejectedExecutionException:&amp;nbsp;Task&amp;nbsp;co&lt;a style=&quot;background-color: #ffc9af;&quot; href=&quot;http://m.xxx.xx.TrainWorker&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://m.xxx.xx.TrainWorker&lt;/a&gt;&amp;nbsp;rejected&amp;nbsp;from&amp;nbsp;java.util.concurrent.ThreadPoolExecutor[Running,&amp;nbsp;pool&amp;nbsp;size&amp;nbsp;=&amp;nbsp;16,&amp;nbsp;active&amp;nbsp;threads&amp;nbsp;=&amp;nbsp;2,&amp;nbsp;queued&amp;nbsp;tasks&amp;nbsp;=&amp;nbsp;1,&amp;nbsp;completed&amp;nbsp;tasks&amp;nbsp;=&amp;nbsp;167]&lt;/span&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&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;오류가 발생한 스레드 풀을 만드는 코드는 아래와 같다 우리는 corePoolSize와 maximumPoolSize를 같은 값으로 사용하고 있다&lt;br /&gt;-&amp;gt; 풀 사이즈는 고정이다(생성되거나 줄어들지 않는다)&lt;/p&gt;
&lt;pre id=&quot;code_1688992679286&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    workerExecutor = new ThreadPoolExecutor(poolSize, poolSize, 10, TimeUnit.MINUTES, new LinkedBlockingQueue&amp;lt;&amp;gt;(1));
    workerExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());   // 작업큐가 꽉 찼을 때 Reject된 task가 RejectedExecutionException을 던짐&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ThreadPool을 생성하는 코드를 파악해보자&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fff599;&quot;&gt;workerExecutor = new ThreadPoolExecutor(&lt;span style=&quot;background-color: #fff599;&quot;&gt;poolSize&lt;/span&gt;, poolSize, 10, TimeUnit.MINUTES, new&amp;nbsp;&lt;span style=&quot;background-color: #fff599;&quot;&gt;LinkedBlockingQueue&amp;lt;&amp;gt;(1));&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;인수의 의미를 모른다면 밑에 더보기를 클릭하자&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인수의 의미(순서대로)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #fbfbfb; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;corePoolSize&lt;span&gt;&lt;span&gt;&amp;nbsp;&amp;ndash; 유휴 상태인 경우에도 풀에 유지할 스레드 수입니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;maximumPoolSize&lt;span&gt;&lt;span&gt;&amp;nbsp;&amp;ndash; 풀에서 허용할 최대 스레드 수입니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;keepAliveTime&lt;span&gt;&lt;span&gt;&amp;nbsp;&amp;ndash; 스레드 수가 코어보다 많은 경우 유휴 스레드가 새 작업을 기다리는 최대 시간입니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;unit&lt;span&gt;&lt;span&gt;&amp;ndash; keepAliveTime&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;인수 &amp;nbsp;의 시간 단위&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;workQueue&lt;span&gt;&lt;span&gt;&amp;ndash; Runnable&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;작업이 실행되기 전에&amp;nbsp;&lt;/span&gt;&lt;span&gt; 보관하는 데 사용할 대기열 .&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;인수의 의미만 봤을 때는 pool이 차는 순서가 아래와 같을꺼라고 오해하기 쉽다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;corePoolSize -&amp;gt; maximumPoolSize -&amp;gt; workQueue&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제로는 아래와 같이 workQueue를 먼저 채운다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;corePoolSize -&amp;gt; workQueue -&amp;gt; maximumPoolSize&amp;nbsp;&lt;/blockquote&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1881&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dp3tqL/btsm8Zd7wel/7ofZiZ0fAY8S6e4A13CxS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dp3tqL/btsm8Zd7wel/7ofZiZ0fAY8S6e4A13CxS0/img.png&quot; data-alt=&quot;공식 문서 참고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dp3tqL/btsm8Zd7wel/7ofZiZ0fAY8S6e4A13CxS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdp3tqL%2Fbtsm8Zd7wel%2F7ofZiZ0fAY8S6e4A13CxS0%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;1881&quot; height=&quot;176&quot; data-origin-width=&quot;1881&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공식 문서 참고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이전에도 동일한 오류가 터졌었는데 이 코드를 디버깅하면서 &lt;/span&gt;&lt;b&gt;acative threds 가 아직 꽉 차지 않았는데 queued tasks가 채워졌다는게&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt; 의문이었다 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;오류의 원인은 &lt;/span&gt;&lt;b&gt;execute를 동시&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;에 해서 그런가보다! 하고 execute 하는 메서드에 synchronized를 걸었다.&lt;br /&gt;-&amp;gt; 잘못된 선택..&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ThreadPoolExecutor.execute() 함수 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;아래 함수는 threaPoolExecuter의 execute 함수이다. &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;대충 확인해보면 새로운 command가 들어왔을 때 아래와 같은 로직으로 진행된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;1. worker의 개수가 corePoolSize 보다 작으면 thread를 그냥 추가한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;2. 아니라면 워커큐에 저장하려고 command를 저장하려고 시도한다&lt;br /&gt;-&amp;gt; 우리 코드의 경우 워커큐 사이즈 이상의 요청은 하지 않는다 따라서 이 코드는 무조건 성공해야 한다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;3. 만약 2의 작업이 실패하면 최대 Thread 수 보다 작을 때 Thread를 추가&lt;br /&gt;-&amp;gt; 이 코드는 타는일이 없어야 한다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688993628198&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
            /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
            
        int c = ctl.get();
        if (workerCountOf(c) &amp;lt; corePoolSize) {	//최저 Thread 수 보다 작다면 Thread 추가 -&amp;gt; pass
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) &amp;amp;&amp;amp; workQueue.offer(command)) {	//Queue 에 저장(offer)하려고 시도 -&amp;gt; 여기서 실패하고 아래로 넘어감 왜? 
            int recheck = ctl.get();
            if (! isRunning(recheck) &amp;amp;&amp;amp; remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //위의 offer가  false를 리턴해야만, 최대 Thread 수 보다 작을때 Thread 추가한다. 
        // ***-&amp;gt; 우리는 core의 개수와 max의 개수가 동일하기 때문에 쓰레드 추가하려면 무조건 터짐!! 여기로 넘어오면 안됨
        else if (!addWorker(command, false))
            reject(command);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fff599;&quot;&gt;1)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (isRunning(c) &amp;amp;&amp;amp; workQueue.offer(command)) {&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;background-color: #fff599;&quot;&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;//Queue 에 저장(offer)&lt;/span&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;하려고 시도한다. &lt;br /&gt;-&lt;span style=&quot;background-color: #fff599; color: #ff0000;&quot;&gt;&amp;gt; 여기서 실패하고 아래로 넘어간다 왜?&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fff599;&quot;&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;&lt;span style=&quot;background-color: #fff599; color: #ff0000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드가 문제같음 이 코드에서 넘어가면 안됨 우리는 &lt;span style=&quot;background-color: #fbfbfb; color: #000000; text-align: left;&quot;&gt;corePoolSize 이상의 요청은 하지 않기 때문에 workerQ&lt;/span&gt;ueue(대기열)는 항상 비어있어야하지 않나?&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;디버깅 해보니 위 코드에서는 workerQueue의 개수가 1인데 다음로직인 아래 코드로 내려가니 workerQueue가 0이다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fff599;&quot;&gt;&amp;nbsp;2)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else&amp;nbsp;if&amp;nbsp;(!addWorker(command,&amp;nbsp;false))&lt;/span&gt;&lt;span style=&quot;background-color: #fff599;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;//위의&amp;nbsp;offer가&amp;nbsp; false를 리턴해야&lt;/span&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;만,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;최대 Thread 수 보다 작을때&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fff599; color: #009e25;&quot;&gt;Thread 추가한다. &lt;br /&gt;-&amp;gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;우리는 corePoolSize = maximumPoolSize = poolSize로 같기 때문에 queue를 사용하게 되면 maximumPoolSize를 초과하기 때문에 무조건 터진다!! &lt;/span&gt;&lt;span style=&quot;background-color: #fff599; color: #ff0000;&quot;&gt;여기로 넘어오면 안됨&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; workerQueue가 1일 때 또 넣으려고 하니까 터지나보다!?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 예상 시나리오를 아래처럼 생각했다&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. 1) 코드 실행할 때는workerQueue에 1개 있음(곧 쓰레드에서 가져갈 것)&lt;br /&gt;2. workerQueue에서 빠짐&lt;br /&gt;3. 2) 코드 실행 중 터짐(지금은 workerQueue가 비어있음)&lt;br /&gt;-&amp;gt; 사실 여기까지 내려오면 안됨&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 방법 : SynchronousQueue 전략&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. LinkedBlockingQueue(우리가 사용하던 전략)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedBlockingQueue(1) : 1개의 큐를 두고 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. SynchronousQueue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;task를 큐에 들고있지 않고, 바로 스레드로 넘겨버린다 &lt;br /&gt;-&amp;gt; 대기하는 쓰레드와 매칭만 사켜줌. 내부적으로 저장하는 공간이 없음&lt;br /&gt;=&amp;gt; 우리가 원하는 전략&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;✔ 우리는 사실 SynchronousQueue 를 써야 했던 상황이었다!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;따라서 코드를 아래와 같이 바꿨고, 한달에도 여러번 터지던 쓰레드풀은 더 이상 터지지 않는다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706786017034&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    workerExecutor = new ThreadPoolExecutor(poolSize, poolSize, 10, TimeUnit.MINUTES, new SynchronousQueue&amp;lt;&amp;gt;());
    workerExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());   // 작업큐가 꽉 찼을 때 Reject된 task가 RejectedExecutionException을 던짐&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;</description>
      <category>ㄴspring boot</category>
      <category>Java</category>
      <category>LinkedBlockingQueue</category>
      <category>SynchronousQueue</category>
      <category>ThreadPoolExecutor</category>
      <category>멀티 쓰레드</category>
      <category>쓰레드</category>
      <category>자바 쓰레드</category>
      <author>rangrangerang</author>
      <guid isPermaLink="true">https://rangerang.tistory.com/80</guid>
      <comments>https://rangerang.tistory.com/80#entry80comment</comments>
      <pubDate>Tue, 11 Jul 2023 09:24:21 +0900</pubDate>
    </item>
  </channel>
</rss>