<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>devlog.akasai</title>
    <link>https://akasai.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 16 Apr 2026 19:46:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>akasai</managingEditor>
    <image>
      <title>devlog.akasai</title>
      <url>https://tistory1.daumcdn.net/tistory/4475567/attach/c33b0949eaa444bca55e515ff0fe6249</url>
      <link>https://akasai.tistory.com</link>
    </image>
    <item>
      <title>Promise.allSettled()</title>
      <link>https://akasai.tistory.com/34</link>
      <description>&lt;figure id=&quot;og_1638973983088&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;Promise.allSettled() | devlog.akasai&quot; data-og-description=&quot;Promise.allSettled함수는 iterator의 모든 Promise함수들의 결과가 처리( 또는 )될 때까지 대기한 뒤 결과를 반환하는 함수입니다. 이와 관련된 내용을 알아보려 합니다. Promise.all&amp;hellip;&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/node-js/about_promise_allsettled/&quot; data-og-url=&quot;https://akasai.space/node-jsabout_promise_allsettled/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/elWVHv/hyMD4Uh8d2/tPLp3guKmoCoz3idR2uEmK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/b6SQec/hyMEcSj6y0/5s5CWowELaLVTtd0v4glD0/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/node-js/about_promise_allsettled/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/node-js/about_promise_allsettled/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/elWVHv/hyMD4Uh8d2/tPLp3guKmoCoz3idR2uEmK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/b6SQec/hyMEcSj6y0/5s5CWowELaLVTtd0v4glD0/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_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;Promise.allSettled() | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Promise.allSettled함수는 iterator의 모든 Promise함수들의 결과가 처리( 또는 )될 때까지 대기한 뒤 결과를 반환하는 함수입니다. 이와 관련된 내용을 알아보려 합니다. Promise.all&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.allSettled&lt;/b&gt;함수는 iterator의 모든 Promise함수들의 결과가 처리(&lt;code&gt;fulfilled&lt;/code&gt; 또는 &lt;code&gt;rejected&lt;/code&gt;)될 때까지 대기한 뒤 결과를 반환하는 함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 관련된 내용을 알아보려 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.all&lt;/b&gt;은 여러개의 &lt;code&gt;PromiseLike&lt;/code&gt;함수들을 병렬로 실행하여 효율성을 높여주는 함수로 많이 사용되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iterator형태의 매개변수를 받고 배열형태의 결과값을 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병렬로 처리할 수 있다는 편의성과 반대로 iterator안의 함수가 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot; class=&quot;em red&quot;&gt;한 개라도 reject된다면 Promise.all 전체에서 exception이 발생&lt;/span&gt;&lt;/b&gt;하는 특징이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 Promise.allSettled와 Promise.all의 &lt;b&gt;가장 큰 차이점&lt;/b&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;특징&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;PromiseLike&lt;/code&gt; 타입의 &lt;b&gt;배열형태의 결과&lt;/b&gt;를 반환합니다.&lt;/li&gt;
&lt;li&gt;각 &lt;b&gt;결과 Object&lt;/b&gt;는 두가지 프로퍼티(&lt;b&gt;status&lt;/b&gt; &amp;amp; &lt;b&gt;reason/value&lt;/b&gt;)를 가질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;status&lt;/b&gt;는 &lt;code&gt;fulfilled&lt;/code&gt;과 &lt;code&gt;rejected&lt;/code&gt;를 값으로 가집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;value&lt;/b&gt;는 status가 &lt;code&gt;fulfilled&lt;/code&gt;일 때, &lt;b&gt;reason&lt;/b&gt;은 &lt;code&gt;rejected&lt;/code&gt;일 때 갖는 값입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;allSettled&amp;lt;T&amp;gt;(values: Iterable&amp;lt;T&amp;gt;): Promise&amp;lt;PromiseSettledResult&amp;lt;T extends PromiseLike&amp;lt;infer U&amp;gt; ? U : T&amp;gt;[]&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 특징처럼 &lt;b&gt;allSettled&lt;/b&gt;함수는 위와 같은 형태의 Response type을 갖습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;PromiseSettledResult&lt;/code&gt; type은 아래와 같이 정의되므로 2,3,4번과 같은 특징을 같습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;type PromiseSettledResult&amp;lt;T&amp;gt; = PromiseFulfilledResult&amp;lt;T&amp;gt; | PromiseRejectedResult;

interface PromiseFulfilledResult&amp;lt;T&amp;gt; {
    status: &quot;fulfilled&quot;;
    value: T;
}

