<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>bluayer</title>
    <link>https://hack-jam.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 21:55:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>bluayer</managingEditor>
    <image>
      <title>bluayer</title>
      <url>https://tistory1.daumcdn.net/tistory/2874968/attach/c3d51134e2bb4099bfbac9aa4bdfcaae</url>
      <link>https://hack-jam.tistory.com</link>
    </image>
    <item>
      <title>2025년 회고</title>
      <link>https://hack-jam.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;사실 25년 회고는 쓰지 말까하고 고민했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;25년은 정말 여러 일이 있어서 그걸 되돌아보는 것만으로도 꽤 지치는 일이었기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 회고를 쓰기 위해서 내게 높은 집중력이 필요하다고 생각됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;킥오프가 많았던 1월을 보내고, 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;24년 회고의 서론에 이런 말이 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;한 해, 그리고 그 다음 한 해가 아직까지는 매년 색다른 기분이 들고 지금은 이걸 놓치고 싶지 않은 간절함. 특정 시점이 오면 지금의 열정과 호기심을 잃어버리지 않을까, 교만해져서 멈추지 않을까 하는 고민들. 2025년에도 간절한 마음으로 내 분기점을 개척해 나가고 있길 바란다.&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;25년을 지나면서 깨달았던 점은, &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;모든 1년이 힘들었지만 작년 한 해는 유독 하루 하루를 격정적으로 살았다고 생각된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터베이스 ... 말고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년에 데이터베이스를 열심히 공부하면서 자연스럽게 캐시 쪽에 빠르게 전문성을 가지게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해도 여전히 캐시 쪽에 전문성을 가지기 위해서 여러가지를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ElastiCache 발표도 Summit에서 하고, (그 외에도 많이 했지만 500+인원이 들었던 Summit이 유독 기억에 남는다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ElastiCache 서비스 팀과 협업하며 같이 블로그를 작성하기도 하고, (이 블로그가 Re:Invent 영상에 들어갈 줄은...)&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;그리고 공개한 적은 없지만 DBA로의 직무 전환도 검토했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날부터 희망했던 회사였고, 같이 일해보고 싶은 분이 있던 곳이어서 지원했지만 최종 탈락했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 개인적으로 DBA로의 역량은 한참 부족했다고 생각하고, 또 인터뷰를 보면서 느낀거지만 &quot;DBA가 정말 내가 하고 싶은 일이 맞나?&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;DBA가 아니라 DB 플랫폼을 만들고 싶었던건가 -&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;내 강점은 백엔드 개발자면서, 기존에 데이터 파이프라인을 다뤄봤고 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;아이러니하게도 GenAI 임팩 덕에 이런 사고의 전환이 현명한 결정이 되었다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;일이 되게 만드는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;25년은 일하면서 많은 고민을 했던 거 같다. 고민 예시는 다음과 같다 :&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;li&gt;도움을 요청해야 할 사람에게는 어떤 것을 줄 수 있는가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정의 결론은 &quot;어떻게 일이 되게 만드는 걸까?&quot; 였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기 동안 했던 고민의 결과들이 실제 업무상 좋은 성과로 나오게 되면서, 이런 이야기를 듣게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;정우님이 하는 일은 쉽게 결과를 만들어내는 거 같아요. 근데 누군가 하는 일이 쉬워보이면 그게 경지에 오른거라던데..&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인상 깊은 말이었다. 비즈니스가 엮여 있는 현재 포지션에서는 결국 어떻게 일이 되게 만드는지가 중요하구나 라는 생각을 하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 회사에 온 이후로 기술적인 부분 뿐만 아니라, 사람을 대하는 방법도 매년 성장하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI로 인한 할루시네이션이 모든 걸 덮어버리는 데이터 홍수 속에서,&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;내가 써보고 별로인 서비스는 타인에게도 별로다.&lt;/li&gt;
&lt;li&gt;내가 좋다고 생각했던 서비스도 타인의 시선에서는 별로일 수 있다.&lt;/li&gt;
&lt;li&gt;그렇다면 내가 좋다고 생각했던 서비스가 타인에게 필요한 이유는 무엇인가? 그 이유가 없다면 제안하면 안되는 것 아닌가?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 생각 흐름 덕에 무의미한 일을 하는 시간이 줄었다. 일을 (손쉽게) 되게 만들자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;건강&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스 얘기를 하기 전에 이 얘기를 먼저 적어야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;25년 상반기에는 반년 이상 술도, 커피도 못 마실 정도로 건강이 안 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병원에서 둘 다 하지 말라고 권고 받았고, 러닝을 열심히 뛰게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하하. 24년 회고에서 건강 좀 잘 챙기자고 하더니... 쯧&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1년 안에 ... 하자. 2년 안에 ... 하자. 이렇게 시간적 압박을 스스로에게 주는 걸 포기했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간적 압박을 주기 시작하면, 데드라인을 위해서 결과물을 포기하는 상황들이 발생하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 무엇보다 내 심신이 무너졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1년 안에..? 1.5년을 하면 문제가 생기나? -&amp;gt; 전혀 생기지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능하면 요즘에는 주말에 일을 안 하려고 노력하고 있다. 잘 지켜내보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;오픈 소스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년의 Valkey에 기여한 것을 시작으로, 25년에도 오픈소스에 기여를 하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스를 하려고 한 건 아니었지만 Kubecon NA 25에서 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;LMCache에 Valkey connector를 추가하는 작업을 했고 그 과정에서 Pipelining을 통해서 이전 Redis Connector보다 20% 이상 성능을 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LMCache는 KV 캐시를 관리하고 확장시켜줄 수 있는 라이브러리이기 때문에 RTT 시간에 영향을 받는 구조라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연스럽게 Pipelining을 고려해서 작성하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경험을 기반으로 ElastiCache 서비스 팀과 Semantic Caching에 관한 글로벌 블로그도 써 본 흥미로운 경험이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubecon NA 25 부스의 데모를 하다 보니 자연스럽게 Inference on Kubernetes에 관심이 생겨 추론 인프라를 다양한 라이브러리를 통해 살펴보게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 과정에서 KServe에도 S3로부터 모델 다운로드 속도를 최대 2배 개선하는 간단한 PR도 하나 머지했고, 최근에는 새로운 CRD를 제안하고 있는 중이다. 끝까지 잘 될지는 모르겠지만.. LocalModelCache가 너무 불편하다는 의식에서 시작해서 빠르게 행동으로 잘 옮겨봤다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 오픈 소스를 꾸준히, 자주 하게 될지는 사실 잘 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 내가 불편하다고 생각하는 것을 개선해 나가는 것은, 적어도 내가 늘 사람들에게 강조했던 보이스카웃 룰을 지켜나가는 과정이 아닐까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Next step?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubecon NA 25에서 여러 사람을 만나고 협업하는 과정에서 생각보다 내 기술 수준이 낮지 않다는 걸 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 생각보다 영어도 쓰기 시작하면 확확 늘어난다는 것을 경험했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;26년, 27년에는 내 서비스를 운영하거나 만드는 회사를 가고 싶다는 생각이 들기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MLOps 포지션이면 더 좋고, 아니더라도 시스템/플랫폼을 만드는 곳이었으면 좋겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여전히 설레는 마음으로 기술과, 또 세상과 부대끼며 더 나아가 보고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 끝은 어딜까? 내 자신의 앞으로가 점점 궁금해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 25년을 돌아보면 초반에는 가장 불안정했고 점점 안정되어 갔고, 결국 무언가를 많이 이뤄냈다.&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;하지만 여전히 달려보고 싶다. 이전과 같은 속도는 아니더라도 지난 5년간 해온 나를 믿으면서.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;26년엔 무얼 또 할 수 있을 것이며, 나는 무얼 또 준비하고 있을까?&lt;/p&gt;</description>
      <category>Log.Develop/Retrospection</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/71</guid>
      <comments>https://hack-jam.tistory.com/71#entry71comment</comments>
      <pubDate>Tue, 3 Mar 2026 13:22:02 +0900</pubDate>
    </item>
    <item>
      <title>2024년 회고</title>
      <link>https://hack-jam.tistory.com/70</link>
      <description>&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;요즘 처음 회고를 썼던 2020년부터 한 발자국, 한 해가 모두 내 분기점이라는 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 친구들을 만나면 이런 이야기를 듣는다. &quot;이제 적당히 해도 되지 않아?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 일부 동의한다. 그럼에도 불구하고 여전히 간절한 마음과 여러 고민들을 가지고 일하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 해, 그리고 그 다음 한 해가 아직까지는 매년 색다른 기분이 들고 지금은 이걸 놓치고 싶지 않은 간절함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 시점이 오면 지금의 열정과 호기심을 잃어버리지 않을까, 교만해져서 멈추지 않을까 하는 고민들.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025년에도 간절한 마음으로 내 분기점을 개척해 나가고 있길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년에는 참 많은 일이 있었다. 다 지나고 나니 힘들고 슬픈 일보다 행복했던 일이 더 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번 쓱 살펴보자. 일 얘기 안 보고 싶은 분은 밑으로 쭉 스크롤하길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;멘토&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진심으로 올해는 &quot;멘토&quot;라는 키워드를 빼놓고 어떤 내용도 설명할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참 세상에 좋은 어른들이 많음을, 그리고 그런 어른처럼 되고 싶다는 마음에 더 열심히 달릴 수 있었다.&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;크게는 내 다음 스텝을 위해 어떤 것들을 하고 PR 해야하는지 같은 부분들도 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 누군가한테 배우고 싶고, 동료 관계가 되길 바라는 멘토가 될 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노력해보자. 그리고 늘 아낌없는 조언과 지지를 보내주시는 멘토 분들께 감사드린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터베이스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토 얘기하다 뜬금없이 데이터베이스가 나오긴 했다만, 올해를 관통하는 키워드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 멘토 분들이 대부분 데이터베이스 전문가 분들이기도 했고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 애플리케이션 개발자가 아는 수준만큼 데이터베이스에 대해서 알고 있었는데&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;현재는 &quot;ElastiCache 워크로드를 위한 카오스 실험&quot;이라는 재밌는 주제로 글을 쓰고 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 쓴 컨텐츠 중 일부는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #232f3e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/tech/pretesting-database-changes-including-application-with-amazon-aurora-blue-green-deployments/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Amazon Aurora Blue/Green Deployment를 활용하여 애플리케이션 계층을 포함한 데이터베이스 변경 사전 테스트하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1734849440551&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;Amazon Aurora Blue/Green Deployment를 활용하여 애플리케이션 계층을 포함한 데이터베이스 변경 사전 테&quot; data-og-description=&quot;이 글은 애플리케이션 계층을 포함한 데이터베이스 변경 사전 테스트의 중요성과 사전 테스트를 위한 아키텍처를 소개합니다. 특히 Amazon Aurora의 Blue/Green Deployment를 핵심으로 CQRS(Command Query Respon&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/blogs/tech/pretesting-database-changes-including-application-with-amazon-aurora-blue-green-deployments/&quot; data-og-url=&quot;https://aws.amazon.com/ko/blogs/tech/pretesting-database-changes-including-application-with-amazon-aurora-blue-green-deployments/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Gfr1z/hyXSClnsK9/on5tgjdur2C5tSl7x1Y8tK/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385,https://scrap.kakaocdn.net/dn/b3IhTJ/hyXOeNfHcJ/REkqRjRBg7uExJYLEScn4k/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/tech/pretesting-database-changes-including-application-with-amazon-aurora-blue-green-deployments/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/blogs/tech/pretesting-database-changes-including-application-with-amazon-aurora-blue-green-deployments/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Gfr1z/hyXSClnsK9/on5tgjdur2C5tSl7x1Y8tK/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385,https://scrap.kakaocdn.net/dn/b3IhTJ/hyXOeNfHcJ/REkqRjRBg7uExJYLEScn4k/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385');&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 Aurora Blue/Green Deployment를 활용하여 애플리케이션 계층을 포함한 데이터베이스 변경 사전 테&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 글은 애플리케이션 계층을 포함한 데이터베이스 변경 사전 테스트의 중요성과 사전 테스트를 위한 아키텍처를 소개합니다. 특히 Amazon Aurora의 Blue/Green Deployment를 핵심으로 CQRS(Command Query Respon&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;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/tech/amazon-elasticache-serverless-operation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Amazon ElastiCache Serverless 운영하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1734849520730&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;Amazon ElastiCache Serverless 운영하기 | Amazon Web Services&quot; data-og-description=&quot;Amazon ElaistCache Serverless는 캐시를 1분 안에 생성하고 애플리케이션 트래픽 패턴에 따라 용량 크기를 즉시 조정할 수 있는 서버리스 옵션이며, 인기 있는 두 가지 오픈 소스 캐싱 솔루션인 오픈 소&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/blogs/tech/amazon-elasticache-serverless-operation/&quot; data-og-url=&quot;https://aws.amazon.com/ko/blogs/tech/amazon-elasticache-serverless-operation/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLzB10/hyXOoWE1EW/FrixP4fSqPJpcIDhZIQL90/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385,https://scrap.kakaocdn.net/dn/VaHGb/hyXOkmmWX5/v3iaQTWOjp4Gch9hZUlhok/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385,https://scrap.kakaocdn.net/dn/ciJGqo/hyXSza6Ywc/CkCkeilSvwbmKSRQAVkgk0/img.jpg?width=689&amp;amp;height=886&amp;amp;face=181_195_489_531&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/blogs/tech/amazon-elasticache-serverless-operation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/blogs/tech/amazon-elasticache-serverless-operation/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLzB10/hyXOoWE1EW/FrixP4fSqPJpcIDhZIQL90/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385,https://scrap.kakaocdn.net/dn/VaHGb/hyXOkmmWX5/v3iaQTWOjp4Gch9hZUlhok/img.png?width=768&amp;amp;height=385&amp;amp;face=0_0_768_385,https://scrap.kakaocdn.net/dn/ciJGqo/hyXSza6Ywc/CkCkeilSvwbmKSRQAVkgk0/img.jpg?width=689&amp;amp;height=886&amp;amp;face=181_195_489_531');&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 ElastiCache Serverless 운영하기 | Amazon Web Services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Amazon ElaistCache Serverless는 캐시를 1분 안에 생성하고 애플리케이션 트래픽 패턴에 따라 용량 크기를 즉시 조정할 수 있는 서버리스 옵션이며, 인기 있는 두 가지 오픈 소스 캐싱 솔루션인 오픈 소&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;관심을 가지고 공부하는 과정에서 올해 엔지니어로서 내 밸류 포지셔닝이 어떻게 되는지를 고민하는 과정에서 답을 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌다보니 커리어 내내 이런 워크로드들을 다뤄왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전동 킥보드 시스템을 다룰 때도 데이터 플랫폼과 CMS를 다룰 때도 아래의 공통점들이 있었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저지연, 고속 처리가 필요한 워크로드&lt;/li&gt;
