<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Code Art Online</title>
    <link>https://kiritoni.tistory.com/</link>
    <description>안녕하세요, cool &amp;amp; soft한 엔지니어가 되고싶은 토니입니다!</description>
    <language>ko</language>
    <pubDate>Wed, 5 Aug 2026 20:18:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>kiritoni</managingEditor>
    <image>
      <title>Code Art Online</title>
      <url>https://tistory1.daumcdn.net/tistory/6928316/attach/0ded4a294e754766824dee0695f6deb5</url>
      <link>https://kiritoni.tistory.com</link>
    </image>
    <item>
      <title>MZ가 바라본 AWS AI-DLC (일주일간 AWS로 출근지옥...)</title>
      <link>https://kiritoni.tistory.com/58</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;NHN AD에서 인턴으로 근무하면서, AWS에서 일주일간 열리는 AI-DLC 워크샵에 참관할 수 있게 되었습니다.&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;&lt;b&gt;AI-DLC가 무엇이냐 하면...&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기업이 AI 실험 단계에서 프로덕션 준비가 완료된 솔루션으로 나아가도록 돕는 방법론으로, 기술적 역량을 비즈니스 성과와 정렬하는 것을 핵심으로 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;출처:&lt;/i&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776153040995&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;AWS 주간 소식 모음: OpenAI 파트너십, AWS Elemental Inference, Strands Labs 등 | Amazon Web Services&quot; data-og-description=&quot;지난 한 주 동안 저는 AI-DLC(AI 기반 수명 주기) 워크숍을 통해 고객들이 비즈니스를 혁신하도록 지원하는 일에 깊이 몰두했습니다. 2026년 내내 저는 다양한 고객을 대상으로 이러한 세션을 진행&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/blogs/korea/aws-weekly-roundup-openai-partnership-aws-elemental-inference-strands-labs-and-more-march-2-2026/&quot; data-og-url=&quot;https://aws.amazon.com/ko/blogs/korea/aws-weekly-roundup-openai-partnership-aws-elemental-inference-strands-labs-and-more-march-2-2026/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/h2RuV/dJMb8U8UX41/XkhBBQK28FLGMTF3cSYSk1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/tIpEk/dJMb8RRTfFy/OuvQ271CupH3d8kzQfRaAK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/cS6QLN/dJMb83kujAr/xMeZ3EjcKXaYFogynUpssK/img.png?width=1024&amp;amp;height=622&amp;amp;face=78_203_143_391&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/korea/aws-weekly-roundup-openai-partnership-aws-elemental-inference-strands-labs-and-more-march-2-2026/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/blogs/korea/aws-weekly-roundup-openai-partnership-aws-elemental-inference-strands-labs-and-more-march-2-2026/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/h2RuV/dJMb8U8UX41/XkhBBQK28FLGMTF3cSYSk1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/tIpEk/dJMb8RRTfFy/OuvQ271CupH3d8kzQfRaAK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/cS6QLN/dJMb83kujAr/xMeZ3EjcKXaYFogynUpssK/img.png?width=1024&amp;amp;height=622&amp;amp;face=78_203_143_391');&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;AWS 주간 소식 모음: OpenAI 파트너십, AWS Elemental Inference, Strands Labs 등 | Amazon Web Services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;지난 한 주 동안 저는 AI-DLC(AI 기반 수명 주기) 워크숍을 통해 고객들이 비즈니스를 혁신하도록 지원하는 일에 깊이 몰두했습니다. 2026년 내내 저는 다양한 고객을 대상으로 이러한 세션을 진행&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;aws.amazon.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;이렇게 말하면 뭐지...싶고 어려운데, &lt;b&gt;무엇인지 이해하는 것만으로도&lt;/b&gt; 협업의 방법을 바꿀 수 있겠다는 생각이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;최근에는 정말이지 AI없이 개발하는 사람은 없는 것 같습니다. 특히 AI를 통해서 풀스택 개발이 쉬워지면서, 팀 프로젝트에서 한 사람이 처리할 수 있는 일이 굉장히 많아졌습니다. 하지만 회사든 학교든, 우리는 팀이 존재합니다. 먼 미래에는 어떻게 될지는 모르겠지만, 결국에는 팀으로 일하는 것이 인간이라는 생각이 듭니다. 인간만이 할 수 있는 일이 있겠죠...&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팀으로 일하더라도 AI를 사용합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;'내 AI는 이렇게 답하더라, 너의 클로드는 뭐라고 하니?' 등등의 이야기도 꽤 자주 오가는 모습을 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;동기들과 한 프로젝트를 같이 진행해보며 결국에 AI에게 먹일 docs 파일을 깃으로 관리하게 되더라구요!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;docs 파일이 점점 늘어나고, 비즈니스 요구사항에 따라서 바뀌는 건 '코드' 가 아니라 'AI를 위한 문서'임을 자연스레 체감하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 서론은 여기까지 하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;약간의 재미를 위한 출근 썰(일상 공유)과 함께... 마지막으로 느낀 점을 공유해보고자 합니다!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;진행은 회사의 개발팀, 기획팀, 그리고 AWS Solutions Architect분들이 함께해주셨습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;AI-DLC란, AI기반 개발 수명주기를 의미합니다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;1. 인간의 감독 하게 AI 기반 실행&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: #ef5369;&quot;&gt;2. 역동적인 팀 협업&lt;/span&gt;&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;과연 이 두 가지로 &lt;b&gt;'품질 저하 없이', '소프트웨어를 더 빠르게 제공'&lt;/b&gt;하려면 어떻게 해야할까요?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V7Bg1/dJMcafl0PLv/SumA2JBzfOOgOI0a7GU9bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V7Bg1/dJMcafl0PLv/SumA2JBzfOOgOI0a7GU9bK/img.png&quot; data-alt=&quot;출처: AWS Blog&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V7Bg1/dJMcafl0PLv/SumA2JBzfOOgOI0a7GU9bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV7Bg1%2FdJMcafl0PLv%2FSumA2JBzfOOgOI0a7GU9bK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;374&quot; height=&quot;401&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: AWS Blog&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;AWS에서는 이를 위해 세 단계를 제시합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;1. Inception phase (초기 단계): 비즈니스 의도를 상세한 요구사항, 스토리, 유닛으로 변환합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;2. Construction phase (구축 단계): 인셉션에서 검증된 컨텍스트를 사용하여 AI를 통해 개발 및 구축하는 단계입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;3. Operations phase (운영 단계): 이전 단계에서 축적된 컨텍스트를 적용해 인프라를 코드로 관리하고 배포를 진행합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oz7wo/dJMcabDUs3K/rQw1H1tuJArv7dG87KHuWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oz7wo/dJMcabDUs3K/rQw1H1tuJArv7dG87KHuWK/img.png&quot; data-alt=&quot;출처: AWS Blog&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oz7wo/dJMcabDUs3K/rQw1H1tuJArv7dG87KHuWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foz7wo%2FdJMcabDUs3K%2FrQw1H1tuJArv7dG87KHuWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;679&quot; height=&quot;348&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: AWS Blog&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인상깊었던 점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 모두가 참여하는 인셉션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발팀뿐만이 아니라 기획팀도 참여합니다. 어떻게 보면, 기획팀뿐만이 아니라 개발팀도 참여한다고 볼 수 가 있습니다. 개발자는 기획을 상세히 알아야 하고, 기획자라고 해서 개발을 몰라서는 안 됩니다. 기획자분들을 보면서 (제가 학생 신분을 벗어난지 얼마 안 되서 그럴지 모르지만) 나보다 아키텍트를 더 잘 알고 계시지 않을까 하는 생각이 들었습니다. 개발자분들을 보면서는 '주어진 기획을 따르는 것' 뿐만이 아니라 '디테일한 부분을 스스로 제안하고 개선하려는 자세'가 인상깊었습니다. 모두가 한 스크린을 보면서 질문을 던지고 정말 많은 문서를 하나하나 읽으며 짚었습니다. 이 과정에 후반부에 가서는 피로하게 느껴질 수 있다고 생각합니다. 그래서 진행자의 역할이 더욱 두드러졌고, 한 사람, 특히 직책이 높은 한 분이 진행자를 맡기보다 돌아가면서 모두가 진행을 하는 점이 인상깊었습니다. 이번에는 참관을 했지만 나중에는 나도 진행을 할 수 있으면 너무 재밌었겠다는 생각이 들었습니다. 이 과정이 가장~ 길었습니다. 문서 작업은 오래, 개발은 빠르게가 핵심이라고 합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로, md 파일을 만들어 쭉 나열하는 것이 아니라, '함께 trade-off를 이야기하며 선택해나가는 방식'으로 진행하게 됩니다. 나올 수 있는 질문과 선택지를 AI가 md파일 안에 작성합니다. 선택지는 최소 3개 주어집니다. 인간 또한 답변을 md파일 안에 포함해 작성합니다. 예를 들어, ULID vs UUID를 선택해야하는 질문에 대해 'answer: ULID'라고 기록합니다.&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;1536&quot; data-origin-height=&quot;2048&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfBnTi/dJMcacCPwKh/VKDJlh7djsP1x7N4R86qLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfBnTi/dJMcacCPwKh/VKDJlh7djsP1x7N4R86qLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfBnTi/dJMcacCPwKh/VKDJlh7djsP1x7N4R86qLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfBnTi%2FdJMcacCPwKh%2FVKDJlh7djsP1x7N4R86qLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;2048&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;2048&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;kiro 스티커를 받았습니다. 너무 귀여워요!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI-DLC는 kiro와 함께 진행되었습니다.&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;&lt;b&gt;2. 유닛으로 나누어, 개발은 빠르게&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다같이 docs를 정리하고 난 다음에는 팀을 3명정도로 구성하여 개발에 들어갔습니다. 이때, 인셉션에서 합의한 docs의 내용을 바꾸어야 한다면... (특히 개발하면서 그런 일이 정말 많죠! 처음 계획한대로 개발이 안 되죠...) 임의로 바꾸기보다 변경을 요청하고, 모두가 이를 공유해야 합니다.&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;size18&quot;&gt;&lt;b&gt;3. TDD 회의론&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 과정은 TDD를 중심으로 진행되었습니다. AWS의 솔루션 아키텍트 분들도, TDD가 없을때와 있을때의 차이가 많이 난다고 말씀해주시면서 TDD를 추천해주셨습니다. TDD없이 바로 개발을 하게 되면 아마 만족스러운 결과물이 안 나올거라고 이야기해주셨습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 AI-DLC를 참관하며 AI 문서 작업 -&amp;gt; TDD를 순서대로 개발을 해보았지만 아직 잘 못하는 것 같습니다...ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TDD = 상세한 기획 문서 라고 생각합니다. 인간이 개발을 하지 않기에, 할루시네이션에 대비하여 Request에 해당하는 Response는 정확히 알아야 할 필요가 있겠죠. 그래야 인간이 지휘자로서의 역할을 제대로 할 수 있다고 생각합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 운영환경에서의 동작을 보장해주지는 못한다는 점! 그래서인지 TDD에 부정적인 입장을 갖는 개발자분들도 쉽게 볼 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...그럼에도 불구하고 놓친 부분을 잘 잡아주는 점은 좋았다고 생각합니다. 다같이 인셉션을 한다고 해서, 기획 문서가 꼼꼼했다고 해서 저어어엉말 디테일한 부분을 빼먹었을 수 있으니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;마지막으로 TMI 투척!&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;1536&quot; data-origin-height=&quot;2048&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7FxNG/dJMcafGjFVU/piwNik7oblmU4KTBdWqKtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7FxNG/dJMcafGjFVU/piwNik7oblmU4KTBdWqKtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7FxNG/dJMcafGjFVU/piwNik7oblmU4KTBdWqKtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7FxNG%2FdJMcafGjFVU%2FpiwNik7oblmU4KTBdWqKtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;2048&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;2048&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;일주일동안 AWS로 출근하면서 갑자기 변경된 출퇴근 시간과 장소에 체력이 조금 바닥났습니다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구내염도 생기고 얼굴도 퀭해지고...특히 듀얼모니터를 쓸 수 없어서 힘들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7시 반까지 일찍 출근하는 편이어서, 차막힘이나 혼잡함을 생각해본적 없는데..이 정도일줄은...!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0UVOM/dJMcagkTAhG/3srEFc7bgdKWMkSqabj071/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0UVOM/dJMcagkTAhG/3srEFc7bgdKWMkSqabj071/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0UVOM/dJMcagkTAhG/3srEFc7bgdKWMkSqabj071/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0UVOM%2FdJMcagkTAhG%2F3srEFc7bgdKWMkSqabj071%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;414&quot; height=&quot;414&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간식도 정말 많이 제공해주셨습니다. 그래서 살이 많이 쪘습니다... 평소에는 동기들과 점심에 샐러드를 먹는데 점심까지 제공해주셔서 하하...&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;360&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OFN7z/dJMcaciv7oI/eZEXUqRDJ5B9TyJMfzYI6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OFN7z/dJMcaciv7oI/eZEXUqRDJ5B9TyJMfzYI6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OFN7z/dJMcaciv7oI/eZEXUqRDJ5B9TyJMfzYI6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOFN7z%2FdJMcaciv7oI%2FeZEXUqRDJ5B9TyJMfzYI6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;360&quot; height=&quot;480&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 날 마신 센터필드 라떼(?) 이거 추천합니다. 약간 달달해서 좋아요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfFgPG/dJMcagkTAic/a4ORjLdnraDouzuHUfSs31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfFgPG/dJMcagkTAic/a4ORjLdnraDouzuHUfSs31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfFgPG/dJMcagkTAic/a4ORjLdnraDouzuHUfSs31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfFgPG%2FdJMcagkTAic%2Fa4ORjLdnraDouzuHUfSs31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;360&quot; height=&quot;480&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각도 못하고 있었는데 기념품도 챙겨주셔서 감사했습니다!! 특히 바람막이는 운동할 때 잘 입고 있어요~ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;size18&quot;&gt;&lt;b&gt;마무리..&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일주일동안 소중한 경험을 했습니다.. 갑자기 이 주에 작업해야 하는 양이 많아져서 100% 집중하지는 못해서 너무 아쉽습니다 ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;#나도 해보고 싶다!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GDGoC 활동을하며 사이드 프로젝트를 진행하고 있는데 아직 기획 단계라, 꼭! AI-DLC로 진행해보아야겠습니다!!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI로 협업을 어떻게 해야할까? 라는 의문이 드는 개발자분들이라면 이런 방법도 있으니 한번쯤 해보시는 것을 추천드려요 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;#여기 개발 맛집이다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 인스타그램 릴스를 보다가 어떤 개발자님이 하신 이야기를 보았습니다. 이 말에 정말 공감이 되었고 출처를 적어두고 싶었는데 지나가듯 본거라서 기억이 안 나네요... ㅠㅠ &quot;AI 시대에 개발자가 필요 없어진 것 아니냐?&quot;라는 질문에 &quot;축구는 누구나 할 수 있지만 우리는 축구 경기를 본다. 호날두나 메시같은 개발자가 되고싶다.&quot;라고 답해주셨습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 축구보다는 요리가 조~금 더 적절하겠다는 생각이 들었습니다. 우리는 매일 요리를 하고, 요리가 된 걸 사먹기도 합니다. 정말 옛날옛적에... 불도 없었을때는 요리사가 없었겠죠. 그게 직업도 아니었을 거라 생각합니다. 각자 밥을 해먹던 어느날 정말 요리를 맛있게 하는 사람이 등장했겠죠. 그리고 그게 직업이 되었을 거라는 생각이 듭니다. 돈을 받고 요리를 파는 형태. 이들이 나중에는 궁궐에서 일하거나 주막에서 일을하거나... 어찌되었든 스페셜한 분야가 생겨났을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수많은 시간이 흘러 우리는 누구든 요리를 합니다. 충분한 조리도구, 좋은 식재료를 언제든 구할 수 있습니다. 엄마밥도 정말 맛있습니다. 특히 할머니밥은 기절입니다. 그래서 요리사가 필요없어졌을까요? &lt;b&gt;엄마밥 맛있지만 더 맛집을 찾아서 갑니다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI를 만난 개발자도 마찬가지라 생각합니다. 파인다이닝으로 갈지, 일반 식당으로 갈지 그건 이제 개발자의 선택입니다. 파인다이닝이라고 돈 더 잘 버는 건 아닙니다. 일반 식당이 훨씬 더 많은 손님을 받아 매출을 올릴 수 있겠지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;#고객 만족&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Solutions Architect분들도 너무너무 멋있었습니다! 그동안은 그냥 말 그대로 '솔루션 아키텍트.'구나 라고만 생각했었는데... 특히 '고객 만족'에 대해서 제가 너무 추상적으로 생각하고 있었다는 걸 느꼈습니다. 고객이 질문을 하면 친절히 응답해주는 것이 아니라 '직접 뛰어드는 것'에 가까웠습니다. 일하시는 것을 눈으로 보니 더욱 동경하게 되었습니다. 특히 서비스나 도메인을 빠르게 이해하고 합류할 수 있는 능력이 중요해보였습니다. 커뮤니케이션을 하시는 방법도 굉장히 인상깊었습니다. 아무래도 도메인에 속한 현업자가 아니니까 모르는 점이 있을 수밖에 없습니다. 그럼에도 불구하고 모르는 것을 적극적으로 질문해주셨는데, 몰입에 대한 태도가 와닿았습니다. 고객의 입장에서도 만족할 수밖에 없겠구나 하는 생각이 들었습니다..ㅎㅎ&lt;/p&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;</description>
      <category>이야기</category>
      <category>AI</category>
      <category>AWS</category>
      <category>후기</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/58</guid>
      <comments>https://kiritoni.tistory.com/58#entry58comment</comments>
      <pubDate>Sun, 19 Apr 2026 23:03:16 +0900</pubDate>
    </item>
    <item>
      <title>2주안에 AWS SAA + DVA 뽀개기</title>
      <link>https://kiritoni.tistory.com/57</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEfQ6v/dJMcagEWqRt/A3Z3BzPhIPzeOHaosjyIV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEfQ6v/dJMcagEWqRt/A3Z3BzPhIPzeOHaosjyIV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEfQ6v/dJMcagEWqRt/A3Z3BzPhIPzeOHaosjyIV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEfQ6v%2FdJMcagEWqRt%2FA3Z3BzPhIPzeOHaosjyIV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;846&quot; height=&quot;405&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 AWS에서 발급하는 자격증인 SAA, DVA에 관해 작성해보려고 한다!&lt;/p&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;이 글을 읽으면 좋은 분: 정말 빨리 자격증을 취득해야 한다, 이정도 기간 안에도 AWS 자격증 딸 수 있는지 궁금하다, 몇 문제 덤프를 풀어야 합격하는지 궁금하다 하시는 분들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 글을 읽으면 안 좋은 분: AWS를 처음 사용해본다 (혹은 숙련도가 심하게 낮다), AI가 없으면 간단한 배포/운영도 못한다, 정석적으로 공부해보고 싶다 하시는 분들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우선 AWS 자격증 등급에는 크게 Professional, Associate, Foundational이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Professional은 실무에서 2년 이상, Associate는 실무에서 1년 이상 AWS를 사용한 사람을 대상이 시험을 응시하기에 적합하다 (AWS 공식 홈페이지 설명 기준)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 실무에서 AWS를 사용해본 적은 없지만, 교내 프로젝트를 경험하며 EC2, RDS, Route53, ALB, ACM, S3 간단한 IAM 정도는 혼자서 셋팅할 수 있는 정도로 시작을 했다. 그리고 그 상태에서 시험을 대충 응시했으면 떨어졌겠지만, 인턴을 시작하며 대부분의 과제가 AWS 관련이었기 때문에 DynamoDB, S3, Athena, Glue, Bedrock, SQS, EventBridge Scheduler, Lambda, SDK, CDK(찍먹)를 사용해본 정도로 시작하게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;공부 시간&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SAA 시험 일주일 전에 바로 예약을 하고, 공부는 평일에만 진행했다. DVA도 SAA 시험 바로 다음 날에 예약했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그래서 일주일이지만 사실 시험 하나 당 5일, 하루에 평균 2시간 공부했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;인턴을 하고 있어서 엄청난 시간을 투자하기가 어려웠기에, 아침 / 점심 / 오후로 나누어서 짬짬히 공부했다.&amp;nbsp;&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;풀었던 문제&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SAA는 덤프가 있었다. 그런데 덤프를 각잡고 풀지는 않았다. 거의 안 풀었다.&lt;/li&gt;