interface PromiseRejectedResult {
    status: &quot;rejected&quot;;
    reason: any;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;code&gt;Node.js 12.9&lt;/code&gt; 이상, &lt;code&gt;es2020 lib&lt;/code&gt;, &lt;code&gt;TS 3.9&lt;/code&gt; 이상에서 정의되어 있고, 특정 브라우저(IE)는 사용하지 못합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://tc39.es/proposal-promise-allSettled/#sec-performpromiseallsettled&quot;&gt;TC39 스펙&lt;/a&gt;은&lt;/b&gt; 아래와 같이 사용법을 정의합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Accepts &lt;code&gt;iterable&lt;/code&gt; object as an argument.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;not iterable&lt;/code&gt;, &lt;code&gt;throw&lt;/code&gt; an &lt;code&gt;exception&lt;/code&gt; with an error message.&lt;/li&gt;
&lt;li&gt;Iterate the argument if it is &lt;code&gt;iterable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep the &lt;code&gt;results&lt;/code&gt; in an array.&lt;/li&gt;
&lt;li&gt;Wait for all promises to either get &lt;code&gt;resolved&lt;/code&gt;/&lt;code&gt;rejected&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Return the &lt;code&gt;results&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구현&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/**
 * user 목록을 조회하는 함수
 */
async function apiCall(p: number = 1) {
  console.log('### Get API start', p)
  if (p === 0) throw new Error('invalid argument')
  return fetch(`https://reqres.in/api/users?page=${p}`)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API호출을 통해 정보를 조회하는 간단한 로직을 구현하였습니다. 만약 argument가 &lt;b&gt;0이라면 error를 발생&lt;/b&gt;하게 유도하였습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Promise.all&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;async function main() {
  const task = [apiCall(0), apiCall(1)]
  try {
    const result = await Promise.all(task)
    console.log('result', result)
  } catch(e) {
    console.log('error', e)
  }
}

// ### Get API start, 0
// ### Get API start, 1
// error [Error: invalid argument]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.all&lt;/b&gt;을 이용한 로직을 구현해보면 위와 같은 결과를 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 task(iterator)가 동작하였지만, exception발생으로 인해 result가 아닌 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot; class=&quot;em red&quot;&gt;error&lt;/span&gt;&lt;/b&gt;를 확인할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;결론적으로 우리가 원하는 response를 확인할 수 없었습니다.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Promise.allSettled&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;async function main() {
  const task = [apiCall(0), apiCall(1)]
  try {
    const result = await Promise.allSettled(task)
    console.log('result', result)
  } catch(e) {
    console.log('error', e)
  }
}

// ### Get API start, 0
// ### Get API start, 1
// result [ 
//    { status: 'rejected', reason: [Error: invalid argument] }, 
//    { status: 'fulfilled', value: Response {...} }
// ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.all&lt;/b&gt;과 다르게 reject가 발생했음에도 &lt;b&gt;정상적으로 결과&lt;/b&gt;를 받아 볼 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 결과처럼 task(iterator)의 성공여부과 상관없이 결과를 보장한다는 점에서 이점이 있는 것 같습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이슈&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 최근에 추가된 함수이므로 Reference가 다양하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;TS4.5&lt;/code&gt; 미만의 환경에서는 정상적으로 Type 정의가 되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제를 예로들어 설명하자면, Response Type이 &lt;code&gt;PromiseLike&lt;/code&gt;형태로 정의되어 있습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;allSettled&amp;lt;T&amp;gt;(values: Iterable&amp;lt;T&amp;gt;): Promise&amp;lt;PromiseSettledResult&amp;lt;T extends PromiseLike&amp;lt;infer U&amp;gt; ? U : T&amp;gt;[]&amp;gt;;

interface PromiseFulfilledResult&amp;lt;T&amp;gt; {
    status: &quot;fulfilled&quot;;
    value: T;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 &lt;code&gt;fulfilled&lt;/code&gt;된 결과가 반환되면 이미 &lt;b&gt;await&lt;/b&gt;된 Response가 아닌 &lt;b&gt;Promise&amp;lt;{Pending}&amp;gt;&lt;/b&gt; 형태로&lt;br /&gt;정의되는 현상을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 Type 정의의 문제이기 때문에 &lt;b&gt;IDE상의 컴파일 에러&lt;/b&gt;일 뿐이지만, 개발 효율성이 저하되는 문제를 야기합니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;async function main() {
  const task = [apiCall(0), apiCall(1)]
  try {
    const result = await Promise.allSettled(task)
    console.log('result', result[1].value.someThing)
      // Error TS2339: Property 'someThing' does not exist on type 'Promise&amp;lt;Response&amp;gt;'
  } catch(e) {
    console.log('error', e)
  }
}

// ### Get API start, 0
// ### Get API start, 1
// result [ 
//    { status: 'rejected', reason: [Error: invalid argument] }, 
//    { status: 'fulfilled', value: Response {...} }
// ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 &lt;code&gt;TS4.5&lt;/code&gt;버전이 Release되어 &lt;code&gt;Awaited&lt;/code&gt; Type이 추가된 후 해결되었습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;allSettled&amp;lt;T&amp;gt;(values: Iterable&amp;lt;T | PromiseLike&amp;lt;T&amp;gt;&amp;gt;): Promise&amp;lt;PromiseSettledResult&amp;lt;Awaited&amp;lt;T&amp;gt;&amp;gt;[]&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Reference&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-promise.allsettled&quot;&gt;tc39.es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled&quot;&gt;Promise.allSettled()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/TypeScript/blob/main/src/lib/es2020.promise.d.ts&quot;&gt;microsoft/TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming/Node.js</category>
      <category>ES2020</category>
      <category>JavaScript</category>
      <category>node.js</category>
      <category>promise</category>
      <category>TypeScript</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/34</guid>
      <comments>https://akasai.tistory.com/34#entry34comment</comments>
      <pubDate>Wed, 8 Dec 2021 23:32:23 +0900</pubDate>
    </item>
    <item>
      <title>직방 경력 채용 후기</title>
      <link>https://akasai.tistory.com/33</link>
      <description>&lt;p&gt;상반기에 진행했던 이직경험을 공유해보려고 합니다.&lt;/p&gt;
&lt;p&gt;시간이 꽤 지났지만 크게 문제 되지 않는 정도만 적어보겠습니다.&lt;/p&gt;
&lt;p&gt;직방 &lt;strong&gt;부동산 서비스 백엔드 개발&lt;/strong&gt; 파트에 지원하였습니다.&lt;/p&gt;
&lt;h2&gt;전형 방법&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;서류전형&lt;/code&gt; → &lt;code&gt;코딩 테스트&lt;/code&gt; → &lt;code&gt;알고리즘 테스트&lt;/code&gt; → &lt;code&gt;1차 면접&lt;/code&gt; → &lt;code&gt;2차 면접&lt;/code&gt; → &lt;code&gt;임원 면접&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;서류전형&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://career.zigbang.com/&quot;&gt;직방 채용 사이트&lt;/a&gt;에서 채용공고 확인 후 지원하게 되었습니다. &lt;/p&gt;
&lt;p&gt;따로 양식이 있진 않고 개인 이력서를 첨부하는 식이었습니다.&lt;/p&gt;
&lt;p&gt;지금까지 진행했던 프로젝트를 기반의 이력서를 작성하였습니다.&lt;/p&gt;
&lt;p&gt;2주일 전후로 결과 메일을 받았습니다. 향후 진행될 코딩 테스트에 대한 일정이 안내되었습니다.&lt;/p&gt;
&lt;h2&gt;코딩 테스트&lt;/h2&gt;
&lt;p&gt;처음 전형 방법을 확인했을 때 테스트가 2개여서 약간 거부감이 있었습니다.&lt;/p&gt;
&lt;p&gt;첫 테스트가 코딩테스트라고 나와 있었지만 &lt;strong&gt;흔히 알고 있는 코딩테스트는 아니었습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;온라인으로 진행되었고 4시간 동안 풀었습니다. (안내에는 1시간 30분 정도 소요될 것이라고 안내되어 있습니다)&lt;/p&gt;
&lt;p&gt;문제는 &lt;strong&gt;영어&lt;/strong&gt;로 되어있었습니다.&lt;/p&gt;
&lt;h3&gt;문제 유형&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;객관식 문제&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; 컴퓨터공학, 실무에 관련된 지식에 대한 문제. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;실무적용 문제&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; 실제 실무에서 생각해볼 만한 문제.&lt;br&gt; 특정 문제 상황을 제시하고 그 문제를 해결하는 문제.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;생각보다 독특한 문제들이 나와서 당황했지만, 아주 어려운 정도는 아니었습니다.&lt;/p&gt;
&lt;p&gt;약 1주일 정도 후에 결과 메일을 받았습니다.&lt;/p&gt;
&lt;h2&gt;알고리즘 테스트&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;대중적으로 알려진 코딩테스트였습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.goorm.io/&quot;&gt;Groom&lt;/a&gt; 플랫폼을 사용하여 문제는 총 &lt;strong&gt;4문항&lt;/strong&gt;이며 난이도는 Problem Solving에 익숙해져 있다면 어렵지 않는 정도였습니다.&lt;/p&gt;
&lt;p&gt;약 1주일 정도 후에 결과 메일을 받았습니다.&lt;/p&gt;
&lt;h2&gt;1차 면접&lt;/h2&gt;
&lt;p&gt;1차 기술면접이었습니다. &lt;/p&gt;
&lt;p&gt;코로나 시국이었기 때문에 &lt;a href=&quot;https://meet.google.com/&quot;&gt;구글 밋&lt;/a&gt; 이용한 &lt;strong&gt;온라인 면접&lt;/strong&gt;으로 진행되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1시간&lt;/strong&gt;동안 진행되는 &lt;strong&gt;1:3 면접&lt;/strong&gt;이였고, 면접관은 실제 같이 업무를 하게 될 &lt;strong&gt;시니어&lt;/strong&gt;분들이었습니다.&lt;/p&gt;
&lt;h3&gt;유형&lt;/h3&gt;
&lt;p&gt;경력 면접이니만큼 경력 기반의 질문이 많이 이루어졌고, 사용기술에 대한 개념들에 대한 질문도 다수 받았습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;이직 사유&lt;/li&gt;
&lt;li&gt;진행했던 프로젝트에서 이어지는 연계 질문&lt;/li&gt;
&lt;li&gt;활용 가능 기술 스택 기반의 개념 질문&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;기본적인 이론 지식과 실무에서의 활용도를 중요시 생각한다는 느낌을 받았던 면접이었습니다.&lt;/p&gt;
&lt;p&gt;약 10일 정도 후에 결과 메일을 받았습니다.&lt;/p&gt;
&lt;h2&gt;2차 면접&lt;/h2&gt;
&lt;p&gt;2차 면접 역시 코로나로 인한 &lt;strong&gt;온라인 면접&lt;/strong&gt;으로 진행되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1:1 면접&lt;/strong&gt;이었고, 면접관은 &lt;strong&gt;개발팀 리드&lt;/strong&gt;분이었습니다.&lt;/p&gt;
&lt;p&gt;1시간 진행된다고 하셨지만 &lt;strong&gt;약 40분 정도&lt;/strong&gt; 소요되었습니다.&lt;/p&gt;
&lt;h3&gt;유형&lt;/h3&gt;
&lt;p&gt;기술면접 정도의 질문은 아니었지만 약간의 기술적인 부분이 포함된 면접이었습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;기술 기반의 질문.&lt;/li&gt;
&lt;li&gt;동료들과 협업과 관련된 질문(인성 질문).&lt;/li&gt;
&lt;li&gt;성장을 위해 하는 노력&lt;/li&gt;
&lt;li&gt;개발관&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;정답이 있는 질문들은 아녔습니다.&lt;/p&gt;
&lt;p&gt;본인의 경험 등을 바탕으로 소신 있게 답변하였습니다.&lt;/p&gt;
&lt;p&gt;약 20일(2주) 정도 후에 결과 메일을 받았습니다.&lt;/p&gt;
&lt;h2&gt;최종 면접&lt;/h2&gt;
&lt;p&gt;최종 면접도 앞선 2개의 면접과 동일하게 &lt;strong&gt;온라인 면접&lt;/strong&gt;으로 진행되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1:1 면접&lt;/strong&gt;이었고, 면접관은 직방의 &lt;strong&gt;임원&lt;/strong&gt; 중 한 분이였습니다.&lt;/p&gt;
&lt;p&gt;약 &lt;strong&gt;15분&lt;/strong&gt;정도 간단히 진행되었으며, 컬쳐 핏을 맞춰보는 정도의 질문이 오갔습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;최종 결과는 2~3일 정도 이후 유선을 통해 전달받았고&lt;/strong&gt;, 동시에 &lt;code&gt;처우 협의&lt;/code&gt;를 진행하였습니다.&lt;/p&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;몇몇 채용 절차를 진행해보았지만, 개인적으로 &lt;strong&gt;가장 길었던 채용 기간&lt;/strong&gt;이었던 것 같습니다.&lt;/p&gt;
&lt;p&gt;전형 자체도 많은 편이고, 전형 결과도 일정하지 않게 통보가 되어 피로도가 상승했던 것 같습니다.&lt;/p&gt;
&lt;p&gt;입사 후 알고 보니 채용담당자의 퇴사로 인한 내부사정으로 부득이하게 딜레이되었다는 내용을 접하게 되었습니다.&lt;/p&gt;
&lt;p&gt;최종 합격하였고 지원자 입장에서 여러 가지를 고려해보았을 때 만족할만한 조건이라고 생각하여 &lt;strong&gt;입사를 결정&lt;/strong&gt;하였습니다.&lt;/p&gt;
&lt;p&gt;전형을 진행한 지 다소 시간이 지난 상황이라 현재 프로세스와 일치하지 않을 수 있습니다.&lt;/p&gt;
&lt;p&gt;참고하시면 조금은 도움이 되지 않을까 하여 정리해보았습니다.&lt;/p&gt;</description>
      <category>ETC</category>
      <category>개발자</category>
      <category>경력채용</category>
      <category>면접</category>
      <category>백엔드</category>
      <category>서버</category>
      <category>이직</category>
      <category>직방</category>
      <category>후기</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/33</guid>
      <comments>https://akasai.tistory.com/33#entry33comment</comments>
      <pubDate>Fri, 15 Oct 2021 01:48:57 +0900</pubDate>
    </item>
    <item>
      <title>AWS VPC란?</title>
      <link>https://akasai.tistory.com/32</link>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1618153282435&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;VPC란? | devlog.akasai&quot; data-og-description=&quot;AWS기반의 클라우드 환경을 사용하면 자연스럽게 사용하게 되는 리소스가 바로 VPC입니다. 전반적인 구성요소에 대한 개념을 간단하게 알아봤습니다. VPC (Virtual Private Cloud) 논리적으로 격리된 네&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/what-is-aws-vpc/&quot; data-og-url=&quot;https://akasai.github.io/what-is-aws-vpc/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nl2Ff/hyJQBO57lx/nCjO863xF8azHzvqgdxDr1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/what-is-aws-vpc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/what-is-aws-vpc/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nl2Ff/hyJQBO57lx/nCjO863xF8azHzvqgdxDr1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;VPC란? | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;AWS기반의 클라우드 환경을 사용하면 자연스럽게 사용하게 되는 리소스가 바로 VPC입니다. 전반적인 구성요소에 대한 개념을 간단하게 알아봤습니다. VPC (Virtual Private Cloud) 논리적으로 격리된 네&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;AWS기반의 클라우드 환경을 사용하면 자연스럽게 사용하게 되는 리소스가 바로 &lt;code&gt;VPC&lt;/code&gt;입니다.&lt;/p&gt;
&lt;p&gt;전반적인 구성요소에 대한 개념을 간단하게 알아봤습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;VPC (Virtual Private Cloud)&lt;/h2&gt;
&lt;p&gt;논리적으로 &lt;b&gt;격리된 네트워크&lt;/b&gt;를 의미합니다.&lt;/p&gt;
&lt;p&gt;완전히 독립적인 네트워크로서 &lt;b&gt;실제로 같은 네트워크상에 존재&lt;/b&gt;하지만, 논리적으로 &lt;b&gt;다른 네트워크인 것처럼 동작&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;이름&lt;/code&gt;과 &lt;code&gt;IPv4 CIDR&lt;/code&gt; 블록으로 구성되어 있으며, 사설 아이피 대역에 맞추어 구축되어야 합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;사설(Private) 아이피&lt;/b&gt;: 아파트의 실제 주소&lt;/p&gt;
&lt;p&gt;&lt;b&gt;공인(Public) 아이피&lt;/b&gt;: 아파트의 호수&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;넷마스크 숫자는 IP의 범위를 나타내며 계산 방법은 &lt;code&gt;2^(32-n)&lt;/code&gt;입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;192.123.0.0/24 면 2^(32-24)=256. 즉, 245개의 IP주소를 의미합니다. (192.123.0.0 ~ 192.123.1.255)&lt;/blockquote&gt;
&lt;p&gt;VPC의 최대 크기는 &lt;code&gt;16&lt;/code&gt;입니다. 즉, 2^(32 - 16) = &lt;code&gt;65536&lt;/code&gt;개의 IP를 사용가능합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;VPC에서 사용하는 사설아이피 대역&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Class A: 10.0.0.0 ~ 10.255.255.255 (8bit)&lt;/p&gt;
&lt;p&gt;Class B: 172.16.0.0 ~ 172.31.255.255 (12bit)&lt;/p&gt;
&lt;p&gt;Class C: 192.168.0.0 ~ 192.168.255.255 (16bit)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/vpc1.3c7d887.d38b4476acf7b812c912edb6f7e5bb26.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Subnet&lt;/h2&gt;
&lt;p&gt;더 많은 네트워크망을 만들기 위해 VPC를 잘게 쪼개는 과정입니다.&lt;/p&gt;
&lt;p&gt;실제로 리소스가 생성되는 물리적 공간과 연결됩니다.&lt;/p&gt;
&lt;p&gt;각각의 서브넷은 가용영역 안에 존재하며 &lt;code&gt;RDS&lt;/code&gt;, &lt;code&gt;EC2&lt;/code&gt;와 같은 리소스를 위치시킬 수 있습니다.&lt;/p&gt;
&lt;p&gt;VPC보다 작은 단위이기 때문에 서브넷 마스크는 VPC보다 높습니다.&lt;/p&gt;
&lt;p&gt;서브넷의 넷마스크 범위는 &lt;code&gt;16(65535개) ~ 28(16개)&lt;/code&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/vpc2.3c7d887.e05d2cf578e9fd73bd80ca869e393112.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;라우팅 테이블&lt;/h2&gt;
&lt;p&gt;서브넷과 연결된 리소스입니다.&lt;/p&gt;
&lt;p&gt;라우터는 &lt;code&gt;목적지&lt;/code&gt;, 라우팅 테이블은 &lt;code&gt;이정표&lt;/code&gt; 역할을 합니다.&lt;/p&gt;
&lt;p&gt;데이터는 우선 라우터로 향하며 네트워크 요청은 각각 정의된 라우팅 테이블에 따라 작동합니다.&lt;/p&gt;
&lt;p&gt;단, 외부로 통하는 트래픽을 처리할 순 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;인터넷 연결이나 다른 VPC와의 통신은 라우팅 테이블에 규칙을 추가&lt;/b&gt;해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/vpc3.3c7d887.7209e816986722b1fdd0229799624a65.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;인터넷 게이트웨이 (IGW)&lt;/h2&gt;
&lt;p&gt;VPC와 인터넷을 연결해주는 하나의 관문입니다.&lt;/p&gt;
&lt;p&gt;VPC는 격리된 환경이므로 기본적으로 내부 리소스는 인터넷을 사용할 수 없습니다.&lt;/p&gt;
&lt;p&gt;인터넷과 연결되어있는 서브넷을 &lt;code&gt;퍼블릭 서브넷&lt;/code&gt;, 인터넷과 연결되어있지 않는 서브넷을 &lt;code&gt;프라이빗 서브넷&lt;/code&gt;이라고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/vpc4.3c7d887.48f73f4f9c2ad49c60cef148ae6fa053.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;DHCP 옵션셋&lt;/h2&gt;
&lt;p&gt;TCP/IP 상의 호스트로 설정정보를 전달하는 DHCP(Dynamic Host Configuration Protocol) 표준입니다.&lt;/p&gt;
&lt;p&gt;도메인 네임 서버(DNS), 도메인 네임(DN)등의 설정을 합니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;네트워크 ACL&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;Outbound, Inbound&lt;/b&gt; 트래픽을 제어하는 &lt;b&gt;가상 방화벽&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stateless&lt;/code&gt;하게 작동하며 서브넷 단위로 적용가능합니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;시큐리티 그룹&lt;/h2&gt;
&lt;p&gt;서브넷 뿐만 아니라 인스턴스 앞단에서 트래픽을 제어하는 &lt;b&gt;가상 방화벽&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stateful&lt;/code&gt;하게 작동하며 모든 허용을 차단하도록 기본설정되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/vpc5.3c7d887.2ee651e2093fbfd2a2dea6e76298defb.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Stateful vs Stateless&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Stateless&lt;/b&gt;란 &lt;code&gt;HTTP&lt;/code&gt;와 같이 Client의 이전 상태를 기록하지 않는 접속을 의미합니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Stateful&lt;/b&gt;은 Client의 이전 상태를 기록하고 있는 젒속을 의미합니다.&lt;/p&gt;
&lt;p&gt;즉, Stateless는 웹서버가 사용자의 작업을 기억하지 않으며, Stateful은 사용자의 상태를 서버가 기억하고 활용하는 것입니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;NAT&lt;/h2&gt;
&lt;p&gt;Private 서브넷이 인터넷과 통신하기 위한 &lt;b&gt;아웃바운드 인스턴스&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;인바운드는 허용하지 않더라도 업데이트 등의 이유로 아웃바운드가 필요합니다.&lt;/p&gt;
&lt;p&gt;NAT는 &lt;code&gt;Public 서브넷&lt;/code&gt;에서 동작하며 Private 서브넷에서 요청하는 아웃바운드 트래픽을 &lt;code&gt;IGW&lt;/code&gt;와 연결합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;인바운드: 외부 &amp;rarr; 내부&lt;/p&gt;
&lt;p&gt;아웃바운드: 내부 &amp;rarr; 외부&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/vpc6.3c7d887.b62376b980b1507c5d22682e04efdaeb.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/harrythegreat/aws-%EA%B0%80%EC%9E%A5%EC%89%BD%EA%B2%8C-vpc-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-71eef95a7098&quot;&gt;[AWS] 가장쉽게 VPC 개념잡기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://velog.io/@may_soouu/AWS-VPC%EB%9E%80&quot;&gt;AWS VPC란?&lt;/a&gt;&lt;/p&gt;</description>
      <category>Infra</category>
      <category>AWS</category>
      <category>cloud</category>
      <category>subnet</category>
      <category>VPC</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/32</guid>
      <comments>https://akasai.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 12 Apr 2021 00:00:38 +0900</pubDate>
    </item>
    <item>
      <title>Web Server와 WAS</title>
      <link>https://akasai.tistory.com/31</link>
      <description>&lt;figure id=&quot;og_1615856678955&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Web Server와 WAS | devlog.akasai&quot; data-og-description=&quot;자주 헷갈리는 개념인 Web Server와 WAS의 차이점을 알아보았습니다. Web Server Server의 문지기 Http요청이 들어오면 WAS로부터 해석된 HTML문서와 같은 웹페이지를 반환하는 역할을 합니다. 주로 정적(Sta&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/what-is-webserver-and-was/&quot; data-og-url=&quot;https://akasai.github.io/what-is-webserver-and-was/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zUtD1/hyJz4p5o4P/y4jrMrk6O9IeXqRTA0Mb50/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/what-is-webserver-and-was/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/what-is-webserver-and-was/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zUtD1/hyJz4p5o4P/y4jrMrk6O9IeXqRTA0Mb50/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Web Server와 WAS | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;자주 헷갈리는 개념인 Web Server와 WAS의 차이점을 알아보았습니다. Web Server Server의 문지기 Http요청이 들어오면 WAS로부터 해석된 HTML문서와 같은 웹페이지를 반환하는 역할을 합니다. 주로 정적(Sta&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/was1.42db587.98086380203b786f68feca1caaf60028.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;자주 헷갈리는 개념인 &lt;code&gt;Web Server&lt;/code&gt;와 &lt;code&gt;WAS&lt;/code&gt;의 차이점을 알아보았습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Web Server&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Server의 문지기&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Http요청이 들어오면 &lt;code&gt;WAS&lt;/code&gt;로부터 해석된 HTML문서와 같은 웹페이지를 반환하는 역할을 합니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;주로 정적(Static)인 데이터를 처리합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h3&gt;종류&lt;/h3&gt;
&lt;p&gt;Apache, IIS, NginX&lt;/p&gt;
&lt;h3&gt;관점&lt;/h3&gt;
&lt;p&gt;웹서버는 관점에 따라 다르게 해석될 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;H/W 측면&lt;/b&gt;: 실제 물리적인 서버 장비를 의미합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;S/W 측면&lt;/b&gt;: 물리적인 서버에 설치된 프로그램을 의미합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;WAS (Web Application Server)&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;웹서버와 반대로 동적(Dynamic)인 데이터를 처리합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;실제로 Application이 동작하는 부분으로 대게 &lt;code&gt;웹서버&lt;/code&gt;와는 구분이 됩니다.&lt;/p&gt;
&lt;p&gt;실질적인 &lt;b&gt;비즈니스 로직&lt;/b&gt;과 &lt;b&gt;DB 작업&lt;/b&gt;들이 수행되는 곳입니다.&lt;/p&gt;
&lt;h3&gt;종류&lt;/h3&gt;
&lt;p&gt;Tomcat, Web logic, Jeus&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Web Server와 WAS를 분리하는 이유&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/was2.0f43f28.3f6daf7b62e38a9b5e58342fb51cfae0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Web Server의 존재 이유&lt;/h3&gt;
&lt;p&gt;웹서버는 정적인 데이터를 주로 처리하는 역할을 합니다.&lt;/p&gt;
&lt;p&gt;요청에 좀 더 빠른 응답을 할 수 있으며, Application의 부하를 줄일 수 있습니다.&lt;/p&gt;
&lt;h3&gt;WAS의 존재 이유&lt;/h3&gt;
&lt;p&gt;대부분의 웹페이지는 정적/동적인 데이터가 모두 존재합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WAS&lt;/code&gt;는 실질적인 비즈니스 로직이 동작하며 동적인 데이터를 다루는데 이것을 모두 &lt;code&gt;웹서버&lt;/code&gt;에서 처리하기엔 자원 낭비가 심합니다.&lt;/p&gt;
&lt;p&gt;따라서 Application이 동작하고 동적인 데이터를 다루면서 효율적인 자원관리를 할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;두 서버의 분리 이유&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;서버 부하 방지기능을 분리하여 관리하는 측면이 좀 더 빠른 응답을 제공할 수 있습니다.&lt;/li&gt;
&lt;li&gt;모든 데이터(동적, 정적)를 한 서버에서 모두 처리하기에는 H/W 자원은 한정되어 있습니다.&lt;/li&gt;
&lt;li&gt;보안 강화&lt;/li&gt;
&lt;li&gt;외부로부터의 접근을 막아 서버 환경에 대한 노출을 방지할 수 있습니다.&lt;/li&gt;
&lt;li&gt;다양한 WAS 환경 제공성격이 다른 Application들을 동시에 제공할 수 있습니다.&lt;/li&gt;
&lt;li&gt;웹서버가 로드밸런서 역할을 하여 다양한 &lt;code&gt;WAS&lt;/code&gt;와 연결할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;WAS&lt;/code&gt;는 정적/동적인 데이터를 모두 다룰 수 있는 서버입니다. 또한 눈에 띄는 성능저하도 발생하지 않기 때문에 &lt;code&gt;웹서버&lt;/code&gt;가 없어도 페이지를 제공하는 데 어려움이 없습니다.&lt;/p&gt;
&lt;p&gt;하지만 다양한 환경의 Application 활용을 위해 로드밸런서로서의 역할은 큰 도움이 됩니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Web Server Architecture&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Client -&amp;gt; Webserver + DB&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;img src=&quot;https://akasai.space/assets/static/was3.d042d20.3f50965394ee3615a85c2aeefa32f47d.png&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Client -&amp;gt; WAS -&amp;gt; DB&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;img src=&quot;https://akasai.space/assets/static/was4.c98a7a4.b1b34aeb5cc6f18d227d79d78ce86d15.png&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Client -&amp;gt; Webserver -&amp;gt; WAS -&amp;gt; DB&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;img src=&quot;https://akasai.space/assets/static/was5.a0d7643.e3e525a4a356151493b9467fbcb7c619.png&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html&quot;&gt;[Web] Web Server와 WAS의 차이와 웹 서비스 구조&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jeong-pro.tistory.com/84&quot;&gt;WAS 와 웹 서버 차이 (WAS,Web Server) 그리고 아파치, 톰캣&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Infra/Basic</category>
      <category>WAS</category>
      <category>Web server</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/31</guid>
      <comments>https://akasai.tistory.com/31#entry31comment</comments>
      <pubDate>Tue, 16 Mar 2021 10:04:15 +0900</pubDate>
    </item>
    <item>
      <title>DB의 Index (Cluster, Non-Cluster)</title>
      <link>https://akasai.tistory.com/30</link>
      <description>&lt;figure id=&quot;og_1614819589168&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;DB의 Index | devlog.akasai&quot; data-og-description=&quot;인덱스를 간단하게 살펴보고 클러스터 인덱스와 넌 클러스터 인덱스를 알아보았습니다. Index란? 추가적인 쓰기와 저장공간을 사용하여 Database 테이블의 검색속도를 높여주는 자료구조입니다. CU&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/db-index/&quot; data-og-url=&quot;https://akasai.github.io/db-index/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b9rjnv/hyJscBH3vN/3sSW5ETFWpr6gGKpHYYlxK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/db-index/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/db-index/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b9rjnv/hyJscBH3vN/3sSW5ETFWpr6gGKpHYYlxK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;DB의 Index | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;인덱스를 간단하게 살펴보고 클러스터 인덱스와 넌 클러스터 인덱스를 알아보았습니다. Index란? 추가적인 쓰기와 저장공간을 사용하여 Database 테이블의 검색속도를 높여주는 자료구조입니다. CU&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;인덱스를 간단하게 살펴보고 클러스터 인덱스와 넌 클러스터 인덱스를 알아보았습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Index란?&lt;/h2&gt;
&lt;p&gt;추가적인 &lt;b&gt;쓰기&lt;/b&gt;와 &lt;b&gt;저장공간&lt;/b&gt;을 사용하여 Database 테이블의 &lt;b&gt;검색속도&lt;/b&gt;를 높여주는 자료구조입니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;CUD 작업&lt;/b&gt;(&lt;code&gt;Insert&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;)은 기본적으로 &lt;b&gt;R 작업&lt;/b&gt;(&lt;code&gt;Select&lt;/code&gt;)을 선행하기 때문에&lt;/p&gt;
&lt;p&gt;효율적인 인덱스의 사용은 테이블의 CRUD 작업의 성능을 높여줍니다.&lt;/p&gt;
&lt;p&gt;인덱스로 설정되지 않은 컬럼의 조회는 &lt;code&gt;Full Scan&lt;/code&gt;수행하기 때문에 속도 저하를 가져옵니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;특징&lt;/h2&gt;
&lt;p&gt;최신화된 Index는 성능향상을 보장하지만 인덱스가 적용된 컬럼에 CUD 작업이 발생한다면 &lt;b&gt;Overhead가 발생&lt;/b&gt;합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;INSERT&lt;/b&gt; (C)&lt;/p&gt;
&lt;p&gt;새로운 데이터에 대한 인덱스를 추가합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;DELETE&lt;/b&gt; (D)&lt;/p&gt;
&lt;p&gt;삭제되는 데이터에 대한 인덱스를 제외처리 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;UPDATE&lt;/b&gt; (U)&lt;/p&gt;
&lt;p&gt;기존 인덱스는 제외처리, 새로운 데이터에 대한 인덱스를 추가합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;조회(Read) 속도뿐만 아니라 전반적인 성능향상을 기대할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;모든 &lt;b&gt;CUD 작업&lt;/b&gt;(&lt;code&gt;Insert&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;)은 기본적으로 &lt;b&gt;R 작업&lt;/b&gt;(&lt;code&gt;Select&lt;/code&gt;)을 선행하기 때문에&lt;/p&gt;
&lt;p&gt;연관되는 대부분의 작업에서 성능개선을 기대할 수 있습니다.&lt;/p&gt;
&lt;p&gt;따라서 &lt;b&gt;전체적인 시스템 부하 역시 줄일 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;추가적인 저장공간이 필요합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;인덱스란 결국 별도의 페이지를 생성하는 작업이기 때문에 자연스럽게 저장공간이 필요합니다.&lt;/p&gt;
&lt;p&gt;또한, 잘못된 사용이나 무분별한 사용(남/오용)은 &lt;b&gt;성능 저하라는 역효과를 가져옵니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;위에서 설명한 특징들 때문에 인덱스의 크기는 점점 증가하기 때문입니다.&lt;/p&gt;
&lt;h3&gt;주의점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;데이터의 중복도가 낮은 컬럼(카디널리티가 낮은)을 기준으로 생성하도록 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Join&lt;/code&gt;, &lt;code&gt;Where&lt;/code&gt;, &lt;code&gt;Order by&lt;/code&gt;조건이 자주 사용되는 컬럼을 기준으로 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;CUD 작업&lt;/b&gt;이 빈번하지 않는 컬럼을 기준으로 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;사용하지 않는 인덱스는 반드시 제거합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;클러스터 인덱스 (Cluster Index)&lt;/h2&gt;
&lt;p&gt;테이블당 1개 생성할 수 있는 인덱스입니다.&lt;/p&gt;
&lt;p&gt;테이블 생성 시 &lt;b&gt;Primary Key(PK)&lt;/b&gt;를 지정하면 자동으로 클러스터 인덱스가 생성됩니다.&lt;/p&gt;
&lt;p&gt;생성 시 인덱스는 열(Column) 단위로 생성되며, 지정한 열에 대하여 페이지 전체를 물리적으로 다시 정렬합니다.&lt;/p&gt;
&lt;p&gt;Root페이지와 Leaf페이지로 구성되며, Root페이지는 &lt;b&gt;Leaf페이지의 주소&lt;/b&gt;가 Leaf페이지는 &lt;b&gt;실제 데이터 페이지&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p&gt;읽기 속도는 향상되지만 쓰기/수정의 속도는 상대적으로 느립니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/ci.3a8aa63.c1456b22b1d2478f6f085037c1895161.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;MAX&lt;/code&gt;, &lt;code&gt;MIN&lt;/code&gt;, &lt;code&gt;COUNT&lt;/code&gt;등의 쿼리로 &lt;b&gt;범위 또는 Group By&lt;/b&gt; 등의 조회를 할 때 이상적입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;조회 시 특정 지점(인덱스의 키가 지정하는)으로 바로 찾기 때문에 효율적입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;페이지 전송을 최소화하고 캐시 히트를 극대화 할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;데이터 페이지 뿐만 아니라 인덱스 페이지의 파편화 현상이 발생합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Insert&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;를 위한 추가작업이 발생합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;생성/변경 등이 발생할 때 오랜 시간이 걸립니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;넌클러스터 인덱스 (Non-Cluster Index)&lt;/h2&gt;
&lt;p&gt;테이블당 여러 개 생성할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이미 &lt;b&gt;Primary Key(PK)&lt;/b&gt;로 지정되어 있더라도 강제적으로 넌클러스터드 인덱스를 지정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;데이터 페이지는 따로 존재하며 별도의 &lt;b&gt;인덱스 페이지&lt;/b&gt;를 생성합니다.&lt;/p&gt;
&lt;p&gt;Root페이지는 Leaf페이지의 주소를 저장하며 Leaf페이지는 데이터 페이지의 실제 데이터 주소를 저장하는 &lt;b&gt;포인터&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/nci.c9c4c4d.eec01f16f19cd30d966175bc38681da6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;테이블 생성 시에 인덱스를 생성하기 위해선 제약조건이 필요합니다. 기본 제약조건은 PK와 UNIQUE뿐입니다.&lt;/blockquote&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;데이터를 신속하게 찾을 때 큰 도움이 됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클러스터 인덱스와 연관된 오버헤드를 줄이는데 도움이 됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;하나 이상의 인덱스 생성을 통해 성능향상을 기대할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;논리적인 정렬을 지원할 뿐, 물리적인 정렬이 발생하지 않습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인덱스 조회 시 비용이 많이 발생합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클러스터 인덱스의 변경이 발생할 때 그에 상응하는 업데이트가 발생합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;요약&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;클러스터 인덱스는 키 기반으로 테이블 데이터를 정렬하지만, 넌클러스터 인덱스는 데이터는 따로 저장되며 그 위치만을 인덱싱합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클러스터 인덱스는 인덱스의 Leaf페이지에 실제 데이터를 저장하지만, 넌클러스터 인덱스는 데이터를 저장하지 않습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클러스터 인덱스는 추가적인 저장공간이 필요없지만, 넌클러스터 인덱스는 추가 저장공간이 필요합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클러스터 인덱스는 데이터 접근 속도가 빠르지만, 넌클러스터 인덱스는 상대적으로 느립니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.guru99.com/clustered-vs-non-clustered-index.html&quot;&gt;Clustered vs Non-clustered Index: Key Differences with Example&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mongyang.tistory.com/75&quot;&gt;인덱스(클러스터, 비클러스터) 개념&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lng1982.tistory.com/144&quot;&gt;클러스터드 인덱스와 넌 클러스터드 인덱스&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://swconsulting.tistory.com/381&quot;&gt;클러스터/넌클러스트 인덱스 (cluster index/noncluster index)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Database/Basic</category>
      <category>Cluster Index</category>
      <category>Database</category>
      <category>index</category>
      <category>Noncluster Index</category>
      <category>PostgreSQL</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/30</guid>
      <comments>https://akasai.tistory.com/30#entry30comment</comments>
      <pubDate>Thu, 4 Mar 2021 09:59:21 +0900</pubDate>
    </item>
    <item>
      <title>MSA(Microservice Architecture)이란?</title>
      <link>https://akasai.tistory.com/29</link>
      <description>&lt;figure id=&quot;og_1614128107505&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MSA(Microservice Architecture)이란? | devlog.akasai&quot; data-og-description=&quot;실무에서 실제로 사용중인 아키텍처 패턴인 MSA에 대하여 간략히 알아보았습니다. MSA(Microservice Architecture)란? Microservice Architecture의 약자로 독립적인 배포가 가능한 서비스들로 구성된 아키텍처&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/what-is-msa&quot; data-og-url=&quot;https://akasai.github.io/what-is-msa/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b06uMW/hyJmmZKOKE/VKKuCnQR7MlDxBXsrEQQRK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/what-is-msa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/what-is-msa&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b06uMW/hyJmmZKOKE/VKKuCnQR7MlDxBXsrEQQRK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;MSA(Microservice Architecture)이란? | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;실무에서 실제로 사용중인 아키텍처 패턴인 MSA에 대하여 간략히 알아보았습니다. MSA(Microservice Architecture)란? Microservice Architecture의 약자로 독립적인 배포가 가능한 서비스들로 구성된 아키텍처&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/msa1.2671d65.c58ceab6f8a66ff89f7470c24ab6c29b.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;실무에서 실제로 사용중인 아키텍처 패턴인 MSA에 대하여 간략히 알아보았습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;MSA(Microservice Architecture)란?&lt;/h2&gt;
&lt;p&gt;Microservice Architecture의 약자로 독립적인 배포가 가능한 서비스들로 구성된 아키텍처라고 요약할 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In short, the microservice architectural style is an approach to developing a single application as a suite of small services,&lt;br /&gt;each running in its own process and communicating with lightweight mechanisms,&lt;br /&gt;often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery.&lt;br /&gt;There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;위 문장에서 표현하듯 독립적으로 배포가 가능하고(independently deployable) 각각 동작하는(each running in its own process) 작은 서비스(small services)입니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;등장배경&lt;/h2&gt;
&lt;p&gt;Enterprise 환경에서 서비스의 크기가 커짐에 따라 모놀리식(Monolithic) Architecture의 한계점이 발생하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #dddddd;&quot; class=&quot;callout&quot;&gt; &lt;b&gt;모놀리식(Monolithic) 아키텍처&lt;/b&gt; &lt;br /&gt;소프트위어의 모든 구성요소가 한 곳에서 관리되는 아키텍처. 유지보스가 용이하여 소규모 프로젝트에서 합리적이다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/msa2.2665e34.862f27ecc403338cb444ecb2c35b82d6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;모놀리식(Monolithic) 아키텍처의 한계점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;서비스가 커질수록 개발내용의 영향도 파악 / 시스템 구조 파악이 어려움.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;빌드/테스트 시간의 증가로 인한 배포 시간의 증가.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;특정 서비스(기능)의 Scaling(Scale Out, Scale Up 등)이 어려움.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;일부분의 장애가 전체 장애가 될 가능성이 큼.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;특정 개발언어에 종속적.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;MSA의 특징&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;독립적인 배포가 가능 (Independently deployable)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;서비스 단위로 분리되었기 때문에 각각의 서비스들을 독립적으로 배포할 수 있습니다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;b&gt;느슨한 결합 (Loosely coupled)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;각 서비스에 대한 의존성을 최소화하므로 결합도가 낮습니다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;b&gt;높은 유지성, 테스트 가능성 (Highly maintainable and testable)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;분리된 서비스별로 관리되기 때문에 유지하기 편하고 테스트도 독립적으로 가능합니다.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;b&gt;팀 단위 구성이 가능 (Owned by a small team)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;서비스 단위로 팀 구성을 하여 개발/운영 할 수 있습니다.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;b&gt;사업 단위(서비스 단위)의 조직 (Organized around business capabilities)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;각 서비스의 단위를 사업의 단위로 판단할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;MSA에서의 Service&lt;/h3&gt;
&lt;p&gt;MSA 환경에서 Service를 정의하자면 다음과 같이 표현할 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;독립적인 배포가 가능한 단위&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서로 간의 의존성이 최소화되는 단위&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;개별적인 프로세스로 동작하는 단위&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서로 간 가벼운 방식(REST, RPC 등)을 통한 통신&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;크기가 작을 뿐 하나의 모놀리식 구조와 유사한 단위&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;MSA의 장단&lt;/h2&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;서비스별 독립적인 배포가 가능하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;계속 언급되는 특징이지만 가장 큰 특징이자 장점이라고 볼 수 있습니다.&lt;br /&gt;전체 서비스의 중단없이 개별적인 서비스를 자유롭게 배포할 수 있습니다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Scaling&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;모놀리식의 한계점을 극복할 수 있습니다.&lt;br /&gt;모놀리식 환경과 달리 특정 서비스의 부하로 스케일링이 필요할 경우 해당 서비스만 별도로 확장이 가능합니다. 클라우드 환경에서는 적합하다고 볼 수 있습니다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;장애 대응&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;모놀리식 환경에서는 일부의 장애가 전체 서비스의 장애가 될 가능성이 높습니다.&lt;br /&gt;하지만 분리된 환경에서 일부의 장애는 전체 서비스에 큰 영향을 미치지 않습니다.&lt;/p&gt;
&lt;p&gt;상대적으로 부분적 장애 격리가 수월하지만, 의존도에 따라서 장애 확산의 가능성은 분명 존재합니다.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;폴리글랏&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;한 가지 언어에 종속되는 모놀리식 환경의 특징과 달리 각 서비스 다양한 언어/환경에서 구성이 가능합니다. 따라서 전체 서비스에 영향을 주지 않고 신기술 적용이 용이합니다.&lt;/p&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;성능&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;분리된 서비스는 리소스를 소모합니다. 모놀리식 환경에서는 없는 각 서비스 간의 추가적인 통신이 필요합니다.&lt;br /&gt;그로 인해 Latency가 증가하고 이를 해결할 추가적인 방법이 필요합니다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;트랜잭션&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;MSA의 큰 단점 중 한 개입니다. 물리적으로 서비스가 분리되어 있어 트랜잭션의 복잡도가 증가합니다.&lt;br /&gt;분산 트랜잭션에 대한 대응이 없다면 데이터의 일관성에서 장애 요소가 존재합니다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;테스트&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;서비스가 분산되어 있기 때문에 통합 테스트에 대한 불편함이 증가합니다.&lt;br /&gt;각각의 서비스를 테스트할 수 있다는 장점은 있지만, 전체 서비스에 대한 테스트를 위해 다양한 방법을 고려해야 합니다.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;데이터&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;물리적으로 분리되는 서비스의 특징 때문에 데이터 역시 분산될 가능성이 높습니다(DB의 분리).&lt;br /&gt;이로 인해 데이터의 조회가 어렵고 정합성을 보장하는데 어려움이 있습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/msa3.3d2bee5.4b5916740b8761bc5ceec516ee4fb484.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;클라우드 환경의 등장과 컨테이너 기술들의 발전으로 현재 가장 많은 관심을 받는 아키텍처라고 생각합니다.&lt;/p&gt;
&lt;p&gt;심지어는 개발의 시작부터 MSA를 고려하는 상황도 발생하고 있습니다.&lt;/p&gt;
&lt;p&gt;많은 장점이 있는 아키텍처이지만 그만큼 단점이나 고려야 할 부분도 많이 존재합니다.&lt;/p&gt;
&lt;p&gt;모든 아키텍처 설계가 그렇듯 개발에 앞서 사용해야 할 정당한 근거 아래 도입해야 합리적인 선택이 되리라 생각합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;비용: 특정 서비스 아키텍처를 도입할 경우 비용을 얼마나 절감할 수 있는가?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;개발 생산성: 마이크로서비스를 요구할 만큼 시스템 복잡도가 높은가? 또는 복잡도를 지나치게 높인 마이크로서비스가 생산성을 저해하고 있지는 않은가?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;운영: 개발팀에게 개발과 운영을 동시에 요구할 만큼 인프라가 준비되어 있는가?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/microservices.html&quot;&gt;Microservices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://channy.creation.net/articles/microservices-by-james_lewes-martin_fowler&quot;&gt;마이크로서비스 &amp;ndash; MicroServices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://microservices.io/index.html&quot;&gt;Microservice Architecture&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.samsungsds.com/kr/insights/msa.html&quot;&gt;Do Not Use MSA - 마이크로서비스 아키텍처가 꼭 필요한가요?&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/Architecture</category>
      <category>architecture</category>
      <category>microservice</category>
      <category>마이크로 서비스</category>
      <category>아키텍처</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/29</guid>
      <comments>https://akasai.tistory.com/29#entry29comment</comments>
      <pubDate>Wed, 24 Feb 2021 09:53:58 +0900</pubDate>
    </item>
    <item>
      <title>TTL을 이용한 DynamoDB Stream Trigger</title>
      <link>https://akasai.tistory.com/28</link>
      <description>&lt;figure id=&quot;og_1613641418554&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;TTL을 이용한 DynamoDB Stream Trigger | devlog.akasai&quot; data-og-description=&quot;주기적으로 캐싱을 해야 하는 작업이 있어 삽질해본 경험을 공유하려 합니다. 단순하게 Crontab이나 배치 등을 이용하여 처리하는 방법과 Request 단위로 캐싱을 하는 방법을 생각해보았지만, 여러 &quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/use-the-dynamodb-stream/&quot; data-og-url=&quot;https://akasai.github.io/use-the-dynamodb-stream/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/boUFs2/hyJjP1aQf3/iNVsQKpTAOBO7B8PmheK9K/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/use-the-dynamodb-stream/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/use-the-dynamodb-stream/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/boUFs2/hyJjP1aQf3/iNVsQKpTAOBO7B8PmheK9K/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;TTL을 이용한 DynamoDB Stream Trigger | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;주기적으로 캐싱을 해야 하는 작업이 있어 삽질해본 경험을 공유하려 합니다. 단순하게 Crontab이나 배치 등을 이용하여 처리하는 방법과 Request 단위로 캐싱을 하는 방법을 생각해보았지만, 여러&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/dynamodb.3fc491b.4f92fe577361a25b0c00efa078ed733e.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;주기적으로 캐싱을 해야 하는 작업이 있어 삽질해본 경험을 공유하려 합니다.&lt;/p&gt;
&lt;p&gt;단순하게 Crontab이나 배치 등을 이용하여 처리하는 방법과&lt;/p&gt;
&lt;p&gt;Request 단위로 캐싱을 하는 방법을 생각해보았지만, 여러 조건이 존재해서 아래 방법을 선택했습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Data Modeling&lt;/h2&gt;
&lt;p&gt;기존 API의 latency를 줄이기 위한 일부 데이터를 캐싱하는 작업이였기 때문에 스키마를 복잡하게 모델링하진 않았습니다.&lt;/p&gt;
&lt;p&gt;키를 기준으로 Map을 요소로하는 List를 구성하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda-table.543306f.fb4201c9a5e255f798b508a1d46b6007.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Storage&lt;/h2&gt;
&lt;p&gt;일반적으로 캐싱이라면 NoSQL을 통해 처리하고 있고 현업에서는 &lt;code&gt;Redis&lt;/code&gt;, &lt;code&gt;DynamoDB&lt;/code&gt;를 사용하고 있습니다.&lt;/p&gt;
&lt;p&gt;구상하고 있는 스키마에 적합한 것은 &lt;code&gt;DynamoDB&lt;/code&gt;라고 판단했습니다.&lt;/p&gt;
&lt;p&gt;Redis 역시 다양한 dataType을 지원하지만 &lt;b&gt;Map을 요소로 하는 List&lt;/b&gt;를 구성하기엔 DynamoDB가 적합하다고 생각했습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;TTL (Time To Live)&lt;/h2&gt;
&lt;p&gt;Crontab또는 배치를 사용하지 않고 어떻게 주기적으로 캐싱을 할 것인지가 중요한 포인트였습니다.&lt;/p&gt;
&lt;p&gt;Redis와 DynamoDB 둘 다 TTL 기능을 지원하고 있습니다.&lt;/p&gt;
&lt;p&gt;Redis는 TTL에 대한 evnet를 Subscribe 하는 추가적인 개발이 필요했지만 DynamoDB는 &lt;code&gt;Stream Trigger&lt;/code&gt;를 이용해 &lt;code&gt;Lambda&lt;/code&gt;를 호출할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이런 이점들을 고려하여 최종적으로 DynamoDB를 선택하여 개발을 시작했습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;DynamoDB 세팅&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;일반적인 세팅과 같이 AWS Console에서 테이블 세팅을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda1.57ae31b.e17e4921fbc664202af7c56a3a4d422d.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;테이블이 생성되면 TTL로 설정하고자 하는 Attribute를 입력한 뒤 TTL을 설정합니다.&lt;/p&gt;
&lt;p&gt;TTL은 반드시 Number타입으로 세팅되어야 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda2.4ccb719.52ef30463b9847df0c0e1d2661d3a4b4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Stream 세팅을 통해 &lt;code&gt;ARN&lt;/code&gt;을 획득합니다.&lt;/p&gt;
&lt;p&gt;스트림에는 총 &lt;b&gt;4가지 타입&lt;/b&gt;이 존재합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;키만 보기&lt;/p&gt;
&lt;p&gt;DynamoDB의 &lt;b&gt;키(HachKey/SortKey)값&lt;/b&gt;만 Stream으로 전송합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;새 이미지&lt;/p&gt;
&lt;p&gt;새롭게 수정된 레코드 내용을 Stream으로 전송합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이전 이미지&lt;/p&gt;
&lt;p&gt;기존 레코드 내용만 Stream으로 전송합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;새 이미지와 이전 이미지&lt;/p&gt;
&lt;p&gt;변경된 내용과 이전 내용이 모두 Stream으로 전송됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda3.b5f4831.9b3dc69ab30c98b349ec723f34444787.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;생성된 ARN을 바탕으로 Lambda트리거 세팅을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda4.626fdb9.4d4588d0a03360cad121aa22f1e55e17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Lambda 세팅&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.serverless.com/&quot;&gt;Serverless Framework&lt;/a&gt;를 통해 환경 세팅을 했습니다.&lt;/p&gt;
&lt;p&gt;배포하면 자동으로 관련된 Role을 생성해주기 때문에 Console 내 작업은 더 이상 하지 않았습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;serverless.yml 세팅&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;  functions:
  main:
    handler: main.handler
    events:
      - stream:
          arn: arn:aws... # 뒤쪽 타임스탬프까지 모두 입력
          type: dynamodb
          batchSize: 100
    memorySize: 256
    timeout: 180 &lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Serverless Framework에서 제공하는 플로우대로 배포를 합니다.&lt;/p&gt;
&lt;p&gt;배포 완료 후 Console을 통해 확인하면 DynamoDB와 연결된 내용을 확인 할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;DynamoDB의 트리거&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda5.2b08a90.9aeafb6b7d4327efa42e0f7521799f56.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Lambda의 트리거&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/lambda6.42db587.b063d51e0e1c9858a6a81a7db580d5e0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;위와 같이 세팅이 완료되면 준비는 끝났습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이후 DynamoDB의 레코드에 특정 이벤트가 발생하면 Lambda함수로 Event가 전송됩니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;{
  Records: [
    {
      eventID: '...',
      eventName: 'INSERT',
      eventVersion: '1.1',
      eventSource: 'aws:dynamodb',
      awsRegion: '...',
      dynamodb: {
        ApproximateCreationDateTime: 1613373723,
        Keys: { content: { S: '테스트' } },
        NewImage: { ttl: { N: '1613373820' }, content: { S: '테스트' } },
        SequenceNumber: '4500000000033167407696',
        SizeBytes: 41,
        StreamViewType: 'NEW_AND_OLD_IMAGES'
      },
      eventSourceARN: 'arn:aws:...'
    },
    {
      eventID: '...',
      eventName: 'REMOVE',
      eventVersion: '1.1',
      eventSource: 'aws:dynamodb',
      awsRegion: '...',
      dynamodb: {
        ApproximateCreationDateTime: 1613373723,
        Keys: { content: { S: '테스트' } },
        NewImage: { ttl: { N: '1613373820' }, content: { S: '테스트' } },
        SequenceNumber: '4500000000033167407696',
        SizeBytes: 41,
        StreamViewType: 'NEW_AND_OLD_IMAGES'
      },
      eventSourceARN: 'arn:aws:dynamodb:...'
    },
    ...
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Record는 배열이며 동시간대 발생하는 다수의 이벤트들이 함께 들어옵니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;eventName객체&lt;/b&gt;는 &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;REMOVE&lt;/code&gt;, &lt;code&gt;MODIFY&lt;/code&gt; 등이 있으며, &lt;b&gt;dynamodb객체&lt;/b&gt;에 실제 레코드 정보가 담겨 있습니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;주의점&lt;/h2&gt;
&lt;p&gt;무작정 TTL의 장점만을 보고 사용하기에는 주의해야 할 사항들이 존재합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;TTL 속성에 숫자 데이터 형식을 사용해야 합니다. 다른 데이터 형식(예: 문자열)은 지원되지 않습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TTL 속성은 Epoch 시간 형식을 사용해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt; Linux Terminal: date +%s

 Python: import time; int(time.time())

 Java: System.currentTimeMillis() / 1000L

 JavaScript: Math.floor(Date.now() / 1000)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DynamoDB가 항목을 삭제할 때까지 최소 48시간 동안 기다립니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;만료 날짜는 5년을 넘지 않아야 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Lambda로 전송된 스트림은 온전하게 끝나지 않는다면 Failover를 계속 수행합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;이는 장점이 될 수도 있지만, 무한실행이라는 치명적인 오류를 가져옵니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;적절한 Lambda함수 처리가 필요합니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html&quot;&gt;DynamoDB TTL&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/ko/premiumsupport/knowledge-center/dynamodb-ttl-items-not-deleted/&quot;&gt;TTL 특징&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Database/DynamoDB</category>
      <category>AWS</category>
      <category>dynamodb</category>
      <category>Event Stream</category>
      <category>lambda</category>
      <category>serverless</category>
      <category>TTL</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/28</guid>
      <comments>https://akasai.tistory.com/28#entry28comment</comments>
      <pubDate>Thu, 18 Feb 2021 18:43:12 +0900</pubDate>
    </item>
    <item>
      <title>EDA(Event Driven Architecture)이란?</title>
      <link>https://akasai.tistory.com/27</link>
      <description>&lt;figure id=&quot;og_1612970013023&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;EDA(Event Driven Architecture)이란? | devlog.akasai&quot; data-og-description=&quot;최근 기존 구조를 고도화하는 작업을 진행했습니다. 동기 처리되던 로직을 비동기로 변경하면서 EDA(Event Driven Architecture)를 도입하였습니다. 관련된 내용을 정리해보려고 합니다. EDA(Eventt Driven Ar&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/what-is-eda/&quot; data-og-url=&quot;https://akasai.github.io/what-is-eda/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dj0WDM/hyJeELHRy9/I9Dmq44wW7dMVAuP7nz6vk/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/what-is-eda/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/what-is-eda/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dj0WDM/hyJeELHRy9/I9Dmq44wW7dMVAuP7nz6vk/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;EDA(Event Driven Architecture)이란? | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;최근 기존 구조를 고도화하는 작업을 진행했습니다. 동기 처리되던 로직을 비동기로 변경하면서 EDA(Event Driven Architecture)를 도입하였습니다. 관련된 내용을 정리해보려고 합니다. EDA(Eventt Driven Ar&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/eda_1.b1f4eea.44b6014efa2517f0e3015313aa2c67f1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;최근 기존 구조를 고도화하는 작업을 진행했습니다.&lt;/p&gt;
&lt;p&gt;동기 처리되던 로직을 비동기로 변경하면서 EDA(Event Driven Architecture)를 도입하였습니다.&lt;/p&gt;
&lt;p&gt;관련된 내용을 정리해보려고 합니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;EDA(Eventt Driven Architecture)란?&lt;/h2&gt;
&lt;p&gt;분산된 시스템에서 &lt;b&gt;이벤트&lt;/b&gt;를 생성(발행)하고 발행된 이벤트를 수신자에게 전송하는 구조로 수신자는 그 이벤트를 처리하는 방식의 &lt;code&gt;아키텍처&lt;/code&gt;입니다.&lt;/p&gt;
&lt;p&gt;분산 아키텍처 환경에서 상호 간 결합도를 낮추기 위해 &lt;b&gt;비동기 방식으로 메시지를 전달하는 패턴&lt;/b&gt;으로 주로 Message Broker(&lt;code&gt;Kafka&lt;/code&gt;, &lt;code&gt;RabbitMQ&lt;/code&gt;)와 결합하여 구성됩니다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;EDA의 구성요소&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Event Generator (Publisher, Producer, Creater)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;표준화된 형식의 이벤트를 생성(발행)합니다. 생성된 이벤트는 &lt;code&gt;Event Channel&lt;/code&gt;로 전송합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Event Channel (Bus)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Event Generator&lt;/code&gt;에서 &lt;code&gt;Event Processing Engine&lt;/code&gt;으로 수집된 데이터를 전파하는 메커니즘입니다.&lt;/p&gt;
&lt;p&gt;즉, 이벤트를 필요로 하는 시스템까지 발송하는 역할입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Event Processing Engine (Consumer, Processor)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;수신한 이벤트를 식별/처리하는 역할을 합니다. 처리 결과에 따라 새로운 이벤트를 생성할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer&lt;/code&gt;는 이벤트의 송신자에 대한 정보를 알 필요가 없습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/eda_2.d25c033.c281ca3843c645c19e735dd11a992999.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;EDA의 동작 방식&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Message 생성 (Publish/Subscribe)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;이벤트&lt;/b&gt;가 생성되면 &lt;code&gt;Subscriber(수신자)&lt;/code&gt;에게 전달합니다.&lt;/p&gt;
&lt;p&gt;이벤트는 반복되어 전달되지 않으며, 수신자는 송신자의 정보를 알 필요가 없습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event Source&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Event Processor&lt;/code&gt;에게 이벤트를 전달하는 역할을 합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Event Source&lt;/code&gt;는 1개 이상일 수 있으며, 1개 이상의 &lt;code&gt;Event Processor&lt;/code&gt;에게 전달합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event Processor&lt;/p&gt;
&lt;p&gt;수신된 이벤트에 대한 여러 &lt;code&gt;Action&lt;/code&gt;을 수행하는 역할입니다.&lt;/p&gt;
&lt;p&gt;단일 이벤트에 대하여 타임스템프를 추가한다거나, 파생 이벤트를 만드는 등의 작업을 수행합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event Consumer&lt;/p&gt;
&lt;p&gt;이벤트에 대한 처리를 합니다. 실질적인 &lt;b&gt;Biz Logic&lt;/b&gt;을 수행합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Event Processing Style&lt;/h3&gt;
&lt;p&gt;각 특징에 맞게 4가지로 구분된 Event Process Style이 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Simple Event Processing&lt;/p&gt;
&lt;p&gt;각 이벤트가 직접적으로 수행할 &lt;code&gt;Action&lt;/code&gt;과 매핑됩니다.&lt;/p&gt;
&lt;p&gt;일반적으로 실시간 &lt;b&gt;작업의 흐름(Flow of Work)&lt;/b&gt;을 처리할 때 사용합니다.&lt;/p&gt;
&lt;p&gt;처리 시간과 비용이 적습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event Streaming Processing&lt;/p&gt;
&lt;p&gt;일반적인 이벤트와 중요한 이벤트가 모두 발생하며 이를 필터링하여 수신자에게 전달합니다.&lt;/p&gt;
&lt;p&gt;일반적으로 실시간 &lt;b&gt;정보의 흐름(Flow of Information)&lt;/b&gt;을 처리할 때 사용합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complex Event Processing&lt;/p&gt;
&lt;p&gt;일반적인 이벤트 패턴을 통해 복잡한 이벤트를 추론하는 방법입니다.&lt;/p&gt;
&lt;p&gt;예를 들면 일반적인 주식의 등락을 파악하여 투자할 타이밍을 추론할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Online Event Processing&lt;/p&gt;
&lt;p&gt;비동기 분산 이벤트 로그를 사용하여 복잡한 이벤트를 처리하며 지속해 데이터를 관리합니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;높은 확정성과 일관성&lt;/b&gt;을 가지며 유연하게 대처 가능한 패턴입니다.&lt;/p&gt;
&lt;p&gt;하지만 처리 시간을 보장할 수 없습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;토폴로지 구성&lt;/h2&gt;
&lt;p&gt;일반적으로 한가지 작업만 필요한 단순한 단일 이벤트일 경우에는 &lt;code&gt;Broker Topology&lt;/code&gt;를&lt;/p&gt;
&lt;p&gt;이벤트 조율이 필요한 복잡한 이벤트 플로우일 경우 &lt;code&gt;Mediator Topology&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Mediator Topology (중재자 토폴로지)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;여러 단계의 과정을 중재자를 통해 조율할 필요성이 있으면 일반적으로 사용합니다.&lt;/p&gt;
&lt;p&gt;동시에 처리하지 않거나 실행 전에 처리해야 할 요소가 있으 사용하는 토폴로지입니다.&lt;/p&gt;
&lt;p&gt;큐를 이용하여 사전처리를 진행한 후 관련된 &lt;code&gt;Consumer&lt;/code&gt;에게 전달합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/eda_3.670b0e6.b5c31c1e662a0bfea82c9b7816a90fad.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Broker Topology (브로커 토폴로지)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;큐나 중재자 없이&lt;/b&gt; 이벤트와 응답을 직접적으로 연관시키고자 할 때 사용합니다.&lt;/p&gt;
&lt;p&gt;이벤트 플로우가 단순한 중앙집중식 토폴로지이며 &lt;code&gt;Message Broker&lt;/code&gt;와 &lt;code&gt;Consumer&lt;/code&gt;가 가장 중요한 요소입니다.&lt;/p&gt;
&lt;p&gt;모든 작업은 비동기로 처리되며 이벤트에 대한 조율이 필요 없습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/eda_4.0314d39.7ba919f10f436c2f2d6684ad2226252f.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;EDA의 장단점&lt;/h2&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Loosely Coupling&lt;/p&gt;
&lt;p&gt;분산 시스템간 &lt;b&gt;느슨한 결합도&lt;/b&gt;를 제공합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;분산된 시스템간 의존성 배제&lt;/p&gt;
&lt;p&gt;&lt;b&gt;약속된 Message를 통해 통신&lt;/b&gt;하기 때문에 다른 시스템의 정보를 알 필요가 없으므로 시스템 간 의존성이 배제됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;확장성, 탄력성 향상&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Broker Dependency&lt;/p&gt;
&lt;p&gt;시스템 간 의존도는 낮아지지만 &lt;b&gt;메시지브로커에 대한 의존성&lt;/b&gt;이 발생합니다.&lt;/p&gt;
&lt;p&gt;만약 메시지 브로커의 장애가 발생하면 큰 장애로 확산될 가능성이 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transaction 단위 분리&lt;/p&gt;
&lt;p&gt;장애나 이슈발생시 &lt;b&gt;Retry/Rollback&lt;/b&gt;에 대한 고려가 필요합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;시스템 Flow파악이 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;디버깅이 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;EDA를 선택할 때 고려할 특징&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Multicast 통신&lt;/p&gt;
&lt;p&gt;한 개의 이벤트 &lt;code&gt;Publisher&lt;/code&gt;는 다양한 &lt;code&gt;Consumer&lt;/code&gt;에게 이벤트를 전달할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;실시간 전송&lt;/p&gt;
&lt;p&gt;실시간으로 발생하는 이벤트에 대한 처리가 가능합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비동기 통신&lt;/p&gt;
&lt;p&gt;비동기로 통신이 이루어지므로 &lt;code&gt;Publisher&lt;/code&gt;는 처리 결과를 기다릴 필요가 없습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;세밀한 통신&lt;/p&gt;
&lt;p&gt;한 덩어리의 큰 이벤트(데이터)보다 작고 자세한 이벤트로 통신이 이루어집니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이벤트 온톨로지&lt;/p&gt;
&lt;p&gt;이벤트들은 확실하게 구분된 특징을 지니며 그에 상응하는 &lt;code&gt;Consumer&lt;/code&gt;에게 전달됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;자유로운 배포&lt;/p&gt;
&lt;p&gt;느슨할 결합도를 제공하므로 새로운 서비스의 배포가 자유롭습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;요약&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://akasai.space/assets/static/eda_5.087b3d3.6919f370881ad1787877db4ae1342b65.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;프로그래밍 관점뿐만아니라 다방면에서 적용가능한 아키텍처 패턴입니다.&lt;/p&gt;
&lt;p&gt;복잡성/역동성에 가장 효율적으로 대응가능한 아키텍처입니다.&lt;/p&gt;
&lt;p&gt;이벤트를 통해 데이터간 연결이 생성된다는 점이 가장 중요하므로 &lt;b&gt;EDA에는 고정된 구조가 없습니다.&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;특징을 잘 파악하고 적절히 사용한다면 상당히 만족스러운 아키텍처 설계를 할 수 있을 것입니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.xenonstack.com/blog/eda-for-cloud-native-kubernetes/&quot;&gt;Event-Driven Architecture for Cloud-Native in Kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.theodo.com/2019/08/event-driven-architectures-rabbitmq/&quot;&gt;Introduction to Event-driven Architectures With RabbitMQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch02.html&quot;&gt;Event-Driven Architecture&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jaehue.github.io/post/event-driven/#fn:3&quot;&gt;내 멋대로 구현한 이벤트 드리븐&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Architecture</category>
      <category>architecture</category>
      <category>event driven</category>
      <category>아키텍처</category>
      <category>이벤트 드리븐</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/27</guid>
      <comments>https://akasai.tistory.com/27#entry27comment</comments>
      <pubDate>Thu, 11 Feb 2021 00:13:02 +0900</pubDate>
    </item>
    <item>
      <title>PUBG 경력 채용 후기</title>
      <link>https://akasai.tistory.com/26</link>
      <description>&lt;p&gt;작년 하반기에 지원했었던 경험을 간단하게 적어보려고 합니다.&lt;/p&gt;
&lt;p&gt;시간이 꽤 지났지만 크게 문제 되지 않는 정도만 적어보겠습니다.&lt;/p&gt;
&lt;p&gt;게임 개발 파트가 아니라 백오피스 &lt;b&gt;서버 개발 부분이었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;현재는 크래프톤으로 합병된 걸로 알고 있습니다.&lt;/p&gt;
&lt;h2&gt;전형 방법&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;서류전형&lt;/code&gt; &amp;rarr; &lt;code&gt;필기 테스트&lt;/code&gt; &amp;rarr; &lt;code&gt;기술면접&lt;/code&gt; &amp;rarr; &lt;code&gt;임원면접&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;서류전형&lt;/h2&gt;
&lt;p&gt;원티드에 뜬 채용공고를 보고 지원하였습니다.&lt;/p&gt;
&lt;p&gt;원티드가 답변이 다소 느린 느낌을 받아서 따로 이력서를 작성한 뒤 &lt;a href=&quot;https://careers.pubg.com/#/ko/seoul&quot;&gt;PUBG 채용사이트&lt;/a&gt;에서 직접 제출하였습니다.&lt;/p&gt;
&lt;p&gt;지금까지 진행했던 프로젝트를 기반의 이력서를 작성하였습니다.&lt;/p&gt;
&lt;p&gt;약 1주일 정도 후에 결과 메일을 받았습니다. 향후 진행될 테스트에 대한 일정 조율이 메일로 진행되었습니다.&lt;/p&gt;
&lt;h2&gt;필기 테스트&lt;/h2&gt;
&lt;p&gt;코딩 테스트를 무서워하는 편이라 필기 테스트라는 소식에 &lt;b&gt;조금&lt;/b&gt; 안심했습니다.&lt;/p&gt;
&lt;p&gt;(물론 의미 없는 안심이었습니다.)&lt;/p&gt;
&lt;p&gt;시험은 &lt;b&gt;서초사옥&lt;/b&gt;에서 진행되었고 &lt;b&gt;1시간 30분&lt;/b&gt; 동안 문제를 풀었습니다.&lt;/p&gt;
&lt;h3&gt;문제 유형&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;서술형 문제&lt;/code&gt;&lt;br /&gt;특정 키워드에 대한 설명을 하는 서술형 문제가 다수 출제되었습니다.&lt;br /&gt;&lt;b&gt;CS기본, 아키텍처, DB기본 이론, 기초 보안&lt;/b&gt; 등 기본적인 기술에 대한 지식이 필요했습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;손 코딩 문제&lt;/code&gt;&lt;br /&gt;두 종류의 손코딩 문제가 나왔습니다.&lt;br /&gt;특정 코드를 제시하고 그 결과를 예상하는 문제.&lt;br /&gt;실제 알고리즘 구현을 요구하는 코딩 문제.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;실무적용 문제&lt;/code&gt;&lt;br /&gt;실제 실무에서 생각해볼 만한 문제가 나왔습니다.&lt;br /&gt;특정 문제 상황을 제시하고 그 문제를 해결하는 방법을 서술하는 문제.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;까다로운 문제도 몇 개 있었으며, 완벽하게 풀지는 못했습니다.&lt;/p&gt;
&lt;p&gt;아는 부분은 확실하게 적었지만, 애매한 문제들은 최대한 적으려고 했습니다.&lt;/p&gt;
&lt;p&gt;약 1주일 정도 후에 결과 메일을 받았고, 서류전형과 동일하게 차후 면접 일정을 조율했습니다.&lt;/p&gt;
&lt;h2&gt;기술면접&lt;/h2&gt;
&lt;p&gt;필기 테스트와 마찬가지로 &lt;b&gt;서초사옥&lt;/b&gt;에서 진행되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1:3 면접&lt;/b&gt;이었지만 사측의 사정으로 &lt;b&gt;1시간&lt;/b&gt; 동안 &lt;b&gt;1:2 면접&lt;/b&gt;이 진행되었습니다.&lt;/p&gt;
&lt;p&gt;면접관은 실제 같이 업무를 하게 될 &lt;b&gt;시니어&lt;/b&gt;분들이었습니다.&lt;/p&gt;
&lt;h3&gt;유형&lt;/h3&gt;
&lt;p&gt;경력 면접이니 만큼 경력 기반의 질문이 많이 이루어졌습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;이직사유&lt;/li&gt;
&lt;li&gt;진행했던 프로젝트에서 이어지는 연계 질문&lt;/li&gt;
&lt;li&gt;활용 가능 기술 스택 기반의 질문&lt;/li&gt;
&lt;li&gt;PUBG에서 사용하는 기술스택 기반의 질문&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;자세한 질문 내용은 남기기 힘들지만 경력 면접다운 질문들이 대다수였습니다.&lt;/p&gt;
&lt;p&gt;가장 중요한 건 본인이 사용해본 기술들에 대한 확실한 이해 도라고 생각합니다.&lt;/p&gt;
&lt;p&gt;기존 전형들과 마찬가지로 1주일 후에 결과 메일을 받았고, 차후 면접 일정을 조율했습니다.&lt;/p&gt;
&lt;p&gt;다른 회사들과 다르게 이 단계에서 &lt;b&gt;원천징수 영수증, 직전 연봉계약서, 희망연봉&lt;/b&gt; 등의 정보를 요청했습니다.&lt;/p&gt;
&lt;h2&gt;임원면접&lt;/h2&gt;
&lt;p&gt;마지막 면접이었습니다.&lt;/p&gt;
&lt;p&gt;앞선 두 전형과 동일하게 &lt;b&gt;서초사옥&lt;/b&gt;에서 진행하였고 기존 회의실과 다른 회의실에서 진행하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;개발본부장님&lt;/b&gt;과 &lt;b&gt;HR 담당자&lt;/b&gt; 두 분이 참여하였습니다.&lt;/p&gt;
&lt;p&gt;원래는 부사장님도 참여하신다고 합니다. (다행히 전 못 뵀습니다.)&lt;/p&gt;
&lt;p&gt;1시간 진행된다고 하셨지만 &lt;b&gt;약 40분 정도&lt;/b&gt; 소요되었습니다.&lt;/p&gt;
&lt;h3&gt;유형&lt;/h3&gt;
&lt;p&gt;기술면접 정도의 질문은 아니었지만 약간의 기술적인 부분이 포함된 면접이었습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;기술 기반의 질문.&lt;/li&gt;
&lt;li&gt;동료들과 협업과 관련된 질문(인성 질문).&lt;/li&gt;
&lt;li&gt;평소 성장을 위해 어떤 노력을 하는지?&lt;/li&gt;
&lt;li&gt;인사 관련 질문&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;정답이 있는 질문들은 아녔습니다.&lt;/p&gt;
&lt;p&gt;본인의 경험 등을 바탕으로 소신 있게 답변하였습니다.&lt;/p&gt;
&lt;p&gt;사전에 제출한 &lt;b&gt;연봉 관련 정보를 바탕으로 확인하는 시간&lt;/b&gt;을 마지막으로 면접이 종료되었습니다.&lt;/p&gt;
&lt;p&gt;최종면접자들에게는 &lt;code&gt;소정의 상품(다이어리)&lt;/code&gt;을 제공하였습니다.&lt;/p&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;1주일 단위로 빠르게 전형이 진행되었기 때문에 지원자 입장에선 매우 만족스러웠습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;최종 결과는 유선을 통해 전달받았고,&lt;/b&gt; 동시에 &lt;code&gt;연봉 조율&lt;/code&gt;을 진행하였습니다.&lt;/p&gt;
&lt;p&gt;면접 과정에서 불편한 부분도 분명 존재했습니다. 하지만 회사와 팀이 원하는 바를 알 수 있는 과정이었다고 생각합니다.&lt;/p&gt;
&lt;p&gt;개인적인 사정으로 최종 입사는 고사하였지만, 이 내용이 도움이 되면 좋겠습니다.&lt;/p&gt;</description>
      <category>ETC</category>
      <category>PUBG</category>
      <category>경력채용</category>
      <category>면접</category>
      <category>백엔드</category>
      <category>서버</category>
      <category>펍지</category>
      <category>후기</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/26</guid>
      <comments>https://akasai.tistory.com/26#entry26comment</comments>
      <pubDate>Fri, 29 Jan 2021 01:41:28 +0900</pubDate>
    </item>
    <item>
      <title>async/await 병목현상 줄여보기</title>
      <link>https://akasai.tistory.com/25</link>
      <description>&lt;figure id=&quot;og_1611829693852&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;async/await 병목현상 줄여보기 | devlog.akasai&quot; data-og-description=&quot;블로그 글을 보다 나는 지금 어떻게 개발하고 있는지 궁금해서 직접 테스트해보았다. async/await를 습관적으로 쓰고 있지만, 잘 쓰고 있는지 되돌아보는 계기가 되었다. Async/Await의 병목현상 Promise&quot; data-og-host=&quot;akasai.space&quot; data-og-source-url=&quot;https://akasai.space/hr-await-bottle-neck&quot; data-og-url=&quot;https://akasai.github.io/hr-await-bottle-neck/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KxpJq/hyI52zBhwk/KPfl1kk7yCvInymsQkUdqk/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://akasai.space/hr-await-bottle-neck&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://akasai.space/hr-await-bottle-neck&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KxpJq/hyI52zBhwk/KPfl1kk7yCvInymsQkUdqk/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;async/await 병목현상 줄여보기 | devlog.akasai&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;블로그 글을 보다 나는 지금 어떻게 개발하고 있는지 궁금해서 직접 테스트해보았다. async/await를 습관적으로 쓰고 있지만, 잘 쓰고 있는지 되돌아보는 계기가 되었다. Async/Await의 병목현상 Promise&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;akasai.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;블로그 글을 보다 나는 지금 어떻게 개발하고 있는지 궁금해서 직접 테스트해보았다.&lt;/p&gt;
&lt;p&gt;async/await를 습관적으로 쓰고 있지만, 잘 쓰고 있는지 되돌아보는 계기가 되었다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Async/Await의 병목현상&lt;/h2&gt;
&lt;p&gt;Promise의 등장으로 &lt;code&gt;callback&lt;/code&gt; 함수 불편한 부분이 많이 개선되었다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;async/await&lt;/b&gt;의 등장은 &lt;code&gt;.then()&lt;/code&gt; 체인으로 인한 가독성까지도 보완하였다.&lt;/p&gt;
&lt;p&gt;하지만, 정리되지 않은 사용은 함수 수행시간에 상당한 영향을 줄 수 있다.&lt;/p&gt;
&lt;h3&gt;함수 정의&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const Promise1 = () =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, 1000))

const Promise2 = () =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, 1100))

const Promise3 = () =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, 1200, 900))

