<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>모던플로우</title>
    <link>https://modernflow.tistory.com/</link>
    <description>현재 진행하는 개발 과정을 자주 기록하는 곳</description>
    <language>ko</language>
    <pubDate>Sat, 25 Jul 2026 14:02:01 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>모플로</managingEditor>
    <image>
      <title>모던플로우</title>
      <url>https://tistory1.daumcdn.net/tistory/4458600/attach/7e698efc68204d1fb7dd9e79b82bc47d</url>
      <link>https://modernflow.tistory.com</link>
    </image>
    <item>
      <title>Key-Value-Store 만들면서 겪은 이슈</title>
      <link>https://modernflow.tistory.com/163</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Key-Value-Store를 구현하는 과정에서 docker-compose를 사용했는데 기대하던 실험 결과가 나오지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 제가 만난 이슈와 해결방법에 대해 공유하려합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;간단한 Key Value Store 프로젝트 소개&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1692539350468&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hojihun5516/key-value-store&quot; data-og-description=&quot;Contribute to hojihun5516/key-value-store development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hojihun5516/key-value-store&quot; data-og-url=&quot;https://github.com/hojihun5516/key-value-store&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Nt8jJ/hyTIOQ4nbv/VHFUWLsVKpYQd030JQvZN1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/hojihun5516/key-value-store&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hojihun5516/key-value-store&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Nt8jJ/hyTIOQ4nbv/VHFUWLsVKpYQd030JQvZN1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - hojihun5516/key-value-store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to hojihun5516/key-value-store development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) User는 Proxy 서버로 데이터 저장을 요청합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Proxy 서버는 해시링을 통해 적절한 Store 서버에 저장을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Store 서버는 1초에 1번씩 redis에 헬스 카운트를 올리고, Service Discovery는 5초에 한번씩 Store서버가 죽었는지 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 죽은 Store 서버가 있다면 Service Discovery 서버는 Proxy 서버로 '해시링에서 죽은 스토어 서버를 제거' 하라는 요청을 보냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-&amp;gt; &quot;cap, pacelc 이론을 통해 스토어 서버가 장애시 PA로 가용성을 보장하고, 일반 상황시 EL로 일관성을 희생하여 더 적은 지연 시간을 가져간다&quot; 라는 실험주제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 원하는 실험방법은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;초당 n*100&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;번의 Request를 보내는데 도중 Store 서버 1개를 중단시키고 장애가 복구되는 과정을 모니터링 하는것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림은 제가 구현한 서버의 구성도입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kvstore-infra.png&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EUzfp/btsrNByxWL7/oRoYeOyiep91tXD1dQa52k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EUzfp/btsrNByxWL7/oRoYeOyiep91tXD1dQa52k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EUzfp/btsrNByxWL7/oRoYeOyiep91tXD1dQa52k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEUzfp%2FbtsrNByxWL7%2FoRoYeOyiep91tXD1dQa52k%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;897&quot; height=&quot;809&quot; data-filename=&quot;kvstore-infra.png&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;Situation&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Store A를 제거했을 때 전체 요청 중 약 '1/3이 실패 응답', '2/3가 성공 응답'으로 오길 기대했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Store A를 제거했을 때 Proxy 서버로부터 응답 속도가 지연되면서 요청수 자체가 줄어들었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2023-08-20-22-14-32.png&quot; data-origin-width=&quot;3448&quot; data-origin-height=&quot;886&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TbmoL/btsrypNNu7p/ssAvsGcZ1vMrEA4KHYKtak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TbmoL/btsrypNNu7p/ssAvsGcZ1vMrEA4KHYKtak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TbmoL/btsrypNNu7p/ssAvsGcZ1vMrEA4KHYKtak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTbmoL%2FbtsrypNNu7p%2FssAvsGcZ1vMrEA4KHYKtak%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;3448&quot; height=&quot;886&quot; data-filename=&quot;KakaoTalk_Photo_2023-08-20-22-14-32.png&quot; data-origin-width=&quot;3448&quot; data-origin-height=&quot;886&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;Task&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;가장먼저 에러로그를 확인했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692537702484&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.net.SocketTimeoutException: Read timed out&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692537710564&quot; class=&quot;routeros&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.net.ConnectException: Connection timed out&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692537577389&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.net.SocketException: Connection reset
        at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323) ~[na:na]
        at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) ~[na:na]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Store A를 제거했을 때 매번 다른 에러가 떴습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Connection이 잘 안돼서 pending이 걸리는것같은데... 라는 생각이 들었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Store 서버를 종료했는데도 불구하고 죽은 Store A서버에 요청을 보내고 응답을 기다리는게 이해가 안됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 가끔씩 원하는 방향대로 성공했는데 이 때 뜨는 에러는 아래와 같은 UnknownHostException이였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692537550149&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.net.UnknownHostException: store-service-1
        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567) ~[na:na]
        at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]&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;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;Action&lt;/span&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;UnknownHostException이 떴을때는 실험이 잘 됐기 때문에, Store A 서버를 죽였을때는 dns서버가 Store A 서버를 제대로 인식하지 못해야 한다고 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 docker의 dns캐시에 대해 알아보게됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker는 dns가 내부적으로 사용되고 있고, dns를 통해 service name과 ip를 맵핑시켜서 통신합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;***&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;컨테이너 통신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Docker Compose에서는 서비스 이름을 사용하여 다른 컨테이너에 접근할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이는 내부적으로 Docker의 DNS 서버가 관리하며, 서비스 이름을 해당 컨테이너의 IP 주소로 변환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;***&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 Docker Process를 끄면서 동시에 DNS서버를 강제 리프레쉬 하는 방향을 생각했지만 &lt;a href=&quot;https://docs.docker.com/network/#dns-services&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식문서&lt;/a&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;i&gt;제가 생각한 방법은 Connection Timeout&lt;/i&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;을 핸들링 하는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;같은 Docker network에서 connection timeout을 낮추는 방법을 선택했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;극단적으로 1ms는 너무 낮은값이지만 같은 도커 네트워크 환경이고, 실험을 위해 사용하는 방법이기 때문에 괜찮다고 판단했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-20 오후 10.40.38.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0kgfh/btsrBZHN2Vh/mSckyVOFejqY62bQs54WwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0kgfh/btsrBZHN2Vh/mSckyVOFejqY62bQs54WwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0kgfh/btsrBZHN2Vh/mSckyVOFejqY62bQs54WwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0kgfh%2FbtsrBZHN2Vh%2FmSckyVOFejqY62bQs54WwK%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;602&quot; height=&quot;186&quot; data-filename=&quot;스크린샷 2023-08-20 오후 10.40.38.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;Result&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Store A 서버를 죽였을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장애시 PA를 통해 전체 요청중 1/3이 실패, 2/3이 성공 응답이 오는것을 확인할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;total_requests_per_second_1692540423.png&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;1110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MxvTn/btsrCT1p2vy/y3X6SzWNav7kw1mpNzxM0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MxvTn/btsrCT1p2vy/y3X6SzWNav7kw1mpNzxM0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MxvTn/btsrCT1p2vy/y3X6SzWNav7kw1mpNzxM0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMxvTn%2FbtsrCT1p2vy%2Fy3X6SzWNav7kw1mpNzxM0k%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;1708&quot; height=&quot;1110&quot; data-filename=&quot;total_requests_per_second_1692540423.png&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;1110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/설계</category>
      <category>connection timeout</category>
      <category>Docker</category>
      <category>docker dns</category>
      <category>keyvaluestore</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/163</guid>
      <comments>https://modernflow.tistory.com/163#entry163comment</comments>
      <pubDate>Sun, 20 Aug 2023 22:46:50 +0900</pubDate>
    </item>
    <item>
      <title>RabbitMQ 자세히 알아보자</title>
      <link>https://modernflow.tistory.com/162</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. RabbitMQ 란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;서버간 메세지를 전달해주는 오픈소스 메세지 브로커입니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;RabbitMQ는 AMQP프로토콜을 구현한 메세지 브로커입니다.&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;AMQP란?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;AMQP란 Advanced Message Queuing Protocol로 client application과 middleware broker와의 메세지를 주고 받기 위한 프로토콜이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 구조&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;rabbitmq_structure.webp&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yetZG/btspNP6KqDW/AEb5pXlsbvbAnpQaRcbxm0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yetZG/btspNP6KqDW/AEb5pXlsbvbAnpQaRcbxm0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yetZG/btspNP6KqDW/AEb5pXlsbvbAnpQaRcbxm0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyetZG%2FbtspNP6KqDW%2FAEb5pXlsbvbAnpQaRcbxm0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;350&quot; data-filename=&quot;rabbitmq_structure.webp&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;1) Producer&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;메시지를&amp;nbsp;보낼&amp;nbsp;때&amp;nbsp;RabbitMQ에&amp;nbsp;직접&amp;nbsp;연결하고&amp;nbsp;메시지를&amp;nbsp;&lt;b&gt;publish(발행)&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;2) Exchanges&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;Exchange는 받은 메시지를 하나 이상의 Queue에 라우팅(전달)합니다. &lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;라우팅 방식은 Exchange의 타입에 따라 다릅니다.&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;- &lt;b&gt;Direct Exchange&lt;/b&gt;: Routing Key가 특정 Queue의 Binding Key와 정확히 일치할 때 메시지를 해당 Queue로 라우팅합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;- &lt;b&gt;Topic&amp;nbsp;Exchange&lt;/b&gt;:&amp;nbsp;Routing&amp;nbsp;Key와&amp;nbsp;Binding&amp;nbsp;Key&amp;nbsp;사이에&amp;nbsp;와일드카드&amp;nbsp;매칭을&amp;nbsp;허용하여&amp;nbsp;메시지를&amp;nbsp;라우팅합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;- &lt;b&gt;Fanout&amp;nbsp;Exchange&lt;/b&gt;:&amp;nbsp;Binding&amp;nbsp;Key를&amp;nbsp;무시하고&amp;nbsp;모든&amp;nbsp;연결된&amp;nbsp;Queue에&amp;nbsp;메시지를&amp;nbsp;브로드캐스트합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;- &lt;b&gt;Headers&amp;nbsp;Exchange&lt;/b&gt;:&amp;nbsp;Routing&amp;nbsp;Key를&amp;nbsp;무시하고&amp;nbsp;메시지의&amp;nbsp;헤더&amp;nbsp;속성을&amp;nbsp;기반으로&amp;nbsp;메시지를&amp;nbsp;라우팅합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;3) Bindings&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;Binding은 Exchange와 Queue 사이의 연결을 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;Binding을 통해 Exchange는 어떤 Queue에 메시지를 전달할지 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;4) Queues&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;Queue는&amp;nbsp;&lt;/span&gt;메시지를 저장하는 버퍼입니다. 각 Queue는 메시지를 받아서 저장하고, Consumer가 처리할 준비가 될 때까지 메시지를 보관합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;5) Consumer&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;Consumer는&amp;nbsp;Queue에&amp;nbsp;연결되어&amp;nbsp;있으며,&amp;nbsp;메시지가&amp;nbsp;Queue에&amp;nbsp;도착하면&amp;nbsp;그&amp;nbsp;메시지를&amp;nbsp;가져와서&amp;nbsp;처리합니다.&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.&amp;nbsp; 언제 쓰는건데?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 글을 쓰는 주요 목적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시가 있다면 이해가 빠르죠!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 서비스 설계 상황&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- MSA 서비스(계정, 쿠폰, 알림)로 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 비즈니스 요구사항&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 회원가입을 하면 가입 환영 쿠폰을 발급해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 회원가입을 하면 가입 인사 이메일을  전송합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 해결방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-1) message Queue를 쓰지 않는다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가입 시 자동으로 이벤트 참여를 시키려면 회원가입(signUp)함수에 지속적으로 추가해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 회원가입이라는 함수는 많은 일을 하게되고 비즈니스 복잡도가 증가하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이 방법으로도 비즈니스 요구사항을 해결할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690887808593&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 계정서버