&lt;li&gt;높은 쓰루풋, 즉 짧은 윈도우 내에 대량의 데이터가 움직이는 워크로드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황들을 해결하려고 비동기 아키텍처나 RxJava 같은 것도 적용해보고 그랬다.&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;그래서 이 부분은 중간 경험이 있는 내가 잘할 수 있을 듯해서 인메모리 데이터베이스, 현재는 Valkey를 열심히 파기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(근데 인메모리 데이터베이스를 하다보면 기존 데이터베이스인 RDBMS를 많이 살펴보게 된다. 숨만 쉬어도 공부가 2배가 되는 기적!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 최근에 흥미로운 회사들의 글들이 나오기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 성숙도가 꽤 높은 인메모리 데이터베이스가 시대의 흐름을 타고 있다는 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-baseweb=&quot;heading&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.uber.com/en-KR/blog/how-uber-serves-over-40-million-reads-per-second-using-an-integrated-cache/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How Uber Serves Over 40 Million Reads Per Second from Online Storage Using an Integrated Cache&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(++ 글은 못 찾겠지만 피그마 글도 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;어쩌다보니 Valkey 컨트리뷰터&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 참 뜬금없다. 원래는 올해 할 생각도 별로 없었는데, 블로그 컨텐츠 쓰다보니 필요해서 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스에 기여하는 건 예전부터 생각해오고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;친구인 L군이 늘 권장하기도 했고 관심있는 프로젝트의 소스코드를 보는게 도움이 많이 된다고 생각했기 때문이다.&lt;/p&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;11월부터 블로그 컨텐츠를 쓰고 있었는데 redis-benchmark, valkey-benchmark를 이용해 테스트를 하다보니 결과가 이상했다.&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;처음에는 당연히 &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;이슈에 올라가 있긴 하길래 대충 12월 초면 누가 만들어주겠지~ 했는데 아무도 손 안대더라...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그냥 내가 했다. &lt;s&gt;(답답해서 내가 뛴다)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 이걸 작성해야지 하고 했던 건 아니고 코드를 이해하고 나니 금방할 거 같아서 그냥 짰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 이해하는데 하루, 코드 작성하는데 하루, 테스트 해보고 고치는데 하루 정도를 써서 PR을 두근두근하며 올렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 4~5일 지나도 아무도 내 PR 안 보길래 같은 회사에 있는 (...안면 있을 리 없는) 메인테이너를 핑 했더니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 회사의 Sr.SDE가 리뷰어로 붙었다. (왠지 모를 내적 친밀감)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘이 한 2주동안 새벽 시간에 코멘트로 핑퐁하면서 다 고쳤고, 현재는 머지되어 release-notes 태그가 붙었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(... 16 commit, 43 conversation, +168 &amp;amp; -186 lines의 향연)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-22 at 3.55.45 PM.png&quot; data-origin-width=&quot;2266&quot; data-origin-height=&quot;1060&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4GNFq/btsLreTgYyc/9zZ8crAKZtPjJxablfRlVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4GNFq/btsLreTgYyc/9zZ8crAKZtPjJxablfRlVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4GNFq/btsLreTgYyc/9zZ8crAKZtPjJxablfRlVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4GNFq%2FbtsLreTgYyc%2F9zZ8crAKZtPjJxablfRlVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2266&quot; height=&quot;1060&quot; data-filename=&quot;Screenshot 2024-12-22 at 3.55.45 PM.png&quot; data-origin-width=&quot;2266&quot; data-origin-height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 곳에 공유했던 간단한 느낀 점.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-22 at 3.55.03 PM.png&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nnes7/btsLrPyQljj/DFsG3hFp6bIk8QeKZrOlxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nnes7/btsLrPyQljj/DFsG3hFp6bIk8QeKZrOlxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nnes7/btsLrPyQljj/DFsG3hFp6bIk8QeKZrOlxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNnes7%2FbtsLrPyQljj%2FDFsG3hFp6bIk8QeKZrOlxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1394&quot; height=&quot;288&quot; data-filename=&quot;Screenshot 2024-12-22 at 3.55.03 PM.png&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;288&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;내가 만지작하던 Valkey여서 그랬는지 재밌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;25년에는 이번처럼 유의미한 PR 2~3개를 더 올려보는 것을 목표하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이외에도&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일한 거는 많은데 쓰기 귀찮다. 여행 갔다온 거나 쓰련다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;여행&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 여행을 많이 갔다 왔다. 혼자서, 형들이랑, 부모님이랑, 친구랑 등등 정말 다양한 멤버로 갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웃픈 에피소드지만 올해 첫 여행을 갔던 4월에는 무려 만 2주 동안 장기휴가를 가면서 이런 생각을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;번아웃 온 거 조금도 안 나아지면 다이렉트 퇴사간다.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문장으로 쓰고 나니 슬프기보다 좀 웃긴 거 같기도ㅋㅋㅋㅋㅋ 약간 MZ의 패기 같다&lt;/p&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/uWd16/btsLrhboiA1/bvzIYBYqbP8Brs1Rbnk001/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uWd16/btsLrhboiA1/bvzIYBYqbP8Brs1Rbnk001/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;1163&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-04-32.jpeg&quot; style=&quot;width: 38.8675%; margin-right: 10px;&quot; data-widthpercent=&quot;39.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uWd16/btsLrhboiA1/bvzIYBYqbP8Brs1Rbnk001/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuWd16%2FbtsLrhboiA1%2FbvzIYBYqbP8Brs1Rbnk001%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1153&quot; height=&quot;1163&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/23E7m/btsLsrK94Hq/8fZDKDwUI9PJeWK0YUYT40/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/23E7m/btsLsrK94Hq/8fZDKDwUI9PJeWK0YUYT40/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-04-56 002.jpeg&quot; style=&quot;width: 29.4035%; margin-right: 10px;&quot; data-widthpercent=&quot;30.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/23E7m/btsLsrK94Hq/8fZDKDwUI9PJeWK0YUYT40/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F23E7m%2FbtsLsrK94Hq%2F8fZDKDwUI9PJeWK0YUYT40%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbQ2gY/btsLsdfbSbm/F3XbInKojtXogukhGaNjXK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbQ2gY/btsLsdfbSbm/F3XbInKojtXogukhGaNjXK/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-04-56 001.jpeg&quot; style=&quot;width: 29.4035%;&quot; data-widthpercent=&quot;30.11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbQ2gY/btsLsdfbSbm/F3XbInKojtXogukhGaNjXK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbQ2gY%2FbtsLsdfbSbm%2FF3XbInKojtXogukhGaNjXK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;4월 여행 : 그란 카나리아 - 포르투 - 마드리드&lt;/figcaption&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/dfGpM4/btsLtGU8X7Q/NTqajK5KwUliOyUnaus3I1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfGpM4/btsLtGU8X7Q/NTqajK5KwUliOyUnaus3I1/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;956&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-08-33 001.jpeg&quot; style=&quot;width: 48.9392%; margin-right: 10px;&quot; data-widthpercent=&quot;50.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfGpM4/btsLtGU8X7Q/NTqajK5KwUliOyUnaus3I1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfGpM4%2FbtsLtGU8X7Q%2FNTqajK5KwUliOyUnaus3I1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zkaeT/btsLrQdtred/svcEEc84gRqlwzh5eBkiM0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zkaeT/btsLrQdtred/svcEEc84gRqlwzh5eBkiM0/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-08-33 002.jpeg&quot; style=&quot;width: 24.3676%; margin-right: 10px;&quot; data-widthpercent=&quot;24.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zkaeT/btsLrQdtred/svcEEc84gRqlwzh5eBkiM0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzkaeT%2FbtsLrQdtred%2FsvcEEc84gRqlwzh5eBkiM0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHz8uR/btsLrwlYoHD/LHhXuKkPrZxmzD5t0CeO9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHz8uR/btsLrwlYoHD/LHhXuKkPrZxmzD5t0CeO9k/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-08-33 003.jpeg&quot; style=&quot;width: 24.3676%;&quot; data-widthpercent=&quot;24.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHz8uR/btsLrwlYoHD/LHhXuKkPrZxmzD5t0CeO9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHz8uR%2FbtsLrwlYoHD%2FLHhXuKkPrZxmzD5t0CeO9k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;형들이랑 간 여름 제주도&lt;/figcaption&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/bBXdrz/btsLstCcKWD/eNAVCkHAwEs9AZCAyHAbPK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBXdrz/btsLstCcKWD/eNAVCkHAwEs9AZCAyHAbPK/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;1136&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-15-52 001.jpeg&quot; data-widthpercent=&quot;32.25&quot; style=&quot;width: 31.4966%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBXdrz/btsLstCcKWD/eNAVCkHAwEs9AZCAyHAbPK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBXdrz%2FbtsLstCcKWD%2FeNAVCkHAwEs9AZCAyHAbPK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;811&quot; height=&quot;1136&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yLmWt/btsLteLkBF9/6XFMFc29etIepvK5L5Xh2k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yLmWt/btsLteLkBF9/6XFMFc29etIepvK5L5Xh2k/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-15-53 002.jpeg&quot; style=&quot;width: 33.0889%; margin-right: 10px;&quot; data-widthpercent=&quot;33.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yLmWt/btsLteLkBF9/6XFMFc29etIepvK5L5Xh2k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyLmWt%2FbtsLteLkBF9%2F6XFMFc29etIepvK5L5Xh2k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brkH13/btsLsrYJtsh/Y2kTmghaBpztxG2acHGp9K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brkH13/btsLsrYJtsh/Y2kTmghaBpztxG2acHGp9K/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-15-53 003.jpeg&quot; style=&quot;width: 33.0889%;&quot; data-widthpercent=&quot;33.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brkH13/btsLsrYJtsh/Y2kTmghaBpztxG2acHGp9K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrkH13%2FbtsLsrYJtsh%2FY2kTmghaBpztxG2acHGp9K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;부모님이랑 간 여름 삿포로&lt;/figcaption&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/1jqrD/btsLrCT6pkR/KvizdxrPJq3RAyr7oUJKf1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1jqrD/btsLrCT6pkR/KvizdxrPJq3RAyr7oUJKf1/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;956&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-17-48 003.jpeg&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1jqrD/btsLrCT6pkR/KvizdxrPJq3RAyr7oUJKf1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1jqrD%2FbtsLrCT6pkR%2FKvizdxrPJq3RAyr7oUJKf1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/svr2i/btsLrjAs52i/5QkUHU49eLlBDf1UaM3cgk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/svr2i/btsLrjAs52i/5QkUHU49eLlBDf1UaM3cgk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;956&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-17-47 002.jpeg&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/svr2i/btsLrjAs52i/5QkUHU49eLlBDf1UaM3cgk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsvr2i%2FbtsLrjAs52i%2F5QkUHU49eLlBDf1UaM3cgk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;솬이랑 간 늦여름 오사카&lt;/figcaption&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/uOJpV/btsLrVsdPhL/DfKn4ioXd2Q6kK9RwGFH0k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uOJpV/btsLrVsdPhL/DfKn4ioXd2Q6kK9RwGFH0k/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-20-13 003.jpeg&quot; style=&quot;width: 25.8663%; margin-right: 10px;&quot; data-widthpercent=&quot;26.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uOJpV/btsLrVsdPhL/DfKn4ioXd2Q6kK9RwGFH0k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuOJpV%2FbtsLrVsdPhL%2FDfKn4ioXd2Q6kK9RwGFH0k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F1P1l/btsLtISY9ox/oVFwqHiNhhKdLmTPlkNk7k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F1P1l/btsLtISY9ox/oVFwqHiNhhKdLmTPlkNk7k/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-20-13 002.jpeg&quot; style=&quot;width: 25.8663%; margin-right: 10px;&quot; data-widthpercent=&quot;26.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F1P1l/btsLtISY9ox/oVFwqHiNhhKdLmTPlkNk7k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF1P1l%2FbtsLtISY9ox%2FoVFwqHiNhhKdLmTPlkNk7k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mnqAQ/btsLresj2S6/19PkptOiGDQET94D8ruqMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mnqAQ/btsLresj2S6/19PkptOiGDQET94D8ruqMk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1081&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-22-16-20-13 001.jpeg&quot; style=&quot;width: 45.9419%;&quot; data-widthpercent=&quot;47.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mnqAQ/btsLresj2S6/19PkptOiGDQET94D8ruqMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmnqAQ%2FbtsLresj2S6%2F19PkptOiGDQET94D8ruqMk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1081&quot;/&gt;&lt;/span&gt;&lt;/div&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숨겨 놓은 23년 회고를 보니 참 무거운 내용이 많더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해도 무거운 내용이 가득 가득했지만 25년을 위해 남은 기간동안 비워내보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성장은 매년하고 있으니, 지금과 같은 마음가짐으로 25년도에는 건강을 훨씬 더 잘 챙기며 가면 될 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재밌게, 잘 가보자고 25년!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(P.S. 벌써 이 블로그에서만 70번째 글이라니..)&lt;/p&gt;</description>
      <category>Log.Develop/Retrospection</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/70</guid>
      <comments>https://hack-jam.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 22 Dec 2024 16:26:45 +0900</pubDate>
    </item>
    <item>
      <title>SOPT Makers 활동 회고</title>
      <link>https://hack-jam.tistory.com/68</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;서론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌다보니 거의 1년 만에 블로그에 글을 쓰게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 개인 블로그에 글을 쓰는 것에 좀 민감해하는 부분이 있어서 블로그에서 테크니컬한 컨텐츠를 다루지 않다보니,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 쓸 얘기가 많지 않아서 글 쓰는 것을 좀 멀리하게 된 거 같다.&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~2기를 하기도 했고 거의 1년에 가까운 기간동안 애정을 가지고 활동해서 회고를 써야 겠다는 생각을 많이 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 내 홈그라운드인 서버 파트에서 활동했고, 서버 리드도 한 기수하고, 기회가 닿아서 솝트 앱잼 멘토로도 갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해보니 내가 생각해도 회고 쓸 만하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;요즘 하는 사이드 플젝 없지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문으로 시작하게 된 활동이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;친한 친구가 권유했고, 같이 쿠키파킹을 함께 만들었던 형도 권유했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시에 한창 데중어설 스터디를 하고 있었고 개인적으로 사이드 플젝보다 배움에 대한 갈망이 더 컸기 때문에 고민이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 같이 일해보고 싶었던 사람들이 해당 기수에 활동할 가능성이 높았고 나도 &quot;숨구멍 하나 만들어두지 뭐~ &quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 안일한 마음 가짐으로 시작하게 된 활동이었다. &lt;s&gt;진짜 어림도 없는 소리였다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tech Stack Migration&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시에 Node.js 기반으로 간단한 CRUD가 작성되어 있었고 User는 0명인데 2개의 Micro service로 나눠져 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 확실히 관리 포인트 측면에서 너무 이르게 나눈 Micro service는 합쳐야겠다고 생각했다. (Max total user가 2~3K였기 때문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술 스택은 Node.js로도 1~2년 회사에서 일했었기 때문에 딱히 거부감은 없었지만, 장기적인 관점에서 Spring Boot로 가야한다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨌거나 SOPT는 대학생들이 하는 동아리고, 채용 한파가 오기 전이었음에도 불구하고 Node.js 채용은 거의 말라비틀어지고 있었기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;돌이켜보면 꽤 괜찮은 선택지였던 거 같다. 1기 합류 전에 0기가 있었는데, 0기 멤버들하고도 컨택하면서 이런 컨센서스를 미리 맞춰뒀었기 때문에 옮겨가는 것에 큰 문제가 없었다. 기존 코드베이스도 합쳐봐야 1000줄도 안 됐기 때문에 퇴근하고도 1~2주면 옮길 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이렇게 바꿔서 우리 팀에서는 나 혼자 일하게 되긴 했지만, 다른 몇몇 팀도 컨센서스가 잘 맞춰져서 원활하게 Spring Boot를 선택하게 되었고 후술할 2기 활동 때에 SOPT에서도 Spring Boot를 커리큘럼으로 가져가서 아주 좋은 선택지였다고 생각한다.&lt;/p&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;- 새로운 사람이 충분히 1달 내에 따라올 수 있는 기술 스택인지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 보편적인 기술, 특히 상업적 용도로 코드를 작성하는 회사들의 스택에 비해 어떤지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;프로덕트는 절대로 나 혼자서 완성할 수 없으며 어쩌면 누군가는 나의 Spirit을 전달해야 할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 의미에서 보편적인 스택을 선택하는 것이 나에게는 꽤 중요한 요소라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(물론 취미 생활할 때는 퍼포먼스도 따져보면서 Go로 작성해보고 Rust도 써보고 내가 재밌어보이는 스택으로 작성한다)&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;개발.. and development... and... again..&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1기나 2기나 이 부분은 더하거나 덧붙일 부분이 없다. 그냥 끝없이 개발했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 아침부터 저녁까지 개발하고 저녁부터 새벽까지 메이커스 개발을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 2기 때는 서버 리드까지 했기 때문에 내가 회사를 두 개 다니는 기분을 많이 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오전에는 분명 회사에서 빌빌대고 있는데, 오후에는 진짜 회사 리드처럼 이것저것 체크했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(사실 1기를 하면서 1기에서 원하는 것을 얻지 못한 분들이 서버 파트에 많았다. 그래서 내가 활동할 2기는 그런 일이 없었으면 해서 리드를 자처했고 후에 실제로 꽤 많은 사람이 남아서 이 부분은 초심을 잘 지키지 않았나 싶다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 햄스터 쳇바퀴도 나보다 좀 쉴 틈이 있었을 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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기 Recruiting을 준비하기 위해서 활동 기수랑도 많이 접점을 만들기 위해서 노력했고, 그 후의 기수를 생각해서 인터뷰 프로세스, 커피챗 등에서 충분히 신뢰할 수 있고 도전할 수 있는 환경임을 설명하려고 많이 노력했던 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경험은 나중에 돈 주고 배울 수 없는, 회사에서 리크루팅을 하게 되면 진짜 도움이 많이 될 경험이라고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1기 때는 당시에 우연찮게 지금 회사 프로세스도 밟고 있었고, 이전 회사에서 팀 이동에 대한 이야기도 하고 있었기 때문에 꽤 신경쓸 부분이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 굉장히 린하게, 많은 부분을 잘 개발하고 운영했다고 생각한다.&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;1기 때는 린하게 움직일 수 있는 환경이었으나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2기가 되면서 확실히 서비스가 전반적으로 커지고 Complex해졌으며, 리드로 활동하며 communication에 많은 리소스를 쏟게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 개발적으로 많은 걸 할 수 있는 환경임은 부인할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;유저가 있고, 팀과 팀원이 있으며, 트래픽이 있고, 레거시가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대학생이나 주니어 레벨의 동아리원이라면 무조건 해봐야 하는 경험이라고 생각하며 언제나 추천하고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그래도 사람이 남는다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 보면 &quot;으악! 개발하다 난 죽었어요!&quot;라는 맥락이긴 한데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 나는 회사 일에도 좀 미쳐있는 사람이어서 24/7을 일에 쏟는 경향이 있을 뿐더러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;가능하면 더 좋은 걸 만들고 싶고, 가능하면 더 나아지고 싶다.&quot;라는 생각이 강해서 그런 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(메이커스 사람들 대부분이 하드워커라 나랑 좀 비슷하긴 한데, 그래도 적당히 잘 놀면서 잘 일한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메이커스 내에는 꽤 다양한 커뮤니케이션 활동이 있다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;더 안 해? 더 안 하세요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 많이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토링해줬던 활동 기수 친구들한테 듣기도 하고, 같이 프로덕트를 만들던 친구들한테 듣기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확실히 1년이나 했기 때문에 프로덕트, 도메인에 익숙하고 코드 베이스도 내가 바닥부터 만들었기 때문에 너무 잘 알고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누군가한테는 우스운 이야기일 수 있겠지만, 나는 내가 그 프로덕트를 잘 만들 수 있기 때문에 그만하기로 결심했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 안정적인 환경이 아니라 도전하는 환경에 놓이고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그걸 위해서 지금 회사에 왔고 입사 1주년이 가까워지는 지금까지도 나에게 계속 챌린지를 주면서 내가 potential을 터뜨리기를 기다리고 있는 회사다. 그것도 내 potential의 bar를 굉장히 높게 책정하면서 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 회사 일에 더 집중하고 싶은 마음이 커졌고, 그 사이에 번아웃도 오면서 조금만 지나면 더 이상 좋아하는 일을 못하게 될 거 같은 마음이 생겨 더더욱 회사에 집중하고 싶어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;농담삼아 하는 이야기지만 강철의 연금술사처럼 &quot;정답이다! 연금술사!&quot; 이런 답변을 스스로에게 들을 수 있을 때까지는 이렇게 살지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 지금까지는 만족스럽게 잘 살고 있다. 끝!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;P.S.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 누가 읽을지는 모르겠지만 아마 활동을 고민하고 있는 친구들이 많이 읽을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리쿠르팅 때도 늘 했던 이야기지만, 메이커스 활동을 고민하고 있다면 면접관들에게 그 고민을 맡겼으면 좋겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당락에 대한 부분은 면접관이 결정할 부분이기 때문에 지원자가 고민한다고 될 일이 아니다. 고민하지 말고 지원했으면 좋겠다는 이야기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적어도 1, 2기 때의 정신이 지켜진다면, 메이커스 조직원들은 늘 지원자 친화적인 면접 과정을 만들기 위해 노력하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원자에게 많은 이야기를 듣고 싶으며, 지원자의 실력보다 성장에 대한 열망이 큰 가치로 여겨지며, 지원자가 면접에서 많은 것을 얻어갈 수 있도록 하는 것에 목적을 둔 프로세스를 만들기 위해 노력했으며, 또한 할 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접의 당락과 상관없이 좋은 면접 경험을 만들기 위해 노력하고 있기 때문에 고민은 한 편으로 접어두고 지원해보는 것이 좋지 않을까 생각한다.&lt;/p&gt;</description>
      <category>Log.Develop/Retrospection</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/68</guid>
      <comments>https://hack-jam.tistory.com/68#entry68comment</comments>
      <pubDate>Wed, 15 Nov 2023 21:31:45 +0900</pubDate>
    </item>
    <item>
      <title>2022년 회고</title>
      <link>https://hack-jam.tistory.com/67</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022년 회고를 쓰기에 앞서, 2020년과 2021년 회고를 읽어봤습니다.&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;저의 2022년을 상징하는 키워드라고 한다면 &quot;의외의 기회들&quot;인 것 같습니다.&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;b&gt;의외의 기회 (1)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 생긴 첫 번째 기회는 링크드인을 통해 찾아왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국내에서 유명한 핀테크 회사의 리쿠르터 분이 링크드인을 통해 지원해볼 생각이 있는지 물어봐주신 것이 계기였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시에 진행하고 있던 프로젝트가 계속 Drop될까 말까 하던 상황이어서 회사에 회의감이 들던 찰나였기 때문에,&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;i&gt;&lt;b&gt;그런데... 여기서 아주 탈탈 털렸습니다... &lt;/b&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;당시에 대규모, 대용량 시스템 설계에 대해서 이해도가 아예 없는 상태였고,&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;그걸 제가 한 것처럼 설명했으니.. 당연히 탈탈 털리는 게 정상이었던 거죠.&lt;/p&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;시스템 설계에 대한 이해도가 너무 부족하다. (특히 대규모, 대용량 처리에 관한)&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;지금하고 있는 일 혹은 내 소속의 분위기가 좀 루즈하다고 나 또한 매너리즘에 빠져있으면 안 된다.&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 면접 덕분에 루즈하게 가져가려고 했던 2022년의 계획과 액션들이 완전히 즉각적으로 실행되게 되었습니다.&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;b&gt;Action 1. 일을 줄이자&lt;br /&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쏟는 리소스에 비해서 지지부진했던 일들을 정리했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이드 프로젝트도 그렇고, 스터디도 그렇고 쏟는 리소스에 비해서 결과물이 개인적인 기준에 못 미치는 경우가 좀 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적으로 일을 여기저기 벌려놓았지만 일을 잘 관리하지 못하고 있다는 생각이 들었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 벌려놓은 일들이 2개라면 각각 50%씩 쏟거나 최대 60%까지 쏟을 수 있는데 4개, 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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Action 2. 데중어설 스터디&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 적극적으로 드라이브하지는 않던 스터디였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요성을 느끼고 있기는 했지만 마음속으로는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;뭐, 그래도 한 두 번은 읽으려고 시도했었으니깐. 생각보다 어렵진 않았던 거 같은데.&quot;라는 안일한 생각이 있었던 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 위에서 말한 것처럼 탈탈 털리게 되고, 스터디를 하자고 제안했던 친구가 강하게 드라이브를 걸면서 적극적으로 하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Action 1에서 설명했듯 일을 정리하게 되니 자연스럽게 스터디에 쏟을 수 있는 시간이 많아졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 과정에서 책에서 설명하는 레퍼런스 논문이나 흥미가 있던 글들을 찾아볼 수 있게 되었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연스럽게 이해도도 엄청나게 깊어지는 효과를 가져왔습니다.&lt;/p&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;이 책을 정리할 때 보통 8시간 정도 걸릴 정도로 꽤 열심히 정리하고 이해하면서 읽으려고 노력했던 거 같습니다.&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://bluayer.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bluayer.com/56&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671895470238&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;Chapter 1. Reliability, Scalability, Maintainability&quot; data-og-description=&quot;소개 본 글은 데이터 중심 어플리케이션(마틴 클레프만)으로 스터디하며 해당 책의 내용을 요약 정리한 내용입니다. https://github.com/ddia-study/ddia-study GitHub - ddia-study/ddia-study: 데이터 중심 어플리&quot; data-og-host=&quot;bluayer.com&quot; data-og-source-url=&quot;https://bluayer.com/56&quot; data-og-url=&quot;https://bluayer.com/56&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7cVRr/hyQZHoG8Eg/oXSCEM1LlGBs0MkMTZvIKk/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023,https://scrap.kakaocdn.net/dn/Bic87/hyQ1jGuvgn/c6GSgIEgk6XSe9HjsJCwFK/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023,https://scrap.kakaocdn.net/dn/pjipe/hyQ1ptbAax/yVex9T6mBSnGl1OebCc6c0/img.png?width=1480&amp;amp;height=800&amp;amp;face=0_0_1480_800&quot;&gt;&lt;a href=&quot;https://bluayer.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://bluayer.com/56&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7cVRr/hyQZHoG8Eg/oXSCEM1LlGBs0MkMTZvIKk/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023,https://scrap.kakaocdn.net/dn/Bic87/hyQ1jGuvgn/c6GSgIEgk6XSe9HjsJCwFK/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023,https://scrap.kakaocdn.net/dn/pjipe/hyQ1ptbAax/yVex9T6mBSnGl1OebCc6c0/img.png?width=1480&amp;amp;height=800&amp;amp;face=0_0_1480_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Chapter 1. Reliability, Scalability, Maintainability&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 본 글은 데이터 중심 어플리케이션(마틴 클레프만)으로 스터디하며 해당 책의 내용을 요약 정리한 내용입니다. https://github.com/ddia-study/ddia-study GitHub - ddia-study/ddia-study: 데이터 중심 어플리&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;bluayer.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(제 블로그에도 글이 올라가있지만, 깃헙 링크를 공유해 봅니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/ddia-study/ddia-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ddia-study/ddia-study&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671891583833&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&quot; data-og-description=&quot;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cL01f7/hyQZRSognX/okU69NLdWNeOC0LUA5GDbk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ddia-study/ddia-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cL01f7/hyQZRSognX/okU69NLdWNeOC0LUA5GDbk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Action 3. 화상 영어&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 외국계 회사를 가보고 싶다는 생각은 늘 가지고 있었는데 이에 대한 액션은 따로 없다는 생각을 해왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표를 재수정하는 과정에서 자연스럽게 영어 능력에 대한 걱정이 생기게 되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아는 형이 추천해준 화상영어 사이트에서 화상영어를 시작하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 말하자면, 일주일에 40분씩 영어로 말하는 것이 어려운 게 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;40분 동안 제 생각을 말하는 것이 더 어려웠던 것 같습니다.&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;한 번 굴러가기 시작하니깐 눈송이가 눈덩이가 되고, Avalanche가 되어 굴러갈 수 있다는 확신이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데중어설 스터디가 끝나고 나서도 조급해하지 않고 제 부족한 지식을 채울 수 있는 책들을 많이 읽어나가고 있었는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 날 우연찮게 흥미로운 기회를 보게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의외의 기회 (2)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-24 오후 11.29.51.png&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9FB4o/btrUt2YaGJq/XlKUEG2iqE0vgHbXnlFqLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9FB4o/btrUt2YaGJq/XlKUEG2iqE0vgHbXnlFqLK/img.png&quot; data-alt=&quot;동아리 슬랙에서 보게 된 기회&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9FB4o/btrUt2YaGJq/XlKUEG2iqE0vgHbXnlFqLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9FB4o%2FbtrUt2YaGJq%2FXlKUEG2iqE0vgHbXnlFqLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1146&quot; height=&quot;192&quot; data-filename=&quot;스크린샷 2022-12-24 오후 11.29.51.png&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;192&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;제가 운영진으로 활동하고 있던 AUSG라는 AWS 관련 대학생 동아리에서 아는 형이 이런 글을 올려줬습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2년 경력 이상이라고 적혀있어서 큰 기대를 하지 않고 이력서 리뷰 이벤트를 신청하게 되었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리쿠르터 분께 연락이 왔고 자연스럽게 프로세스를 진행하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 Associate SA 자격증을 따면서&lt;i&gt; &quot;진짜 이런 일을 하는 직무가 있나?&quot;&lt;/i&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;i&gt;&quot;이렇게 좋은 회사에서 날 굳이...?&quot;&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;그런데 Phone Screening을 통과하고 WBS(White Boarding Session)을 통과하면서 생각이 좀 달라졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 WBS를 진행하면서, 배우고 공부하고 싶은 내용들이 많아졌고 스스로도 Deep Dive 해서 공부해볼 수 있는 경험이었기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;놓치지 않고 싶은 정말 좋은 기회라는 생각을 하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 LP를 보면서는 전문 지식에 더해 커뮤니케이션 스킬도 뛰어난, 이런 사람들과 함께 일해보고 싶다는 생각도 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;(사실 거의 2~3개월에 가까운 프로세스여서 죽어나가고 있었지만..)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로는 이 회사에 합격하게 되어서 정말 행복합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 예상했던 것처럼 끝내주게 멋진 동료들과 좋은 문화까지 매일 감탄하고 많이 배우고 있습니다.&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;이제부터는&lt;/b&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;첫 Public Speaking&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 동아리의 내부 발표 행사나 작은 발표들은 늘 거절하지 않고 진행하고 있었는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표에 대한 감을 잃지 않으려고 노력하는 점도 있었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람들에게 지식 전파를 하는 과정에서 스스로 얻는 게 많아서 지속적으로 해오고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 중,&lt;b&gt; AWS Community Day&lt;/b&gt; 행사에서 발표할 수 있는 기회를 동아리를 통해 얻게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(방금 전에 등장했던 AUSG, 그 동아리가 맞습니다  )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표자로 신청을 하기 전에 여러 고민을 했는데요,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;잘못된 지식 전파에 대한 걱정&lt;/li&gt;
&lt;li&gt;생각보다 꽤 큰 행사 규모라 달달 떨 거 같은 느낌&lt;/li&gt;
&lt;li&gt;유튜브에 평생 남을 흑역사.. &lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만... 아는 형의 한 마디가 결국 신청을 하게 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;AWS 들어가면 외부 행사 Public Speaking에 제한이 있을 텐데, 지금 밖에 없어!!&quot;&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;(진짜 달달 떨면서 발표한 게 느껴져서.. 셀프 피드백은 해야 하지만 다시 볼 자신이 없네요 흑흑)&lt;/p&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;a href=&quot;https://youtu.be/H7W_AI5heSo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/H7W_AI5heSo&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=H7W_AI5heSo&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/dkNMLD/hyQ1n3bkt9/KoZuGojSE1qI64HEAyu390/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&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;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/H7W_AI5heSo&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 Athena에 관심이 있어서 써 봐야겠다는 생각 정도는 있었는데, 데모를 준비하며 써 보니 꽤 유용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 발표를 기회로 Athena와 내부 엔진인 Presto에 큰 관심을 가지게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기회가 있으면 Presto에도 contribution을 해보고 싶네요 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;(그리고 Public Speaking은.. 늘 한 번 더 고려해보고 하는 걸로...)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;장기 여행&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산업기능요원 복무가 끝나는 날짜와 이직한 회사로 입사하는 날짜 사이에 텀이 존재했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 이 기간에는 미뤄두고 미뤄뒀던 여행을 가게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휴가도 꽤 많이 남았던 터라 남은 휴가도 다 털고 여행을 가게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 병무청에 신고해야 하는 일도 있었는데, 이전 회사 분들이 되게 잘 도와주신 덕에 잘 신청할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-24-23-57-25.jpeg&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MT524/btrUyg8pFXc/SlnoLpu1r8dHveMV7aUI7k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MT524/btrUyg8pFXc/SlnoLpu1r8dHveMV7aUI7k/img.jpg&quot; data-alt=&quot;군인은 국외 여행 허가도 받아야 해요...흑&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MT524/btrUyg8pFXc/SlnoLpu1r8dHveMV7aUI7k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMT524%2FbtrUyg8pFXc%2FSlnoLpu1r8dHveMV7aUI7k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;310&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-24-23-57-25.jpeg&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;659&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;s&gt;솔직히 혼자 가서 너무 재밌었...크흠&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 10개 넘는 미술관을 가서 조용히 시간도 보내기도 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최애 영화인 비포 시리즈의 장소들을 찾아가기도 하고,&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;s&gt;(이라 쓰고 자랑이라 읽는)&lt;/s&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/92nAP/btrUBa0WJv3/barqPiny8DdKzKmEszLMXk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/92nAP/btrUBa0WJv3/barqPiny8DdKzKmEszLMXk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-36 002.jpeg&quot; width=&quot;317&quot; height=&quot;423&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/92nAP/btrUBa0WJv3/barqPiny8DdKzKmEszLMXk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F92nAP%2FbtrUBa0WJv3%2FbarqPiny8DdKzKmEszLMXk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uymkD/btrUwnAb2m2/4SkgW670D0YXxHxM0YVFL1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uymkD/btrUwnAb2m2/4SkgW670D0YXxHxM0YVFL1/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-36 001.jpeg&quot; width=&quot;298&quot; height=&quot;397&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uymkD/btrUwnAb2m2/4SkgW670D0YXxHxM0YVFL1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuymkD%2FbtrUwnAb2m2%2F4SkgW670D0YXxHxM0YVFL1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;피렌체와 15만원짜리 기차표를 끊고 당일치기 갔던 베네치아&lt;/figcaption&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/D9Z9N/btrUwrJgft1/yjJ7yHY9tgzxWM2kQIPQN0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D9Z9N/btrUwrJgft1/yjJ7yHY9tgzxWM2kQIPQN0/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-36 003.jpeg&quot; width=&quot;290&quot; height=&quot;515&quot; style=&quot;width: 26.6624%; margin-right: 10px;&quot; data-widthpercent=&quot;27.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D9Z9N/btrUwrJgft1/yjJ7yHY9tgzxWM2kQIPQN0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD9Z9N%2FbtrUwrJgft1%2FyjJ7yHY9tgzxWM2kQIPQN0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;811&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvP8oH/btrUwpdJaEI/cWhsKL8NoOWYtZqK3KZGy1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvP8oH/btrUwpdJaEI/cWhsKL8NoOWYtZqK3KZGy1/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-36 004.jpeg&quot; width=&quot;305&quot; height=&quot;407&quot; style=&quot;width: 35.506%; margin-right: 10px;&quot; data-widthpercent=&quot;36.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvP8oH/btrUwpdJaEI/cWhsKL8NoOWYtZqK3KZGy1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvP8oH%2FbtrUwpdJaEI%2FcWhsKL8NoOWYtZqK3KZGy1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TAZXs/btrUwrWLJbM/tiaDuIM2PspR0KtxKwEDzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TAZXs/btrUwrWLJbM/tiaDuIM2PspR0KtxKwEDzk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-37 005.jpeg&quot; width=&quot;193&quot; height=&quot;257&quot; style=&quot;width: 35.506%;&quot; data-widthpercent=&quot;36.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TAZXs/btrUwrWLJbM/tiaDuIM2PspR0KtxKwEDzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTAZXs%2FbtrUwrWLJbM%2FtiaDuIM2PspR0KtxKwEDzk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;미슐랭 1 star, 비포 선셋의 산책로, 사진 찍어줄 사람이 없어서 셀카 밖에 못 찍었던 나...&lt;/figcaption&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/4pnRK/btrUwsVGYRL/KB1MxatkLr7tDIyZYvfEC0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4pnRK/btrUwsVGYRL/KB1MxatkLr7tDIyZYvfEC0/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-37 006.jpeg&quot; width=&quot;278&quot; height=&quot;371&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/4pnRK/btrUwsVGYRL/KB1MxatkLr7tDIyZYvfEC0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4pnRK%2FbtrUwsVGYRL%2FKB1MxatkLr7tDIyZYvfEC0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pQklp/btrUuYAWObk/wT83OkpCafF3FOHhNpv3FK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pQklp/btrUuYAWObk/wT83OkpCafF3FOHhNpv3FK/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-filename=&quot;KakaoTalk_Photo_2022-12-25-00-03-37 007.jpeg&quot; width=&quot;226&quot; height=&quot;301&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pQklp/btrUuYAWObk/wT83OkpCafF3FOHhNpv3FK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpQklp%2FbtrUuYAWObk%2FwT83OkpCafF3FOHhNpv3FK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;40만원짜리 기차타고 당일치기 갔던 런던, 마지막 날 숙소였던 네덜란드 잔담&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2020년 회고를 보니, 남은 2년 동안 산업기능요원을 조용히 잘 보내고 싶다는 이야기를 썼었더군요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;솔직히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;2년동안 좌충우돌하며 조용히 보내지는 못했던 거 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주변 사람들은 제 앞날이 밝다고 말해줘도, 스스로 확신이 없어 고민 속에 멍하니 밤을 새기도 했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매해 빠짐없이 잘하고 싶다는 욕심과 이 정도면 적당히 해도 되지 않을까라는 생각이 치열하게 싸웁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고, 주변에서 끊임없이 응원해주고 아껴줘서 잘해올 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 모든 어려움을 잘 이겨낼 수 있었던 이유는 언제나 주변 사람들에게 있지 않나 싶습니다. 감사합니다&amp;hearts;️&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022년에는 우연히 찾아온 기회를 잘 잡아서 회고를 쓰는 오늘 행복할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년에도 안주하지 않고 더 많이 듣고 배울 수 있었으면 좋겠습니다. 회고 끝!&lt;/p&gt;</description>
      <category>Log.Develop/Retrospection</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/67</guid>
      <comments>https://hack-jam.tistory.com/67#entry67comment</comments>
      <pubDate>Sun, 25 Dec 2022 00:18:21 +0900</pubDate>
    </item>
    <item>
      <title>Notion에서 Postgres를 샤딩하면서 얻은 교훈 (번역)</title>
      <link>https://hack-jam.tistory.com/66</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;역자 서론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글은 노션 블로그에 작성되어 있는&amp;nbsp;&lt;span style=&quot;background-color: #fffefc; color: #111111;&quot;&gt;Garrett Fidalgo의&lt;/span&gt;&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://www.notion.so/ko-kr/blog/sharding-postgres-at-notion&quot;&gt;&lt;i&gt;코끼리 방목 : Notion에서 Postgres를 샤딩하면서 얻은 교훈&lt;/i&gt;&lt;/a&gt;&lt;/b&gt;&amp;nbsp; (&quot;코끼리&quot;는 PostgreSQL의 마스코트라, 코끼리 방목이라는 표현을 사용한 것 같습니다)을 읽고 번역한 글입니다. 참고로 Notion 팀에 허락을 받고 번역한 글이 아니며, 따라서 해당 글은 언제든지 내려갈 수 있습니다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 초에 우리는 예정된 유지 관리를 위해 5분동안 Notion을 중단했습니다. 우리는 &quot;향상된 안정성과 성능&quot;을 암시했고, 이를 위해서 몇달동안 매우 긴박하고 집중적으로 팀 규모의 작업을 했습니다. 바로, Notion의 PostgreSQL 모놀리스(monolith)를 수평 분할된 데이터 플릿으로 샤딩하는 것이었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는&amp;nbsp;이런&amp;nbsp;전환을&amp;nbsp;진행하는&amp;nbsp;동안,&amp;nbsp;사소한&amp;nbsp;영향들에&amp;nbsp;관해&amp;nbsp;조용히&amp;nbsp;했습니다만,&amp;nbsp;기쁘게도&amp;nbsp;사용자들은&amp;nbsp;이런&amp;nbsp;개선을&amp;nbsp;빠르게&amp;nbsp;알아차렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;@notionhq가 최근에 얼마나 빨라졌는지 놀랍습니다. &quot;말하지 않고 보여주기&quot;는 강력합니다.&lt;br /&gt;- Guillermo Rauch&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;하지만 단일 유지 관리 기간이 전체 스토리를 말해주지는 않습니다. 우리 팀은 향후 몇 년동안의 Notion을 더 빠르고 안정적으로 만들기 위해 해당 마이그레이션을 설계하는데 몇 달을 보냈습니다. 우리가 어떻게 샤딩을 했고, 우리가 무엇을 배웠는지 알려주겠습니다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;샤딩하기로 결정했을 때&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩은 애플리케이션의 성능을 개선하기 위한 우리의 목표들 중 중요한 마일스톤이었습니다. 지난 몇 년간, 더 많은 사람들이 삶의 일부분에서 노션을 사용하는 것을 보며 뿌듯했습니다. 그리고 이는 당연히 회사들의 모든 위키들, 프로젝트 추적기, Pok&amp;eacute;dexes&lt;i&gt;(&lt;b&gt;역&lt;/b&gt;: 포켓몬 백과사전)&lt;/i&gt;와 같은 저장해야 할 수십 억 개의 새로운 블록, 파일, 공간들을 의미했습니다. 2020년 중반까지, 우리 서비스가 5년의 시간 동안 4배의 성장을 해온 것을 보니, 우리가 지원할 수 있는 Postgres 모놀리스의 능력을 곧 넘을 것은 분명했습니다. on-call 상태의 엔지니어는 DB CPU가 치솟아&amp;nbsp;잠에서 깨는 경우가 종종 있었고 간단한 catalog-only 마이그레이션들은 안전하지 않고 불확실해졌습니다.&lt;i&gt;&lt;i&gt;(&lt;/i&gt;&lt;b&gt;역&lt;/b&gt; : catalog는 Postgresql에서 메타데이터 시스템 DB를 말합니다. 즉 스키마에 컬럼을 추가한다던지 등의 간단한 작업도 실행할 때조차 엔지니어들이 불안해했다는 것으로 받아들이면 될 것 같습니다.)&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;빠르게 성장하는 스타트업은 샤딩과 관련한 trade-off를 섬세하게 헤쳐나가야 합니다. 그동안 여러 블로그 글에서는 유지 관리 부담의 증가 애플리케이션 수준 코드의 새로운 제약 조건, 아키텍처 경로 종속성 등 샤딩의 위험성을 이미 설명해 왔습니다.&lt;i&gt;&lt;b&gt;(1)&lt;/b&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;우리가 샤딩을 결정하게 만든 시점은, Postgres의 &lt;code&gt;VACUUM&lt;/code&gt; 프로세스가 계속 멈춰서 DB가 죽은 튜플들로부터 디스크 공간을 회수하지 못하는 상황에 도달했을 때였습니다. 디스크 용량을 늘릴 수도 있었지만, Postgres가 기존 데이터에 영향이 가지 않도록 모든 쓰기 처리를 중지할 수 있는 안전 메커니즘인 transaction ID(TXID) wraparound에 대한 걱정이 더 컸습니다. TXID wraparound가 프로덕트에 실질적 위협이 될 수 있기에, 우리 인프라 팀은 힘을 내서 일을 시작했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;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;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이를 이해하기 위해서는, Postgres에서 동시성 처리를 어떻게 하는지 알아야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postgres는 동시성을 제어하기 위해 사용하는 방법으로 &lt;b&gt;MVCC(Multi Version Concurrency Control)&lt;/b&gt;를 채택했습니다. 간단히 설명하자면, 데이터를 읽을 때는 특정 버전의 snapshot을 읽고, 데이터를 쓸 때는 버전을 증가시키며 데이터를 생성하고 사용자는 마지막 버전의 데이터를 읽게 됩니다. 참고로 여기서 트랜잭션마다 ID를 주고 실행하게 되는데, 본글에서는 이를 &lt;b&gt;TXID&lt;/b&gt;라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 두 가지 문제가 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;첫 째,&lt;/b&gt; MVCC를 채택한 DB에서는 불필요한 튜플이 디스크에 남게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;둘 째,&lt;/b&gt; Postgres에서 TXID는 32비트이며 약 40억개의 트랜잭션만 지원할 수 있기 때문에, TXID가 최대값에 도달하면 wraparound(overflow 감지 후 처리), 즉 0부터 다시 시작하게 만듭니다. 당연히 wraparound가 일어나게 되면, 과거 트랜잭션들은 아주 미래의 트랜잭션처럼 보이게 됩니다. 이렇게 되면 과거 트랜잭션이 실행되고 있지만 실제로는 반영되지 않는 기이한 현상이 일어나게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지 문제를 해결하기 위해서 &lt;b&gt;&lt;i&gt;주기적으로&lt;/i&gt;&lt;/b&gt; &lt;code&gt;VACUUM&lt;/code&gt; 프로세스(auto_vacuum)를 실행하면 된다고 합니다.&lt;/p&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;code&gt;VACUUM&lt;/code&gt;은 Postgres에서 사용하는 일종의 Disk 관련 GC 프로세스라고 생각하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트로 삭제되거나 더 이상 사용되지 않은 튜플은 테이블에서 물리적으로 바로 제거되지 않고, VACUUM을 통해 처리합니다. 따라서 이를 통해 첫 번째 문제를 해결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 문제는 완벽하게 해결되지 않는데, Postgres는 일반 TXID와 Frozen TXID를 함께 사용합니다. VACUUM 프로세스는 데이터의 버전을 고정시키기 때문에 이 과정에서 Frozen TXID와 함께 해당 row를 고정시키게 됩니다. 그런데 이 Frozen TXID는 모든 Normal TXID보다 과거에 처리된 것이라고 여겨지기 때문에 고정이 되었다면, wrapaorund가 일어나도 문제 없이 반영됩니다. 그러나 두 번째 문제는 이런 방법에도 불구하고 쓰기량이 급증하게 되면 wraparound가 일어나고 나서 데이터가 손실될 수 있습니다.&lt;/p&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;a href=&quot;https://devcenter.heroku.com/articles/postgresql-concurrency&quot;&gt;https://devcenter.heroku.com/articles/postgresql-concurrency&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.sentry.io/2015/07/23/transaction-id-wraparound-in-postgres&quot;&gt;https://blog.sentry.io/2015/07/23/transaction-id-wraparound-in-postgres&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.postgresql.org/docs/9.3/sql-vacuum.html&quot;&gt;https://www.postgresql.org/docs/9.3/sql-vacuum.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND&quot;&gt;https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1&gt;샤딩 스키마 설계&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점진적으로 더 무거운 인스턴스로 DB를 수직 확장하는 대신, 여러 DB에 걸쳐 데이터를 분할하여 수평 확장하는 것이 샤딩의 아이디어입니다. 성장을 위해 추가적인 호스트를 쉽게 가동할 수 있습니다. 하지만 안타깝게도 이제 데이터가 분산되어 있기 때문에 설정을 통해 성능과 일관성(consistency)를 최대화하는 시스템을 설계해야 합니다.&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;Application 레벨의 샤딩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 자체 파티셔닝 체계를 구현하고 애플리케이션 로직에서 쿼리를 라우팅하기로 했습니다. 초기에는 Postgres용 Citus와 MySQL용 Vitess와 같은 샤딩/클러스터링 솔루션도 고려했습니다. 그러나 이런 솔루션들은 단순하고 즉시 사용할 수 있는 cross-shard 도구들을 제공하지만, 실제 클러스터링 원리는 불투명해서 우리는 우리가 직접 데이터 분산을 제어할 수 있는 방법을 더 원했습니다. &lt;i&gt;&lt;b&gt;(2)&lt;/b&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;애플리케이션 레벨의 샤딩을 사용하려면 다음과 같은 설계 결정을 내려야 했습니다.&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&gt;어떤 데이터를 샤딩해야 하나요?&lt;/b&gt;&lt;br /&gt;우리 데이터 셋을 독특하게 만드는 부분 중 하나는 &lt;code&gt;block&lt;/code&gt; 테이블이 여러 요소(크기, 깊이 및 분기)가 있는 다양한 사용자의 생성 콘텐츠 트리를 반영한다는 것입니다. 예를 들어, 한 명의 대기업 고객은 여러 개인 작업 공간을 합친 것보다 평균적으로 더 많은 부하를 만듭니다. 우리는 관련 데이터의 지역성을 유지하면서 필요한 테이블만 샤딩하고 싶었습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터를 어떻게 분할해야 합니까?&lt;/b&gt;&lt;br /&gt;좋은 파티션 키들은 튜플이 샤드에 균일하게 분산되도록 합니다. 분산 조인(distributed join)들은 비싸고 트랜잭션 보장은 일반적으로 단일 호스트로 제한되기 떄문에 파티션 키의 선택은 애플리케이션 구조에 의존하게 됩니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;얼마나 많은 샤드를 생성해야 하고 그 샤드를 어떻게 구성해야 합니까?&lt;/b&gt;&lt;br /&gt;테이블당 논리적 샤드 수, 논리적 샤드와 물리적 호스트 간의 구체적인 매핑을 고려해야 합니다&lt;b&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;⚒ &lt;/b&gt;역자의 설명 &lt;b&gt;⚒&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노션은 문서 작성과 관련하여 여러 단위를 가지고 있습니다. &lt;code&gt;block&lt;/code&gt; , &lt;code&gt;workspace&lt;/code&gt; , &lt;code&gt;comment&lt;/code&gt; 등등 인데, 노션의 비즈니스 레이어에서 도메인적 개념들이라고 생각하시면 편합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.notion.so/blog/data-model-behind-notion&quot;&gt;https://www.notion.so/blog/data-model-behind-notion&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결정 1 : 블록과 관련된 모든 데이터를 함께 샤딩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Notion의 데이터 모델은 데이터베이스의 한 row를 차지하는 블록의 개념이 중심이기 떄문에 &lt;code&gt;block&lt;/code&gt; 테이블은 샤딩의 최우선 순위였습니다. 그러나 블록은 &lt;code&gt;space&lt;/code&gt; (workspaces)나 &lt;code&gt;discussion&lt;/code&gt; (page 수준 및 인라인 토론 스레드들) 같은 다른 테이블을 참조할 수 있습니다. 결과적으로 &lt;code&gt;discussion&lt;/code&gt; 은 &lt;code&gt;comment&lt;/code&gt; 의 테이블을 참조할 수도 있고.. 이런 식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 일종의 FK 관계를 통해 &lt;b&gt;&lt;code&gt;block&lt;/code&gt; 테이블으로부터 도달할 수 있는 모든 테이블&lt;/b&gt;을 샤딩하기로 결정했습니다. 이러한 모든 테이블을 샤딩할 필요는 없지만 관련 블록이 다른 물리적 샤드에 저장되어 있는 동안 레코드가 기본 DB에 저장되어 있으면 다른 데이터 저장소에 쓸 때 불일치가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;블록이 삭제된 경우, 해당 블록과 관련한 comment도 업데이트 되어야 하는데, 각각에 저장소에 요청하다 하나는 성공하고, 하나는 실패하는 경우&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결정 2 : 워크스페이스 ID로 블록 데이터 파티셔닝&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩할 테이블을 결정한 후에는 테이블을 나눠야 했습니다. 좋은 파티션 스키마를 선택하는 것은 데이터의 연결성과 분포에 의해 크게 좌우됩니다. Notion은 팀 기반 제품이기 때문에 다음 결정은 데이터를 워크스페이스 ID로 파티셔닝하는 것이었습니다.&lt;i&gt;&lt;b&gt;(3)&lt;/b&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;각 워크스페이스에는 생성 시 UUID가 할당되므로, 우리는 UUID 공간을 균일한 버켓들로 파티셔닝할 수 있습니다. 샤딩된 테이블의 각 row는 블록이거나 다른 것과 관련이 있는 것이었고 &lt;b&gt;각 블록은 정확히 한 워크스페이스에만 속하기 때문&lt;/b&gt;에 워크스페이스 ID를 파티션 키로 사용했습니다. 사용자는 일반적으로 한 번에 단일 워크스페이스에서 데이터를 쿼리하기 때문에, 우리는 대부분의 cross-shard 조인을 피합니다.&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;결정 3 : 용량 계획&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postgres를 샤딩하기 :&lt;br /&gt;&quot;1M Requests를 하는 1명의 사용자와 1개의 Request를 하는 1M 사용자와 싸우시겠습니까?&amp;rdquo;&lt;/p&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;파티셔닝 스키마를 결정한 우리의 목표는 기존 데이터를 처리하고 적은 노력으로 2년 사용량 예측을 충족할 수 있도록 확장할 수 있는 샤드 설정을 설계하는 것이었습니다. 다음은 몇 가지 제약 사항이었습니다.&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&gt;인스턴스 유형&lt;/b&gt;&lt;br /&gt;IOPS로 수량화된 디스크 처리량은 AWS 인스턴스 유형과 디스크 볼륨 모두에 의해 제한됩니다. 기존 수요를 충족하려면 총 60,000개 이상의 IOPS가 필요했으며 필요한 경우 추가로 확장할 수 있는 용량이 필요했습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;물리적 및 논리적 사드 수&lt;/b&gt;&lt;br /&gt;Postgres의 허밍을 유지하고 RDS 복제 보장을 유지하기 위해 테이블당 500GB, 물리적 DB당 10TB의 상한선을 설정했습니다. 샤드가 DB에 고르게 분할될 수 있도록 많은 논리적 샤드와 물리적 DB를 선택해야 했습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인스턴스 수&lt;/b&gt;&lt;br /&gt;인스턴스가 많을수록 유지 관리 비용이 높아지지만 시스템이 더 강력해집니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비용&lt;/b&gt;&lt;br /&gt;우리는 청구서가 DB 설정에 따라 선형으로 확장되기를 원했고 컴퓨팅 및 디스크 공간을 별도로 확장할 수 있는 유연성을 원했습니다.&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;수치를 계산한 후, 우리는 32개의 물리적 데이터베이스에 고르게 분산된 480개의 논리적 샤드로 이루어진 아키텍처를 결정했습니다. 계층 구조는 다음과 같습니다 :&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;물리적 DB (총 32개)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Postgres 스키마로 표현되는 논리적 샤드(DB당 15개, 총 480개)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;block&lt;/code&gt; 테이블 (논리적 샤드당 1개, 총 480개)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;collection&lt;/code&gt; 테이블 (논리적 샤드당 1개, 총 480개)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;space&lt;/code&gt; 테이블 (논리적 샤드당 1개, 총 480개)&lt;/li&gt;
&lt;li&gt;모든 샤드 테이블을 위한 외의 것들.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;size16&quot;&gt;  &lt;b&gt;왜 480개의 샤드인가?&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;480은 많은 수로 나눌 수 있습니다. 균일한 샤드 분포를 유지하면서 물리적 호스트를 추가하거나 제거할 수 있는 유연성을 제공합니다. 예를 들어, 32개에서 40개로 물리적 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;2의 거듭제곱 수로 설정하는 것이 컴퓨터 과학에서의 전부였는 줄 알았는데, 아니었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #252525;&quot;&gt;Pick values with a lot of factors!&lt;/span&gt;&lt;/b&gt;&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;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;1.webp&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xcqDK/btrFjwYT23G/hERR0mwFolEKojGXHmg6S1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xcqDK/btrFjwYT23G/hERR0mwFolEKojGXHmg6S1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xcqDK/btrFjwYT23G/hERR0mwFolEKojGXHmg6S1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxcqDK%2FbtrFjwYT23G%2FhERR0mwFolEKojGXHmg6S1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;389&quot; data-filename=&quot;1.webp&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1450&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;우리는 15개의 자식 테이블이 있는 DB당 단일 파티션 &lt;code&gt;block&lt;/code&gt; 테이블을 유지관리하는 대신 &lt;code&gt;schema001.block&lt;/code&gt; , &lt;code&gt;schema002.block&lt;/code&gt; 등을 별도의 테이블로 구성하기로 결정했습니다. 기본적으로 분할된 테이블은 또 다른 라우팅 로직을 도입합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Application 코드&lt;/b&gt; : 워크스페이스 ID &amp;rarr; 물리적 DB&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Partition 테이블&lt;/b&gt; : 워크스페이스 ID &amp;rarr; 논리적 스키마&lt;/li&gt;
&lt;/ol&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;sharding-illustration-2.webp&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWnLX/btrFe3RFdNj/D2oLiIl22vnPbP2iOfJt6k/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWnLX/btrFe3RFdNj/D2oLiIl22vnPbP2iOfJt6k/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWnLX/btrFe3RFdNj/D2oLiIl22vnPbP2iOfJt6k/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWnLX%2FbtrFe3RFdNj%2FD2oLiIl22vnPbP2iOfJt6k%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;315&quot; data-filename=&quot;sharding-illustration-2.webp&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1200&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;우리는 워크스페이스 ID에서 논리적 샤드로 라우팅하기 위한 single source of truth(SSOT)를 원했기 때문에 테이블을 별도로 구성하고 애플리케이션에서 모든 라우팅을 수행하기로 결정했습니다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;샤드로 마이그레이션&lt;/h1&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;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Double-write(이중 쓰기)&lt;/b&gt;&lt;br /&gt;들어오는 쓰기가 이전 DB와 새 DB 모두에 적용됩니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Backfill&lt;/b&gt;&lt;br /&gt;Double-write가 시작되면 이전 데이터를 새 DB로 마이그레이션 합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Verification&lt;/b&gt;&lt;br /&gt;새 DB의 데이터 무결성을 확인합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Switch-over&lt;/b&gt;&lt;br /&gt;실제로 새 DB로 전환합니다. 이것은 점진적으로 수행될 수 있습니다. e.g. double-read를 한 다음 전체 읽기를 마이그레이션하기&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;감사 로그(audit log)로 이중 쓰기(double-write)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 쓰기 단계는 새 DB가 아직 사용되지 않더라도 새 데이터가 이전 DB와 새 DB를 모두 채우도록 합니다. 이중 쓰기에는 몇 가지 옵션이 있습니다.&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&gt;두 DB 모두에 직접 쓰기&lt;/b&gt;&lt;br /&gt;보기에는 간단해 보이지만 어느 쓰기에든 문제가 있으면 DB 간에 불일치가 빠르게 발생할 수 있으므로, 이 접근 방식은 ciritical-path 프로덕션 DB에 사용하기 너무 취약합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;논리적 복제&lt;/b&gt;&lt;br /&gt;publish/subscribe 모델을 사용하여 여러 DB에 명령을 브로드캐스트하는 내장 Postgres 기능입니다. 원천(source) DB와 타겟(target) DB 간의 데이터 수정 기능이 제한적입니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;감사 로그(audit log)와 catch-up 스크립트&lt;/b&gt;&lt;br /&gt;마이그레이션 중인 테이블에 대한 모든 쓰기를 추적하기 위해 감사 로그 테이블을 생성합니다. catch-up 프로세스는 감사 로그를 통해 반복하고 각 업데이트를 새 DB들에 적용해서 필요에 따라 수정합니다.&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;a href=&quot;https://www.postgresql.org/docs/10/logical-replication-architecture.html#LOGICAL-REPLICATION-SNAPSHOT&quot;&gt;초기 스냅샷&lt;/a&gt; 단계에서 &lt;code&gt;block&lt;/code&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;오래된 데이터 backfill&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들어오는 쓰기가 새 DB로 성공적으로 전파되면 기존 데이터를 모두 마이그레이션하기 위해 backfill 프로세스를 시작했습니다. 프로비저닝한 &lt;code&gt;m5.24xlarge&lt;/code&gt; 인스턴스에 96개의 CPU로, 우리의 최종 스크립트는 프로덕션 환경을 backfill하는데 3일 정도 걸렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만한 가치가 있는 모든 backfill은 오래된 데이터를 쓰기 전에 &lt;b&gt;레코드 버전들을 비교&lt;/b&gt;하고 최신 업데이트가 있는 레코드를 건너 뛰어야 합니다. 어떤 순서로든 캐치업 스크립트와 backfill을 실행하면 새 DB가 결국 모놀리스를 복제하도록 수렴됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚒ 역자의 설명&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;⚒&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Backfill 이란 누락된 과거의 데이터를 채워넣어 데이터의 공백이 없이 채워지게 하는 것을 뜻합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;DB를 마이그레이션 하는 과정이기 때문에, double write를 하는 최신 데이터를 제외하고 과거의 데이터를 채워넣어야 한다는 맥락에서 backfill이라는 단어를 사용한 것으로 생각됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&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;b&gt;정확성을 검증&lt;/b&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&gt;검증 스크립트&lt;/b&gt; : 우리의 스크립트는 모놀리스의 각 레코드를 샤딩된 레코드와 비교하여 주어진 값에서 시작되는 UUID 공간의 연속 범위를 검증했습니다. 전체 테이블 스캔은 엄청나게 비용이 많이 들기 때문에 무작위로 UUID를 샘플링하고 인접 범위를 확인했습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;⚒ 역자의 설명 ⚒&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;직역하니깐 정말 하나도 이해가 되지 않습니다.   &lt;br /&gt;&lt;br /&gt;간단히 얘기해서 전체 테이블 스캔(Full Scan)이 비싸기 때문에 임의의 값을 선정(샘플링)하고, 그 값의 주변 값들(인접 범위)에 대해서 검증하는 방식이라는 이야기입니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;Dark&amp;rdquo; 읽기&lt;/b&gt; : 읽기 쿼리를 마이그레이션하기 전에 기존 DB와 새 DB 모두에서 데이터를 가져오는 플래그를 추가했습니다.(이것을 다크 읽기라고 부름) 우리는 이러한 레코드들을 비교하고 샤딩된 사본을 삭제하여 프로세스에서 불일치를 기록했습니다. 다크 읽기를 도입하면서 API 레이턴시가 증가했지만 전환이 원활할 것이라는 확신이 생겼습니다.&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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;배운 어려운 교훈들&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩 프로젝트의 많은 부분들이 Notion 엔지니어 팀을 최고로 사로잡았지만, 우리가 뒤늦게 재검토해야 할 결정이 많이 있었습니다. 다음은 몇 가지 예시입니다 :&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&gt;더 일찍 샤드하세요&lt;/b&gt; : 소규모 팀일 때 우리는 조기 최적화와 관련한 tradeoff들을 잘 알고 있었습니다. 하지만 우리는 기존 DB에 부담이 가중될 때까지 기다렸고, 더 많은 부하를 추가하지 않도록 마이그레이션을 매우 절약하며 해야 했습니다. 이 제한으로 인해 논리적 복제를 사용하여 이중 쓰기를 할 수 없었습니다. 워크스페이스 ID(파티션 키)는 아직 이전 DB에 채워지지 않았으며 &lt;b&gt;해당 컬럼을 backfill했으면 우리 모놀리스의 부하가 악화&lt;/b&gt;되었을 것입니다. 대신 우리는 샤드에 쓸 때 각 행을 즉석에서 다시 채웠으므로 사용자 정의 catch-up 스크립트가 필요했습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다운타임 없는 마이그레이션을 목표로 하세요.&lt;/b&gt; 이중 쓰기 처리량은 최종 전환에서 주요 병목 현상이었습니다. 일단 서버를 중단한 후에는 catch-up 스크립트가 쓰기를 샤드에 전파하는 것을 마쳐야 했습니다. 전환하는 동안 샤드를 따라잡는 데 30초 미만을 소비하도록 스크립트 최적화에 일주일을 더 썼다면, 가동 중지 시간 없이 LB 수준에서 hot-swap이 가능했을 수도 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;별도의 파티션 키 대신 결합 기본 키(combied primary key)를 도입하세요.&lt;/b&gt; 오늘 날, 샤딩된 테이블의 행은 복합 키를 사용합니다. 이전 DB의 PK인 &lt;code&gt;id&lt;/code&gt; 와 현재의 파티션 키인 &lt;code&gt;space_id&lt;/code&gt; 말이죠. 어쨌든 전체 테이블 스캔을 수행해야 했기 때문에 두 키를 하나의 새 컬럼으로 결합하여 애플리케이션 전체에 &lt;code&gt;space_ids&lt;/code&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;이러한 가정에도 불구하고 샤딩은 엄청난 성공을 거두었습니다. Notion 사용자의 경우 몇 분의 가동 중지 시간으로 제품이 눈에 띄게 빨라졌습니다. 내부적으로, 주어진 우리는 시간에 민감한 목표 내에서 협력하는 팀워크와 결단력 있는 실행을 증명할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;각주&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1)&lt;/b&gt; 불필요한 복잡성을 도입하는 것 외에도 미리 샤딩하는 것에 대한 과소 평가된 위험은 비즈니스 측면에서 잘 정의되기 전의 프로덕트 모델을 제한할 수 있다는 점입니다. 예를 들어, 개발팀이 사용자 별로 샤딩한 후, 팀 중심의 프로덕트 전략으로 전환하게 된다면 아키텍처 임피던스 불일치로 인해 상당한 기술적 문제가 발생하고 특정 피쳐들이 제한될 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚒ 역자의 설명&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;⚒&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;임피던스 불일치(Impedance Mismatch)&lt;/b&gt;는 백엔드 개발자라면 보통 &lt;i&gt;객체-관계 임피던스 불일치&lt;/i&gt;(DB 스키마와 실제 애플리케이션의 객체 간 불일치를 뜻한다)로 많이 들어봤을 것입니다. 일반적으로 내가 현재 가지고 있는 것과 원하는 것이 다르다는 의미로 임피던스 불일치라는 용어를 사용합니다. 본 글에서는 사용자 별로 샤딩해서 데이터를 분리해놨는데(내가 가지고 있는 데이터 구조), 팀 중심의 프로덕트로 변경하게 되면 팀 별로 샤딩되어 있길 원할 것이라는(내가 원하는 것) 의미로 사용되었습니다. 결론적으로, 가지고 있는 것과 원하는 것 사이의 스키마가 달라져서 생기는 불일치라고 생각하면 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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; 패키지 솔루션 이외에도 DynamoDB와 같은 다른 DB 시스템으로 전환(우리의 use case에서는 너무 위험해서 불가), 디스크 처리량 향상을 위해 베어메탈 NVMe 대용량 인스턴스에서 Postgres를 실행하는(백업 및 복제 유지 관리 비용 때문에 제외) 등 여러 대안을 고려했습니다.&lt;/p&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; 일부 속성을 기반으로 데이터를 나누는 key-based 파티셔닝 외에도 서비스에 의한 &lt;i&gt;수직 파티셔닝&lt;/i&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;&lt;b&gt;  역자의 말&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 글을 소개해주고, 번역에 대한 피드백을 부탁했던&lt;b&gt; lmu&lt;/b&gt; 덕에 좀 더 읽기 쉬운 글이 되었습니다. 감사합니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Log.Develop/Architecture&amp;amp;Design</category>
      <category>Lessons learned from sharding Postgres at Notion</category>
      <category>PostgreSQL</category>
      <category>postgresql 샤딩</category>
      <category>sharding postgres</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/66</guid>
      <comments>https://hack-jam.tistory.com/66#entry66comment</comments>
      <pubDate>Mon, 20 Jun 2022 19:00:01 +0900</pubDate>
    </item>
    <item>
      <title>Google True Time(구글 트루 타임)</title>
      <link>https://hack-jam.tistory.com/65</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 중심 어플리케이션 책을 읽으면서 스터디 하던 중, Google True Time에 관한 이야기가 나왔다.&lt;br&gt;해당 내용이 더 궁금해서 찾아본 내용을 정리했다.&lt;br&gt; &lt;br&gt;&lt;a href=&quot;https://bluayer.com/60&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://bluayer.com/60&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;Chapter 8. 분산 시스템의 골칫거리 - Part 1&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;소개 본 글은 데이터 중심 어플리케이션(마틴 클레프만)으로 스터디하며 해당 책의 내용을 요약 정리한 내용입니다. https://github.com/ddia-study/ddia-study GitHub - ddia-study/ddia-study: 데이터 중심 어플..&quot; data-og-host=&quot;bluayer.com&quot; data-og-source-url=&quot;https://bluayer.com/60&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b1jfFB/hyOIfmtrjw/jYCKkMkWighUjv76l9ZTAK/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023,https://scrap.kakaocdn.net/dn/hAWCQ/hyOIe2bhZg/NnfX7U5AMfKWKvbfErRayK/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023&quot; data-og-url=&quot;https://bluayer.com/60&quot;&gt;
 &lt;a href=&quot;https://bluayer.com/60&quot; target=&quot;_blank&quot; data-source-url=&quot;https://bluayer.com/60&quot;&gt;
  &lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b1jfFB/hyOIfmtrjw/jYCKkMkWighUjv76l9ZTAK/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023,https://scrap.kakaocdn.net/dn/hAWCQ/hyOIe2bhZg/NnfX7U5AMfKWKvbfErRayK/img.jpg?width=800&amp;amp;height=1023&amp;amp;face=0_0_800_1023')&quot;&gt; 
  &lt;/div&gt;
  &lt;div class=&quot;og-text&quot;&gt;
   &lt;p class=&quot;og-title&quot;&gt;Chapter 8. 분산 시스템의 골칫거리 - Part 1&lt;/p&gt;
   &lt;p class=&quot;og-desc&quot;&gt;소개 본 글은 데이터 중심 어플리케이션(마틴 클레프만)으로 스터디하며 해당 책의 내용을 요약 정리한 내용입니다. https://github.com/ddia-study/ddia-study GitHub - ddia-study/ddia-study: 데이터 중심 어플..&lt;/p&gt;
   &lt;p class=&quot;og-host&quot;&gt;bluayer.com&lt;/p&gt;
  &lt;/div&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; &lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Google True Time API란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 시스템 내에서 시계는 물리적이든, 논리적이든 잘못될 가능성이 매우 높다.&lt;br&gt; &lt;br&gt;&lt;i&gt;&lt;b&gt;시계 읽기를 어떤 시점으로 생각하는 것은 타당하지 않기 때문에 어떤 신뢰 구간에 속하는 시간의 범위로 읽는 게 나을 것이다.&lt;/b&gt;&lt;/i&gt;&lt;br&gt;라는 것이 True Time의 기본적인 아이디어다.&lt;br&gt;따라서 True TIme은 해당 시계의 신뢰구간을 제시하는 방식으로 설계되어 있다.&lt;br&gt; &lt;br&gt;참고로 True Time은 Google Spanner 내부에서 사용되고 있다고 한다.&lt;br&gt;&lt;a href=&quot;https://cloud.google.com/spanner&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://cloud.google.com/spanner&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;Cloud Spanner &amp;nbsp;|&amp;nbsp; Google Cloud&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;무제한 확장, 강력한 일관성, 최대 99.999%의 가용성을 갖춘 완전 관리형 관계형 데이터베이스입니다.&quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/spanner&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhVnk1/hyOH88L2Xq/SDuKVWkWVnanRyhA01Gtq0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/D4zqX/hyOIe2bF5j/rEtLMZ3cbkQ1Wp1HB0SYJk/img.jpg?width=600&amp;amp;height=338&amp;amp;face=363_84_478_210,https://scrap.kakaocdn.net/dn/eVCiJ/hyOImeSmg7/CzfrxRxHgikjeqgGxVB8eK/img.jpg?width=596&amp;amp;height=338&amp;amp;face=436_73_525_170&quot; data-og-url=&quot;https://cloud.google.com/spanner?hl=ko&quot;&gt;
 &lt;a href=&quot;https://cloud.google.com/spanner?hl=ko&quot; target=&quot;_blank&quot; data-source-url=&quot;https://cloud.google.com/spanner&quot;&gt;
  &lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhVnk1/hyOH88L2Xq/SDuKVWkWVnanRyhA01Gtq0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/D4zqX/hyOIe2bF5j/rEtLMZ3cbkQ1Wp1HB0SYJk/img.jpg?width=600&amp;amp;height=338&amp;amp;face=363_84_478_210,https://scrap.kakaocdn.net/dn/eVCiJ/hyOImeSmg7/CzfrxRxHgikjeqgGxVB8eK/img.jpg?width=596&amp;amp;height=338&amp;amp;face=436_73_525_170')&quot;&gt; 
  &lt;/div&gt;
  &lt;div class=&quot;og-text&quot;&gt;
   &lt;p class=&quot;og-title&quot;&gt;Cloud Spanner &amp;nbsp;|&amp;nbsp; Google Cloud&lt;/p&gt;
   &lt;p class=&quot;og-desc&quot;&gt;무제한 확장, 강력한 일관성, 최대 99.999%의 가용성을 갖춘 완전 관리형 관계형 데이터베이스입니다.&lt;/p&gt;
   &lt;p class=&quot;og-host&quot;&gt;cloud.google.com&lt;/p&gt;
  &lt;/div&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Google True Time 는 어떻게 만들어져 있나?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
 &lt;li&gt;TrueTime API는 &lt;b&gt;atomic clock&lt;/b&gt;과 &lt;b&gt;GPS&lt;/b&gt;를 참조&lt;/li&gt;
 &lt;li&gt;GPS 시계도 오류가 날 수 있는 이유가 많다고 함 (안테나/수신기 오류, 로컬 무선 간섭, 스푸핑 등등)&lt;/li&gt;
 &lt;li&gt;Data Center(이하 DC)당 time master 머신 세트, 머신당 time slave 데몬로 구현되어 있음. 마스터에는 GPS 수신기가 있다고 함&lt;/li&gt;
 &lt;li&gt;전용 안테나가 있는 마스터가 따로 있고, 얘는 간섭을 이유로 물리적으로 분리되어 있음. 해당 마스터 이외의 마스터는 atomic clock을 장비하고 있고, 이를 Armageddon masters(아마겟돈 마스터) 라고 함&lt;/li&gt;
 &lt;li&gt;모든 데몬이 여러 마스터로부터 polling 함. 한 마스터의 오류에 대한 취약성을 줄이기 위해서.&lt;/li&gt;
 &lt;li&gt;마스터, 데몬 둘다 로컬 시계가 잘못됐다고 여겨지면 evict(축출) 시키는 로직도 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;True Time에서 적합한 신뢰 구간을 찾기 위해서 사용하는 알고리즘 : Marzullo's algorithm&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt; 
 &lt;p data-ke-size=&quot;size16&quot;&gt;Marzullo's algorithm is efficient in terms of time for producing an optimal value from a set of estimates with&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Confidence_interval&quot;&gt;confidence intervals&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;where the actual value may be outside the confidence interval for some sources. - &lt;a href=&quot;https://en.wikipedia.org/wiki/Marzullo%27s_algorithm&quot;&gt;https://en.wikipedia.org/wiki/Marzullo%27s_algorithm&lt;/a&gt;&lt;/p&gt; 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;br&gt; &lt;br&gt;&lt;i&gt;&lt;b&gt;원본 논문 :&lt;/b&gt;&lt;/i&gt;&lt;br&gt;&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/ko//archive/spanner-osdi2012.pdf&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://static.googleusercontent.com/media/research.google.com/ko//archive/spanner-osdi2012.pdf&lt;/span&gt;&lt;/a&gt;&lt;br&gt;해당 논문의 5~6pg에 있는 내용을 정리한 것.&lt;br&gt; &lt;br&gt; &lt;/p&gt;</description>
      <category>Log.Develop/Other</category>
      <category>google spanner</category>
      <category>google true time</category>
      <category>true time</category>
      <category>구글 스패너</category>
      <category>구글 트루타임</category>
      <category>트루타임</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/65</guid>
      <comments>https://hack-jam.tistory.com/65#entry65comment</comments>
      <pubDate>Fri, 10 Jun 2022 10:53:23 +0900</pubDate>
    </item>
    <item>
      <title>Chapter 7. Transaction(트랜잭션) - Part 1</title>
      <link>https://hack-jam.tistory.com/64</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소개&lt;/b&gt;&lt;/h2&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;a href=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;https://github.com/ddia-study/ddia-study&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654825147793&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&quot; data-og-description=&quot;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ddia-study/ddia-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;트랜잭션은 애플리케이션에서 몇 개의 읽기와 쓰기를 하나의 논리적 단위로 묶는 방법이다. (중략) 트랜잭션은 자연법칙이 아니다. 데이터베이스에 접속하는 애플리케이션에서 프로그래밍 모델을 단순화하려는 목적으로 만든 것이다.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ACID의 의미&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACID 표준을 따르지 않는 시스템을 BASE(Basically Available, Soft state, Eventual consistency)라고 부른다.&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;&lt;b&gt;원자성(Atomicity)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원자성은 동시성과 관련이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원자성 없이는 여러 변경을 적용하는 도중 오류가 발생하면 어떤 변경은 효과가 있고 어떤 것은 그렇지 않은지 알기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;abortability&lt;/b&gt;이 원자성보다 나은 단어같다고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;일관성(Consistency)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터에 관한 어떤 선언(불변식(invariant))이 있다는 것이다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;격리성(Isolation)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 동시에 여러 클라이언트에서 데이터베이스에 접속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 데이터에 접근한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격리성은 동시에 실행되는 서로 격리된다는 것을 의미하고, 트랜잭션은 다른 트랜잭션을 방해할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 실제로는 여러 트랜잭션이 동시에 실행됐떠라도 트랜잭션이 커밋됐을 때의 결과가 트랜잭션이 순차적으로 실행됐을 때의 결과와 동일하도록 보장한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;지속성(Durability)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속성은 트랜잭션이 성공적으로 커밋됐다면 하드웨어 결함이 발생하거나 데이터베이스가 죽더라도 트랜잭션에서 기록한 모든 데이터는 손실되지 않는다는 보장이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속성을 보장하려면 데이터베이스는 트랜잭션이 성공적으로 커밋됐다고 보고하기 전에 쓰기나 복제가 완료될 때까지 기다려야 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;단일 객체 연산과 다중 객체 연산&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다중 객체 트랜잭션은 어떤 읽기 연산과 쓰기 연산이 동일한 트랜잭션 내에 속하는지 알아낼 수단이 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관계형 데이터베이스는 이런 식으로 연산을 묶는 방법이 없는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 어떤 키에 대한 연산은 성공하고 나머지 키에 대한 연산은 실패해서 데이터베이스가 부분적으로 갱신된 상태가 될 수 있다.&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;&lt;b&gt;단일 객체 쓰기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 클라이언트에서 동시에 같은 객체에 쓰려고 할 때 갱신 손실(lost update)을 방지하므로 유용하다.&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;&lt;b&gt;다중 객체 트랜잭션의 필요성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 분산 데이터 스토어는 다중 객체 트랜잭션을 포기했지만, 근본적으로 트랜잭션을 막는 것은 아무것도 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 객체 삽입, 갱신, 삭제만으로 충분한 사용 사례도 있지만, 여러 개의 다른 객체에 실행되는 쓰기 작업이 코디네이션 되어야 하는 상황도 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;오류와 어보트 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션의 핵심 기능은 오류가 생기면 어보트되고 안전하게 재시도할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 모든 시스템이 그렇진 않기 때문에 오류 복구가 애플리케이션에게 책임이 있는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어보트된 트랜잭션을 재시도하는 것은 간단하고 효과적인 오류 처리 메커니즘이지만 완벽하지는 않다.&lt;/p&gt;</description>
      <category>Log.Develop/DDIA</category>
      <category>chapter 7</category>
      <category>data driven intensive application</category>
      <category>ddia</category>
      <category>데이터 중심 애플리케이션 설계</category>
      <category>데중어설</category>
      <category>챕터 7</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/64</guid>
      <comments>https://hack-jam.tistory.com/64#entry64comment</comments>
      <pubDate>Fri, 10 Jun 2022 10:38:59 +0900</pubDate>
    </item>
    <item>
      <title>Chapter 10. Batch Processing(일괄 처리)</title>
      <link>https://hack-jam.tistory.com/63</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소개&lt;/b&gt;&lt;/h2&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;a href=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;https://github.com/ddia-study/ddia-study&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654824746644&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&quot; data-og-description=&quot;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ddia-study/ddia-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h2&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;스트림 처리 시스템 : near-real-time processing / nearline processing&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;b&gt;유닉스 도구로 일괄 처리하기&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;단순 로그 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 많은 데이터 분석이 수 분 내에 awk, sed, grep, sort, uniq, xargs의 조합으로 결과를 얻을 수 있고 놀라울 정도로 잘 수행된다.&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;b&gt;정렬 대 인메모리 집계&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL 해시 테이블을 메모리에 유지&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;중소 규모의 웹사이트 대부분은 고유 URL과 해당 URL 카운트를 대략 1GB 메모리에 담을 수 있다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;유닉스 철학&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;유닉스 파이프&lt;/b&gt; : 다른 방법으로 데이터 처리가 필요할 때 정원 호스와 같이 여러 다른 프로그램을 연결하는 방법이 필요하다. 이것은 I/O 방식이기도 하다.&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;b&gt;동일 인터페이스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 프로그램이 다른 어떤 프로그램과도 연결 가능하려면 프로그램 모두가 같은 입출력 인터페이스를 사용해야 한다는 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유닉스에서 인터페이스는 파일이다. 파일은 단지 순서대로 정렬된 바이트의 연속이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;로직의 연결과 분리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이프는 한 프로세스의 stdout을 다른 프로세스의 stdin과 연결한다. 이때 중간 데이터를 디스크에 쓰지 않고 작은 인메모리 버퍼를 사용해 프로세스 간 데이터를 전송한다.&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;b&gt;투명성과 실험&lt;/b&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;/li&gt;
&lt;li&gt;파이프라인을 중단하고 출력을 파이프를 통해 less로 보내 원하는 형태의 출력이 나오는지 확인 가능&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;유닉스 도구를 사용하는 데 가장 큰 제약은 단일 장비에서만 실행된다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;바로 이 점이 하둡 같은 도구가 필요한 이유다.&lt;/b&gt;&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;b&gt;맵리듀스와 분산 파일 시스템&lt;/b&gt;&lt;/h2&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;HDFS = 비공유 원칙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NAS, SAN에서 사용하는 공유 디스크와는 반대&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NameNode라는 중앙 서버는 특정 파일 블록이 어떤 장비에 저장됐는지 추적한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장비가 죽거나 디스크가 실패하는 경우를 대비하기 위해 파일 블록은 여러 장비에 복제된다. (단순 복제 혹은 삭제 코딩)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAID랑 비슷하지만 파일의 접근과 복제가 특별한 하드웨어 장치 없이 평범한 데이터 센터 네트워크 상에서 이뤄진다는 점이다.&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;&lt;b&gt;맵리듀스 작업 실행하기&lt;/b&gt;&lt;/h3&gt;
&lt;ol 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;b&gt;&lt;i&gt;(Map)&lt;/i&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;키를 기준으로 키-값 쌍을 모두 정렬한다.&lt;/li&gt;
&lt;li&gt;정렬된 키-값 쌍 전체를 대상으로 리듀스 함수를 호출한다. &lt;b&gt;&lt;i&gt;(Reduce)&lt;/i&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2, 4단계는 사용자가 직접 작성해야 한다.&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;Mapper&lt;/b&gt; : 매퍼는 모든 입력 레코드마다 한 번씩만 호출하며, 레코드로부터 키와 값을 추출하는 작업이다. 각 레코드는 독립 처리된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reducer&lt;/b&gt; : 매퍼가 생산한 키-값 쌍을 받아 같은 키를 가진 레코드를 모으고 출력 레코드를 생산한다. 예시로 동일 URL의 출현 횟수가 있다.&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;b&gt;맵리듀스의 분산 실행&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유닉스 명령어 파이프라인과의 가장 큰 차이점은 맵리듀스가 병렬로 수행하는 코드를 직접 작성하지 않고도 여러 장비에서 동시에 처리가 가능하다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 입력으로 HDFS 상의 디렉터리를 사용하는 것이 일반적이고, 입력 디렉터리 내 각 파일 또는 파일 블록을 독립된 맵 태스크에서 처리할 독립 파티션으로 간주한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 가까이서 연산하기&lt;/b&gt; : 각 매퍼 입력 파일의 복제본이 있는 장비에 RAM, CPU가 충분하면 해당 작업을 수행. 네트워크 부하 감소, 지역성 증가의 이점.&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;b&gt;&quot;셔플&quot;&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 셔플 작업은 매퍼에서 하는 건가? 아님 프레임워크?&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;맵리듀스 워크플로&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스 작업 하나로 해결할 수 있는 문제의 범위는 제한적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 맵리듀스 작업을 연결해 workflow로 구성하는 방식은 꽤 일반적이다.&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;(스케줄러 : Oozie, Azkaban, Luigi, &lt;b&gt;Airflow&lt;/b&gt;, Pinball)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(하둡용 고수준 도구 : Pig, &lt;b&gt;Hive&lt;/b&gt;, Cascading, Crunch, FlumeJava)&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;b&gt;리듀스 사이드 조인과 그룹화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 레코드가 다른 레코드와 연관이 있는 것은 일반적 : FK, Document Reference&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;맵리듀스에 파일 집합이 입력으로 주어졌다면, Full table scan 함.&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;b&gt;사용자 활동 이벤트 분석 예제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일괄 처리에서 처리량을 높이기 위해서는 가능한 한 장비 내에서 연산을 수행해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 좋은 방법은 사용자 데이터베이스의 사본을 가져와 사용자 활동 이벤트 로그가 저장된 분산 파일 시스템에 넣는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정렬 병합 조인 (sort-merge join)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스 프레임워크에서 키로 매퍼의 출력을 파티셔닝해 키-값 쌍으로 정렬한다면 같은 사용자의 활동 이벤트와 사용자 레코드는 리듀서의 입력으로 서로 인접해서 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보조 정렬&lt;/b&gt; : 리듀서가 항상 사용자 DB를 먼저 보고 활동 이벤트를 시간 순으로 보게 하는 식으로 맵리듀스에서 작업 레코드를 재배열하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리듀서는 특정 사용자 ID의 모든 레코드를 한 번에 처리하므로 한 번에 사용자 한 명의 레코드만 메모리에 유지하면 되고 네트워크로 아무 요청도 보낼 필요가 없다.&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;b&gt;같은 곳으로 연관된 데이터 가져오기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병합 정렬 조인 중 매퍼와 정렬 프로세스는 특정 사용자 ID로 조인 연산을 할 때 필요한 모든 데이터를 한 곳으로 모은다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 사용자 ID 별로 리듀서를 한 번만 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스는 모든 네트워크 통신을 직접 관리하기 때문에 특정 장비가 죽어도 고민할 필요가 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그룹화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스로 그룹화 연산을 구현하는 가장 간단한 방법은 매퍼가 키-값 쌍을 생성할 떄 그룹화할 대상을 키로 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스 위에서 그룹화와 조인의 구현은 상당히 유사하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;쏠림 다루기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키 하나에 너무 많은 데이터가 연관된다면 &quot;같은 키를 가지는 모든 레코드를 같은 장소로 모으는&quot; 패턴은 제대로 작동하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 레코드를 &lt;b&gt;linchpin object&lt;/b&gt; 또는 &lt;b&gt;hot key&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;핫스팟 완화&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pig : skewed join(핫키 판단을 위해 샘플링하고, 조인 수행 시 임의로 선택한 리듀서로 보냄. 핫 키를 여러 리듀서에 퍼뜨려서 처리하게 하는 방법)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hive : 테이블 메타데이터에 핫 키를 명시적으로 지정하고 관련 레코드를 따로 저장한다. 해당 테이블에서 조인할 때 핫 키를 가지는 레코드는 &lt;b&gt;map-side join&lt;/b&gt;을 사용해 처리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;map-side join&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reduce-side join&lt;/b&gt; : 조인 로직을 리듀서에서 수행. 입력 데이터에 대한 가정이 필요 없고, 리듀서 입력을 병합해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;map-side-join&lt;/b&gt; : 입력 데이터에 대한 특정 가정이 필요. 조인을 더 빠르게 수행&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;브로드캐스트 해시 조인&lt;/b&gt;&lt;/h3&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;작은 입력을 큰 입력의 모든 파티션에 &quot;브로드캐스트&quot;한다.&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;&lt;b&gt;파티션 해시 조인(partitioned hash join/bucketed map join)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조인의 입력을 파티셔닝 한다면 조인을 각 파티션에 독립적으로 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝을 제대로 했다면 조인할 레코드 모두가 같은 번호의 파티션에 위치하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 각 매퍼는 각 입력 데이터셋 중 파티션 한 개만 읽어도 충분하다.&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;&lt;b&gt;맵 사이드 병합 조인&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 데이터셋이 같은 방식으로 파티션이 됐을 뿐 아니라 같은 키를 기준으로 정렬됐다면 변형된 맵사이드 조인을 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리듀서에서 일반적으로 수행하는 것과 동일한 병합 연산을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일괄 처리 워크플로의 출력&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;검색 색인 구축&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 엔진 색인 구축을 위해 구글에서 맵리듀스 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정해진 문서 집합을 대상으로 전문 검색이 필요하다면 일괄 처리가 색인을 구축하는 데 매우 효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매퍼는 필요에 따라 문서 집합을 파티셔닝 하고 각 리듀서가 해당 파티션에 대한 색인을 구축한다.&lt;/p&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;Q. 색인 추출에 가깝게 처리한다는 건가?&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;일괄 처리의 출력으로 키-값을 저장&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분류기 같은 머신러닝 시스템(스팸 필터, 이상 검출, 이미지 인식 등)을 구축하거나 추천 시스템을 구축할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일괄 처리 값을 저장해야 하는데 이를 DB에 태우면 각종 문제가 생길 수 있다. (DB 과부하, 네트워크 요청으로 인한 성능 저하 등등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 내부에 일괄 처리 작업 내부에 데이터베이스 파일을 생성해서 저장한다.&lt;br /&gt;(Voldmort, Terrapin, ElephantDB, HBase Bulk loading)&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;&lt;b&gt;일괄 처리 출력에 관한 철학&lt;/b&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;/li&gt;
&lt;li&gt;minimizing irreversibility&lt;/li&gt;
&lt;li&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;b&gt;하둡 vs 분산 데이터베이스&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MPP(Massively Parallel Processing, 분석 SQL을 병렬 질의에 초점) vs MapReduce &amp;amp; Distributed File System(아무 프로그램이나 실행할 수 있는 운영체제 같은 속성)&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;&lt;b&gt;저장소의 다양성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HDFS는 데이터가 어떤 형태여도 상관없음(Data Lake, Datawarehouse와 연관)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sushi principle&lt;/li&gt;
&lt;li&gt;ETL&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;b&gt;처리 모델의 다양성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머신러닝, 추천 시스템, 전문 검색 색인 등 범용적인 데이터 처리 모델이 필요한 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스를 이용하면 자신이 작성한 코드를 대용량 데이터셋 상에서 쉽게 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;빈번하게 발생하는 결함을 줄이는 설계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵리듀스는 실패를 견딜 수 있고, 개별 태스크 수준에서 작업을 재수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 데이터를 되도록 디스크에 기록하려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일괄 처리 작업은 우선순위가 낮을 수 있는데, 온라인 서비스에서 쓰고 남은 자원을 모아 연산을 수행할 수 있게 되어 있다.&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;b&gt;맵리듀스를 넘어&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일괄 처리 방법의 대안?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;중간 상태 구체화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 한 작업에서 다른 작업으로 데이터를 옮기는 &quot;중간 상태(Intermediate state)&quot;가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간 상태를 파일로 쓰는 과정을 구체화(mateerialization)라고 하는데, 완전히 구체화하는 mapreduce는 단점이 여러 개 있다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터플로 엔진&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;Spark, Flink, Tez&lt;/b&gt;&lt;/i&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;b&gt;데이터 플로 엔진&lt;/b&gt;이라 부른다.&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;li&gt;중간 상태를 잘 활용해서 I/O가 훨씬 적게 듦&lt;/li&gt;
&lt;li&gt;선행 단계 끝나기를 기다릴 필요 없음&lt;/li&gt;
&lt;li&gt;각 태스크마다 JVM 구동 필요 없음&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;i&gt;내결함성&lt;/i&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;주어진 데이터가 어떻게 연산됐는지를 추적. (RDD 추상화, 체크포인트 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 재연산시 다른 결괏값이 나올 수 있어서, 비결정적 원인을 제거해야 함(매번 다른 난수 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Trade-off를 잘 고려하자.&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;&lt;b&gt;그래프와 반복 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프 분석 알고리즘 : PageRank&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;그래프를 맵리듀스 방식으로 처리하려면 계속 반복적으로 따라갈 간선이 없는지 등등 체크해야 함. =&amp;gt; 비효율적&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프리글 처리모델(Pregel, BSP)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BSP(Bulk Synchronous parallel, Pregel 모델) : 일괄 처리 그래프의 최적화 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 정점은 다른 정점으로 &quot;메시지를 보낼&quot; 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 개별 정점에서 함수를 호출해 모든 메시지를 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;내결함성&lt;/i&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;b&gt;&lt;i&gt;병렬 실행&lt;/i&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;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고수준 API와 언어&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도 지원한다 이제! (in 데이터플로 엔진)&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;&lt;b&gt;선언형 질의 언어로 전환&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하이브, 스파크, 플링크는 조인 알고리즘을 알아서 최적화해줌(질의 최적화기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언적인 방법으로 조인을 지정하면, 질의 최적화기가 최적의 수행 방법을 결정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;데이터 플로 엔진(선언형 질의 + 질의 최적화기) = MPP와 비슷하며 성능도 비슷&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다양한 분야를 지원하기 위한 전문화&lt;/b&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;/li&gt;
&lt;li&gt;k-nearest neighbor(공간 알고리즘)&lt;/li&gt;
&lt;li&gt;유전자 분석 알고리즘&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Log.Develop/DDIA</category>
      <category>chapter 10</category>
      <category>data driven intensive application</category>
      <category>ddia</category>
      <category>데이터 중심 애플리케이션 설계</category>
      <category>데중어설</category>
      <category>챕터 10</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/63</guid>
      <comments>https://hack-jam.tistory.com/63#entry63comment</comments>
      <pubDate>Fri, 10 Jun 2022 10:32:07 +0900</pubDate>
    </item>
    <item>
      <title>Chapter 9. 일관성과 합의 - Part 2</title>
      <link>https://hack-jam.tistory.com/62</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소개&lt;/b&gt;&lt;/h2&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;a href=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;https://github.com/ddia-study/ddia-study&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654824760972&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&quot; data-og-description=&quot;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ddia-study/ddia-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;분산 트랜잭션과 합의&lt;/b&gt;&lt;/h2&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리더 선출 : Split brain&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;&lt;b&gt;원자적 커밋과 2PC&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션의 결과는 &lt;b&gt;커밋&lt;/b&gt; 성공이나 &lt;b&gt;어보트&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;단일 노드에서 분산 원자적 커밋으로&lt;/b&gt;&lt;/h3&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;어떤 노드에서는 커밋이 성공하고 다른 노드에서는 실패해서 원자성 보장을 위반하기 쉽다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 노드들은 어보트가 필요하지만, 다른 노드들은 성공적으로 커밋될 수 있다.&lt;/li&gt;
&lt;li&gt;어떤 커밋 요청은 네트워크에서 손실되어 타임아웃 때문에 어보트될 수 있다.&lt;/li&gt;
&lt;li&gt;어떤 노드들은 커밋 레코드가 완전히 쓰이기 전에 죽어서 복구할 때 롤백될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 커밋은 되돌릴 수 없어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보상 트랜잭션(compensating transaction)&lt;/b&gt; : 커밋된 트랜잭션의 효과를 나중에 다른 트랜잭션이 취소하는 것.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2PC&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 노드가 커밋되거나 모든 노드가 어보트되도록 보장하는 알고리즘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션이 커밋할 준비가 되면 coordinator가 1단계를 시작한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션은 분산 트랜잭션을 시작하기 원할 때 coordinator에게 트랜잭션 ID를 요청한다.&lt;/li&gt;
&lt;li&gt;애플리케이션은 각 참여자에서 단일 노드 트랜잭션을 시작하고 단일 노드 트랜잭션에 전역적으로 유일한 트랜잭션 ID를 붙인다.&lt;/li&gt;
&lt;li&gt;각 노드에 준비 요청을 보내서 커밋할 수 있는지 &quot;준비 요청&quot;을 물어본다.
&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;모두 네라고 응답했으면 coordinator는 커밋할지 안 할지 최종적 결정을 한다. 추후 죽는 경우에 어떻게 결정했는지 알 수 있도록 그 결정을 디스크에 있는 트랜잭션 로그에 기록해야 한다. -&amp;gt; &lt;b&gt;커밋 포인트&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;커밋 포인트가 남으면 요청이 실패하거나 타임아웃이 될 때 성공할 때까지 영원히 재시도해야 한다.&lt;/li&gt;
&lt;li&gt;아니요라고 한 노드라도 응답하면 2단계에서 모든 노드에 어보트를 보낸다.&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;&lt;b&gt;coordinator 장애&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;coordinator가 준비 요청을 보내고 나서 &quot;네&quot;에 투표한 다음 장애가 났다면, 참여자는 기다리기만 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태에 있는 참여자의 트랜잭션을 in doubt 혹은 uncertain이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2PC가 완료할 수 있는 유일한 방법은 코디네이터가 복구되기를 기다리는 것뿐이다.&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;&lt;b&gt;3PC&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론상으로는 노드에 장애가 나도 멈추지 않도록 원자적 커밋 프로토콜을 non-blocking하게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기약 없는 네트워크 지연과 프로세스 중단이 있는 대부분 실용적 시스템에서 3PC는 원자성을 보장하지 못한다.&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;&lt;b&gt;현실의 분산 트랜잭션&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 분산 트랜잭션 =&amp;gt; ex. MySQL의 경우, 10배 이상 느림.&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;b&gt;데이터베이스 내부 분산 트랜잭션&lt;/b&gt; : 분산 DB에서 DB 노드 간 트랜잭션 지원 -&amp;gt; 아래의 방법보다 쉽고, 흔히 매우 잘 동작한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Heterogeneous 트랜잭션&lt;/b&gt; : 서로 다른 벤더의 DB일 수도, 메시지 브로커처럼 비데이터베이스 시스템일 수도 있다.&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;b&gt;정확히 한 번 메시지 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Heterogeneous 트랜잭션&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;그러므로 메시지와 그 처리 과정의 side effect를 원자적으로 커밋함으로써 effectively exactly once 처리되도록 보장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 이런 분산 트랜잭션은 트랜잭션의 영향을 받는 모든 시스템이 동일한 원자적 커밋 프로토콜을 사용할 수 있을 때만 가능하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;XA Transaction(eXtended Architecture)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;heterogeneus 기술에 걸친 2단계 커밋을 구현하는 표준.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XA는 네트워크 프로토콜이 아니라, 트랜잭션 코디네이터와 연결되는 인터페이스를 제공하는 API일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드라이버가 XA를 지원한다는 것은 연산이 분산 트랜잭션의 일부가 돼야 하는지 알아내기 위해 XA API를 호출한다는 것을 뜻한다.&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;트랜잭션 코디네이터는 XA API를 구현한다.&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;&lt;b&gt;의심스러운 상태에 있는 동안 잠금을 유지하는 문제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션이 의심스러운 상태에 빠지는 것이 왜 문제일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 잠금과 관련이 있다. 데이터베이스 트랜잭션은 보통 더티 쓰기를 막기 위해 그들이 변경한 로우에 로우 수준의 독점적인 잠금을 획득한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 직렬성 격리를 원한다면 2단계 잠금을 사용하는 데이터베이스는 트랜잭션에서 읽은 로우에 공유 잠금도 획득해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 트랜잭션이 커밋하거나 어보트할 때까지 이런 잠금을 해제할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 2단계 커밋을 사용할 때 트랜잭션은 의심스러운 상태에 있는 동안 내내 잠금을 잡고 있어야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;코디네이터 장애에서 복구하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론상으로는 코디네이터가 죽은 후 재시작하면 로그로부터 그 상태를 깨끗하게 복구하고 의심스러운 트랜잭션을 해소해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 현실에서는 orphaned 의심스러운 트랜잭션, 즉 코디네이터가 어떤 이유 때문인지 그 결과를 결정할 수 없는 트랜잭션이 생길 수 있다.&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;여러 XA 구현에는 참여자가 코디네이터로부터 확정적 결정을 얻지 않고 의심스러운 트랜잭션을 어보트하거나 커밋할지를 일방적으로 결정할 수 있도록 하는 &lt;b&gt;경험적 결정(heuristic decision)&lt;/b&gt;이라고 부르는 비상 탈출구가 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;분산 트랜잭션의 제약&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XA 트랜잭션은 여러 참여 데이터 시스템이 서로 일관성을 유지하게 하는 실제적이고 중요한 문제를 해결해 주지만 지금까지 본 것처럼 XA 트랜잭션도 중요한 운영상 문제를 가져온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 핵심 구현은 트랜잭션 코디네이터 자체가 트랜잭션 결과를 저장할 수 있는 일종의 DB여야 한다는 점이고 따라서 다른 중요한 DB와 동일하게 신경 써서 접근해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코디네이터가 복제되지 않은 경우 SPOF가 될 수 있다.&lt;/li&gt;
&lt;li&gt;코디네이터의 로그가 지속적인 시스템 상태의 중대한 부분이 된다. 코디네이터 로그는 죽은 후에 의심스러운 트랜잭션을 복구하기 위해 필요하므로 DB 자체만큼 중요하다.&lt;/li&gt;
&lt;li&gt;XA는 광범위한 데이터 시스템과 호환돼야 하므로 최소 공통분모가 될 필요가 있다.&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;&lt;b&gt;내결함성을 지닌 합의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 문제 : 하나 또는 그 이상의 노드들이 값을 제안할 수 있고 합의 알고리즘이 그 값 중 하나를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 알고리즘은 다음 속성을 만족해야 한다.&lt;/p&gt;
&lt;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;/li&gt;
&lt;li&gt;&lt;b&gt;무결성&lt;/b&gt; : 어떤 노드도 두 번 결정하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유효성&lt;/b&gt; : 한 노드가 값 v를 결정한다면 v는 어떤 노드에서 제안된 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&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;p data-ke-size=&quot;size16&quot;&gt;내결함성이 상관없다면 처음 세 개의 속성을 만족시키는 것은 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 한 노드를 &quot;독재자&quot;로 하드 코딩하고 그 노드가 모든 결정을 내리게 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종료 속성은 내결함성의 아이디어를 형식화한다. 어떤 노드들에 장애가 나더라도 다른 노드들은 여전히 결정을 내려야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 시스템 모델은 노드가 &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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 대부분의 합의 구현은 과반수의 노드에 장애가 나거나 심각한 네트워크 문제가 있더라도 안전성 속성(동의, 무결성, 유효성)을 항상 만족한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;합의 알고리즘과 전체 순서 브로드캐스트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대다수의 합의 알고리즘은 값의 sequence에 대해 결정해서 전체 순서 브로드캐스트 알고리즘을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 회마다 노드들은 다음에 보내기 원하는 메시지를 제안하고 전체 순서 상에서 전달될 다음 메시지를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 전체 순서 브로드캐스트는 합의를 여러 번 반복하는 것과 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;단일 리더 복제와 합의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리더를 선출하려면 먼저 리더가 필요해 보이고, 합의를 해결하려면 먼저 합의를 해결해야 할 것 같다. 어떻게 해결할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;에포크 번호 붙이기와 정족수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 프로토콜(뷰스탬프 복제, 팍소스, 라프트, 잽)은 모두 내부적으로 어떤 형태로든 리더를 사용하지만 리더가 유일하다고 보장하지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 더 약한 보장을 하는데, 이 프로토콜들은 epoch number를 정의하고 각 에포크 내에서는 리더가 유일하다고 보장한다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리더 선출&lt;/li&gt;
&lt;li&gt;리더의 제안에 대한 투표&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 것은 제안에 대한 투표가 성공하면 그 제안에 투표한 노드 중 최소 하나는 가장 최근의 리더 선출에도 참여했어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 제안에 대한 투표를 할 때 에포크 번호가 더 큰 것이 있다고 밝혀지지 않았다면 현재 리더는 에포크 번호가 더 높은 리더 선출이 발생하지 않았다고 결론을 내릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;합의의 제약&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 알고리즘 : 안전성 속성을 가져오고, 내결함성을 유지하지만 다양한 이슈가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;성능&lt;/li&gt;
&lt;li&gt;엄격한 과반수 동작으로 인한 비용&lt;/li&gt;
&lt;li&gt;네트워크 지연이 심한 경우 리더 선출에 시간을 더 쓸 수 있음&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;&lt;b&gt;멤버십과 코디네이션 서비스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주키퍼 &amp;amp; etcd는 전부 메모리 안에 들어올 수 있는 작은 양의 데이터를 보관하도록 설계됐다. (지속성을 위해 디스크에 쓰기는 한다.)&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;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;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;&lt;b&gt;작업을 노드에 할당하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주키퍼 예시&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 개의 서비스 중 하나가 리더나 주 구성요소로 선택돼야 할 때&lt;/li&gt;
&lt;li&gt;파티셔닝 된 자원이 있고 어떤 파티션을 어느 노드에 할당해야 할지 결정해야 할 때. =&amp;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;&lt;b&gt;서비스 찾기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주키퍼, etcd, Consul =&amp;gt; Service Discovery로 활용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 디스커버리는 합의가 필요한가? =&amp;gt; 굳이... (DNS, 다층 캐시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 시스템이 누가 리더인지 안다면 다른 서비스들이 리더가 누구인지 찾는 데 사용.&lt;/p&gt;</description>
      <category>Log.Develop/DDIA</category>
      <category>chapter 9</category>
      <category>data driven intensive application</category>
      <category>ddia</category>
      <category>데이터 중심 애플리케이션 설계</category>
      <category>데중어설</category>
      <category>챕터 9</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/62</guid>
      <comments>https://hack-jam.tistory.com/62#entry62comment</comments>
      <pubDate>Fri, 10 Jun 2022 10:30:24 +0900</pubDate>
    </item>
    <item>
      <title>Chapter 8. 분산 시스템의 골칫거리 - Part 2</title>
      <link>https://hack-jam.tistory.com/61</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소개&lt;/b&gt;&lt;/h2&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;a href=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;https://github.com/ddia-study/ddia-study&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654824921251&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&quot; data-og-description=&quot;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-url=&quot;https://github.com/ddia-study/ddia-study&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ddia-study/ddia-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ddia-study/ddia-study&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PSn9W/hyOH97COPU/ZsSDf0xPggZ7qVR3OV1qK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;지식, 진실, 그리고 거짓말&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;분산 시스템에는 공유 메모리가 없고 지연 변동이 큰 신뢰할 수 없는 네트워크를 통해 메시지를 보낼 수 있을 뿐이며 부분 장애, 신뢰성 없는 시계, 프로세스 중단에 시달릴 수 있다.&lt;/i&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;신뢰성 없는 시스템 모델에서 잘 동작하는 소프트웨어를 만드는 게 가능할지라도 그것이 간단하지는 않다.&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;b&gt;진실은 다수결로 결정된다.&lt;/b&gt;&lt;/h3&gt;
&lt;ol 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;stop-the-world를 경험하는 노드라고 하자. 아무 요청도 처리 못하고 응답도 하지 못한다. 노드는 정상적으로 돌아오지만, 이미 죽었다고 선언됐을 가능성이 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 시스템은 한 노드에만 의존할 수는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 여러 분산 알고리즘은 &lt;b&gt;정족수(quorum)&lt;/b&gt;, 즉 노드들 사이의 투표에 의존한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드의 과반수 이상을 정족수로 삼는게 가장 흔하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리더와 잠금&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템이 오직 하나의 뭔가가 필요할 때가 자주 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스플릿 브레인을 피하기 위해 오직 한 노드만 데이터베이스 파티션의 리더가 될 수 있다.&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;분산 시스템에서 이를 구현하려면 주의해야 한다.&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;Hbase Example : 데이터 오염 사례&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;b&gt;펜싱 토큰&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠금 서버가 잠금이나 임차권을 승인할 때마다 fencing token도 반환한다고 가정한다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;마틴 클레프만이 fencing token에 대해서 서술한 글에서는 Redis의 Redlock 알고리즘이 어떤 문제가 있는지 설명해놨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Redis Redlock&lt;/i&gt; : DLM(Distributed Lock Manager)를 구현하는 알고리즘. N개의 마스터에서 Lock 이슈로 인해 일어날 수 있는 문제를 해결하기 위한 알고리즘이다. Quorum 이상의 인스턴스에서 Lock을 획득하면 lock을 얻은 것으로 보는 알고리즘.&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;p data-ke-size=&quot;size16&quot;&gt;The algorithm relies on the assumption that while there is no synchronized clock across the processes, the local time in every process updates at approximately at the same rate, with a small margin of error compared to the auto-release time of the lock.&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 경쟁 이슈로 인해 오염이 가능하기 때문에 펜싱 토큰을 쓰는 것이 필요하지만, Redlock에는 해당 메커니즘이 존재하지 않는다.&lt;/li&gt;
&lt;li&gt;Redis는 분산 노드를 사용할텐데, 단순한 카운터 같은 걸로 펜싱 토큰을 발급하기 쉽지 않다. 펜싱 토큰 발행에도 합의 알고리즘이 필요하다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis Redlock : &lt;a href=&quot;https://redis.io/docs/reference/patterns/distributed-locks/&quot;&gt;https://redis.io/docs/reference/patterns/distributed-locks/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654824955070&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;Distributed Locks with Redis&quot; data-og-description=&quot;A Distributed Lock Pattern with Redis&quot; data-og-host=&quot;redis.io&quot; data-og-source-url=&quot;https://redis.io/docs/reference/patterns/distributed-locks/&quot; data-og-url=&quot;https://redis.io/docs/reference/patterns/distributed-locks/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://redis.io/docs/reference/patterns/distributed-locks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://redis.io/docs/reference/patterns/distributed-locks/&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;Distributed Locks with Redis&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A Distributed Lock Pattern with Redis&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;redis.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자의 글 : &lt;a href=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot;&gt;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654824954620&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;How to do distributed locking &amp;mdash; Martin Kleppmann&amp;rsquo;s blog&quot; data-og-description=&quot;Tweet How to do distributed locking Published by Martin Kleppmann on 08 Feb 2016. As part of the research for my book, I came across an algorithm called Redlock on the Redis website. The algorithm claims to implement fault-tolerant distributed locks (or ra&quot; data-og-host=&quot;martin.kleppmann.com&quot; data-og-source-url=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; data-og-url=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chlvsd/hyOH90TQtE/KMIArRgGDnZms3JJFDvpIk/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400,https://scrap.kakaocdn.net/dn/dcd4rE/hyOIf06c9U/fvRjD7ufTbvdouFTJ60Hj0/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400&quot;&gt;&lt;a href=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chlvsd/hyOH90TQtE/KMIArRgGDnZms3JJFDvpIk/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400,https://scrap.kakaocdn.net/dn/dcd4rE/hyOIf06c9U/fvRjD7ufTbvdouFTJ60Hj0/img.png?width=1100&amp;amp;height=400&amp;amp;face=0_0_1100_400');&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;How to do distributed locking &amp;mdash; Martin Kleppmann&amp;rsquo;s blog&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Tweet How to do distributed locking Published by Martin Kleppmann on 08 Feb 2016. As part of the research for my book, I came across an algorithm called Redlock on the Redis website. The algorithm claims to implement fault-tolerant distributed locks (or ra&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;martin.kleppmann.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;del&gt;대충 다 읽어봤는데, 머리가 정말 아프다...&lt;/del&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;비잔틴 결함&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 시스템의 문제는 노드가 &quot;거짓말&quot; (임의의 결함이 있거나 오염된 응답을 보냄)을 할지도 모른다는 위험이 있다면 훨씬 더 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 노드가 실제로는 받지 않은 특정 메시지를 받았다고 주장할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 동작을 &lt;b&gt;Byzantine fault&lt;/b&gt;라고 하며 이렇게 신뢰할 수 없는 환경에서 합의에 도달하는 문제를 &lt;b&gt;Byzantine Generals Problem&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;항공우주 산업 환경에서 컴퓨터의 메모리나 CPU 레지스터에 저장된 데이터는 방사선에 오염돼서 그 컴퓨터가 다른 노드에게 전혀 예측할 수 없는 방식으로 반응할 수 있다.&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;시스템이 Byzantine fault-tolerant하게 만드는 프로토콜은 매우 복잡하고 내결함성을 지닌 임베디드 시스템은 하드웨어 수준의 지원에 의존한다.&lt;/p&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://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C-1%EB%B6%80-%EB%B9%84%EC%9E%94%ED%8B%B4-%EA%B2%B0%ED%95%A8-%EB%B0%A9%EC%A7%80-89ad2b7d1b65&quot;&gt;https://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C-1%EB%B6%80-%EB%B9%84%EC%9E%94%ED%8B%B4-%EA%B2%B0%ED%95%A8-%EB%B0%A9%EC%A7%80-89ad2b7d1b65&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654824951837&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;블록체인의 기본 원리 이해, 제 1부:비잔틴 결함 방지&quot; data-og-description=&quot;이 글은 Georgios Konstantopoulos가 쓴 Understanding Blockchain Fundamentals, Part 1: Byzantine Fault Tolerance을 번역한 글입니다. 오역이 있으면 Private Note&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C-1%EB%B6%80-%EB%B9%84%EC%9E%94%ED%8B%B4-%EA%B2%B0%ED%95%A8-%EB%B0%A9%EC%A7%80-89ad2b7d1b65&quot; data-og-url=&quot;https://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C-1%EB%B6%80-%EB%B9%84%EC%9E%94%ED%8B%B4-%EA%B2%B0%ED%95%A8-%EB%B0%A9%EC%A7%80-89ad2b7d1b65&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cMlFEb/hyOIkagIQC/gT1IUG16E67G5sMSaOrjF0/img.png?width=1200&amp;amp;height=966&amp;amp;face=0_0_1200_966,https://scrap.kakaocdn.net/dn/c1iGvJ/hyOIdhT0XS/NZMRGg0p1ph8Jyr0KtoZUk/img.png?width=1246&amp;amp;height=1004&amp;amp;face=0_0_1246_1004,https://scrap.kakaocdn.net/dn/6OKRF/hyOIbdjQVR/f6SYwoXRHCm65jBV270RX0/img.png?width=1067&amp;amp;height=561&amp;amp;face=0_0_1067_561&quot;&gt;&lt;a href=&quot;https://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C-1%EB%B6%80-%EB%B9%84%EC%9E%94%ED%8B%B4-%EA%B2%B0%ED%95%A8-%EB%B0%A9%EC%A7%80-89ad2b7d1b65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C-1%EB%B6%80-%EB%B9%84%EC%9E%94%ED%8B%B4-%EA%B2%B0%ED%95%A8-%EB%B0%A9%EC%A7%80-89ad2b7d1b65&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cMlFEb/hyOIkagIQC/gT1IUG16E67G5sMSaOrjF0/img.png?width=1200&amp;amp;height=966&amp;amp;face=0_0_1200_966,https://scrap.kakaocdn.net/dn/c1iGvJ/hyOIdhT0XS/NZMRGg0p1ph8Jyr0KtoZUk/img.png?width=1246&amp;amp;height=1004&amp;amp;face=0_0_1246_1004,https://scrap.kakaocdn.net/dn/6OKRF/hyOIbdjQVR/f6SYwoXRHCm65jBV270RX0/img.png?width=1067&amp;amp;height=561&amp;amp;face=0_0_1067_561');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;블록체인의 기본 원리 이해, 제 1부:비잔틴 결함 방지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 글은 Georgios Konstantopoulos가 쓴 Understanding Blockchain Fundamentals, Part 1: Byzantine Fault Tolerance을 번역한 글입니다. 오역이 있으면 Private Note&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;b&gt;약한 형태의 거짓말&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약한 형태의 거짓말로부터 보호해주는 메커니즘은 완전한 비잔팀 내결함성을 지니지는 않지만 그럼에도 더욱 나은 신뢰성으로 향하는 간단하고 실용적인 발걸음이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #666666;&quot;&gt;네트워크 패킷의 오염 검출을 피하는 경우&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;It turns out that ZooKeeper was not catching unhandled exceptions from its critical threads, meaning that if one died, the ZooKeeper process would continue to run without it. - &lt;a href=&quot;https://www.pagerduty.com/blog/the-discovery-of-apache-zookeepers-poison-packet/&quot;&gt;https://www.pagerduty.com/blog/the-discovery-of-apache-zookeepers-poison-packet/)&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자 입력 sanitization&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NTP 클라이언트 사용 시 여러 서버 쓰기&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;&lt;b&gt;시스템 모델과 현실&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템에서 발생할 것으로 예상되는 결함의 종류를 정형화해야 하는데, 이를 위해 &lt;b&gt;시스템 모델&lt;/b&gt;(알고리즘이 가정하는 것을 기술한 추상화)을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타이밍 가정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동기식 모델 : 모든 것(네트워크 지연, 프로세스 중단, 시계 오차)에 제한이 있다는 모델.&lt;/li&gt;
&lt;li&gt;부분 동기식 모델 : 대부분의 시간에는 동기식 시스템처럼 동작하지만 때때로 한계치를 초과한다는 모델.&lt;/li&gt;
&lt;li&gt;비동기식 모델 : 타이밍에 대한 어떤 가정도 할 수 없으며, 심지어는 시계가 없을 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;노드 장애
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;crash-stop 결함&lt;/li&gt;
&lt;li&gt;crash-recovery 결함&lt;/li&gt;
&lt;li&gt;비잔틴 결함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실 시스템을 모델링하는 데는 죽으면 복구하는 결함을 지닌 부분 동기식 모델이 일반적으로 가장 유용하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;알고리즘의 정확성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘은 시스템 모델에서 발생하리라고 가정한 모든 상황에서 그 속성들을 항상 만족시키면 해당 시스템 모델에서 정확하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 모든 노드가 죽거나 모든 네트워크 지연이 무한히 길어진다면 어떤 알고리즘도 아무것도 할 수 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;safety and liveness&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일성, 단조 일련번호는 안전성 속성이지만 가용성은 활동성 속성이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안전성 : 나쁜 일은 일어나지 않는다. 속성이 깨진 특정 시점을 가리킬 수 있고, 위반을 취소할 수 없다.&lt;/li&gt;
&lt;li&gt;활동성 : 좋은 일은 eventually 일어난다. 어떤 시점을 정하지 못할 수 있지만 항상 미래에 그 속성을 만족시킬 수 있다는 희망이 있다.&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;</description>
      <category>Log.Develop/DDIA</category>
      <category>chapter 8</category>
      <category>data driven intensive application</category>
      <category>ddia</category>
      <category>데이터 중심 애플리케이션 설계</category>
      <category>데중어설</category>
      <category>챕터 8</category>
      <author>bluayer</author>
      <guid isPermaLink="true">https://hack-jam.tistory.com/61</guid>
      <comments>https://hack-jam.tistory.com/61#entry61comment</comments>
      <pubDate>Fri, 10 Jun 2022 10:28:30 +0900</pubDate>
    </item>
  </channel>
</rss>