const Promise4 = (time) =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, time))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;테스트를 위해 각각 &lt;b&gt;1000, 1100, 1200&lt;/b&gt; 그리고 &lt;b&gt;param&lt;/b&gt; 값 만큼 딜레이되는 Promise함수를 만들었다.&lt;/p&gt;
&lt;h3&gt;현상 확인&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const main = async () =&amp;gt; {

    const test1 = await Promise1() // 1000
    const test2 = await Promise2() // 1100
    const test3 = await Promise3() // 1200
    const test4 = await Promise4(test3) // 900

}

main();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 함수들을 &lt;b&gt;async/await&lt;/b&gt; 를 이용하여 실행시키면 동기적으로 동작하기 때문에 총 &lt;b&gt;4200ms&lt;/b&gt; 의 수행속도를 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;callout&quot;&gt;Nodejs의 이벤트 처리 특성상 정확히 &lt;b&gt;4200ms&lt;/b&gt;가 나오지 않을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Promise.all&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const main = async () =&amp;gt; {

    const [test1, test2, test3] = await Promise.all([
        Promise1(),
        Promise2(), 
        Promise3(), 
    ]) 
    const test4 = await Promise4(test3) 

}

main();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Promise 함수들을 동시처리할 때 가장많이 사용하는 함수인 &lt;code&gt;Promise.all&lt;/code&gt; 을 이용하여 &lt;b&gt;4200ms&lt;/b&gt; 에서 &lt;b&gt;2100ms&lt;/b&gt;까지 성능개선을 하였다.&lt;/p&gt;
&lt;p&gt;거의 절반에 가까운 개선이다.&lt;/p&gt;
&lt;p&gt;각 함수들간 의존성이 없을 땐 &lt;code&gt;Promise.all&lt;/code&gt;을 이용하면 상당한 효과를 볼 수 있다.&lt;/p&gt;
&lt;h3&gt;의존성을 갖는 함수&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const main = async () =&amp;gt; {

    const [test1, test2, test3] = await Promise.all([
        Promise1(), 
        Promise2(), 
        Promise4(await Promise3())
    ]) 

}

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 의존성을 갖는 함수의 수행위치를 변경하면 속도 개선을 기대할 수 있다.&lt;/p&gt;
&lt;p&gt;하지만 위 코드의 수행속도는 &lt;b&gt;2100ms&lt;/b&gt; 으로 앞서 수행했던 코드와 동일하다.&lt;/p&gt;
&lt;p&gt;왜 일까??&lt;/p&gt;
&lt;h3&gt;최적화된 코드&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Promise.all&lt;/code&gt; 을 이용한 개선 결과를 보면 수행시간이 같은 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;이는 처음 구성했던 함수들의 수행시간과 연관이 있다. 개선이 기대되는 함수 &lt;code&gt;Promise3&lt;/code&gt;의 수행시간이 &lt;b&gt;1200ms&lt;/b&gt;로 가장 늦게 종료되는 함수였기 때문에 Worst-case의 수행시간이 측정되었다.&lt;/p&gt;
&lt;p&gt;첫 함수의 조건을 좀 변경해보면 눈에 띄는 결과를 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const Promise1 = () =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, 3000, 1))