&lt;li&gt;DVA는 덤프가 없었고, examtopics에서 문제를 사거나 풀지는 않았다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;대부분 클로드한테 문제를 내달라고 하고 푸는 방식으로 진행했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;문제 수로만 따지면 SAA 200문제, DVA 100문제 정도 풀고 시험에 들어갔다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;최소 400~500문제를 풀으라는 블로그들이 많았다. 그렇게 풀면 900점 이상 나올 거 같다. 하지만 난 시간이 없기 때문에!&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;공부 방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말한 것처럼 덤프를 거의 풀지 않고 AI와 함께 공부했다.&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;size18&quot;&gt;짧은 시간 안에 공부를 하는 방법 with Claude&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 총 10세트씩 진행하며, 클로드가 한 문제씩 내준다.&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;3. 매일 아침에는 이전날의 오답 정리 노트를 읽는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 매일 오후 (공부 마무리할 시간)에는 오늘의 오답 노트를 쭉 정리한다. 복사+붙여넣기로 노션에 차곡차곡 날짜별 토글을 누적시킨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 문제를 풀 때에는,&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;&lt;/li&gt;
&lt;li&gt;클로드에게는 문제별로 시험 팁을 요청하는 것이 좋다. 이 팁이 헷갈릴 때 굉장히 도움이 되고, 문제를 무작정 풀면서 팁을 찾아가는 것보다 유용하다. 팁을 통해서 AWS 시험식 생각 흐름/판단 방식을 익힌다.&lt;/li&gt;
&lt;li&gt;정리를 할 때에는 그룹화를 하는 것이 중요하다. AWS 서비스 종류가 엄청나게 많은데, 비슷한 것끼리 비슷한 위치에 있을 수 있도록 헤딩 (#, ##, ###) 을 사용해서 묶어준다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;개념을 정리할 때에는 최대한 복붙하지 않고 스스로 타이핑한다. 이 과정에서 더 잘 기억에 남았다. 더 궁금한 점이 생기면 바로바로 클로드에게 물어본다.&lt;/li&gt;
&lt;li&gt;세트를 많이 돌리고 나면 클로드에게 스스로 점검을 시켜야 하는 부분이 있다. 내가 SAA 또는 DVA 시험에 출제되는 내용 중 몇 퍼센트를 커버했는지 꼭 질문하자.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;클로드가 중간 중간에 '오답 집중 공략' 세트를 할지 '새로운 문제'를 계속 풀어볼지 물어보면 '새로운 문제'를 선택한다. 최대한 많은 문제와 개념을 머리에 넣어야 한다. 오답 집중 공략은 시험 당일 또는 전날에 해도 충분하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험을 보려고 시험을 봤지만, 나는 인턴 과제를 하고 있었기 때문에 공부하며 배운 것을 바로 적용해보면서 익혔다. 그래서 과제가 시험에도 도움이 되고, 시험이 과제에 도움이 되었다. VPC Gateway Endpoint설정, ElastiCache, S3 생명주기 관리 등등... 문제를 풀면서 '어 이건 되게 유용한데? 이렇게 설계해도 되는구나?'라는 생각이 많이 들었다. 그런 부분들은 바로바로 적용해보아서 재밌었다. SOA에도 관심이 있고... (일단 지금은 힘들어서 바로는 못 딸 거 같지만!) 조금 시간을 더 들여서 SAP도 보고싶어졌다.&lt;/p&gt;</description>
      <category>인프라/AWS</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/57</guid>
      <comments>https://kiritoni.tistory.com/57#entry57comment</comments>
      <pubDate>Fri, 27 Mar 2026 17:00:41 +0900</pubDate>
    </item>
    <item>
      <title>[RDBMS와 NoSQL의 추구미] 돌고 도는 트레이드 오프</title>
      <link>https://kiritoni.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;교내 프로젝트에서 백엔드를 맡으면, 거의 무의식적으로 손이 먼저 움직입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API 설계하고, ERD 그리고, MySQL 연결하고. NoSQL을 쓴 발표를 본 기억이 거의 없습니다.. 아마 하나 정도였나? 그리고 저도 마찬가지였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 그랬을까 생각해보면, 솔직히 귀찮아서였습니다. 엔티티로 딱딱 떨어지는 데이터를 테이블에 넣으면 편하고, 기술의 트레이드 오프를 고민할 이유가 없었습니다. 학교 프로젝트에서 트래픽이 터질 일은 없으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 RDBMS를 파다 보면 어느 순간 '동시성 문제'와 마주하게 됩니다. 그리고 솔직히, 학부 수준에서 이걸 제대로 겪기는 어렵다고 생각합니다. Race condition을 억지로 만들어놓고 &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;최근에 NoSQL을 다시 들여다보면서 이런 생각이 들었습니다. RDBMS가 느리다면, 그건 정확성을 위해 속도를 포기한 것이다. 그럼 반대로, 정말 빠르게 처리해야 하는 상황에서는 정합성을 어떻게 지키는 걸까? NoSQL은 그 문제를 어떻게 풀고 있을까?&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;철학의 차이를 이해하자&lt;/span&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;RDBS의 핵심 철학은 '틀리느니 차라리 멈춰라'입니다 데이터의 정확성과 일관성이 최우선이고, 그것을 위해서라면 속도나 가용성을 일부 희생하는 선택을 기꺼이 합니다. ACID가 그것의 결정체.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS가 DynamoDB(앞으로 NoSQL 대신에 Dynamo를 기준으로 서술)를 만든 배경을 짚어봅시다. 2004년 amazon 내부에서 있었던 한 일화로 DynamoDB가 탄생합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;전자상거래 플랫폼은 기본 키만으로 쿼리하는 등 단순한 사용 패턴을 사용했음에도 불구하고 관계형 데이터베이스의 한계를 시험하고 있었습니다. 이러한 사용 패턴은 관계형 데이터베이스의 복잡성을 요구하지 않습니다. (중략)&lt;br /&gt;&lt;br /&gt;이 데이터베이스 문제에 대한 COE(Correction of Error) 과정에서 당시 20세였던 스와미나탄(스와미) 시바수브라마니안&lt;br /&gt;&amp;nbsp;(현재 AWS 데이터베이스, 분석 및 머신러닝 조직의 부사장)이라는 젊고 어쩌면 순진했던 인턴이 &quot;왜 이런 작업에 관계형 데이터베이스를 사용하는 거죠? 이런 워크로드에는 SQL 수준의 복잡성과 트랜잭션 보장이 필요하지 않은데요.&quot;라고 질문했습니다.&lt;br /&gt;&lt;br /&gt;이러한 계기로 아마존은 데이터 저장소 아키텍처를 재고하고 최초의 다이나모 데이터베이스를 구축하게 되었습니다.&amp;nbsp;&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;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/aws/happy-birthday-dynamodb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://aws.amazon.com/ko/blogs/aws/happy-birthday-dynamodb/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1774252401957&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;Happy 10th Birthday, DynamoDB! ??? | Amazon Web Services&quot; data-og-description=&quot;On January 18th 2012, Jeff and Werner announced the general availability of Amazon DynamoDB, a fully managed flexible NoSQL database service for single-digit millisecond performance at any scale. During the last 10 years, hundreds of thousands of customers&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/blogs/aws/happy-birthday-dynamodb/&quot; data-og-url=&quot;https://aws.amazon.com/blogs/aws/happy-birthday-dynamodb/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b3ybIb/dJMb8XR438z/ntq1gbCAqzVBr3WipJR8jK/img.png?width=768&amp;amp;height=386&amp;amp;face=0_0_768_386,https://scrap.kakaocdn.net/dn/sEcgy/dJMb9iIGvTu/W4SaET9H6JDLvxz3rljqP0/img.png?width=768&amp;amp;height=386&amp;amp;face=0_0_768_386,https://scrap.kakaocdn.net/dn/eVyQ0/dJMb9bv1HKo/MaOUkRPZ7Tq8Ehl11lGTQK/img.jpg?width=2544&amp;amp;height=738&amp;amp;face=0_0_2544_738&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/aws/happy-birthday-dynamodb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/blogs/aws/happy-birthday-dynamodb/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b3ybIb/dJMb8XR438z/ntq1gbCAqzVBr3WipJR8jK/img.png?width=768&amp;amp;height=386&amp;amp;face=0_0_768_386,https://scrap.kakaocdn.net/dn/sEcgy/dJMb9iIGvTu/W4SaET9H6JDLvxz3rljqP0/img.png?width=768&amp;amp;height=386&amp;amp;face=0_0_768_386,https://scrap.kakaocdn.net/dn/eVyQ0/dJMb9bv1HKo/MaOUkRPZ7Tq8Ehl11lGTQK/img.jpg?width=2544&amp;amp;height=738&amp;amp;face=0_0_2544_738');&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;Happy 10th Birthday, DynamoDB! ??? | Amazon Web Services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;On January 18th 2012, Jeff and Werner announced the general availability of Amazon DynamoDB, a fully managed flexible NoSQL database service for single-digit millisecond performance at any scale. During the last 10 years, hundreds of thousands of customers&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;aws.amazon.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;그래서, DynamoDB의 다른 철학을 한 줄로 요약하면 '느려지느니, 차라리 빠르게 처리하고 나중에 맞춰라'가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DynamoDB는 온디맨드 모드 기준, 초당 수백만개의 요청을 처리할 수 있음과 동시에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;트래픽에 따라 자동으로 확장됩니다.&lt;/span&gt; RDS의 경우에는 초당 요청 수로 단순 비교를 할 수는 없지만... 인스턴스의 스펙에 종속되어있습니다. 그래서 두 DB의 형태는 '추구미'가 서로 다르다고 할 수 있겠지요.&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;RDBMS의 동시성 추구미: 비관적 잠금 (Pessimistic Locking)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RDBMS는 동시성 문제를 '충돌이 일어날 것이라고 가정하고 미리 막는' 방식으로 처리하는데, 이것이 비관적 잠금입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1774252590180&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;  -- A 출금
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;  -- B 입금
COMMIT;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두 쿼리는 반드시 같이 성공하거나 같이 실패해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 개발자가 직접 명시해줄수도 있고, 쿼리 하나만 날리는 경우에는 자동으로 BEGIN -&amp;gt; 실행 -&amp;gt; COMMIT을 걸어줍니다. (auto commit)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDBMS는 이처럼 비관적 잠금을 기본으로 제공하고, 낙관적 잠금은 개발자가 version 컬럼을 직접 구현하는 방식으로 사용할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DynamoDB의 동시성 추구미: 낙관적 잠금 (Optimistic Locking)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;DynamoDB는 반대로 '충돌이 거의 없을 것이라고 가정하고, 충돌이 났을 때만 처리하는'방식을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;락이 없으니 처리량은 높지만, 충돌이 잦은 환경에서는 재시도가 폭발적으로 늘어납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낙관적 잠금 전략을 직접 구현해도 되지만, AWS SDK for Java에서는 `@DynamoDBVersionAttribute`를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DynamoDB가 버전 번호를 할당하고, 이후 업데이트 할때마다 버전 번호가 자동으로 올라갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;동시성 문제를 아예 피하는 방법은 atmoic counter 이다.&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;read-modify-write 사이클을 없애줍니다. 이 사이클은 DB에서 현재 값을 읽어오고, 애플리케이션에서 값을 수정하고, 수정한 값을 다시 DB에 쓰는 과정을 말합니다. 이 사이클 사이의 간격 때문에 동시성 문제가 발생합니다. 이러한 문제는 서버가 여러 대일때 더 두드러집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DynamoDB에서 이를 해결하는 핵심은 '읽기 자체를 안 한다'는 것입니다. read-modify-write 사이클 자체가 없어서, 애플리케이션은 현재 값이 뭔지 모릅니다.. 수정 명령 (ex. 조회수에 1 더해줘) 만 DB에 던져둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 쓰기 요청은 수신된 순서대로 적용됩니다. '현재 값이 얼마인지'를 애플리케이션에서 알 필요가 없고, DB가 순서대로 처리해주기 때문에 충돌이 생길 여지 자체가 없어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 멱등성이 없습니다. 따라서 네트워크 오류로 애플리케이션이 재시도를 할 경우에는 카운터가 두 번 증가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결론: 조회수처럼 약간의 오차가 괜찮은 값에는 좋지만, 결제 금액처럼 정확해야 하는 값에는 사용해서는 안 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;[출처] https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1774319419137&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;Working with items and attributes in DynamoDB - Amazon DynamoDB&quot; data-og-description=&quot;With GetItem, you must specify the entire primary key, not just part of it. For example, if a table has a composite primary key (partition key and sort key), you must supply a value for the partition key and a value for the sort key.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters&quot; data-og-url=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cFIy7Q/dJMb8QelGe6/VHKjVu8fQmsJ5AczWkYHs1/img.png?width=674&amp;amp;height=663&amp;amp;face=0_0_674_663,https://scrap.kakaocdn.net/dn/cEhpoG/dJMb8VNuQQc/jhZMR1nRKtBIFGbanSJZjK/img.png?width=657&amp;amp;height=663&amp;amp;face=0_0_657_663&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cFIy7Q/dJMb8QelGe6/VHKjVu8fQmsJ5AczWkYHs1/img.png?width=674&amp;amp;height=663&amp;amp;face=0_0_674_663,https://scrap.kakaocdn.net/dn/cEhpoG/dJMb8VNuQQc/jhZMR1nRKtBIFGbanSJZjK/img.png?width=657&amp;amp;height=663&amp;amp;face=0_0_657_663');&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;Working with items and attributes in DynamoDB - Amazon DynamoDB&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;With GetItem, you must specify the entire primary key, not just part of it. For example, if a table has a composite primary key (partition key and sort key), you must supply a value for the partition key and a value for the sort key.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.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;h4 data-ke-size=&quot;size20&quot;&gt;DynamoDB도 2018년부터 트랜잭션을 지원합니다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`TransactWriteItems`를 사용하면 여러 item을 하나의 트랜잭션으로 묶을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 내부적으로 2-Phase Commit으로 동작합니다. 그래서 일반 쓰기 대비 비용이 2배입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;throughput 소모도 2배입니다. DynamoDB에서 트랜잭션은 RDB처럼 쓰라고 만든 게 아니기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'꼭 필요한 일부 케이스'에만 선택적으로 쓰는 것이 의도된 사용법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 비관적 락도 지원은 하지만, aws docs에 따르면 RDMS처럼 row를 잡아두고 대기시키는 방식이 아니라(`FOR UPDATE`), 충돌 시 트랜잭션 전체를 날리는 방식입니다. (`TransactWriteItems`) 물론 워딩은 '비관적 락'이라고 해놓았긴 합니다..ㅎㅎ&lt;/p&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://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/BestPractices_PessimisticLocking.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;[출처] https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/BestPractices_PessimisticLocking.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1774319419776&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;DynamoDB 트랜잭션을 사용한 비관적 잠금 - Amazon DynamoDB&quot; data-og-description=&quot;버전 확인을 조건 표현식으로 추가하여 트랜잭션을 낙관적 잠금과 결합할 수 있습니다. 이는 추가 보호 계층을 제공하지만 트랜잭션이 충돌을 감지하는 데 필요하지 않습니다.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/BestPractices_PessimisticLocking.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/BestPractices_PessimisticLocking.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/BestPractices_PessimisticLocking.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/BestPractices_PessimisticLocking.html&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;DynamoDB 트랜잭션을 사용한 비관적 잠금 - Amazon DynamoDB&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;docs.aws.amazon.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;h4 data-ke-size=&quot;size20&quot;&gt;Eventually Consistency 읽기에서도 트레이드오프가 있습니다.&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 DynamoDB는 Eventually Consistent Read입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 분산 시스템에서 데이터 업데이터가 즉시 모든 노드에 반영되지 않더라도, 일정 시간이 지나면 결국 모든 복제본이 최종적으로 동일한 데이터를 가지게 되는 일관성 모델입니다. 고가용성을 위해 강한 일관성을 포기하고 일시적인 데이터 불일치를 허용합니다. 그 덕분에 어떤 노드에서든 바로 응답할 수 있으니 빠르고, 노드가 몇 대든 상관없으니 스케일아웃에도 유리하겠지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eventually consistent read는 strongly consistent read의 절반 금액입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결국에 돌고도는 트레이드 오프이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고가용성을 얻기 위해 복제를 하고➡️ 복제를 하니까 일시적 불일치가 생기고 ➡️ 그 불일치를 허용하는 모델이 eventually consistency...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DynamoDB는 왜 RDS랑 다르게 서버리스? ➡️ 처음부터 그렇게 (분산 환경 전제로) 태어났으니까... ➡️ 왜 분산환경이어야되는데? ➡️ 다시 위로 돌아가... 고가용성을 얻기 위해 복제를 하고... ➡️ ➡️ ➡️ ➡️ ➡️♾️♾️♾️♾️♾️&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DynamoDB에게 무슨 질문을 하든 다시 처음으로 돌고 돌아가게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 이러한 특성을 어떻게 활용해야 할까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋아요, 조회수처럼 약간의 지연이 괜찮은 데이터는 그대로 두는 것이 맞습니다. (물론 인스타 좋아요 수 하나가 절박한 사람은 계속해서 새로고침을 하겠지만...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 재고수량, 잔액처럼 정확성이 중요한 데이터는 Strongly Consistent를 쓰거나, 아예 설계 단계에서 DynamoDB가 적합한지 다시 생각해봐야 합니다. 대신 RDBMS는 단일 인스턴스에서는 트랜잭션으로 동시성을 제어하기 쉽지만, 트래픽이 늘어나 스케일아웃이 필요해지는 순간 Redis 같은 외부 도구로 분산 락을 따로 관리해줘야 하는 복잡도가 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 RDBMS가 맞냐, NoSQL이 맞냐는 동시성 문제에서도 한 번 생각해보는 것이 좋습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 조금의 불일치는 허용할 수 있는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 그리고 동시성 문제를 앞으로 어떻게 핸들링 해나갈 것인지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 나의 생각 정리.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;DynamoDB는 다른 문제를 풀기 위한 트레이드오프를 선택한 도구이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;도구의 철학을 이해하면, 트레이드오프가 보이고, 트레이드오프가 보이면 올바른 선택을 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>인프라/AWS</category>
      <category>AWS</category>
      <category>dynamodb</category>
      <category>NoSQL</category>
      <category>RDB</category>
      <category>rdbms</category>
      <category>RDS</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/56</guid>
      <comments>https://kiritoni.tistory.com/56#entry56comment</comments>
      <pubDate>Tue, 24 Mar 2026 17:13:26 +0900</pubDate>
    </item>
    <item>
      <title>AWS Athena 쿼리 성능 최적화하기</title>
      <link>https://kiritoni.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Athena에서 느린 쿼리, 리소스 초과 오류, 불필요한 비용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;AWS 공식 문서를 바탕으로 Athena 쿼리를 더 빠르고 효율적으로 만드는 핵심 기법을 정리해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;색깔별 구분&lt;/b&gt;&lt;/span&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;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;Athena + RDB 범용적으로 적용 가능: 초록색&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #000000;&quot;&gt;부분적으로 RDB에도 적용 가능: 빨간색&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;Athena 전용(RDB는 해당 없음): 회색&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;1. 조인 순서: 큰 테이블을 왼쪽에&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Athena는 분산 해시 조인을 실행할 때, 오른쪽 테이블을 빌드측으로 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 해시 테이블이 메모리를 초과하면 쿼리가 실패합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;항상 작은 테이블을 JOIN 오른쪽에 배치합니다.&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 style=&quot;color: #000000;&quot;&gt;해시 조인이란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 테이블을 조인할 때, 가장 직관적인 방법은 모든 행을 일일이 비교하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;orders 100 만행 x customers 10만행 = 1,000억번 비교 -&amp;gt; 당연히 너무 느립니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해시 조인이란 이 문제를 해결하는 방식인데, 사전(dictionary)을 만드는 것과 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;작은 테이블(customers)로 먼저 '해시 테이블'이라는 조회표를 메모리에 만들어 두고, 큰 테이블(orders)을 한 줄씩 읽으면서 조회 표에서 찾습니다. 전화번호부를 처음부터 끝까지 찾는 대신, 이름 색인으로 바로 찾는 것과 같습니다.&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;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 분산 해시 조인이란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Athena는 데이터를 혼자 처리하는 게 아니라, 여러 워커 노드가 병렬로 처리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&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 style=&quot;color: #000000;&quot;&gt;그래서 왜 '작은 테이블을 오른쪽에'가 중요할까?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;빌드 측 (작은 테이블)의 해시 테이블은 각 노드의 메모리에 올라가야 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 빌드 측이 너무 크면 메모리가 부족해서 쿼리가 실패합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Athena는 자동으로 작은 테이블을 빌드 측으로 쓰려고 하지만, 작성자가 직접 써줘야 할 떄도 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TIP) 빌드 측 크기를 메모리에 맞출 수 없다면, 빌드 테이블의 하위 세트를 나눠 여러번 조인하는 방식을 고려해볼 수 있어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;2. 윈도우 함수 대신 집계 함수 사용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;윈도우 함수는 모든 레코드를 유지하므로, `Query exhausted resources at this scale factor` 오류의 주범이 됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;row_number, rank대신 max_by, min_by, arbitrary같은 집계 함수를 활용하면 메모리 사용량을 크게 줄일 수 있습니다.&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 style=&quot;color: #000000;&quot;&gt;집계함수 vs 윈도우 함수&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;집계함수 (GROUP BY와 함께)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;행을 합쳐서 줄임, 메모리 사용 적음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SUM, COUNT, MAX, max_by등이 해당&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그룹당 결과가 딱 1행 나옴.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;윈도우 함수 (OVER와 함께)&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;행을 유지하며 계산, 전체를 메모리에 보관&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ROW_NUMBER(), RANK(), LAG()등이 해당&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5행이 들어오면 5행이 그대로 나오되, 순번같은 컬럼이 하나 추가됨&lt;/span&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;&lt;span style=&quot;color: #000000;&quot;&gt;arbitrary()는 GROUP BY를 쓸 때 생기는 SQL 문법 제약을 피하기 위한 함수입니다.&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SELECT에 쓴 컬럼은 반드시 GROUP BY에 있거나 집계 함수로 감싸야 하는데, 특정 집계가 필요하지 않다면 arbitrary()로 묶어서 에러를 피할 수 있습니다. 메모리도 아끼고 오류도 없앨 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773647050927&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT 
    user_id, 
    MAX(order_date) as last_order,
    ARBITRARY(address) as any_address -- 사용자 주소가 여러 개여도 하나만 가져옴
FROM orders
GROUP BY user_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;3. GROUP BY 절 최적화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;GROUP BY 절에는 꼭 필요한 열만 포함해야 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;숫자는 문자열보다 메모리를 덜 사용합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 카테고리 이름 대신, 카테고리 ID로 그룹화하는 것이 도움이 됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿼리 오류를 피하기 위해 GROUP BY에 추가하는 열은 arbitrary()함수로 대체할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #000000;&quot;&gt;4. 상위 N개 쿼리: ORDER BY + LIMIT&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Athena는 ORDER BY와 LIMIT이 함께 사용될 때 전용 최적화 작업을 수행합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 최근 N개, 또는 가장 빈번한 N개 값을 찾을 때, row_number() 윈도우 함수 대신 이 방법이 권장됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;5. 필요한 열만 SELECT&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;열 기반 형식 (parquet, ORC)을 사용할 때, SELECT * 대신 필요한 열만 지정하면 s3에서 읽는 데이터 양도 함께 줄어듭니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결과 열 수가 너무 많으면 ` &lt;span style=&quot;text-align: start;&quot;&gt;GENERIC_INTERNAL_ERROR: io.airlift.bytecode.CompilationException&lt;/span&gt; ` 오류가 발생할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TIP) Athena는 스캔한 데이터 용량만큼 과금됩니다. 열 수를 줄이면 쿼리 속도 뿐만 아니라, 비용도 함께 절감됩니다.&lt;/span&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #ffc1c8;&quot;&gt;6. 근사 집계 함수 사용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정확한 값이 필요하지 않은 분석이라면 근사 함수를 사용하여 메모리와 실행 시간을 크게 줄일 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;COUNT(DISTICT)대신 approx_distinct&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;7. LIKE 대신 regexp_like, 검색 범위 고정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;`LIKE '%substring%'`처럼 앞뒤 와일드카드를 모두 사용하면 전체 문자열을 스캔합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;접두사 검색이라면 `'substring%'`으로 검색을 고정하거나,` regexp_like(col, '^substring')`을 사용하세요.&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;&lt;span style=&quot;color: #000000;&quot;&gt;regex_like가 like보다 유리한 경우&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;여러 패턴을` | `(or) 로 한번에 검사&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;like를 세 번 따로 쓰는 것보다 regex_like가 더 빠름&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정규 표현식 엔진이 더 빠르게 처리한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;like 5개짜리 쿼리를 regexp_like 하나로 바꾸면 17% 빨라진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;8. UNION ALL vs UNION&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UNION은 중복 제거를 위해 모든 레코드를 처리하기 때문에, 메모리와 컴퓨팅 자원을 많이 소모합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;중복 제거가 꼭 필요한 경우가 아니라면 반드시 UNION ALL을 사용하세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;9. 대용량 결과는 UNLOAD로 내보내기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반 쿼리 결과는 압축되지 않은 단일 csv로 저장되지만, `UNLOAD`는 워커 노드에서 병렬로 직접 쓰기 때문에 훨씬 빠릅니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;parquet, json등 압축 방식으로도 저장할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TIP) 결과가 수만행을 초과하거나, 후속 분석을 위해 압축/컬럼형 포맷이 필요할 때 UNLOAD를 선택하세요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;10. 자주 쓰는 집계는 CTAS로 구체화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여러 쿼리가 동일한 조인과 집계를 공유한다면, `CREATE TABLE AS SELECT(CTAS)`또는 Glue ETL로 결과를 새 테이블로 사전 계산해둡니다. 대시보드처럼 동일 로직을 반복 실행하는 경우에 특히 효과적입니다. 단, 새 테이블을 주기적으로 최신 상태로 갱신해야 합니다.&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;&lt;span style=&quot;color: #000000;&quot;&gt;CTAS = Create Table As Select&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;CTAS로 공통 부분을 먼저 저장하고, 이후 위젯들은 가벼운 쿼리만 날림&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;조인 결과를 새 테이블로 저장 -&amp;gt; 이후 쿼리는 이 테이블만 읽음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 자주 쓰는 복잡한 쿼리를 미리 계산해서 테이블로 저장해두는 것.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;11. 쿼리 결과 재사용 설정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;짧은 시간 안에 동일한 쿼리가 여러번 실행될 때 (ex. 여러 사용자가 같은 대시보드 오픈), Athena의 쿼리 결과 재사용 기능을 활성화하면 이전 결과를 반환합니다. TTL을 지정해 refresh를 제어할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #9feec3; color: #000000;&quot;&gt;12. EXPLAIN으로 실행 계획 사전 분석&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;복잡한 조인 조건은 모든 레코드를 교차 비교시킬 수 있어서, 실행 시간이 레코드 수의 제곱에 비례해 증가합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿼리를 실행하기 전에 EXPLAIN문으로 실행 계획을 확인하고 병목을 사전에 파악하면 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/athena/latest/ug/performance-tuning-query-optimization-techniques.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/ko_kr/athena/latest/ug/performance-tuning-query-optimization-techniques.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1774146358102&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;쿼리 최적화 - Amazon Athena&quot; data-og-description=&quot;이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/athena/latest/ug/performance-tuning-query-optimization-techniques.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/athena/latest/ug/performance-tuning-query-optimization-techniques.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/athena/latest/ug/performance-tuning-query-optimization-techniques.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/athena/latest/ug/performance-tuning-query-optimization-techniques.html&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;쿼리 최적화 - Amazon Athena&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;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>인프라/AWS</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/55</guid>
      <comments>https://kiritoni.tistory.com/55#entry55comment</comments>
      <pubDate>Mon, 16 Mar 2026 16:42:58 +0900</pubDate>
    </item>
    <item>
      <title>  자바 17의 Record 공식 문서 살펴보기 - Record는 불변인가?</title>
      <link>https://kiritoni.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 전달하기 위한 DTO(Data Transfer Object) 클래스를 만들 때, 우리는 항상 getter, setter, equals, hashCode, toString을 기계적으로 만들어야 했습니다. (Lombok 라이브러리가 필수였던 이유).&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;핵심 개념:&lt;/b&gt; Record는 &quot;불변(Immutable) 데이터 객체&quot;를 아주 쉽게 생성할 수 있게 해주는 새로운 클래스 타입입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 장점:&lt;/b&gt; 레코드로 만들면 필수 메서드가 자동으로 생성됩니다. 간결성 &amp;amp; 불변성이라는 장점을 가져갈 수 있어요.&lt;/li&gt;
&lt;li&gt;근데 이렇게 불변 데이터 객체라고만 말할 수 있을까? 놉!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비교하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름과 나이 데이터를 담아서 전달하는 간단한 DTO(Data Transfer Object) 클래스를 만들 때를 비교해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❌ Before (Java 17 이전):&lt;/b&gt; 고작 데이터 2개를 담는 클래스인데, 생성자부터 getter, equals, hashCode, toString까지 수십 줄의 보일러플레이트(상투적인) 코드가 필요했습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class UserDto {
    private final String name;
    private final int age;

    public UserDto(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    @Override
    public boolean equals(Object o) { /* 생략 */ }
    @Override
    public int hashCode() { /* 생략 */ }
    @Override
    public String toString() { /* 생략 */ }
}
&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;b&gt;✅ After (Java 17 이후 - Record 도입):&lt;/b&gt; 마법처럼 단 한 줄로 끝! 불변성 보장과 모든 필수 메서드 생성을 컴파일러가 알아서 처리해줍니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public record UserDto(String name, int age) {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공식문서 짚어보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://openjdk.org/jeps/359&quot;&gt;https://openjdk.org/jeps/359&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;openjdk에 따르면, 자바는 의례적인 절차가 너무 많고 특히 Data Carrier를 생성할 때 그 특징이 두드러집니다. 그래서 이러한 불만을 해결하기 위해서 record를 만들었습니다. record의 목표는 단순히 코드를 줄이는 것은 아닙니다. &amp;ldquo;데이터를 데이터 그 자체로 모델링&amp;rdquo;하는 것이 주된 목적입니다. 올바른 의미를 부여하면, 코드는 자연스럽게 줄어든다는 철학을 담고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 record는 불변인가?&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;Record는 얕은 불변 (Swallowly Immutable)데이터를 담기 위한 제한적 형태의 클래스입니다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상자는 바꿀 수 없지만, 상자 안에 담긴 내용물 (객체)이 가변적 (List, Map, Set이나 사용자 정의 객체)이라면 그 내용물까지는 지켜주지 못한다는 의미입니다.&lt;/li&gt;
&lt;li&gt;record의 모든 컴포넌트는 암묵적으로 final이다. 즉, 한 번 할당된 참조값(주소)는 절대로 바꿀 수 없다는 뜻!&lt;/li&gt;
&lt;li&gt;예를 들어 record 안에 가변 객체 List가 들어있다고 하면, record는 이 리스트가 가리키는 주소값이 바뀌는 것은 막아주지만, 그 주소지에 있는 실제 리스트의 내부 데이터가 수정되는 것은 막아주지 못합니다.&lt;/li&gt;
&lt;li&gt;왜 깊은 불변이 아닌가? &amp;rarr; record의 성능과 유연성 때문이라고 생각합니다. 내부 객체까지 강제로 불변으로 만들려면, 컴파일러가 모든 참조를 추적하면서 복사본을 만들어야 하는데 비효율적입니다. 개발자에게 이 문제를 던집니다.&lt;/li&gt;
&lt;li&gt;개발자는 진정한 불변 객체로 만들고 싶다면&amp;hellip; 가변 객체를 불변 객체로 변환해서 저장하는 방법을 선택할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제약 사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제약 사항은 Data Carrier로서의 역할을 명확히 하기 위함입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속 불가 (extends)&lt;/li&gt;
&lt;li&gt;상태 외 인스턴스 필드 불가 (정적 static 필드는 가능)&lt;/li&gt;
&lt;li&gt;변경 불가: 암묵적으로 final 클래스입니다. abstract가 될 수 없고 모든 컴포넌트 역시 암묵적으로 final입니다.&lt;/li&gt;
&lt;li&gt;제약 사항 외에는 일반 클래스처럼 인터페이스 구현(implements), 제네릭 사용, 정적 메서드 선언, 커스텀 메스 작성 등 모두 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;튜플 대신 Record를 사용한 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(openjdk는)이름이 없는 튜플을 사용할 수도 있었지만 다음의 이유로 record를 선택했습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름의 중요성: 자바는 명확한 이름을 중요하게 생각합니다. String, String 튜플보다 firstName, lastName을 가진 클래스가 훨씬 명확하고 안전합니다.&lt;/li&gt;
&lt;li&gt;튜플은 생성자를 통한 데이터 유효성 검증 기능이 없습니다.&lt;/li&gt;
&lt;li&gt;Record는 데이터와 관련된 행위를 한 곳에 묶어둘 수 있지만, 순수 데이터인 튜플은 불가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공식 문서에서 추천하는 다른 기능과의 시너지&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저도 생각하고 써본적은 없는데 추천하는 시너지라고 하니까 좀 보기는 해야겠습니다&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Sealed Types &amp;rarr; 데이터의 종류를 제한한다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터페이스는 누구나 구현할 수 있지만, sealed는 내 자식은 얘네뿐이다!라고 제한해줍니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 지불방식은 카드와 계좌이체 두 종류밖에 없다고 정해줄 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pattern Matching &amp;rarr; 데이터를 꺼내는 형식을 자동화한다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존에는 타입을 확인하고, 강제로 변환하고, 메서드를 호출하는 3단계 과정이 필요했습니다.&lt;/li&gt;
&lt;li&gt;public void process(PaymentMethod method) { if (method instanceof Card) { // 1. 너 카드 맞니? (타입 확인) Card card = (Card) method; // 2. 그럼 카드로 변신해! (형변환) String num = card.cardNumber(); // 3. 카드 번호 좀 꺼내줘 (데이터 추출) System.out.println(&quot;카드 결제: &quot; + num); } else if (method instanceof Transfer) { Transfer transfer = (Transfer) method; System.out.println(&quot;계좌 이체: &quot; + transfer.accountNo()); } }&lt;/li&gt;
&lt;li&gt;record는 구조가 투명하기 때문에, 컴파일러가 상자를 열어서 내용물을 바로 변수에 담아줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 딱 '카드'와 '계좌이체' 두 종류만 있다고 선언 (Sealed)
public sealed interface PaymentMethod permits Card, Transfer {}

public record Card(String cardNumber, String bank) implements PaymentMethod {}
public record Transfer(String accountNo) implements PaymentMethod {}

// 패턴매칭
public void process(PaymentMethod method) {
    var result = switch (method) {
        // 'Card'라는 상자를 열어서 cardNumber와 bank를 바로 변수로 꺼냄 (패턴 매칭)
        case Card(var num, var bank) -&amp;gt; &quot;카드번호 &quot; + num + &quot;로 결제&quot;;
        
        // 'Transfer' 상자를 열어서 accountNo를 바로 꺼냄
        case Transfer(var acc) -&amp;gt; &quot;계좌 &quot; + acc + &quot;에서 이체&quot;;

    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 switch문에서 하나라도 빼먹은 게 있으면 컴파일 시점에 에러를 잡아줘서 default를 따로 쓸 필요가 없어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 만약에 여기서 gift card라는 결제 수단이 생겨서 permit에 추가한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제수단이 포함된 모든 switch문에 gift card를 추가하지 않은 곳은 컴파일 에러가 납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결국 sealed가 우리의 비즈니스 로직을 나 대신 감시해주고, default&amp;hellip;runtime exception을 날릴 필요가 없어져요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 누가봐도 결제수단의 의도를 잘 파악할 수 있음!&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java</category>
      <category>java</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/54</guid>
      <comments>https://kiritoni.tistory.com/54#entry54comment</comments>
      <pubDate>Fri, 6 Mar 2026 18:22:43 +0900</pubDate>
    </item>
    <item>
      <title>배민의 마이크로서비스 여행기 살펴보기</title>
      <link>https://kiritoni.tistory.com/53</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;오늘은 우아콘 2020...이라 좀 오래됐지만&lt;br /&gt;기업에서는 MSA를 어떻게 적용하게 되었는지 궁금해서&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=BnS6343GTkY&quot;&gt;https://www.youtube.com/watch?v=BnS6343GTkY&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=BnS6343GTkY&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bYZDzv/dJMb8865wph/Xkz3Q3KWQT5YRJGTM7N4Pk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=542_154_712_340,https://scrap.kakaocdn.net/dn/d3rYAC/dJMb83kpzJS/uIJR1BxKvWD9BW5w2qc5EK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=542_154_712_340,https://scrap.kakaocdn.net/dn/xDbTL/dJMb81fPgny/CF0KCB7slgRubJIgrmYWC1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=542_154_712_340&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[우아콘2020] 배달의민족 마이크로서비스 여행기&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/BnS6343GTkY&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2015&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2015년의 배민은 모든 서비스가 루비 DB에 연결되어있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 루비가 죽는 순간 모든 서비스가 죽는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때는 리뷰 테이블에 뭔가 문제가 있었는데, 하나의 오류가 다른 서비스 전체에 영향을 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해보면, 리뷰는 부가 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 리뷰 서비스에서 장애가 발생해도 고객이 주문하는 데 문제가 없어야 하는 것이 상식적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2016&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2016년부터는 하루 주문수가 10만을 돌파한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 php를 사용했지만, 이후 java로 교체하게 된다.&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;i&gt;1) 자바가 대용량 트래픽 안정적이다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;2) 국내 개발자 수급이 용이하다.&lt;/i&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;그리고 이때부터 MSA로의 도전을 시작하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제, 주문중계를 독립시켰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 더해 AWS 클라우드 인프라로 이전을 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;내가 느낀 가장 인상깊은 부분은 이 지점이었다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MSA를 기술적으로 하고 싶어서라기 보다는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매년 2.3배가 주문이 느는 상황에서 다들 서버가 버틸 수 있을지, 레거시를 감당할 수 있을지 걱정하기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 시스템에서 계속 장애가 나고 해결하기 어려웠기 때문에 배민은 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;+) 넷플릭스에서는 MSA가 기술적 선택이 아니라 생존의 문제였다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;지금은 배달 주문은 앱으로 하는 것이 배민 덕분에 정말 당연해졌지만,&lt;br /&gt;옛날을 기준으로 생각해보면 배민의 결제 서비스가 죽어도 전화로 주문하면 된다.&lt;br /&gt;진짜 옛날에는 배달책(?) 같은 거에서 찾아보고 전화 주문을 많이 했었지... &lt;br /&gt;게다가 그 시절에는 법적으로 돈과 관련된 것을 클라우드에 올릴 수 없어서 결제는 IDC일 수밖에 없었다고 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&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;size16&quot;&gt;주문 중계 서비스는 간단히 포워딩하는 서버이다. 예를 들어 가게에 주문이 들어오면 사장님은 앱, PC, 단말기 등에서 주문을 확인할 수 있는데 주문 접수를 중간에서 포워딩해준다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;파리바게뜨 알바생으로 3년동안 일했었는데, 배민에서 보통 주문이 들어오면 사장님 폰이 제일 먼저 울린다 (카톡)&lt;br /&gt;그리고 조금의 시간이 지나서 포스기에도 알림이 온다.&lt;br /&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;중간에서 가볍게 node.js로 돌아가고 있었지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;(배민의 메인 기술이 Java였지만 필요성에 의해서 조금씩 맞는 기술 스택을 선택했다고 한다) &lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에는 무거워져서 java로 바꾸게 된다.&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;치킨 디도스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람들이 선착순 할인에 환장한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자들은 매우 싫어한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1일차&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각한 것보다 몇배 이상 트래픽이 몰렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트 서버 자체가 죽어서 백엔드 주문 단에 들어오지도 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2일차&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 다음날도 이벤트가 있었다... 빨리 수습을 해야하는 상황.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 개발자들이 기적을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 IDC에서 AWS로의 이전이 한 달짜리 프로젝트였는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IDC 장비를 도저히 수급할 수 없어서 프론트 서버 이전이 하루가 걸렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결국 프론트 단에서는 트래픽 받을 수 있었는데 주문 서버(IDC에 있던게) 죽어버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB는 스펙이 좋아서 IDC로 버텼는데 프론트 서버, 주문 서버는 버틸 수가 없어서 AWS로 이전하게 된다.&lt;/p&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;3일차&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배민에서 AWS로 어지저찌 서버를 늘려서 결제도 잘 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 그 다음 단인 PG사에서 트래픽을 감당하지 못하고 죽어버렸다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4일차&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PG사에서 2배의 장비를 투입했고 치킨 디도스가 성공했다.&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;2017&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때부터는 하루 주문 수기 20만 건을 돌파했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS로 이전하고 있긴 했지만, 일부에 불과했고 비즈니스 로직을 손볼 것들이 너무 많았다고 한다.&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;&quot;대장애의 시대&quot;&lt;/b&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;배민이 안 되면 전화 주문이라도 할 줄 알았는데(옛날 기준), 그렇지 않다고 한다.&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;blockquote data-ke-style=&quot;style2&quot;&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;배민이 죽으면 요기요로 가서 요기요 서버가 터진다. 요기요가 안되면 또 다른 어플로 가서 거기 서버가 죽는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&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;그래서, 배민은 생존에 의해 MSA를 해야한다고 느끼게 되었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루비 DB에서 elastic search로 가게 목록 + 검색을 빼냈다.&lt;/li&gt;
&lt;li&gt;결과적으로는 루비 부하가 좀 줄었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2018&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서는 레거시 시스템을 개선하는 일이 우선순위가 높아지기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 매출에 거의 영향을 안 주기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 윗선에 레거시 시스템 개선을 설득하기 매우 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시기에는 하나의 가게는 하나의 광고만 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다보니 여러개의 광고를 하기 위해 사장님이 가게를 하나 더 파는 꼼수(?)가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 개발자들은 하나의 가게가 여러 광고를 할 수 있게 만들고 싶었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 광고를 하는 데 이득이 발생하니 회사도 그 방향이 더 이득이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이때는 장애에 대응하는 게 더 중요하다고 판단했고 미뤄지게 되었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가게 상세 (주요 장애 포인트)&lt;/li&gt;
&lt;li&gt;쿠폰, 포인트 탈루비&lt;/li&gt;
&lt;li&gt;오프라인 모드 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때의 프론트 서버는 php로, 루비 DB를 바라보고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루비를 다이나모 DB로 옮기고 싶었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 작업을 1~5분 주기로 돌려 AWS 다이나모 DB로 데이터를 퍼부었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 어쨌든 루비 DB로 가는 부담이 줄었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이나모 DB는 차로 따지면 스포츠카이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽을 매우 잘받지만 싱크가 좀 안 맞는 문제가 있었다. (당연함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 요구사항 바뀌면 수천줄짜리 배치 쿼리도 계속 바꾸어야 한다는 문제가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문, 리뷰 탈루비&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배민 서비스에서는 주문이 제일 복잡하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 모든 시스템이랑 다 엮여있기 때문이다.&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;1. 주문&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;&lt;/li&gt;
&lt;li&gt;비즈니스 연관도가 높다.&lt;/li&gt;
&lt;li&gt;지금은 하루 수백만 데이터가 쌓인다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 광고&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로시저 사용 1위&lt;/li&gt;
&lt;li&gt;돈을 다루다 보니까.. 돈 문제 삐끗하면 큰일난다. 회사의 메인 수익원 역할.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;콘웨이의 법칙&lt;/b&gt;&lt;br /&gt;시스템 설계가 조직의 구조를 따라간다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&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;size16&quot;&gt;이때의 주문 서버는 이렇게 두 개로 나뉘어 개발되고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 배민 주문 로직 &amp;gt; 배민 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 라이더스 주문 로직 &amp;gt; 라이더스 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 조직도 달랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 문제는 배민 라이더스는 배민이랑 비슷하게 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;똑같은 거 같은데 다르고... 완전 다르지도 않고....(애매함..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나중에 시스템을 통합하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 통합이 잘 안 됐다. 그래서 그냥 따로 서비스를 하고 있던 상황이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아예 새로운 주문 테이블을 설계하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 하나로 정리하고 애플리케이션 레벨에서 나눠서 서비스했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 크게 두 가지 방법이 있었다.&lt;/p&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;1️⃣ 주문 시스템 -&amp;gt; (기존) API 기반 데이터 전달&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 리뷰 시스템 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 레거시 DB 싱크&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 라이더스 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex. 음식 받으면 리뷰 쓰라는 푸쉬 알림을 API로 줌.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2️⃣ 이벤트 기반의 MSA&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 네 가지로 정의한다 : 생성, 접수, 배달완료, 취소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 주문 시스템은 이벤트만 발행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 시스템이 리뷰 시스템을 consume만 하는 방식으로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 다른 시스템이랑 주문 시스템이랑 상관이 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리뷰 시스템이 죽었다 살면 SQS에 쌓여 있으면 깨어나서 다시 consume하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 회복력이 좋아지는 효과가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 주문 시스템은 SQS를 만들고 시스템에 꽂기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 주문팀이 행복해지는 효과도 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;연동해주세요&quot; X ➡️ SQS만들테니 꽂아서 쓰세요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;여기에서 내가 예전에 개발했던 서버 관리 자동화 시스템이 생각났다.&lt;br /&gt;&lt;br /&gt;나도 API를 외부 서버로 호출하는 일이 있었는데&lt;br /&gt;외부 서버에 대한 의존성이 늘어나는 것 같고 처리 안 되면 어쩌지 불안불안...&lt;br /&gt;막말해서... 요청 들어왔는데 까치가 또 날아들어서 서버 꺼지면 어떡함? 이라능 생각도...&lt;br /&gt;그럼 중간에 없어진 애는 어케 되는 거지... &lt;br /&gt;+ 연동에 대한 부담은 덤. 계속 바뀌는 API 문서를 확인하고 반영하느라 지쳤는데&lt;br /&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;p data-ke-size=&quot;size18&quot;&gt;남은 레거시 2대장!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 가게 업주&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 광고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 가게랑 광고랑 1:1이라고 했었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 바꾸기 어려웠던 이유가 가게(shop) 테이블 안에 광고가 컬럼으로 들어가있었다.&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;그래서 이 프로젝트 하려면 서비스를 stop 해야한다. ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거 손대면 저거가.. 저거 손대면 저거가...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술적으로 MSA로 가려면 3~4달은 서비스 중단해야한다.&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;size18&quot;&gt;프로젝트 먼데이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 '프로젝트 먼데이'라는 것을 진행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로젝트에만 기술을 집중하겠다는 의사결정을 하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 이 프로젝트는 하나만 바꿔서 해결할 수 없는 문제였고, 하나 손대면 다 문제가 생기는 상황이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 이렇게 분리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 가게 상세 &amp;gt; 가게 노출 CQRS&lt;span style=&quot;background-color: #ffffff; color: #0a0a0a; text-align: start;&quot;&gt;(Command Query Responsibility Segregation)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 모델 사용 (서비스 조회용 가게 data를 분리한다.)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 가게 목록 + 검색 &amp;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;이때 API 조회 형식 vs CQRS 아키텍처 중 어떠한 의사결정을 했을까?&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;size18&quot;&gt;1안 - API 조회 형식으로.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 동기화에 대한 고민이 필요없고, 간단하다.&lt;/li&gt;
&lt;li&gt;장애 전파가 전파된다. 즉, 하나가 죽으면 연쇄적으로 죽는다.&lt;/li&gt;
&lt;li&gt;고성능 조회의 트래픽이 이곳 저곳... 다른 도메인으로 전파된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이론적으로 모든 시스템 대용량 트래픽 고려하겠지만 이상적인 상황이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 1안에서는 &lt;b&gt;3가지 문제&lt;/b&gt;가 있다고 정리할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성능&lt;/b&gt;&lt;/p&gt;
&lt;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;메인, 가게 리스트, 가게 상세 등은 초당 15000회 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장애 격리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스나 DB에 장애가 발생해도 고객 서비스를 유지하고 주문도 가능해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 동기화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 분산되어있어 동기화도 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2안 - CQRS 아키텍처 (전체를.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령 시스템과 조회 시스템을 분리하고, 조직 또한 분리함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 뒤에 들을 게 조금 더 남았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 들으면 나머지도 정리해서 느낀점과 함께 업데이트 할 예정@!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>이야기</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/53</guid>
      <comments>https://kiritoni.tistory.com/53#entry53comment</comments>
      <pubDate>Fri, 20 Feb 2026 16:17:05 +0900</pubDate>
    </item>
    <item>
      <title>GPU 서버 관리 자동화 시스템 알림 병목 해결기 (소비자-생산자 패턴, Redis Message Queue 알아보기)</title>
      <link>https://kiritoni.tistory.com/52</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;저는 1년간 교내 서버 관리자로 근무하면서 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;GPU 서버 관리 자동화 시스템&lt;/span&gt;의 백엔드를 개발해왔습니다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;오늘은 이때 마주했던 문제를 해결하는 방법, &lt;br /&gt;그리고 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;생산자(Producer)-소비자(Consumer) 패턴&lt;/span&gt;에 대해 작성해보려고 합니다!&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요구사항&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;먼저 이해를 돕기 위해 비즈니스 요구사항을 살펴보겠습니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GPU 서버의 각 컨테이너(정확히는 Pod)에는 &lt;b&gt;만료 기한&lt;/b&gt;이 있습니다. 사람이 직접 수작업으로 컨테이너를 내리는 대신, 정해진 만료 기한에 따라서 &lt;b&gt;컨테이너가 자동으로 정리&lt;/b&gt;되어야 합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;GPU 서버 관리 자동화 시스템에는 웹 UI가 존재합니다. 각 사용자는 &lt;b&gt;웹 UI에 대한 계정&lt;/b&gt;이 있으며, 계정 또한&lt;b&gt; 만료 기한&lt;/b&gt;이 존재합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;웹 UI 계정별로 컨테이너는 여러개 생성될 수 있습니다. 앞서 말했던 것처럼 여러개의 컨테이너에는 여러개의 만료기한이 각각 존재합니다.&lt;/li&gt;
&lt;li&gt;사용자 알림은 &lt;b&gt;Slack과 Email로&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 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;A. 스케줄러&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스케줄러를 사용해 매일 아침 8시(업무 시작 시간 전)에 만료 기한을 확인하는 동작이 수행됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;만료 기한이 지난 계정/컨테이너라면 각각 아래의 작업 수행합니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1. 계정: 만료된 계정은 soft-delete를 합니다. (이후 처리 방법은 생략)&lt;/li&gt;
&lt;li&gt;2. 컨테이너:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2-1. 만료된 컨테이너는 인프라 서버에 컨테이너 정리 및 Ubuntu 계정 &lt;b&gt;삭제 요청&lt;/b&gt;을 보냅니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;2-2. 삭제 요청이 수행되면, MySQL로 관리되는 UID/GID &lt;b&gt;회수 작업&lt;/b&gt;을 수행합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;B. 알림 전송&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Slack 및 Email 알림은 다음과 같은 기준으로 전송됩니다.&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;1. 계정: 계정 삭제 7, 3, 1일 전 및 완료 시 사용자 알림 전송&lt;/li&gt;
&lt;li&gt;2. 컨테이너: 컨테이너 삭제 7, 3, 1일 전 및 완료 시 사용자 알림 전송&lt;/li&gt;
&lt;li&gt;3. 관리자 알림: 작업 완료 및 오류 발생 시 관리자에게 Slack 알림 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 디테일한 작업이 수행되다보니, 처음 구현했을 당시에는 에러가 이곳저곳 튀어나왔습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 스프링 내부에서 작업을 온전히 처리하는 것이 아니라, Slack API와 저희 팀에서 개발했던 외부 인프라 API까지 호출해야 하는 상황이었기 때문입니다. 따라서 어느 구간에서 에러가 터질 지 확신할 수가 없었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 제가 주목했던 부분은 &lt;span style=&quot;color: #ef5369;&quot;&gt;Slack API를 호출하고 다음 작업을 수행하는 부분&lt;/span&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;Slack API에는 종류별로 정도는 다르지만 Rate Limit(속도 제한)이 존재합니다.&lt;/li&gt;
&lt;li&gt;짧은 시간 내에 너무 많은 요청이 들어오면 `429 Too Many Requests` 에러를 뱉습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이 에러가 발생하면 이후에 예정되어있던 작업들이 모두 멈추게 됩니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;예를 들어, 사용자 1, 2, 3의 컨테이너를 정리해야 한다고 가정합니다.&amp;nbsp;&lt;br /&gt;2번에서 429에러가 발생하면, 2번의 컨테이너는 정리된 채로 알림만 가지 않습니다.&amp;nbsp;&lt;br /&gt;3번의 컨테이너는 정리되지 않고 알림도 가지 않습니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하나의 스케줄러였지만 &lt;span style=&quot;color: #ef5369;&quot;&gt;하나의 작업 실패가 전체 루프를 중단시킨다는 문제&lt;/span&gt;가 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 사용자별 작업이 원자성을 가져야 하지만 보장되지 않고 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Redis를 완충 지대로 활용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 방법이 있지만, 저는 기존에 구성되어있던 Redis를 활용했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis를 단순 저장소가 아닌 메시지 큐로 활용하는 방법이 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`LPUSH` / `RPOP` / `BRPOP`을 사용하면 순서가 보장되는 큐로 사용할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  Redis 명령어 정리하기&lt;/b&gt;&lt;br /&gt;- LPUSH: 큐의 왼쪽(Head)에 데이터를 넣습니다. 여기에서는 알림 메시지를 생성하는 생산자가 사용합니다.&lt;br /&gt;- RPOP: 큐의 오른쪽(Tail)에서 데이터를 꺼냅니다. 여기에서는 소비자가 사용하며, First-In-First-Out 구조가 만들어집니다.&lt;br /&gt;- BRPOP: RPOP의 Blocking 버전입니다. 큐에 데이터가 없으면 설정한 시간동안 대기하다가 데이터가 들어오는 즉시 꺼내옵니다. 반복적인 Polling으로 인한 리소스 낭비를 줄일 수 있습니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생산자(Producer)와 소비자(Consumer)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;생산자(Producer)는 큐에 작업을 쌓고&lt;/span&gt;, &lt;span style=&quot;color: #ef5369;&quot;&gt;소비자(Consumer)는&lt;/span&gt; 자신의 처리 능력에 맞춰 &lt;span style=&quot;color: #ef5369;&quot;&gt;작업을 가져옵니다&lt;/span&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 시스템 간 결합도록 낮추고(Decoupling), 갑작스러운 트래픽 폭주(Burst)를 완충할 수 있습니다.&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;생산자(Producer): 알림이 발생하면 직접 API를 호출하지 않고 Redis List에 데이터를 넣기만 합니다. (Push)&lt;/li&gt;
&lt;li&gt;큐 (Queue) 전송해야 할 알림 데이터를 보관합니다. (Redis)&lt;/li&gt;
&lt;li&gt;소비자(Consumer): 1초마다 큐에서 하나씩 빼서 Slack API로 전송합니다. (Pop)&lt;/li&gt;
&lt;li&gt;➡️ 이 구조를 통해 속도조절 &amp;amp; 비결합(계정 삭제 비즈니스 로직과 알림 발송 로직이 분리됨)이라는 두 가지 장점을 챙길 수 있었습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt; ️ Redis외에 메시지 큐를 구현하는 옵션들&lt;/b&gt;&lt;br /&gt;- RabbitMQ, Apache Kafka, AWS SQS, In-Memory Queue (Java Blocking Queue) 등이 있습니다.&amp;nbsp;&lt;br /&gt;- 위 프로젝트에서는 RabbitMQ, Kafka를 적용하면 오버엔지니어링이라고 생각했습니다.&lt;br /&gt;- SQS의 경우 온프레미스 환경에서 관리하고 있었기 때문에 제외했습니다.&lt;br /&gt;- Java BlockingQueue는 간단하지만 당연하게도 애플리케이션이 종료되면 큐에 담긴 데이터가 사라집니다.&amp;nbsp;&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;  만약 Redis 없이 멀티스레드로만 해결했다면?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;1) 만약 뮤텍스 or 세마포어를 활용했다면&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Slack API의 속도를 제한하기 위해 Semaphore를 사용했다면, 스케줄러 스레드 자체가 대기 상태에 빠질 것입니다.&lt;/li&gt;
&lt;li&gt;알림 전송 스레드가 10개로 제한되어있는데, 1000개의 알림이 몰린다면 나머지 990개 요청은 세마포어 permit을 받기 위해 줄을 서서 기다려야 합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;결과적으로, 알림 전송이 끝날 때까지 스케줄러 스레드가 종료되지 못하고 리소스를 점유하게 됩니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;2) JVM의 BlockingQueue에 알림을 쌓아두고 멀티스레드로 소비한다면&lt;/span&gt;&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;&lt;/li&gt;
&lt;li&gt;그래서 시스템 관점에서 Redis를 사용했고, 덕분에 알림 데이터를 보관할 수 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;3) 멀티 스레드 방식에는 해당 서버 내부에서만 유효하기 때문에&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redis를 큐로 사용하면 서버가 몇 대가 되든 하나의 큐를 공유합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;따라서 전역적인 속도 제어가 가능해집니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;물론 아예 다른 Slack API 키를 사용하면 block 당하는 것을 막을 수도 있다고 생각합니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 서버가 늘어남에 따라 키도 계속 늘어나면 관리하기 복잡해지는 이슈가!&lt;/li&gt;
&lt;li&gt;서버마다 다른 키를 쓰면 어떤 서버에서 알림이 나갔는지 추적하기가 어렵습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Slack App 설정이 서버 수만큼 늘어납니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;워크스페이스의 앱 설치 개수 제한 등...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;로컬 멀티스레딩 원리를 분산 환경으로 확장해보기&lt;/blockquote&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 152px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 19px;&quot;&gt;설명 Index&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%; height: 19px;&quot;&gt;Key word&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;여기에서는?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%; height: 19px;&quot;&gt;Bounded Buffer (유한 버퍼)&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;Redis List -&amp;gt; 메모리가 제한된 거대한 전역 공유 버퍼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%; height: 38px;&quot;&gt;Mutual Exclusion (상호 배제)&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 38px;&quot;&gt;Redis의 Single-Thread 원자성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 19px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%; height: 19px;&quot;&gt;Race Condition (경합 상태)&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;LPUSH / RPOP -&amp;gt; 데이터가 들어오고 나가는 순서 보장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%; height: 38px;&quot;&gt;Condition Sync (wait/notify)&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 38px;&quot;&gt;Worker의 fixedDelay &amp;amp; BRPOP -&amp;gt; 큐 상태에 따른 유연한 작업 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 19px;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%; height: 19px;&quot;&gt;Busy Waiting 방지&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;Scheduling -&amp;gt; 무의미한 루프 대신 시스템 자원을 효율적으로 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 로컬 메모리가 아닌 외부 저장소를 선택하면서, 서버가 꺼져도 데이터가 유실되지 않는 지속성을 확보합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Java의 synchronized는 단일 서버 내에서만 동작합니다. Redis는 Single-Thread라는 특성을 가지고 있는데, 모든 명령어를 순차적으로 처리하기 때문에 수많은 생산자(서버)가 동시에 알림을 넣어도 데이터 꼬임 없이 안전하게 저장합니다.&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;3) 여러 스케줄러가 동시에 돌아갈 때 알림 순서가 뒤바뀌거나 중복 전송될 위험이 있습니다. Redis의 LPUSH / RPOP은 원자적 연산이기 때문에, 먼저 들어온 알림이 먼저 나가는 FIFO구조를 보장합니다.&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;4) Java의 `wait` / `notify`는 할 일이 없으면 스레드를 재우고(wait), 일이 들어오면 깨웁니다(signal). 이를 네트워크 기반으로 확장하면 Worker의 `fixedDelay`, Redis의 `Pop`을 조합합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`fixedDelay`: Spring의 `fixedDelay`를 활용해 소비 주기를 1초로 제한 (Slack Rate Limit 회피용)&lt;/li&gt;
&lt;li&gt;`BRPOP`(Blocking Right POP): 큐가 비어있을 때 무의미하게 응답을 받는 대신, 데이터가 들어올 때까지 Redis가 연결을 붙잡고 기다려줍니다. (정해진 timeout까지만!) 데이터가 들어오는 즉시 워커를 깨워 처리합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 큐가 찼는지 / 비었는지 계속 확인하는 Busy Waiting대신, Spring의 스케줄러를 사용해 정해진 주기에만 워커가 작동합니다. 알림이 없는 시간대에는 CPU를 거의 점유하지 않습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; 조금 더 챙겨볼 디테일&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. TransactionalEventListener활용&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 `@EventLister`도 있고, `@TransactionalEventListener`도 있습니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 `@EventLister`: `publishEvent()`가 호출되는 즉시 실행.&lt;/li&gt;
&lt;li&gt;`@TransactionalEventListener`: Publisher의 트랜잭션 상태에 따라 이벤트 소비 시점(phase)을 조절.&lt;/li&gt;
&lt;li&gt;만약 계정 삭제 중간에 이벤트를 발행했는데, 이후에 어떤 이후로 DB 작업이 롤백된다면? -&amp;gt; DB 데이터는 복구되었지만, 사용자에게는 이미 '계정 삭제'알림이 전송되는 불일치 현상이 발생합니다. 따라서 `@TransactionalEventListener`로 소비 시점을 조절하였습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Phase 설정하기: `AFTER_COMMIT`을 활용했습니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB에 계정 삭제가 실제로 성공한 후에만 알림을 보내야 하고, DB 작업은 실패했는데 알림만 가면 안 되기 때문입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;즉 '이벤트 발행 시점'과 '실제 알림 발송 시점'이 분리됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;계정 삭제 로직이 포함된 DB 트랜잭션이 최종 커밋되기 전까지는 알림이 큐에 담기지 않습니다. 이를 통해서 무결성을 더욱 강화할 수 있었습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚠️ 다른 옵션과 `AFTER_COMMIT` 비교하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`@TransactionalEventListener`에는 다양한 phase 옵션이 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;&lt;span data-path-to-node=&quot;8,1,0,0&quot;&gt;BEFORE_COMMIT&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;트랜잭션이 커밋되기 직전에 실행&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;커밋 전에 반드시 수행되어야 하는 부가 로직이 있을 때 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;AFTER_COMMIT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;트랜잭션이 성공적으로 완료된 후 실행&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;DB 작업은 롤백되었는데 알림만 발송되는 '데이터 불일치'를 원천적으로 차단합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;AFTER_ROLLBACK&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;트랜잭션이 실패했을 때 실행&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;실패 시 로그를 남기거나 복구 작업이 필요할 때 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;AFTER_COMPLETION&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;성공/실패 여부와 상관없이 실행&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;작업 완료 후 리소스를 정리할 때 사용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Fallback로직&amp;nbsp;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AlarmService.pushToQueue에서 Redis가 죽어버렸을 때 직접 전송으로 전환합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;메시지 큐 자체가 장애가 났을 때 시스템이 마비되지 않도록 방어적으로 설계했습니다.&amp;nbsp;&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. 비동기 처리&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,0&quot;&gt;기존 방식 (동기/Blocking):&lt;/b&gt; 스케줄러가 알림을 보낼 때마다 Slack API의 응답이 올 때까지 기다려야 했습니다. 만약 전송해야 할 알림이 100개이고 각각 0.5초가 걸린다면, 스케줄러는 알림 전송에만 50초를 소모하게 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;개선 후 (비동기/Non-blocking):&lt;/b&gt; 이제 스케줄러는 Redis 큐에 데이터를 &lt;b data-index-in-node=&quot;48&quot; data-path-to-node=&quot;6,1,0&quot;&gt;'던지기만'&lt;/b&gt; 하고 바로 다음 유저의 삭제 로직으로 넘어갑니다. 큐에 넣는 작업은 밀리초(ms) 단위로 끝나기 때문에, 전체 스케줄러 수행 시간이 단축될 수 있었습니다.&amp;nbsp;&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;  앞으로 더 수정한다면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Worker의 Retry 전략&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;현재 코드에서는 catch 블록에서 &lt;b&gt;로그만&lt;/b&gt; 남기고 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;간단하게는 시스템 에러 시 메시지를 유실하지 않기 위해 큐에 다시 집어넣는 rightPush 재시도 로직을 추가하면 좋겠습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약에 코드가 잘못되어 발생하는 에러일 경우에는 무한루프를 돌 수 있기 때문에 retry 횟수를 지정해야 할 것 같습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;네트워크 일시 오류 시 재시도 로직이나, 끝까지 실패한 메시지를 보관하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DLQ(Dead Letter Queue)&lt;/b&gt;를 추가적으로 구현하면 안정성이 더 강화될 수 있다는 생각이 들었습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재시도를 여러번 했는데도 계속 실패하는 메시지를 처리하면 좋겠습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;메인 큐와 죽은 메시지 큐를 따로 분리해두고 재시도 횟수가 넘은 메시지들을 보관합니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이를 통해 문제있는 메시지가 메인 시스템의 흐름을 방해하지 않습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;나중에 개발자가 DLQ를 확인해서 디버깅을 하거나, 쌓인 메시지를 수동으로 재발송할 수 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>이야기</category>
      <category>gdgoc</category>
      <category>java</category>
      <category>project</category>
      <category>server</category>
      <category>Spring boot</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/52</guid>
      <comments>https://kiritoni.tistory.com/52#entry52comment</comments>
      <pubDate>Mon, 9 Feb 2026 16:20:33 +0900</pubDate>
    </item>
    <item>
      <title>우리팀 아기를 위한 - Github 히스토리 기반 인수인계 봇 만들기 with Spring AI 찍먹</title>
      <link>https://kiritoni.tistory.com/51</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;팀의 신입이 모든 히스토리를 짧은 시간 안에 다 읽고, 지식을 흡수하기란 매우 어려운 일이다.&amp;nbsp;&lt;/span&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;p data-ke-size=&quot;size16&quot;&gt;나 역시도 신입 서버 관리자로 들어왔을 때, 파편화된 문서들을 읽는 데 시간이 오래 걸렸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 내가 서버 관리자 업무 자동화 시스템을 개발하면서는, PR / Issue / Wiki등등을 열심히 쓰려고 노력했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1년이 지났고, 새로운 서버 관리자 한 명을 영입하게 되었다.&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;1376&quot; data-origin-height=&quot;1090&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UOhXW/dJMcaaD2xBj/KkMLCRTLqBa23kiHQXn1O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UOhXW/dJMcaaD2xBj/KkMLCRTLqBa23kiHQXn1O0/img.png&quot; data-alt=&quot;우리 팀이 마주한 문제들...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UOhXW/dJMcaaD2xBj/KkMLCRTLqBa23kiHQXn1O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUOhXW%2FdJMcaaD2xBj%2FKkMLCRTLqBa23kiHQXn1O0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1376&quot; height=&quot;1090&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;1090&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우리 팀이 마주한 문제들...&lt;/figcaption&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;1352&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG9iWV/dJMcahb5w5f/2yYoBQ66iEkMUdNYR8bHmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG9iWV/dJMcahb5w5f/2yYoBQ66iEkMUdNYR8bHmK/img.png&quot; data-alt=&quot; &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG9iWV/dJMcahb5w5f/2yYoBQ66iEkMUdNYR8bHmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG9iWV%2FdJMcahb5w5f%2F2yYoBQ66iEkMUdNYR8bHmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1352&quot; height=&quot;220&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 졸업을 앞두게 되어 개발하던 &lt;b&gt;백엔드 파트를 인수인계 해주어야 하는 상황&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 여러명의 신입 관리자들에게 구두로 정보를 전달하는 것은 쉽지 않을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신입 관리자님과 함께 회의가 끝나고 카페에 가서 폴더 구조, 배포 방법, 주의할 점 등등을 설명해주고 있었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 내가 짠 것이.. 반년정도, 아니 세달만 지나도 잘 기억이 안 났다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #0593d3;&quot;&gt;&quot;어.. 뭐였더라.. 어.. 잠깐만..&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #0593d3;&quot;&gt;&quot;이거 이슈에 써놨는데... 아닌가 PR인가?&quot; &lt;/span&gt;라며 &lt;b&gt;깃허브와 주석&lt;/b&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjYEyQ/dJMcahiSds8/UVZo4kXPHURUQgj0zHHz4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjYEyQ/dJMcahiSds8/UVZo4kXPHURUQgj0zHHz4K/img.png&quot; data-alt=&quot;교수님.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjYEyQ/dJMcahiSds8/UVZo4kXPHURUQgj0zHHz4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjYEyQ%2FdJMcahiSds8%2FUVZo4kXPHURUQgj0zHHz4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1374&quot; height=&quot;1000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;교수님.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 이렇게 이야기를 해주셨었는데, 지금 이 상황을 해결하기 위해서 AI를 어떻게 활용할 수 있는지 다시 생각해보게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ef5369;&quot;&gt;&quot;하라는 뜻은 아님&quot;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 얼마만큼의 가능성을 열어줄 수 있을지 궁금해서, 기존에 개발하던 Spring 에 코드를 몇줄 간단히 추가하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 빠르게 결과를 확인하기 위해 swagger-ui 안에서만 활용할 수 있게 빠르게 만들어보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 &lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;Junior Admin Buddy!&lt;/span&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;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;Framework:&lt;/b&gt; Spring Boot 3.3.x &amp;amp; Spring AI&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;External API:&lt;/b&gt; GitHub API (PR 히스토리 및 Wiki 수집)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,2,0&quot;&gt;LLM:&lt;/b&gt; OpenAI GPT-4o-mini&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;TMI)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기존에는 더 높은 버전들을 사용하고 있었는데, Spring AI를 활용하기 위해서 버전을 살짝 낮춰주었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기존 프로젝트는 Spring Boot 3.5.x 기반의 가장 최신 환경으로 구성해놓았었는데, AI 기능을 통합하기 위해 과감히 버전을 3.3.4로 조정할 필요가 있었다.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;- Spring AI의 생태계&lt;/b&gt;: Spring AI는 현재 마일스톤(Milestone) 단계에 있는 프로젝트이다. 따라서 너무 앞서가는 Spring Boot 최신 버전(v3.5+)과는 내부 라이브러리(특히 Bean 로드 및 조건부 설정 로직)에서 충돌이 발생한다.&lt;br /&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;- Bean Definition 오류 해결:&lt;/b&gt; 실제로 3.5.3 버전에서는 Swagger(SpringDoc)와 Spring Cloud Function 간의 클래스 로드 순서 문제로 인해 애플리케이션 자체가 구동되지 않는 현상이 있었다. 이를 해결하기 위해 Spring AI와 가장 호환성이 검증된 3.3.x 라인으로 환경을 맞춰주었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;  Spring AI는 이 프로젝트에서 무슨 역할을 했나?&lt;/h3&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;한 줄 요약 : &lt;br /&gt;Spring AI의 역할은&amp;nbsp;Spring 생태계 개발자들이&amp;nbsp;&lt;br /&gt;자바 애플리케이션에 인공지능 기능을 쉽고 표준화된 방식으로 통합할 수 있도록 돕는 프레임워크이다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;추상화된 인터페이스 (ChatClient)&lt;/b&gt;: 특정 AI 모델(OpenAI, Ollama 등)에 종속되지 않는 인터페이스를 제공합니다. 덕분에 나중에 모델을 교체하더라도 비즈니스 로직(Service 레이어)은 수정할 필요가 없어진다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;유연한 프롬프트 관리 (Fluent API)&lt;/b&gt;: .system(), .user(), .call()과 같은 유연한 메서드 체이닝을 통해 복잡한 프롬프트 구성을 자바 코드 내에서 깔끔하게 관리할 수 있게 해준다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,2,0&quot;&gt;자동화된 인프라 설정&lt;/b&gt;: API 키 설정, 타임아웃 처리, Retry(재시도) 로직 등 번거로운 HTTP 통신 설정을 스프링의 관례(Convention)에 따라 자동으로 처리해 준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&quot;기억나지 않는 과거&quot;를 AI에게 학습시키기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 코드를 짜기 전에 집중해야할 부분은 &lt;i&gt;'어떻게 하면 AI가 단순한 챗봇을 넘어 우리 팀의 맥락을 파악하게 할 지'&lt;/i&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;나는 Issue ➡️ PR &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;➡️&lt;span&gt; &lt;/span&gt;&lt;/span&gt;Wiki 순서로 개발 기록을 정리했어서, Github의 내용을 기반으로 데이터를 가져오면 되겠다고 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Github 데이터 파이프라인&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`kohsuke:github-api`를 활용해 최근 20개의 Closed PR과 Wiki 본문을 긁어오는 `GithubHistoryService`를 만든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 텍스트만 가져오는 게 아니라, '최신순'으로 정렬하여 AI가 과거의 낡은 정보보다 어제의 결정을 더 신뢰하도록 가중치를 두면 둔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Spring AI를 활용한 Prompt Engineering&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수집한 방대한 데이터를 AI에게 그냥 던져주는 것이 아니라, '신입 관리자를 위한 친절한 시니어 관리자'라는 페르소나를 부여해준다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PR 히스토리와 위키 내용을 시스템 프롬프트에 주입한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768658685187&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;너는 신입 관리자를 돕는 'Junior Admin Buddy'야. 
                신입 관리자는 아주 어린 대학생이야. 따라서 부드럽게, 친절하게 대해줘야 해.
                제공된 [PR 히스토리]와 [위키/가이드] 내용을 바탕으로 답변해줘.&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;내가 인수인계할 때 가장 헷갈렸던 &quot;UID/GID 관리 로직&quot;에 대해 직접 질문해보았다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Q. UID/GID를 어떻게 관리하고 있는지 논리적으로 이해가 안 가.&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768658546792&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;안녕하세요! UID(사용자 식별자)와 GID(그룹 식별자)의 관리에 대해 설명해드릴게요.

1. **UID와 GID란?**
   - UID는 시스템에서 각 사용자를 고유하게 식별하기 위한 번호입니다. 
   - GID는 그룹을 식별하기 위한 번호로, 여러 사용자들이 속할 수 있는 그룹을 나타냅니다.

2. **UID/GID 관리 방식**
   - 사용자가 그룹을 만들거나 가입할 때, 해당 그룹에 고유한 GID가 부여됩니다.
   - 사용자가 생성될 때, 시스템은 자동으로 UID를 할당합니다. 이때, UID와 GID는 서로 연관이 있습니다. 예를 들어, 사용자가 그룹을 만들 때 그 사용자의 UID가 그룹의 GID로 설정될 수 있습니다.

3. **사용 신청 프로세스**
   - 사용자가 사용 신청을 시작하면, 해당 사용자의 요청에 따라 우분투 그룹이 생성되거나 기존의 그룹을 선택할 수 있습니다.
   - 사용자가 그룹을 지정하지 않으면, 시스템이 자동으로 UID와 같은 GID를 생성하여 그룹을 만들게 됩니다. 이 과정은 서버에서 자동으로 처리되며, 클라이언트 측에서는 별도로 고려하지 않아도 됩니다.

4. **사용 변경 프로세스**
   - 사용자가 그룹 변경을 원할 경우, 기존의 우분투 그룹을 선택하고 관련 신청서를 작성하여 승인 절차를 받습니다.

이와 같은 방식으로 UID와 GID를 관리하여 사용자와 그룹을 체계적으로 관리할 수 있습니다. 더 궁금한 점이 있으면 언제든지 물어보세요!  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 헷갈릴만한 비즈니스 로직에 대해 질문했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Q. 장기 미접속자는 어떻게 관리하고 있어?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768658599724&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;장기 미접속 사용자 관리는 자동화된 시스템을 통해 이루어지고 있어요. 이 시스템은 매일 오전 09:00에 실행되는 스케줄러에 의해 운영됩니다. 아래는 장기 미접속 사용자를 관리하는 주요 내용이에요:

1. **대상 선정 기준**: 
   - 사용자의 마지막 로그인 시점이 3개월 이상 지났고, Pod 만료일도 3개월 이상 지났을 경우 해당 사용자가 관리 대상이 됩니다.
   - Pod 사용 기록이 없는 유저는 로그인 날짜만으로 판단해요.

2. **알림 발송**: 
   - 삭제 예정일 D-7, D-3, D-1 일전에 사용자에게 Slack 또는 이메일로 경고 알림이 발송됩니다. 이 메시지는 &quot;로그인하면 삭제되지 않습니다&quot;라는 내용이 포함되어 있어요.

3. **Soft Delete (비활성화)**: 
   - 예정일 도래 시 사용자의 계정이 비활성화(isActive = false)되고, &quot;1년 뒤 정보 파기&quot;에 대한 안내가 발송됩니다. 이 상태에서는 사용자가 로그인할 수 없게 됩니다.

4. **Hard Delete (영구 삭제)**: 
   - Soft Delete 상태로부터 1년이 경과하면 사용자의 데이터가 DB에서 영구 삭제됩니다.

이러한 과정을 통해 리소스 관리와 보안을 강화하고 있어요. 혹시 더 궁금한 점이 있으면 언제든지 물어봐 주세요!  &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직은 답변이 만족스럽지가 않다. 더 좋은 결과를 내기 위해 프롬프트를 조금 더 개선해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8cb3be;&quot;&gt;개선된 프롬프트&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768658798970&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Role: 전문적이고 다정한 '시니어 관리자 버디'
너는 대학생 신입 관리자를 1:1로 코칭하는 시니어 서버 관리자야. 
학생의 눈높이에 맞춰 어려운 용어는 풀어서 설명하되, 
실무의 엄중함을 잃지 않도록 따뜻하면서도 명확한 어조(Persona)를 유지해줘.

# Context: 지식 소스 활용 가이드
제공된 데이터를 아래 우선순위에 따라 분석해:
1. [위키/가이드]: 우리 팀의 '법전'이야. 표준 운영 절차(SOP)와 변하지 않는 설정을 여기서 찾아.
2. [PR 히스토리]: 우리 팀의 '일기장'이야. 위키에 반영되지 않은 가장 최신의 변경점, 장애 복구 기록, 동료들의 고민 흔적을 여기서 찾아.

# Reasoning Step (생각의 단계):
답변을 작성하기 전, 스스로 아래 질문을 던져봐:
- &quot;질문한 내용이 위키의 기본 규칙과 충돌하는 최근 PR 내용이 있는가?&quot;
- &quot;이 설명이 이제 막 리눅스를 배운 대학생에게 너무 어렵지는 않은가?&quot;
- &quot;내가 답변하는 근거가 정확히 몇 번 PR 혹은 어떤 위키 페이지에 있는가?&quot;

# Constraint (강력 제약 사항):
- **데이터 부재 시:** 데이터에 없는 내용을 추측해서 답하지 마. 대신 &quot;현재 기록된 데이터 중에는 관련 내용을 찾을 수 없으니, 전임자에게 확인이 필요해 보여요&quot;라고 가이드해줘.
- **최신성:** 동일한 설정에 대해 PR 내용이 여러 개라면, 가장 최근 날짜의 PR을 최종 진실로 간주해.

# Output Format (답변 형식):
1. **  한 줄 요약**: (전체 답변을 한 문장으로)
2. **  정확한 근거**: (출처: [위키 명칭] 또는 [PR #번호])
3. **  상세 가이드**: (신입이 이해하기 쉽게 단계별/항목별 설명)
4. **  선배의 꿀팁**: (해당 이슈와 관련해 주의해야 할 점이나 더 공부하면 좋은 개념)
5. **  탐색 범위 정보**: &quot;본 답변은 202X-XX-XX부터 202X-XX-XX까지의 기록을 바탕으로 작성되었습니다. 더 깊은 맥락은 직접 해당 PR을 열람해보는 것을 추천해요!&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;개선된 점은 아래와 같다.&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;데이터 충돌 시 최신 PR을 우선하도록 명시 (현실적)&lt;/li&gt;
&lt;li&gt;모를 때 '전임자 확인' 등 구체적인 행동을 지시&lt;/li&gt;
&lt;li&gt;'선배의 꿀팁' 섹션을 통해 실무 노하우 전달 (Persona 강화)&lt;/li&gt;
&lt;li&gt;'Reasoning Step'을 넣어 AI가 스스로 검토하게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8cb3be;&quot;&gt;✅ 1번 질문에 대한 결과&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순이 답변을 다는 것이 아니라, 답변을 구조화해주는 모습을 볼 수 있다.&lt;/li&gt;
&lt;li&gt;추가적으로 어떤 자료를 참고해야하는지 출처를 달아서 직접 전달해주고 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;언제부터 언제까지의 기록을 참고했는지 알 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768658986828&quot; class=&quot;html xml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;  **한 줄 요약**: 장기 미접속 사용자에 대한 자동 탈퇴 및 알림 체계를 구축하여 관리하고 있습니다.

  **정확한 근거**: (출처: [PR #171])

  **상세 가이드**:
1. **사용자 판단 기준**: 
   - 마지막 로그인 시점(`lastLoginAt`)이 3개월이 지난 사용자.
   - Pod 사용 기록이 없는 사용자도 포함되어 판단됩니다.

2. **관리 프로세스**:
   - **자동 알림**: 사용자가 삭제되기 7일, 3일, 1일 전에 이메일 및 슬랙으로 경고 알림을 발송합니다.
   - **Soft Delete**: 삭제 예정일에 사용자의 계정을 비활성화(`isActive = false`)하고, 삭제 안내 메시지를 발송합니다.
   - **Hard Delete**: Soft Delete 후 1년이 지나면 해당 계정을 DB에서 완전히 삭제합니다.

3. **스케줄러 설정**: 매일 오전 09:00에 해당 프로세스가 자동으로 실행됩니다.

  **선배의 꿀팁**: 장기 미접속 사용자 관리 시스템은 리소스 관리와 보안을 강화하는 데 큰 도움이 됩니다. 항상 사용자 데이터를 최소한으로 유지하면서도 필요한 경우에는 쉽게 복구할 수 있는 방법을 마련해 두는 것이 좋습니다.

  **탐색 범위 정보**: 본 답변은 2026-01-09부터 2026-01-14까지의 기록을 바탕으로 작성되었습니다. 더 깊은 맥락은 직접 해당 PR을 열람해보는 것을 추천해요!&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 style=&quot;color: #8cb3be;&quot;&gt;&lt;span style=&quot;color: #8cb3be; text-align: start;&quot;&gt;✅ &lt;/span&gt;2번 질문에 대한 결과&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UID/GID에 대한 PR/Issue를 엄청 오래 전에 작성해서, 최근 20개의 결과에 포함되지 않았다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;여기에서는 기록이 없다고 솔직하게 말해주는 모습을 볼 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768658820387&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  **한 줄 요약**: UID와 GID는 사용자와 그룹을 식별하는 고유한 번호로 관리되며, 각 사용자와 그룹의 생성 및 권한 부여를 통해 리소스를 제어합니다.

  **정확한 근거**: 현재 기록된 데이터 중에는 UID/GID 관리에 대한 상세한 내용이 없으니, 전임자에게 확인이 필요해 보여요.

  **상세 가이드**:
1. **UID (User Identifier)**:
   - 각 사용자는 시스템에서 고유한 UID를 가집니다. 이 번호는 사용자가 로그인하거나 시스템 자원에 접근할 때 사용됩니다.
   - 예를 들어, 사용자가 파일에 접근할 때, 시스템은 파일의 소유자 UID와 해당 사용자의 UID를 비교하여 접근 권한을 결정합니다.

2. **GID (Group Identifier)**:
   - GID는 그룹을 식별하는 번호입니다. 사용자는 하나 이상의 그룹에 속할 수 있으며, 그룹에 속한 모든 사용자는 해당 그룹의 권한을 공유합니다.
   - 파일이나 디렉토리에도 소유자와 그룹이 설정되어 있어, 그룹에 속한 사용자들은 그 파일에 대한 접근 권한을 가질 수 있습니다.

3. **계정 생성 시**:
   - 사용자를 생성할 때, 시스템은 자동으로 UID를 부여합니다. 일반적으로 UID는 0부터 시작하여 1씩 증가하며, 시스템의 다른 사용자와 중복되지 않도록 관리됩니다.
   - 그룹을 생성할 때도 마찬가지로 GID가 부여되며, 기본 그룹이 설정됩니다.

4. **리소스 관리**:
   - UID와 GID는 파일 시스템에서 중요한 역할을 합니다. 각 파일에는 소유자 UID와 GID가 할당되어 있어, 해당 사용자와 그룹이 파일에 대한 권한을 결정합니다.
   - 예를 들어, 파일의 소유자가 특정 권한을 부여하지 않으면, 다른 사용자는 파일에 접근할 수 없습니다.

  **선배의 꿀팁**:
- UID와 GID는 보안과 리소스 관리를 위해 매우 중요한 요소입니다. 시스템에서 사용자와 그룹의 권한을 설정할 때, 이러한 식별자를 활용하여 적절하게 관리하는 것이 중요합니다.
- Linux에서는 `id` 명령어를 통해 현재 사용자의 UID와 GID를 쉽게 확인할 수 있으니, 이를 활용해 보세요.

  **탐색 범위 정보**: 본 답변은 202X-XX-XX부터 202X-XX-XX까지의 기록을 바탕으로 작성되었습니다. 더 깊은 맥락은 직접 해당 PR을 열람해보는 것을 추천해요!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;앞으로 어떻게 발전할 수 있을까?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;  더 고민해야 할 점&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;검색 정밀도&lt;/b&gt;: 질문과 상관없는 데이터를 모두 읽게 하는 것은 비효율적이다. 따라서 제목만 먼저 읽고, 노이즈를 걸러내는 게 중요한 작업이 될 것 같다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;Context Window 한계&lt;/b&gt;: 현재 방식은 수집한 20개의 PR과 위키를 통째로 AI에게 전달합니다. 하지만 프로젝트 규모가 커져 기록이 수천 개가 되면, LLM이 한 번에 읽을 수 있는 용량(Token Limit)을 초과하게 됩니다. 이때는 중요한 과거 기록이 누락될 위험이 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1️⃣ Vector DB와 RAG(Retrieval-Augmented Generation) 도입&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 텍스트를 AI에게 던지는 대신 데이터를 의미 단위(Chunk)로 쪼개어 Vector DB에 저장한다.&lt;/li&gt;
&lt;li&gt;사용자의 질문과 가장 관련 있는 &lt;b data-index-in-node=&quot;18&quot; data-path-to-node=&quot;14,1,0&quot;&gt;상위 3~5개의 핵심 조각&lt;/b&gt;만 찾아 AI에게 전달한다&lt;/li&gt;
&lt;li&gt;이를 통해 &lt;b data-index-in-node=&quot;6&quot; data-path-to-node=&quot;14,2,0&quot;&gt;비용 절감, 속도 향상, 정확도 개선&lt;/b&gt;이라는 세 마리 토끼를 잡을 수 있을 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size20&quot;&gt;2️⃣ 다각화된 데이터 소스 통합&amp;nbsp;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;단순히 GitHub 기록뿐만 아니라, 관리 운영에 필요한 더 다양한 채널을 통합하면 더 효과적인 결과를 도출해낼 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;Slack API 연동:&lt;/b&gt; &quot;#장애대응&quot;, &quot;#운영보고&quot; 채널 등을 연동해 실시간 대화 맥락을 파악한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;서버 모니터링 로그:&lt;/b&gt; Prometheus/Grafana의 지표 데이터를 읽어 &quot;지금 서버 상태가 왜 이래?&quot;라는 질문에 실제 수치로 답변을 시킨다.&lt;/li&gt;
&lt;li&gt;다만 슬랙에 정말 중요한 정보가 있을 경우 AI에게 넘기는 것은 좋지 않아보인다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;실제로 사용하려면 많은 노이즈를 제거하고 가공을 해주어야겠지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;정말 간단하게 구현하더라도 직접 깃허브 창을 뒤져볼 일은 없앨 수 있다는 점이 굉장히 매력적이었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;100페이지 뒤질 시간을 줄였다는 점에서 이미 자동화에 한 발자국 다가갔다는 생각이 들었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그럼 안녕!&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>이야기</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/51</guid>
      <comments>https://kiritoni.tistory.com/51#entry51comment</comments>
      <pubDate>Sat, 17 Jan 2026 23:38:39 +0900</pubDate>
    </item>
    <item>
      <title>1년간의 대학교 GPU 서버 관리자 회고...무언가 돈을 받고 한다는 것</title>
      <link>https://kiritoni.tistory.com/50</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;회고를 공개적인 공간에 작성하지 않는데,&lt;br /&gt;낯부끄럽지만 1년간 학부생으로 공부하며 GPU 서버 관리자로 일한 소중한 경험에 대해 기록을 남겨보고자 한다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 전공생은 아니지만, &lt;span style=&quot;color: #ef5369;&quot;&gt;'신입 GPU 서버 관리자 모집'&lt;/span&gt; 공고를 보게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우대 사항에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;- 1~2학년&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;- 석사 과정 희망&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 적혀있었지만, 나는 둘 중에 어느 군데도 해당되지 않았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대학생 기준으로 나이도 든 (화석) 대학원은 죽어도 가기 싫은 학생이었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 우대사항에&lt;i&gt; Spring Boot &amp;amp; Java&lt;/i&gt;가 적혀있는 것을 보았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것이 어떤 의도일까, 고민을 해보았는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혼자서는 답을 낼 수가 없어, 문의를 남기고자 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 내가 수강하던 컴퓨터 시스템이라는 과목의 담당 교수님께서 서버실을 담당하고 계셔서, 수업에 끝난 뒤에 조용히 질문을 드렸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87; font-family: 'Noto Serif KR';&quot;&gt;&quot;귀찮게 수업 다 끝나고 나서 이야기하기는. 쯧&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87; font-family: 'Noto Serif KR';&quot;&gt;&quot;연구실로 따라와!!!!!!!!&quot;&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;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;기말고사를 못보면 넌 안 뽑아준다&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 중간고사를 평균 정도의 성적을 받아서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교수님께서&lt;span style=&quot;color: #ef5369;&quot;&gt; D+&lt;/span&gt;을 주신다고 협박도 하셨었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이력서, 자기소개서, 성적표 등을 내고 면접을 기다리고 있었는데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 최종합격했다고 연락이 왔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 모든 관리자들이 면접없이 들어온 줄 알았는데, 알고보니 내가 아주 아주 특별한 어둠의 경로로 들어온 것이라는 걸 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(좋게 말하면 추천 전형...)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&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;h2 data-ke-size=&quot;size26&quot;&gt;첫 두 달 동안에는 정말 공부만 했다.&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방학인데 더 바빠서 되게 되게 힘들었던 기억이 난다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #a6bc00;&quot;&gt;대학 생활 중, 돌아가고 싶지 않은 순간 중 하나&lt;/span&gt;이기도 하다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공부만 하는 건 힘들지 않았는데 실습이 나를 좀 눈물나게 만들었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;2268&quot; data-origin-height=&quot;3733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zA81i/dJMcagRMCh3/Kp2TaEE8j36RdOOgLluHt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zA81i/dJMcagRMCh3/Kp2TaEE8j36RdOOgLluHt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zA81i/dJMcagRMCh3/Kp2TaEE8j36RdOOgLluHt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzA81i%2FdJMcagRMCh3%2FKp2TaEE8j36RdOOgLluHt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;3733&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;3733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;맥북에서 해도해도 안 되어서 결국 옛날에 쓰던 그램을 가져와서 실습을 했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;정말, 하루종일 아무데도 안 나가고 매일 과제 &amp;amp; 시험을 본 것 같다..&lt;/li&gt;
&lt;li&gt;특히 나는 더 힘들었는데, 전공생들 사이의 비전공생이어서 CS가 부족했다.&lt;/li&gt;
&lt;li&gt;그건 당연하지만... 그렇다고 합리화나 변명을 할 수는 없었다. 같은 돈을 받기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zs0jL/dJMcahpC3BG/CG5Qxja8ZBQcgqMROvOcn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zs0jL/dJMcahpC3BG/CG5Qxja8ZBQcgqMROvOcn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zs0jL/dJMcahpC3BG/CG5Qxja8ZBQcgqMROvOcn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzs0jL%2FdJMcahpC3BG%2FCG5Qxja8ZBQcgqMROvOcn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발과 인프라가 아주 달랐던 지점은 AI가 명확한 해답을 못 내준다는 거였다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발은 AI를 패고 프롬포트를 자세히 입력하면 꽤 쓸만한 답이 나왔지만&lt;/li&gt;
&lt;li&gt;인프라는 상황의 특수성에 영향을 많이 받는 영역인 것 같다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그래서인지 AI가 헛소리를 자주했고, 결국 혼자 생각하면서 해결하는 방법밖에 없었다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버실에서 썩기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혼자서 실습 과제를 몇번 한 뒤에는 서버실에 직접 가서 실습을 할 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JjPmc/dJMcahXty2c/6xOZ3uHcKNfVbLTuPJ8QYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JjPmc/dJMcahXty2c/6xOZ3uHcKNfVbLTuPJ8QYk/img.png&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JjPmc/dJMcahXty2c/6xOZ3uHcKNfVbLTuPJ8QYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJjPmc%2FdJMcahXty2c%2F6xOZ3uHcKNfVbLTuPJ8QYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CTGNr/dJMcaa46oP9/e45jZklq3fKgvMpsjMj3p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CTGNr/dJMcaa46oP9/e45jZklq3fKgvMpsjMj3p0/img.png&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CTGNr/dJMcaa46oP9/e45jZklq3fKgvMpsjMj3p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCTGNr%2FdJMcaa46oP9%2Fe45jZklq3fKgvMpsjMj3p0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFk2ev/dJMcabpoN5m/nRtkyqu3iJGF266SRuRU7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFk2ev/dJMcabpoN5m/nRtkyqu3iJGF266SRuRU7k/img.png&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;33.34&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFk2ev/dJMcabpoN5m/nRtkyqu3iJGF266SRuRU7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFk2ev%2FdJMcabpoN5m%2FnRtkyqu3iJGF266SRuRU7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;혼자서 하는 실습 과제가 행복한 것임을 알 수 있었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;서버실은 은근히 시끄럽고, 나는 처음이라 노캔 에어팟도 안가져왔었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이후에 서버실에 갈때는 꼭 헤드셋을 가지고 간다.&lt;/li&gt;
&lt;li&gt;'내가 혹시나 잘못 건드리면 어떡하지?'하는 두려움과 함께, 서버실에서 조심 조심 실습을 했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;명령어 하나 치고 또 보고 오타 보고...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZK0Tl/dJMcaiIM88P/0dFZiexNxAqeHa707xzIpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZK0Tl/dJMcaiIM88P/0dFZiexNxAqeHa707xzIpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZK0Tl/dJMcaiIM88P/0dFZiexNxAqeHa707xzIpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZK0Tl%2FdJMcaiIM88P%2F0dFZiexNxAqeHa707xzIpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로 부팅한 PC는 복붙따위 할 수 없다. 에러 메시지가 떠도 젬나이한테 못말한다.&lt;/li&gt;
&lt;li&gt;한 번 서버실에 가면 최소 5시간 길면 8시간... 이렇게 있다가 막차 시간에 집에 가기도 했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;아빠가 매우매우 안 좋아하셨다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;안 좋은 것을 버티는 방법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kEIKB/dJMcaiB07E3/xeJVmpknx43ZjlrGRcH6A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kEIKB/dJMcaiB07E3/xeJVmpknx43ZjlrGRcH6A0/img.png&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;true&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kEIKB/dJMcaiB07E3/xeJVmpknx43ZjlrGRcH6A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkEIKB%2FdJMcaiB07E3%2FxeJVmpknx43ZjlrGRcH6A0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spHdv/dJMcabJI659/YUTZKd6ldCK9GXOHINBKkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spHdv/dJMcabJI659/YUTZKd6ldCK9GXOHINBKkk/img.png&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spHdv/dJMcabJI659/YUTZKd6ldCK9GXOHINBKkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FspHdv%2FdJMcabJI659%2FYUTZKd6ldCK9GXOHINBKkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 서버실에서 썩는 것에 해탈했기 때문에 그냥 하더라도 기쁜 마음으로 하고 싶었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그래서 짐빔 한캔을 몰래 마시기를 나에게 허락해주었고 그 효과는 상당했다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;칠색마노: 기쁜 마음으로 서버를 만지니, 어제는 안 되던 애가 되기 시작한 것이다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팔찌는 구슬 108개가 달려있는, 불교학교인 동국대에서 구매한 팔찌이다.&lt;/li&gt;
&lt;li&gt;서버실은 고통의 바다이니 그냥 안 되는 것에 열낼 필요없다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;화가 나면 저 팔찌 세 겹을 풀어서 108개의 구슬을 하나씩 세보았다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;일주일 내내 좋은 일이 있다는 미친 마음으로 생활을 하였다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그래도 2달동안 수습 기간을 거치고나서는, 작지만 돈을 받고 일할 수 있게 되었다!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;리눅스 뽀개기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선배 관리자님..으로부터 전체적으로 부족하지만 리눅스가 부족하다는 이야기를 들었고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 부족한 점을 보충하기 위해 '리눅스 마스터 2급'에 도전해보기로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 어려운 시험은 아니지만 억지로 외우려고 일단 하다보면 이해도 될 거라고 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nTWCS/dJMcai9QDuO/tq2IA7vz5r2Ri1IZjaoSIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nTWCS/dJMcai9QDuO/tq2IA7vz5r2Ri1IZjaoSIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nTWCS/dJMcai9QDuO/tq2IA7vz5r2Ri1IZjaoSIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnTWCS%2FdJMcai9QDuO%2Ftq2IA7vz5r2Ri1IZjaoSIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-15 오후 3.17.44.png&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjVS3Z/dJMcafL6Ry5/t16g2XIOBbCG4ABzwoi4LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjVS3Z/dJMcafL6Ry5/t16g2XIOBbCG4ABzwoi4LK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjVS3Z/dJMcafL6Ry5/t16g2XIOBbCG4ABzwoi4LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjVS3Z%2FdJMcafL6Ry5%2Ft16g2XIOBbCG4ABzwoi4LK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1978&quot; height=&quot;246&quot; data-filename=&quot;스크린샷 2026-01-15 오후 3.17.44.png&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;246&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;1차는 온라인으로 시험을 보면 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;2차는 부끄럽지만 중간에 한번 삐끗해서 (중간.기말 공부하면서 준비를 못했다) 완벽하게 합격하는 데에 오래걸렸다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;시험 총평은... 지엽적인 부분이 분명히 많고 외울 양도 꽤 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;SQLD도 중간에 봤었는데, 하루도 공부 안 하고 합격했었다... 리눅스 마스터가 (내 기준) 더 어려웠던 거 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;with 교수님&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교수님께서 밥도 사주셨다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIvVS4/dJMb996b5MF/KbIuzubF4WV67l2QZLEhfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIvVS4/dJMb996b5MF/KbIuzubF4WV67l2QZLEhfK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-height=&quot;3024&quot; data-origin-width=&quot;4032&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIvVS4/dJMb996b5MF/KbIuzubF4WV67l2QZLEhfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIvVS4%2FdJMb996b5MF%2FKbIuzubF4WV67l2QZLEhfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cakLUG/dJMcagda7VI/xWIq04oFh9kvOlzbkEp3uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cakLUG/dJMcagda7VI/xWIq04oFh9kvOlzbkEp3uK/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cakLUG/dJMcagda7VI/xWIq04oFh9kvOlzbkEp3uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcakLUG%2FdJMcagda7VI%2FxWIq04oFh9kvOlzbkEp3uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GYTu4/dJMcaaYkVCR/YdBE9gSxAWJHXA4ueAK211/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GYTu4/dJMcaaYkVCR/YdBE9gSxAWJHXA4ueAK211/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;33.34&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GYTu4/dJMcaaYkVCR/YdBE9gSxAWJHXA4ueAK211/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGYTu4%2FdJMcaaYkVCR%2FYdBE9gSxAWJHXA4ueAK211%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v7NP8/dJMcahiRkgs/xL1KVfw55TYpUaSzbkucs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v7NP8/dJMcahiRkgs/xL1KVfw55TYpUaSzbkucs0/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.4784%; margin-right: 10px;&quot; data-widthpercent=&quot;57.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v7NP8/dJMcahiRkgs/xL1KVfw55TYpUaSzbkucs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv7NP8%2FdJMcahiRkgs%2FxL1KVfw55TYpUaSzbkucs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezhQFZ/dJMcafk2xCr/qmeENO5hGmQW7Pm7lMBJrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezhQFZ/dJMcafk2xCr/qmeENO5hGmQW7Pm7lMBJrK/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.3588%;&quot; data-widthpercent=&quot;42.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezhQFZ/dJMcafk2xCr/qmeENO5hGmQW7Pm7lMBJrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezhQFZ%2FdJMcafk2xCr%2FqmeENO5hGmQW7Pm7lMBJrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;맛난 먹을 거 먹으러 돌아다니고&lt;/li&gt;
&lt;li&gt;힘들 때 가끔 학교 근처 바에서 혼자 위스키를 마시기도 하는데&lt;/li&gt;
&lt;li&gt;그런 나의 취향을 저격한 곳들을 교수님이 데려가주셨다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그리고 먹고싶은 거 완전 많이 먹고 그동안의 눈물들을 닦았다...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스승의 날에 꽃도 선물해드렸다.&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;1536&quot; data-origin-height=&quot;2048&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwc51b/dJMcacaMynp/mky0wLQE8cikcsXpsHC740/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwc51b/dJMcacaMynp/mky0wLQE8cikcsXpsHC740/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwc51b/dJMcacaMynp/mky0wLQE8cikcsXpsHC740/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwc51b%2FdJMcacaMynp%2Fmky0wLQE8cikcsXpsHC740%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;2048&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;2048&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비싸보인다고 칭찬해주셨다. &lt;s&gt;(교수님 istj)&lt;/s&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;Keep: &quot;무엇이 잘 되었나?&quot;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. 약간은 개발자의 시선으로&amp;nbsp;&lt;/span&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;span style=&quot;color: #ef5369;&quot;&gt;개발자의 시선&lt;/span&gt;으로 &lt;span style=&quot;color: #ef5369;&quot;&gt;업무 프로세스를 개선&lt;/span&gt;할 수 있었다고 생각한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;예를 들어, 수동으로 하던 것들을 내가 경험해본 툴들로 개선하는 것 ex. Dockerfile 수정하고 버전 관리하기, 자동으로 push하기 등등&lt;/li&gt;
&lt;li&gt;그동안 내가 했던 협업의 좋은 것들을 다 때려박기 -&amp;gt; 코드리뷰 열심히하기, 노션 문서화 잘 하기 등등.&lt;/li&gt;
&lt;li&gt;개발자들과 같이 일해온 나였어서 '이건 당연하지 않아?'라고 생각했었지만 그렇지 않았다.&lt;/li&gt;
&lt;li&gt;세상에 당연한 건 없나보다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. 말, 문서화 잘 하기&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그동안은 토이 프로젝트, 1회성 프로젝트, 해커톤용으로 개발을 많이 해왔었다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 &lt;span style=&quot;color: #ef5369;&quot;&gt;내&lt;/span&gt;가 맡은 부분은 &lt;span style=&quot;color: #ef5369;&quot;&gt;내&lt;/span&gt;가 &lt;i&gt;'알잘딱깔센'&lt;/i&gt;잘하면 되는 거고. 돌아가면 되는 거고. 에러나면 해결해서 다시 올리면 되는 거고.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하지만 실제 업무 속에서는 &lt;span style=&quot;color: #0593d3;&quot;&gt;지속적인 인원 교체&lt;/span&gt;가 일어날 수밖에 없고, 그 수많은 히스토리를 감당하는 건 &lt;span style=&quot;color: #0593d3;&quot;&gt;우리&lt;/span&gt;와 &lt;span style=&quot;color: #0593d3;&quot;&gt;신입 관리자&lt;/span&gt;가 된다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 이러한 점을 고려하여 모든 문서를&lt;b&gt; 접근이 쉽게 배치&lt;/b&gt;하고 &lt;b&gt;최신화&lt;/b&gt;해야했다.&lt;/li&gt;
&lt;li&gt;내부 보고서에도 육하원칙을 명확하게!!! &amp;lt;-- 이거 하나는 귀에 피나도록 들어왔다.&lt;/li&gt;
&lt;li&gt;내가 추천한 후배가 신입 관리자에 합격하게 되면서, 그동안 했었던 프로젝트 히스토리를 정리하고 github wiki도 처음 써보았다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그래도 내가 맡은 파트가 제일 문서화가 잘 되었지 않았나!!하고 스스로 칭찬해본다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;Problem: &quot;무엇이 어려웠나?&quot;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. 보편적인 답 찾지 않기&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;내가 부족했던 부분을 정면으로 바라보고 채워야 한다는 경각심을 가지는 계기가 되었다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;나는 내가 부족한 이유가&lt;i&gt; '잘 몰라서'&lt;/i&gt;, '&lt;i&gt;아직 초심자라서'&lt;/i&gt;라고 생각했다.&amp;nbsp;&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 data-sfc-cp=&quot;&quot;&gt;그래서 그런지, 그동안 개발을 하면서는 어떠한 의사결정을 내려야 할 때&lt;b&gt; &lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;가장 보편적인 답&quot;&lt;/span&gt;&lt;/b&gt;을 찾으려고 했었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 서버관리자 일을 하면서 모든 기술은 case by case라는 것을 몸으로 느끼게 되었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;오늘 교수님께서,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&quot;너 여자친구 좋아? 너 여자친구랑 있으면 좋아? 맨날 좋아? 붙어있으면 좋아?&quot;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라고 하셨다.&lt;/li&gt;
&lt;li&gt;이 질문을 하시는 의도는... 모든 선택지는 장단점이 존재하고, &lt;b&gt;아무리 좋은 것도 그 이면에는 단점이&lt;/b&gt; 존재한다는 것이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;결국 보편적인 답이란 없다. &lt;i&gt;확률적으로 더 많이 선택하는 옵션&lt;/i&gt;은 존재하겠지만,&lt;span style=&quot;color: #ef5369;&quot;&gt; '항상 좋은 답'이란 없다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;그래서 뭐가 기준이 되어야 하냐?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글쎄 나도 잘 모르겠다. 여러가지 기준이 있지 않을까. 팀의 수준, 속도, 비용 등...&lt;/li&gt;
&lt;li&gt;뭐가 우리 팀에 더 잘 맞는지 여러방면으로 고려하고 끊임없이 저울질해야하는 요소인 것 같다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;초심자라면 초심자가 가질 수 있는 시선으로, 보편적인 비효율을 개선해보자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. 돈을 받고 일한다는 것&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내향적인 성격이지만, 어떤 주제에 대해 의견을 나누고 의사결정하는 과정이 재미있게 느껴진다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 팀 프로젝트에서 리더도 자주 맡고, 팀원으로 있을 때에도 좋은 대안이 있다면 적극적으로 이야기하는 편이었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 솔직히 말해서 개발을 좋아한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개발을 하면서 개발을 싫어하는 사람은 거의 없을 테지만...&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 &lt;span style=&quot;color: #0593d3;&quot;&gt;돈을 받고 일하는 건 달랐다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;돈이 내 일에 대한 보상&lt;/b&gt;이라고 생각하는 순간, 이 일은 '&lt;u&gt;하기 싫은 것&lt;/u&gt;'이 되어버린다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나도 실제로 약간의 권태기를 느꼈고 '내가 추구하는 삶'이 뭔지, 앞으로 더 어른이 되면 어떻게 할건지 성찰을 했던 한 해였다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pcEBI/dJMcabbRIOg/KKkt6EroYx6JxTmxEF9Dlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pcEBI/dJMcabbRIOg/KKkt6EroYx6JxTmxEF9Dlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pcEBI/dJMcabbRIOg/KKkt6EroYx6JxTmxEF9Dlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpcEBI%2FdJMcabbRIOg%2FKKkt6EroYx6JxTmxEF9Dlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2268&quot; height=&quot;4032&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;span data-sfc-cp=&quot;&quot;&gt;그러던 중, 우리집 아가 (남동생)이 재수를 하면서 아가 나름의 다짐? 또는 철학?을&lt;/span&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;방 벽에 붙여놓은 것을 발견했다.&lt;/span&gt;&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;span data-sfc-cp=&quot;&quot;&gt;나는 개인적으로 3번이 가장 와닿았다.&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; '차곡차곡', '소중히'&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;그냥...그렇게 누구나 고민하면서 차곡차곡 쌓아가고, 나중에 &lt;span style=&quot;color: #0593d3;&quot;&gt;뭔가&lt;/span&gt; 되지 않을까?&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;그렇게 20대는 치열하게 고민하면서 계속해서 &lt;span style=&quot;color: #0593d3;&quot;&gt;쌓이는 것&lt;/span&gt; 같다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;지금은 그저 '하기싫음', '힘이 듦'이겠지만... 언젠가는 &lt;span style=&quot;color: #0593d3;&quot;&gt;거대한 산&lt;/span&gt;이 되어있기를 간절히 바란다.&amp;nbsp;&lt;/span&gt;&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;span style=&quot;font-family: 'Noto Serif KR';&quot; data-sfc-cp=&quot;&quot;&gt;3. 일과 삶의 밸런스 찾기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;업무 시간이 매일 10:00 ~ 18:00로 정해져있었고, &lt;u&gt;오류 신고 &amp;amp; 다른 관리자&lt;/u&gt;들의 요청에 응답하는 &lt;span style=&quot;color: #ef5369;&quot;&gt;제한 시간&lt;/span&gt;이 존재했다. 제한 시간 안에 응답하지 않으면 '경고'가 쌓이게 된다. 경고가 많이 쌓이면 &lt;b&gt;퇴출&lt;/b&gt;.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;물론 응답 시간이 엄청 빡빡하지는 않았지만, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;내가 어디에 있든 &lt;i&gt;(연인과 놀든, 여행을 갔든, 정말 급한 일이 생겼거나 해도...)&lt;/i&gt; 답신을 빨리 하기 위해서 노력해왔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스스로&lt;/span&gt; '천천히 답해도 돼'&lt;/span&gt;라고 생각하지만, &lt;span style=&quot;color: #0593d3;&quot;&gt;'내가 오류 처리 안 해줘서, 이 사용자가 급한 연구 과제 못하고 있으면?'&lt;/span&gt;이라는 생각이 더 강하게 들었다. 그래서 지하철, 버스, 길바닥 등등 노트북을 안 열어본 곳이 없다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;연락도 항시 대기해야 했기에, &lt;s&gt;친구들 카톡 &amp;amp; DM은 죽어라 안 보는 나지만&lt;/s&gt; 계속 핸드폰을 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;아이폰 슬랙 알림이 잘 안 오는 이슈 때문에 직접 슬랙에 들어가서 계에에에에에속 알림을 기다렸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;그러다보니 스트레스가 누적이 되고, '그만두고싶다'는 생각도 든 적이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;결국에 일과 삶의 밸런스는 그 일을 아무리 사랑해도 필요하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;본인이 &lt;b&gt;본인의 한계&lt;/b&gt;를 잘 알고 있어야, &lt;b&gt;한계에 맞게 능력&lt;/b&gt;을 잘 &lt;b&gt;운용&lt;/b&gt;&lt;/span&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span data-sfc-cp=&quot;&quot;&gt;Try: &quot;다음에는 어떻게 다르게 할까?&quot;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 다음에 어딘가에서 일하게 된다면 어떻게 할까?&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무조건 일을 &lt;b&gt;빨리&lt;/b&gt; 배우기.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념을 개념으로만 알고있지 말고, 실수해도 되는 '신입'일때 최대한 많은 것을 흡수하려고 노력할 것이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;처음에 배우는 양이 상당히 중요하다는 것을 느꼈다. 힘들어도 따끔 ~ 좀만 참아 !&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동료&lt;/b&gt;들과 끊임없는 고민과 소통하기. 누구에게나 배울 점이 있고, 이 세상엔 훌륭한 동료들이 존재한다. 나도 그들에 뒤쳐지지 않도록 수시로 내 위치를 확인하고 이야기를 나눠보고 싶다.&lt;/li&gt;
&lt;li&gt;20대의 성장을 위한다면, &lt;b&gt;돈 생각은 잠깐 놔두기&lt;/b&gt;.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;돈은 그냥 맛있는 거 먹고싶을 때 사먹을 수 있을 정도면 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;집갈 때 호떡을 먹을 수 있을 정도면 행복한 거 아닐까...&lt;/li&gt;
&lt;li&gt;돈과 내 일을 저울질하지 말자. 세상은 원래 공정하지 않다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;내 일을 조금 더 사랑해야, 나도 행복해지고 내 주변 사람도 행복해진다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이왕 하는 일이면 웃으면서 하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스스로 멍청하다고 생각하는 &lt;b&gt;의견&lt;/b&gt;도 &lt;b&gt;일단&lt;/b&gt; 내보기.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;내가 경험해본 것이라면&lt;/u&gt; 초심자여도 의견을 못낼 이유가 없다고 느꼈다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GPU 서버관리자동화시스템의 스키마를 정의하면서, 다른 서버관리자들이 정규화를 엄청나게 많이 시켜놨다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;짰던 테이블들도 이런 정규화, 저런 정규화 해가면서 테이블을 계속 쪼개고 있었다. 복합키 등등...&lt;/li&gt;
&lt;li&gt;나는 &lt;span style=&quot;color: #ef5369;&quot;&gt;'내가 비전공자'&lt;/span&gt;라는 생각에 사로잡혀 내 의견을 적극적으로 어필하지 못했다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의심가는 구석이 생겨도, &lt;u&gt;'내가 못해서 뭘 모르는 거일 거야'&lt;/u&gt;라고 먼저 생각하게 되었던 순간들이 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;하지만 나중에 정해진 스키마를 토대로 개발을 하면서 &lt;b&gt;지나친 정규화&lt;/b&gt;는 오히려 개발 속도를 떨어트리고 &lt;b&gt;복잡성&lt;/b&gt;만 증가한다는 것을 체감하게 되었고,&lt;/li&gt;
&lt;li&gt;수많은 엔티티들을 다시 반정규화를 하면서는 '내가 그때 의견을 냈더라면'하는 후회가 들었다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다음에는 적극적으로 의견을 어필해보자. &lt;span style=&quot;color: #ef5369;&quot;&gt;&quot;아님 말고&quot; &quot;틀렸으면 고치면 되지.&quot; &quot;모르면 알면 되지&quot;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0593d3; font-family: 'Noto Serif KR';&quot;&gt;쿨걸의 마인드로.&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFaZjY/dJMcabbRJHs/Wx27W6kVjKNOihM0Faz4qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFaZjY/dJMcabbRJHs/Wx27W6kVjKNOihM0Faz4qk/img.png&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;1390&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2026-01-15 오후 4.30.15.png&quot; style=&quot;width: 32.1752%; margin-right: 10px;&quot; data-widthpercent=&quot;32.94&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFaZjY/dJMcabbRJHs/Wx27W6kVjKNOihM0Faz4qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFaZjY%2FdJMcabbRJHs%2FWx27W6kVjKNOihM0Faz4qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2466&quot; height=&quot;1390&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bscV96/dJMcajgCYhw/qfpEIn4GUtLK7yn2u8DC41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bscV96/dJMcajgCYhw/qfpEIn4GUtLK7yn2u8DC41/img.png&quot; data-origin-width=&quot;2462&quot; data-origin-height=&quot;1370&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2026-01-15 오후 4.30.26.png&quot; style=&quot;width: 32.592%; margin-right: 10px;&quot; data-widthpercent=&quot;33.37&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bscV96/dJMcajgCYhw/qfpEIn4GUtLK7yn2u8DC41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbscV96%2FdJMcajgCYhw%2FqfpEIn4GUtLK7yn2u8DC41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2462&quot; height=&quot;1370&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y7LBc/dJMcabbRJFs/1y79sqCIF97ahualbDGMWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y7LBc/dJMcabbRJFs/1y79sqCIF97ahualbDGMWK/img.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;636&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2026-01-15 오후 4.28.49.png&quot; style=&quot;width: 32.9073%;&quot; data-widthpercent=&quot;33.69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y7LBc/dJMcabbRJFs/1y79sqCIF97ahualbDGMWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY7LBc%2FdJMcabbRJFs%2F1y79sqCIF97ahualbDGMWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1154&quot; height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQyjOC/dJMcabbRJHU/z8DH8QXIHHwKxKzPKvpL90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQyjOC/dJMcabbRJHU/z8DH8QXIHHwKxKzPKvpL90/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2462&quot; data-origin-height=&quot;1398&quot; data-filename=&quot;스크린샷 2026-01-15 오후 4.30.37.png&quot; data-widthpercent=&quot;55.18&quot; style=&quot;width: 54.5373%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQyjOC/dJMcabbRJHU/z8DH8QXIHHwKxKzPKvpL90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQyjOC%2FdJMcabbRJHU%2Fz8DH8QXIHHwKxKzPKvpL90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2462&quot; height=&quot;1398&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOIcXb/dJMcacBQ25F/jZSJJkCVRCxAezrjC3D7xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOIcXb/dJMcacBQ25F/jZSJJkCVRCxAezrjC3D7xK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;590&quot; data-filename=&quot;스크린샷 2026-01-15 오후 4.30.48.png&quot; style=&quot;width: 44.2999%;&quot; data-widthpercent=&quot;44.82&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOIcXb/dJMcacBQ25F/jZSJJkCVRCxAezrjC3D7xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOIcXb%2FdJMcacBQ25F%2FjZSJJkCVRCxAezrjC3D7xK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;844&quot; height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 대학교 5년동안 저의 후진 점을 모르고 좋아해주신 분들, 그리고 응원해주신 분들&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글 보게 되실진 모르겠지만...진심으로 감사했습니다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;곧 졸업해요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕 ~~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔씩오래보자.&lt;/p&gt;</description>
      <category>이야기</category>
      <category>개발자</category>
      <category>대학생</category>
      <category>서버</category>
      <category>회고</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/50</guid>
      <comments>https://kiritoni.tistory.com/50#entry50comment</comments>
      <pubDate>Thu, 15 Jan 2026 16:21:07 +0900</pubDate>
    </item>
    <item>
      <title>AWS RDS(MySQL) Migration하기 (  새 계정으로 이사가요)</title>
      <link>https://kiritoni.tistory.com/49</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 AWS RDS를 다른 계정으로 이전하는 작업을 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 팀에서 쓰던 동아리 홈페이지 AWS 계정의 설정을, 학교와 연결된 회사의 계정으로 옮겨야 하는 상황이라&lt;/p&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;blockquote data-ke-style=&quot;style2&quot;&gt;IT 마이그레이션은 데이터나 소프트웨어를 한 시스템에서 다른 시스템으로 이동하는 것입니다. IT 마이그레이션은 프로젝트에 따라 데이터 마이그레이션, 애플리케이션 마이그레이션, 운영 체제 마이그레이션, 클라우드 마이그레이션 등 한 가지 이상의 이동이 진행될 수 있습니다.&lt;br /&gt;IT 마이그레이션의 일반적인 몇 가지 예시는 다음과 같습니다.&lt;br /&gt;- 애플리케이션 또는 운영 체제(OS) 업그레이드&lt;br /&gt;- 데이터를 한 종류의 데이터베이스에서 다른 종류의 데이터베이스로 이동&lt;br /&gt;- 하나의 데이터 스토리지 시스템을 다른 데이터 스토리지 시스템으로 교체&lt;br /&gt;- 온프레미스 인프라에서 클라우드 인프라로 이동모놀리식 애플리케이션을 컨테이너화된 서비스로 교체&lt;br /&gt;- 일반적으로 IT 마이그레이션 프로젝트에는 조직의 요구 사항에 고도로 특화된 구동 부품 및 요구 사항이 다수 포함되어 있습니다. &lt;br /&gt;인프라 자동화 전략을 반영해 면밀하게 계획을 세우면 IT 마이그레이션이 더 수월해질 수 있습니다.&lt;br /&gt;출처: RedHat&lt;/blockquote&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;생각보다 마이그레이션의 범위가 넓어서 놀랐고, (특히 OS 업그레이드도 마이그레이션에 속한다는 점!)&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리 팀은 AWS에 모든 인프라가 있어서 이것들을 들어서 다른 AWS로 모두 옮겨야 하는 상황!&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  TO-DO : 옮겨야 할 것&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- RDS&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- EC2 (2개)&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- S3&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- ALB&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Route53&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- ACM&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RDS, EC2, S3는 백엔드 팀원 셋이 나눠서 하기로 했고, 나머지 설정은 중요할 것 같아서 다같이 모여서 해보기로 했다.  &lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;백엔드 팀원이 있어서 정말 정말 다행이고 행복하다...&lt;/p&gt;
&lt;p style=&quot;color: #151515; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  이전 목표&lt;/b&gt;&lt;br /&gt;소스 계정 (A):&amp;nbsp;현재 운영 중인&amp;nbsp;암호화된&amp;nbsp;RDS 인스턴스가 있음.대상 계정 (B):&amp;nbsp;아무 설정이 없는 초기 상태의 AWS 계정.&lt;br /&gt;최종 목표:&amp;nbsp;소스 계정(A)의 RDS 데이터를 대상 계정(B)으로 안전하게 이전(복제)한다.&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;지금부터 소스 계정 (A, 기존에 팀에서 사용하던 계정), 대상계정 (B, 아무 설정이 없는 초기 상태의 계정)이라고 설명하겠다.&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;하지만 RDS가 aws/rds(AWS 관리형 키)로 암호화되어 있었고,&lt;/p&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;AWS 관리형 키는 아무리 소스 계정(A)이더라도 직접 정책을 편집할 수가 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정책 편집이 불가능하기 때문에 대상 계정(B)로 키를 사용하도록 공유할 방법이 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 B 계정은 A의 aws/rds로 잠긴 스냅샷을 복호화할 수 없기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`Restoring... cross account... encrypted snapshot is not supported`라는 오류를 마주하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;하지만 방법이 없는 것은 아니다.&amp;nbsp;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;RDS가 암호화된 경우에서, 새로운 AWS 계정으로 마이그레이션하는 방법을 설명해보겠다!&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1단계: 대상계정(B) 에 새 집 준비하기 (VPC)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. VPC 생성&lt;/b&gt;: RDS가 위치할 격리된 네트워크 (VPC)를 생성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 서브넷 생성&lt;/b&gt;: ⚠️고가용성을 위해 최소 2개의 다른 가용 영역 (AZ)에 프라이빗 서브넷을 생성해야 한다.&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;1590&quot; data-origin-height=&quot;1632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbvbon/dJMcadf2I1p/AzL46WCL79gndkH1QviMu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbvbon/dJMcadf2I1p/AzL46WCL79gndkH1QviMu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbvbon/dJMcadf2I1p/AzL46WCL79gndkH1QviMu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbvbon%2FdJMcadf2I1p%2FAzL46WCL79gndkH1QviMu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1590&quot; height=&quot;1632&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;1632&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 'VPC 등'을 선택하면, 라우팅 테이블 등을 자동으로 생성해줘서 편리하다. 만약에 커스텀 설정이 필요하다면 우선 'VPC만'을 선택하면 된다.&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;2048&quot; data-origin-height=&quot;1225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6cmMw/dJMcaawQ4vG/RSDLOmEarc8DtBOcZCGNP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6cmMw/dJMcaawQ4vG/RSDLOmEarc8DtBOcZCGNP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6cmMw/dJMcaawQ4vG/RSDLOmEarc8DtBOcZCGNP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6cmMw%2FdJMcaawQ4vG%2FRSDLOmEarc8DtBOcZCGNP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1225&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완료가 되면 다음으로 넘어간다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. DB 서브넷 그룹 생성&lt;/b&gt;: 위에서 만든 2개의 서브넷을 묶어 RDS가 사용할 'DB 서브넷 그룹'을 생성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDS -&amp;gt; 왼쪽 메뉴의 '서브넷 그룹' &amp;gt; DB 서브넷 그룹 생성으로 접속한다.&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;2048&quot; data-origin-height=&quot;1228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IRKFz/dJMcabWPIfD/tQrvFHicEsoFOWlAapBTO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IRKFz/dJMcabWPIfD/tQrvFHicEsoFOWlAapBTO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IRKFz/dJMcabWPIfD/tQrvFHicEsoFOWlAapBTO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIRKFz%2FdJMcabWPIfD%2FtQrvFHicEsoFOWlAapBTO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1228&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브넷 그룹의 이름을 입력하고, 방금 생성한 새 VPC를 선택해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 서브넷 추가 섹션에서는 위에서 생성했던 2개 이상의 서브넷을 모두 선택해 추가한다.&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;2048&quot; data-origin-height=&quot;1700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpZuLG/dJMb99Y05qY/m6Zy3wMOkYFnPzSfdKJYtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpZuLG/dJMb99Y05qY/m6Zy3wMOkYFnPzSfdKJYtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpZuLG/dJMb99Y05qY/m6Zy3wMOkYFnPzSfdKJYtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpZuLG%2FdJMb99Y05qY%2Fm6Zy3wMOkYFnPzSfdKJYtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1700&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2단계: 소스 계정 (A) 데이터 포장 및 키 공유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 원본 RDS가 있는 A로 돌아오자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를   이삿짐으로 만들어줄 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.   고객 관리형 키 (CMK) 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMS(Key MagementService)를 검색하고 이동한다. 그리고 CMK를 새로 생성해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, '키 사용 권한' 단계에서 B의 ID를 추가해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계정 ID는 프로필 오른쪽 위에서 확인할 수 있다.&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;2048&quot; data-origin-height=&quot;1520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BZYAa/dJMcajtNAaC/gh4PWJ5JPT4pJymU22wvA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BZYAa/dJMcajtNAaC/gh4PWJ5JPT4pJymU22wvA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BZYAa/dJMcajtNAaC/gh4PWJ5JPT4pJymU22wvA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBZYAa%2FdJMcajtNAaC%2Fgh4PWJ5JPT4pJymU22wvA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1520&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGaAaY/dJMcaaDCHye/siNny9BE6P6xGtYT9HLHl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGaAaY/dJMcaaDCHye/siNny9BE6P6xGtYT9HLHl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGaAaY/dJMcaaDCHye/siNny9BE6P6xGtYT9HLHl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGaAaY%2FdJMcaaDCHye%2FsiNny9BE6P6xGtYT9HLHl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1513&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1513&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;2048&quot; data-origin-height=&quot;1519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cE9grO/dJMcahvYQsk/CyIm3ieDuiYYiHJZr8yozk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cE9grO/dJMcahvYQsk/CyIm3ieDuiYYiHJZr8yozk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cE9grO/dJMcahvYQsk/CyIm3ieDuiYYiHJZr8yozk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcE9grO%2FdJMcahvYQsk%2FCyIm3ieDuiYYiHJZr8yozk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1519&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1519&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 KMS에 대해 잠깐 짚고 가자면 아래와 같이 3가지 유형이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;출처: AWS&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kWRGZ/dJMcabJiE2V/TkcK5A2rY3dql7aalIZME1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kWRGZ/dJMcabJiE2V/TkcK5A2rY3dql7aalIZME1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kWRGZ/dJMcabJiE2V/TkcK5A2rY3dql7aalIZME1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkWRGZ%2FdJMcabJiE2V%2FTkcK5A2rY3dql7aalIZME1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1464&quot; height=&quot;776&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 AWS 관리형 키는 사용자가 관리를 할 수가 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객 관리형 키는 제어는 가능하지만 월별 요금이 나가기 때문에 마지막에 꼭 삭제해주는 것이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 수동 스냅샷 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전할 DB의 '수동 스냅샷'을 생성해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 스냅샷은 원본 DB의 키인 aws/rds로 자동 암호화된다.&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;1642&quot; data-origin-height=&quot;1028&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7Me4/dJMcaiaAnYB/fmoNn9xWLHRTcckJ6KnQM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7Me4/dJMcaiaAnYB/fmoNn9xWLHRTcckJ6KnQM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7Me4/dJMcaiaAnYB/fmoNn9xWLHRTcckJ6KnQM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7Me4%2FdJMcaiaAnYB%2FfmoNn9xWLHRTcckJ6KnQM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1642&quot; height=&quot;1028&quot; data-origin-width=&quot;1642&quot; data-origin-height=&quot;1028&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;2048&quot; data-origin-height=&quot;1101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMvjnX/dJMcab3BnIh/zQizf0goOMnQGhkEkIoODK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMvjnX/dJMcab3BnIh/zQizf0goOMnQGhkEkIoODK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMvjnX/dJMcab3BnIh/zQizf0goOMnQGhkEkIoODK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMvjnX%2FdJMcab3BnIh%2FzQizf0goOMnQGhkEkIoODK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1101&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1101&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 스탭샷 복사&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 스냅샷이 생성되면, 선택하고 작업 &amp;gt; 스냅샷 복사&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'암호화 활성화'를 체크하고, 위에서 생성했던 KMS 키를 선택한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서는 aws/rds 키로 잠긴 데이터를 풀어서, 우리가 만든 CMK로 다시 잠그는 재암호화 작업이다.&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;1658&quot; data-origin-height=&quot;1148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UGZKe/dJMcabvLtdA/PV72MX5pwXZ9F4SxrLntuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UGZKe/dJMcabvLtdA/PV72MX5pwXZ9F4SxrLntuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UGZKe/dJMcabvLtdA/PV72MX5pwXZ9F4SxrLntuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUGZKe%2FdJMcabvLtdA%2FPV72MX5pwXZ9F4SxrLntuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1658&quot; height=&quot;1148&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;1148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 스냅샷 공유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 만든 새 스냅샷 &amp;gt; 작업 &amp;gt; 스냅샷 공유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 했던대로 B의 ID를 추가해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3단계: 대상 계정 (B) - 데이터 설치 (복사 후 복원)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 공유 스냅샷 복사&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B에서 RDS &amp;gt; 스냅샷 &amp;gt; 공유된 스냅샷 탭으로 이동한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'복원'이 아닌 '작업' &amp;gt; 스냅샷 복사를 클릭한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화 활성화를 체크하고, KMS는 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;하지만 AWS 관리형 키는 비용이 나가지 않기 때문에 aws/rds키를 선택하는 것을 추천!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서는 A의 CMK로 잠긴 데이터를 풀어서 다시 B로 잠그는 작업을 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 로컬 스냅샷 복원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복사가 완료되면 이 스냅샷을 선택하고, 작업 &amp;gt; 스냅샷 복원을 클릭한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서는 처음에 만들었던 vpc와 subnet group을 선택해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 생성을 클릭하여 복원을 완료하면 끝!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  그럼 이게 어떻게 가능한 것이고, 왜 문제가 생겼던 걸까?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;암호화된 스냅샷 = 잠긴 금고&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;KMS 키 = 금고 열쇠가 된다.&amp;nbsp;&lt;/span&gt;&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;span style=&quot;color: #000000;&quot;&gt;처음에는 금고가 aws/rds라는 키로 잠겨있었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 키는 AWS가 직접 관리하는 건물 마스터키이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;A 계정의 주인이더라도 B 한테 함부로 넘길 수 없다.&amp;nbsp;&lt;/span&gt;&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;span style=&quot;color: #000000;&quot;&gt;그래서 공유 가능한 나만의 개인 열쇠(CMK)를 A 계정에 만든다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;aws/rds로 잠긴 금고에서 데이터를 꺼내, 우리가 만든 CMK로 새 금고를 만든다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것이 '스냅샷 복사'작업이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CMK는 A의 소유이므로 B에게 열쇠를 쓸 수 있게 허락할 수 있다.&lt;/span&gt;&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;span style=&quot;color: #000000;&quot;&gt;하지만 B가 이 금고를 복원하더라도, 여전히 A계정 소유의 열쇠로 잠겨있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 사용허가만 받았을 뿐이지 소유권을 가진 건 아니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 B 계정 소유의 열쇠로 암호화를 해준 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것이 B 계정에서 했던 두 번째 '스냅샷 복사'작업이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 완전히 B가 소유한 금고를 가지게 된다.&amp;nbsp;&lt;/span&gt;&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;&amp;nbsp;&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;span style=&quot;color: #000000;&quot;&gt;마지막으로.. 만들었던 KMS를 꼭 !! 삭제하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매월 1달러정도 요금이 부과된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최소 7일의 유예 기간 후에 영구히 삭제되니 돈 없는 학생은 미리미리 지워서 과금을 방지하자.&amp;nbsp;&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;내가 마이그레이션을 하는 동안,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다른 백엔드 팀원들이 S3, EC2를 마이그레이션 해주었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음에는 다같이 보여서 Route53과 ALB를 마이그레이션하고,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;남은 세세한 작업들(제일 귀찮음)을 해보려고 한다!&lt;/span&gt;&lt;/p&gt;</description>
      <category>인프라/AWS</category>
      <author>kiritoni</author>
      <guid isPermaLink="true">https://kiritoni.tistory.com/49</guid>
      <comments>https://kiritoni.tistory.com/49#entry49comment</comments>
      <pubDate>Tue, 11 Nov 2025 01:24:08 +0900</pubDate>
    </item>
  </channel>
</rss>