fun signUp(userSignUpRequest: UserSignUpRequest){
	...
    val createdUserEntity = userRepository.save(userEntity)
    
    couponClient.issueSignUpCoupon(userId = createdUserEntity.id)
    notificationClient.notifySignUpEmail(userId = createdUserEntity.id)    

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-2) message Queue를 쓴다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Producer(계정)서버에서 가입 이벤트를 발행하고, 가입한 행위를 필요로하는 Consumer(쿠폰, 알림)들이 메시지를 받아갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 작성하면 회원가입 함수는 회원가입을 하고 가입 이벤트를 발행하는 일만 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원가입 했을 때 추가적인 비즈니스 요구사항이 생기면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;계정서버의 작업은 필요 없이,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;메시지를 받아서 작업하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때는 &lt;b&gt;Direct&lt;/b&gt;를 쓰는게 명확하다고 생각합니다&lt;/p&gt;
&lt;pre id=&quot;code_1690887675393&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 계정서버
fun signUp(userSignUpRequest: UserSignUpRequest){
	...
    val createdUserEntity = userRepository.save(userEntity)
    userSignUpEventProducer.publish(
        event = userEventFactory.userSignUpEvent(userEntity = createdUserEntity),
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1690888713252&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 쿠폰 서버
fun receiveUserSignUpMessage(payload: Long, message: Message): Any? {
	issueSignUpCoupon(userId = payload)
}

fun issueSignUpCoupon(userId: Long){
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1690888806738&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 알림 서버
fun receiveUserSignUpMessage(payload: Long, message: Message): Any? {
	notifySignUpEmail(userId = payload)
}

fun notifySignUpEmail(userId: Long){
	...
}&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;4. 메시지 유실에 대해&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1) 사례&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 챕터는 제가 일을 하던중 겪은 이슈를 정리하기위해 추가했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지를 수신하여 외부 서비스 api 호출을 하는 작업을 했는데, 인증 만료로 401 ERROR가 발생했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;지속적으로 외부 서비스에 401 ERROR를 발생시켰고 뒤늦게 발견하게 됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2) 분석&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 로직은  Exception을 던졌고, messageQueue에도 제대로 성공했다는 메시지를 보내지 못했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;rabbitMQ는 성공 메시지를 받지 못해서 메시지를 유실시키지 않게 하기위해 실패한 메시지를 다시 큐에 쌓아둡니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 상황이 계속 반복되어 실패하는 메시지를 통해 외부 서비스를 계속 호출하는 이슈를 만났습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Consumer가 메시지를 성공적으로 처리했음을 RabbitMQ에 알리는 것은 중요합니다.&lt;br /&gt;이것이 &quot;acknowledgment&quot;이며, 이를 통해 RabbitMQ는 메시지를 큐에서 안전하게 제거할 수 있습니다.&lt;br /&gt;만약 이 ack가 전송되지 않으면, RabbitMQ는 메시지가 처리되지 않았다고 가정하고 다른 Consumer에게 메시지를 다시 전송할 것입니다.&lt;/blockquote&gt;</description>
      <category>개발</category>
      <category>AMQP</category>
      <category>MessageQueue</category>
      <category>rabbitmq</category>
      <category>Topic</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/162</guid>
      <comments>https://modernflow.tistory.com/162#entry162comment</comments>
      <pubDate>Wed, 2 Aug 2023 08:10:49 +0900</pubDate>
    </item>
    <item>
      <title>git 폴더별 유저 설정</title>
      <link>https://modernflow.tistory.com/161</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://modernflow.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://modernflow.tistory.com/158&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1676549118748&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;한 디바이스에 git 계정 여러개 등록&quot; data-og-description=&quot;회사에서 깃을 사용하던 중 제 개인 계정도 등록하고 싶어서 공부하게 됐습니다. 1. ssh key 생성 - 경로 이동 cd ~/.ssh - 키 생성 - 여기서 제 깃 이메일과 -f라는 옵션으로 구체적인 파일명을 적어주&quot; data-og-host=&quot;modernflow.tistory.com&quot; data-og-source-url=&quot;https://modernflow.tistory.com/158&quot; data-og-url=&quot;https://modernflow.tistory.com/158&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8N1My/hyRDVTWEuz/wodg4VGg8jgsMbELVoka51/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/biM0Bv/hyREHfsqn3/MN1wQoW495zTeQzAB7kpj0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAYi3v/hyRESBh6Md/SvNpYUTDhlkEYD0eUiydt0/img.jpg?width=1522&amp;amp;height=1706&amp;amp;face=690_671_836_830&quot;&gt;&lt;a href=&quot;https://modernflow.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://modernflow.tistory.com/158&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8N1My/hyRDVTWEuz/wodg4VGg8jgsMbELVoka51/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/biM0Bv/hyREHfsqn3/MN1wQoW495zTeQzAB7kpj0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAYi3v/hyRESBh6Md/SvNpYUTDhlkEYD0eUiydt0/img.jpg?width=1522&amp;amp;height=1706&amp;amp;face=690_671_836_830');&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;한 디바이스에 git 계정 여러개 등록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;회사에서 깃을 사용하던 중 제 개인 계정도 등록하고 싶어서 공부하게 됐습니다. 1. ssh key 생성 - 경로 이동 cd ~/.ssh - 키 생성 - 여기서 제 깃 이메일과 -f라는 옵션으로 구체적인 파일명을 적어주&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;modernflow.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;pre id=&quot;code_1676549071823&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ~/.gitconfig-personal 
[user]
        email=hojihun5516@daum.net
        name=hojihun5516&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1676548983024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#~/.gitconfig

[user]
        name = jihoonheo
        email = company@company.com

[includeIf &quot;gitdir:~/next-step/&quot;]
        path = ~/.gitconfig-personal

[includeIf &quot;gitdir:~/numble/&quot;]
        path = ~/.gitconfig-personal

[core]
        autocrlf = input&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;</description>
      <category>개발/Git</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/161</guid>
      <comments>https://modernflow.tistory.com/161#entry161comment</comments>
      <pubDate>Thu, 16 Feb 2023 21:07:46 +0900</pubDate>
    </item>
    <item>
      <title>Database Index는 언제 써야하는가?</title>
      <link>https://modernflow.tistory.com/160</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 배경&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자 친구들과 이야기를 하던중 sql tuning작업을 통해 조회 쿼리 속도를 높였다는 이야기를 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막연하게 떠오르는 생각은 &quot;아! 당연히 Indexing을 했겠구나&quot; 였지만 그때 문득든 생각이 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Indexing은 쿼리 조회 속도를 높이고 Index를 갱신를 갱신하기 때문에 CUD에 대해서는 느리다&lt;br /&gt;그렇다면 로그를 남기는 것과 유사한 기능을 제외하고, 많은 비즈니스 기능은 빠른 조회를 필요로하는데 이런 테이블에 전부 인덱싱을 해야하는게 좋을까?&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 찾은 결론부터 말하면 &quot;아니다&quot; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에서 데이터를 스캔하는 방식은 풀스캔(Full Scan)과 인덱스 스캔(Index Scan)이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 친구같은 경우는 풀스캔으로 되어있던 방식을 인덱스 스캔으로 변경하여 조회 속도를 높인 케이스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 스캔 종류&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 풀스캔(Full Scan)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Application에서 SELECT * FROM USER WHERE ID = 10; 이라는 쿼리요청이 온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테이블 전체 데이터를 디스크에서 메모리로 옮긴 후 모든 데이터를 조사해서 ID가 10인 USER를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 인덱스 스캔(Index Scan)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Application에서 SELECT * FROM USER WHERE ID = 10; 이라는 쿼리요청이 온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인덱스에서 필요한 데이터가 있는곳을 조사해서 필요한 데이터 블록만 읽는다. (인덱스를 조회해서 필요한 블록만 읽는다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ID가 10인 한건의 데이터가 들어있는 USER 테이블의 데이터 블록만 선택적으로 읽고 반환한다.&lt;/p&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-1 인덱스 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스 구조에대한 글이 아니라서 가볍게 설명하겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) B 트리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 루트, 브랜치, 리프 구조로 리프노드에 데이터블럭의 위치를 저장한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 해시테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;- &lt;span style=&quot;background-color: #ffffff;&quot;&gt;해시함수를 사용하여 변환한 값을 인덱스로 사용하여 키와 데이터를 저장하는 구조입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 그렇다면 언제 풀스캔이 유리한가?&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;테이블의 데이터를 모두 가져가야 하는경우&lt;br /&gt;테이블의 데이터가 많이 없는 경우&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀스캔은 한번의 I/O로 가능한 한 크기의 데이터를 읽어서 I/O수를 줄여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 경우에서 인덱스 스캔을 하게 된다면 읽어야 하는 데이터 블록이 늘어나고, 하나씩 읽어가며 I/O횟수도 늘어납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 인덱싱을 하는게 좋은게 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 키 조회를 자주 쓸때, 필요한 인덱스 구조를 고민해보고 작성해야 한다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Database</category>
      <category>Database</category>
      <category>full scan</category>
      <category>Index</category>
      <category>index scan</category>
      <category>indexing</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/160</guid>
      <comments>https://modernflow.tistory.com/160#entry160comment</comments>
      <pubDate>Sun, 22 Jan 2023 22:46:53 +0900</pubDate>
    </item>
    <item>
      <title>Restful API 설계</title>
      <link>https://modernflow.tistory.com/159</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;이 글을 쓰는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고민&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 저는 현재 회사에서 msa구조를 갖고 서비스를 개발중입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 새로운 기능을 개발하는 도중&lt;span&gt;&amp;nbsp;&lt;/span&gt;자원을 표현하는 계층을 어떻게 표현해줘야 할까?라는 고민을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 본문 하단에 고민에 대한 테스크와 결과를 적어두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Restful api가 나온 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 로이 필딩은 HTTP의 주요 저자 중 한 사람으로 그 당시 웹(HTTP) 설계의 우수성에 비해 제대로 사용되어지지 못하는 모습에 안타까워하며 웹의 장점을 최대한 활용할 수 있는 아키텍처로써 REST(Representational State Transfer)를 발표했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- Rest를 직역하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;자원(리소스)의 표현에 의한 상태 (정보) 전달이라고 해석할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;- 조금 풀어서 해석하면 웹에 존재하는 모든 자원에 고유한 URL을 부여하여 활용하는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Restful api란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- REST 아키텍처 스타일을 따르는 API를 REST API라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- REST 아키텍처를 구현하는 웹 서비스를 RESTful 웹 서비스라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그렇기에 Restful한 api와 Rest api는 같은의미로 사용할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Rest 아키텍쳐 스타일&amp;nbsp;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. URI는 자원의 위치를 표현한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- id가 1인 아이템을 조회한다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# good
GET /items/1

#bad
GET /my-item/listup/1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. HTTP Method (GET, POST, PUT, DELETE 등)를 사용하여 &lt;span&gt;자원에 대한 행위를 &lt;/span&gt;표현합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1673186395212&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 아이템을 등록한다
POST /items
body {&quot;title&quot;:&quot;초코 아이스크림&quot;, &quot;price&quot;: 1000, &quot;type&quot;:&quot;snack&quot;}

#1번 아이템을 가져온다
GET /items/1

#snack타입인 아이템들을 가져온다
GET /items?type=snack

#1번 아이템의 가격을 바꾼다
PATCH /items/1
{&quot;price&quot;:1200}

#1번 아이템의 title과 type을 바꾼다
PUT /items/1
{&quot;title&quot;: &quot;해리포터와 마법사의 돌&quot;, &quot;price&quot;:1000, &quot;type&quot;:&quot;book&quot;}

#1번 아이템을 DB에서 지운다
DELETE /items/1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 설계대로라면 Entity는 아래처럼 유추해볼 수 있습니다&lt;/p&gt;
&lt;pre id=&quot;code_1673219474172&quot; class=&quot;less&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Item(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0L,

    val title: String = &quot;&quot;,

    val price: Int,

    val type: ItemType,
)

enum class ItemType{
    BOOK, SNACK ... ;
}&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-1 Put vs Patch&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Put&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 요&lt;/span&gt;&lt;span&gt;청을 일부분만 보낸 경우 나머지는 default 값으로 수정되는 게 원칙으로 &lt;/span&gt;&lt;span&gt;바뀌지 않는 속성도 모두 보내야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 그렇기 때문에 해당 api를 사용하는 클라이언트는 resource의 상태(값)를 알고 있어야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 해당 resource에 값이 없으면 요청 받은 body로 create해줘도 무방합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 그렇기에 1번을 요청하든 100번을 요청하든 멱등성이 보장됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Patch&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하나의 resource에 하나의 property를 변경합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 멱등성을 보장하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 고민한 테스크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4-1 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- msa구조로 &lt;b&gt;Accounts&lt;/b&gt;서버와 &lt;b&gt;Products&lt;/b&gt;서버가 나눠져있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 쇼핑몰로 예를들면 유저가 좋아요를 클릭한 아이템과 조회한 아이템에 대한 정보를 &lt;b&gt;Accounts&lt;/b&gt;서버에 저장해주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클라이언트의 정렬 조건등에 의해 아이템의 type을 같이 저장해주어야 합니다.&lt;/p&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-2 접근&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 확장 가능성을 고려하여 테이블은 좋아한 아이템, 조회한 아이템을 따로 설계를 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하나의 테이블에서 관리하지 않고, 두개의 테이블에서 관리하기 때문에 api도 분리했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하나의 테이블로 관리하지 않았기 때문에 api에서도 다른 데이터라는 사실을 분명히 드러냈습니다.&lt;/p&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-3 api 스펙 작성&lt;/p&gt;
&lt;pre id=&quot;code_1673187847096&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;* header authorization Bearer ey~~~~~ -&amp;gt; 모든 요청에 JWT토큰을 사용해서 유저 정보를 식별함 (생략)

#사용자가 아이템을 조회했을 때 최근 본 항목에 등록한다
POST /accounts/viewed-items
body {&quot;itemId&quot;:1, &quot;type&quot;:&quot;snack&quot;}

#사용자가 아이템에 대해서 좋아요를 클릭했을때 좋아한 목록에 등록한다
POST /accounts/liked-items
body {&quot;itemId&quot;:1, &quot;type&quot;:&quot;snack&quot;}

#사용자가 좋아한 아이템을 수정한다
PUT /accounts/liked-items
body {&quot;itemId&quot;:1, &quot;type&quot;:&quot;book&quot;}

#사용자가 좋아한 아이템들을 조회한다
GET /accounts/liked-items

#사용자가 좋아한 아이템을 제거한다
DELETE /accounts/liked-items/1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 스펙을 보고 아래와 같은 entity를 유추해볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1673219825695&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class UserLikedItem(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0L,

    val userId: Long = 0L,

    val itemId: Long = 0L,

    val itemType: ItemType = UNKNOWN,

    val likedAt: LocalDateTime = LocalDateTime.now(),
)    

enum class ItemType{
    UNKNOWN, BOOK, SNACK ... ;
}&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-4 스펙 고민&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 논리적 경로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- liked-items와 viewd-items는 논리적으로는 items라는 폴더로 묶어도 괜찮지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그렇다면 아래처럼 가능하지 않을까?&lt;/p&gt;
&lt;pre id=&quot;code_1673188222317&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET /accounts/items/liked-items
GET /accounts/items?type=liked&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결정&lt;/b&gt;: 논리적으로는 그럴 수 있지만, 실제 데이터의 위치를 표현하는게 설계를 직관적으로 꼬지않고 하는것이라고 생각해서 4-3처럼 작성했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Post&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아래처럼 POST의 URI 무언가를 식별하는 키를 같이 넣어주면 안되는가? 라고 생각했지만 이는 잘못된 설계임을 알게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- URI는 데이터를 식별하는 정보로 사용되어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- URI의 정보를 활용해서 데이터를 등록하면 안됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1673188415514&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# bad
POST /accounts/liked-items/1
{&quot;type&quot;:&quot;book&quot;}

# good
POST /accounts/liked-items
{&quot;itemId&quot;:1, &quot;type&quot;:&quot;book&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결정&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 4-3처럼 등록했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 또한 1번 아이템에 대해 멱등성을 보장해야한다면 POST가 아닌 PUT이 올바르다고 생각합니다.&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;5. 추가적인 생각&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 api를 restful 하게 가져갈 수 없지만, restful하게 가져갈 수 있는 api라면 최대한 아키텍처를 지켜주는게 좋다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- restful api가 나온 이유에 대해 생각해보고, 클라이언트 개발자가 api 문서만 보고도 어떤 행위를 하는 api인지 파악할 수 있다면 잘 작성한 문서라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 추가적으로 독자님의 비슷한 경험이나 판단 근거에 대해서 댓글 달아주시면 정말 감사하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/REST&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;위키피디아&lt;/a&gt;에 더 자세한 추가 설명이 나와있습니다.&lt;/p&gt;</description>
      <category>개발/설계</category>
      <category>api 설계</category>
      <category>http</category>
      <category>HTTP method</category>
      <category>Rest</category>
      <category>RESTful API</category>
      <category>restful api 설계</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/159</guid>
      <comments>https://modernflow.tistory.com/159#entry159comment</comments>
      <pubDate>Sun, 8 Jan 2023 23:50:09 +0900</pubDate>
    </item>
    <item>
      <title>한 디바이스에 git 계정 여러개 등록</title>
      <link>https://modernflow.tistory.com/158</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 깃을 사용하던 중 제 개인 계정도 등록하고 싶어서 공부하게 됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. ssh key 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 경로 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cd ~/.ssh&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 키 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여기서 제 깃 이메일과 -f라는 옵션으로 구체적인 파일명을 적어주었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ssh-keygen -t rsa -C hojihun5516@daum.net -f hojihun5516&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(개인계정)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ssh-keygen -t rsa -C company@company.com -f company&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (회사계정 임시로 company라고 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. public key 복사&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;cat hojihun5516.pub&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 위의 명령어로 나온 내용을 복사하여 github-&amp;gt;settings-&amp;gt;ssh keys에 등록해줍니다&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;3. ssh config 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cd ~/.ssh&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vim config&lt;/p&gt;
&lt;pre id=&quot;code_1664778941111&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Host github-hojihun5516
	HostName github.com
	User hojihun5516@daum.net
	IdentityFile ~/.ssh/hojihun5516

Host github-myNickname
	HostName github.com	
	User company@company.com
	IdentityFile ~/.ssh/company&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;span&gt;4. 디바이스에 ssh 등록&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ssh-add hojihun5516&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ssh-add company&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 날 경우 eval $(ssh-agent) 실행하고 다시 등록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 클론 받으셔도되고 remote 변경해서 테스트 해보셔도됩니다~&lt;/p&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>개발/Git</category>
      <category>git</category>
      <category>git config</category>
      <category>다중 계정</category>
      <category>디바이스</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/158</guid>
      <comments>https://modernflow.tistory.com/158#entry158comment</comments>
      <pubDate>Mon, 3 Oct 2022 15:37:08 +0900</pubDate>
    </item>
    <item>
      <title>AWS Codepipeline-Elasticbeanstalk-free tier 자동 배포(3)</title>
      <link>https://modernflow.tistory.com/154</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Codepipeline 생성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CA2jS/btrt7uxuVxs/4Slg4S0QPRo0KdOV6F5ekK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CA2jS/btrt7uxuVxs/4Slg4S0QPRo0KdOV6F5ekK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CA2jS/btrt7uxuVxs/4Slg4S0QPRo0KdOV6F5ekK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCA2jS%2Fbtrt7uxuVxs%2F4Slg4S0QPRo0KdOV6F5ekK%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;1117&quot; height=&quot;690&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 소스 스테이지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Github v2를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 연결에 원하는 Repository 혹은 계정을 등록해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Observer가 해당 repository의 branch를 보고있다가 변경이되면 해당 파이프라인이 실행됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXQx8E/btrt6t6Jvbw/mKeuX5DKeIcxNZ6EMKUrFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXQx8E/btrt6t6Jvbw/mKeuX5DKeIcxNZ6EMKUrFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXQx8E/btrt6t6Jvbw/mKeuX5DKeIcxNZ6EMKUrFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXQx8E%2Fbtrt6t6Jvbw%2FmKeuX5DKeIcxNZ6EMKUrFK%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;1260&quot; height=&quot;870&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;870&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 data-ke-size=&quot;size16&quot;&gt;- 저는 환경변수를 사용해야했기 때문에 제가 작성한 prod.env 파일의 내용들을 빌드 프로젝트에 추가했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NOWUA/btrtY99sTJI/Wycn6klkci1pvW1mV7j9m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NOWUA/btrtY99sTJI/Wycn6klkci1pvW1mV7j9m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NOWUA/btrtY99sTJI/Wycn6klkci1pvW1mV7j9m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNOWUA%2FbtrtY99sTJI%2FWycn6klkci1pvW1mV7j9m0%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;816&quot; height=&quot;784&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;784&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;792&quot; data-origin-height=&quot;904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NPWYo/btrt3QapgqQ/JqxhJ0W21tZSYtx1nT1qGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NPWYo/btrt3QapgqQ/JqxhJ0W21tZSYtx1nT1qGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NPWYo/btrt3QapgqQ/JqxhJ0W21tZSYtx1nT1qGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNPWYo%2Fbtrt3QapgqQ%2FJqxhJ0W21tZSYtx1nT1qGK%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;792&quot; height=&quot;904&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;904&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;812&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k65Gy/btrt4JPLd7R/7N9jGE5u7KZjrVK0X7T9a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k65Gy/btrt4JPLd7R/7N9jGE5u7KZjrVK0X7T9a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k65Gy/btrt4JPLd7R/7N9jGE5u7KZjrVK0X7T9a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk65Gy%2Fbtrt4JPLd7R%2F7N9jGE5u7KZjrVK0X7T9a1%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;332&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;332&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-origin-width=&quot;820&quot; data-origin-height=&quot;769&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/css3ly/btrt6ukfbWY/HbY4oM56HFNL2G5ur31sT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/css3ly/btrt6ukfbWY/HbY4oM56HFNL2G5ur31sT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/css3ly/btrt6ukfbWY/HbY4oM56HFNL2G5ur31sT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcss3ly%2Fbtrt6ukfbWY%2FHbY4oM56HFNL2G5ur31sT1%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;820&quot; height=&quot;769&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;769&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 배포스테이지 추가&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b55O7o/btrt7s7xt7h/LKvEmDiRfUriA5iyFSwaMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b55O7o/btrt7s7xt7h/LKvEmDiRfUriA5iyFSwaMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b55O7o/btrt7s7xt7h/LKvEmDiRfUriA5iyFSwaMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb55O7o%2Fbtrt7s7xt7h%2FLKvEmDiRfUriA5iyFSwaMK%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;903&quot; height=&quot;600&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 배포기다리기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. ElasticBeanstalk에 환경변수 넣어주기&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;1821&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdoJJk/btrt5xhhQa4/sonLMJwSt0zXKCJyK55N9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdoJJk/btrt5xhhQa4/sonLMJwSt0zXKCJyK55N9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdoJJk/btrt5xhhQa4/sonLMJwSt0zXKCJyK55N9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdoJJk%2Fbtrt5xhhQa4%2FsonLMJwSt0zXKCJyK55N9K%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;1821&quot; height=&quot;464&quot; data-origin-width=&quot;1821&quot; data-origin-height=&quot;464&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;1830&quot; data-origin-height=&quot;866&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIX0Wx/btrtXZF1G52/QzMklcvmpUrt5MUB7M5Em1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIX0Wx/btrtXZF1G52/QzMklcvmpUrt5MUB7M5Em1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIX0Wx/btrtXZF1G52/QzMklcvmpUrt5MUB7M5Em1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIX0Wx%2FbtrtXZF1G52%2FQzMklcvmpUrt5MUB7M5Em1%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;1830&quot; height=&quot;866&quot; data-origin-width=&quot;1830&quot; data-origin-height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 접속해보면 배포가 완료되어있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 튜토리얼을 해보시고 생략해도 되는부분이 있다면 알려주시면 감사하겠습니다.&lt;/p&gt;</description>
      <category>개발/AWS</category>
      <category>aws</category>
      <category>CICD</category>
      <category>codepipeline</category>
      <category>ElasticBeansTalk</category>
      <category>NestJS</category>
      <category>Node</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/154</guid>
      <comments>https://modernflow.tistory.com/154#entry154comment</comments>
      <pubDate>Tue, 22 Feb 2022 23:57:24 +0900</pubDate>
    </item>
    <item>
      <title>AWS Codepipeline-Elasticbeanstalk-free tier 자동 배포(2)</title>
      <link>https://modernflow.tistory.com/153</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Elastic Beanstalk 생성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFRjjN/btrt3PPZR1o/mVEcQsAaHum9dT7WMbNVQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFRjjN/btrt3PPZR1o/mVEcQsAaHum9dT7WMbNVQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFRjjN/btrt3PPZR1o/mVEcQsAaHum9dT7WMbNVQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFRjjN%2Fbtrt3PPZR1o%2FmVEcQsAaHum9dT7WMbNVQk%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;965&quot; height=&quot;430&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;430&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-origin-width=&quot;996&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bizxHe/btrt4gtk8ra/TXRQjsY7Ql1eWKtLzuxuc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bizxHe/btrt4gtk8ra/TXRQjsY7Ql1eWKtLzuxuc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bizxHe/btrt4gtk8ra/TXRQjsY7Ql1eWKtLzuxuc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbizxHe%2Fbtrt4gtk8ra%2FTXRQjsY7Ql1eWKtLzuxuc1%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;996&quot; height=&quot;784&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;784&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;1) 환경생성&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czjeSr/btrt1Jv4js5/BxKuGqMy0qSIzAradbMy9k/img.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 네트워크 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아래 데이터베이스 서브넷도 체크해주세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- t2 micro는 가용영역이 2a와 2c만 허용한다고 하네요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQgopU/btrtYdkoQ4a/7Moalkssyuka0ykVfOy71K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQgopU/btrtYdkoQ4a/7Moalkssyuka0ykVfOy71K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQgopU/btrtYdkoQ4a/7Moalkssyuka0ykVfOy71K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQgopU%2FbtrtYdkoQ4a%2F7Moalkssyuka0ykVfOy71K%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;935&quot; height=&quot;856&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;856&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-origin-width=&quot;849&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzrp0f/btrt4hshQ7b/1WFbzAj1E69pNKxiWeYu4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzrp0f/btrt4hshQ7b/1WFbzAj1E69pNKxiWeYu4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzrp0f/btrt4hshQ7b/1WFbzAj1E69pNKxiWeYu4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzrp0f%2Fbtrt4hshQ7b%2F1WFbzAj1E69pNKxiWeYu4K%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;849&quot; height=&quot;596&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발/AWS</category>
      <category>aws</category>
      <category>CICD</category>
      <category>codepipeline</category>
      <category>ElasticBeansTalk</category>
      <category>free tier</category>
      <category>NestJS</category>
      <category>Node</category>
      <category>t2-micro</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/153</guid>
      <comments>https://modernflow.tistory.com/153#entry153comment</comments>
      <pubDate>Tue, 22 Feb 2022 23:57:10 +0900</pubDate>
    </item>
    <item>
      <title>AWS Codepipeline-Elasticbeanstalk-free tier 자동 배포(1)</title>
      <link>https://modernflow.tistory.com/152</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명하기에앞서 CICD를 위해 시도한 것들&lt;/li&gt;
&lt;li&gt;project에 필요한 files&lt;/li&gt;
&lt;li&gt;Elastic Beanstalk 생성&lt;/li&gt;
&lt;li&gt;CodePipeline 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1.설명하기에앞서 CICD를 위해 시도한 것들&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;githubaction&lt;/li&gt;
&lt;li&gt;ECR - ECS(EC2) - ALB&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github Action은 사용하기 편했습니다.&lt;br /&gt;marketplace가 존재하여 원하는 flow는 쉽게 찾을 수 있었습니다.&lt;br /&gt;ECR - ECS(EC2)를 활용하여 배포를 했는데 t2-micro(프리티어용) 인스턴스로는 CD를 할 수 없었습니다.&lt;br /&gt;ENI가 최소 3개가 필요한데 t2-micro는 2개만 지원하기 때문에 아무리 soft memory를 줄여도 이를 해결할 수 없었습니다.&lt;br /&gt;fargate를 사용한다면 쉽게 해결할 수 있겠지만 사이드 프로젝트라서 비용부분을 줄이고 싶었습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 요즘 많이 사용한다는 codepipeline을 사용해봤습니다.&lt;br /&gt;AWS의 codepipeline은 github뿐 아니라 다른 repository에서도 코드를 참조할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;elasticbeanstalk는 Paas로 생각보다 좋았습니다.&lt;br /&gt;제가 코드에 집중할 수 있는 환경을 만들어주었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. project에 필요한 files&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Procfile&lt;br /&gt;프로젝트 root에 Procfile을 만들어주세요&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;web: npm run deploy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) buildspec.yml&lt;br /&gt;프로젝트 root에 buildspec.yml을 만들어주세요&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;version: 0.2
phases:
  install:
    commands:
      - 'npm ci'
  build:
    commands:
      - 'npm run build'
artifacts:
  files:
    - '**/*'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) package.json&lt;br /&gt;package.json의 scripts부분에 해당 deploy명령어를 추가해주세요&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;&quot;scripts&quot;: {
...
&quot;deploy&quot;: &quot;npm ci &amp;amp;&amp;amp; npm run build &amp;amp;&amp;amp; npm run start:prod&quot;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/AWS</category>
      <category>aws</category>
      <category>CICD</category>
      <category>codepipeline</category>
      <category>ElasticBeansTalk</category>
      <category>NestJS</category>
      <category>Node</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/152</guid>
      <comments>https://modernflow.tistory.com/152#entry152comment</comments>
      <pubDate>Tue, 22 Feb 2022 23:57:01 +0900</pubDate>
    </item>
    <item>
      <title>터미널에서 git 인증 id, pw 안될 때</title>
      <link>https://modernflow.tistory.com/147</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;step1.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;root&amp;nbsp;아래에&amp;nbsp;.git-credentials&amp;nbsp;파일&amp;nbsp;생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;step2.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github -&amp;gt; settings -&amp;gt; developer settings 에서 token 발행 (발행 권한 맨위에 1개만 체크해도 됨) - repo 권한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;step3.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;step1에서&amp;nbsp;생성한&amp;nbsp;.git-credentials&amp;nbsp;아래에&amp;nbsp;https://[user&amp;nbsp;id]:[token]@github.com&amp;nbsp;을&amp;nbsp;입력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) https://hojihun5516:ghp_ynQb3Y21Q1XdybCfoID4gq6j8pW3w1ubO@github.com&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;step4.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에&amp;nbsp;git&amp;nbsp;config&amp;nbsp;--global&amp;nbsp;credential.helper&amp;nbsp;store&amp;nbsp;입력&lt;/p&gt;</description>
      <category>개발/Git</category>
      <category>clone</category>
      <category>github</category>
      <author>모플로</author>
      <guid isPermaLink="true">https://modernflow.tistory.com/147</guid>
      <comments>https://modernflow.tistory.com/147#entry147comment</comments>
      <pubDate>Mon, 17 Jan 2022 16:51:47 +0900</pubDate>
    </item>
  </channel>
</rss>