const Promise2 = () =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, 1100, 2))

const Promise3 = () =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, 100, 900))

const Promise4 = (time) =&amp;gt; new Promise((resolve) =&amp;gt; setTimeout(resolve, time || 0))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각 함수들의 수행시간을 &lt;b&gt;3000, 1100, 100&lt;/b&gt; 로 변경하였다.&lt;/p&gt;
&lt;p&gt;위 내용을 바탕으로 동기적으로 함수들을 수행해보면 &lt;b&gt;5100ms&lt;/b&gt;의 수행시간을 기대할 수 있다.&lt;/p&gt;
&lt;p&gt;함수들을 각각 개선해보면 &lt;b&gt;3900ms&lt;/b&gt;까지 줄일 수 있었고, 다시 한번 위쪽의 개선코드를 적용해보았다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const main = async () =&amp;gt; {

    const [test1, test2, test3] = await Promise.all([
        Promise1(),
        Promise2(),
        Promise4(await Promise3())
    ]) 

}

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 적용했을 때, &lt;b&gt;3000ms&lt;/b&gt; 의 결과를 얻었다. 무료 2100ms의 절감효과를 보았다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;결론&lt;/h2&gt;
&lt;p&gt;async/await는 동기적 프로그래밍에 있어 상당히 도움이 되고, 가독성 역시 꽤 높여주고 있다.&lt;/p&gt;
&lt;p&gt;적절한 사용은 큰 문제가 없지만, 다수의 await을 사용은 성능에 큰 영향을 줄 수 있다.&lt;/p&gt;
&lt;p&gt;구현할 때, 함수간 &lt;span class=&quot;em red&quot;&gt;의존성&lt;/span&gt;을 정확히 판단하여 &lt;code&gt;Promise.all&lt;/code&gt;등의 함수를 적절히 사용한다면&lt;br /&gt;미미할지라도 성능향상을 기대할 수 있을 것 같다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://jaeheon.kr/161?utm_source=gaerae.com&amp;amp;utm_campaign=%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%8A%A4%EB%9F%BD%EB%8B%A4&amp;amp;utm_medium=social&amp;amp;fbclid=IwAR3zIs9MMfUi_y-CaiCd9dgJaumpMBzOjdUJFXNg2pWFGioUeDv7pFVsoD8&quot;&gt;await의 함정, 숨은 병목을 찾자&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Node.js</category>
      <category>async</category>
      <category>await</category>
      <category>es6</category>
      <category>JavaScript</category>
      <category>node.js</category>
      <category>promise</category>
      <author>akasai</author>
      <guid isPermaLink="true">https://akasai.tistory.com/25</guid>
      <comments>https://akasai.tistory.com/25#entry25comment</comments>
      <pubDate>Thu, 28 Jan 2021 19:27:44 +0900</pubDate>
    </item>
  </channel>
</rss>