<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>binary-kim 님의 블로그</title>
    <link>https://binary-kim.tistory.com/</link>
    <description>binary-kim 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Tue, 28 Jul 2026 10:14:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>binary-kim</managingEditor>
    <item>
      <title>글또 10기 후기...</title>
      <link>https://binary-kim.tistory.com/30</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;개요&lt;/h4&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;작년 10월 즈음부터 시작했던 글또 10기가 마지막 제출을 앞두고 있어, 마지막 포스팅은 후기를 작성하고자 한다.&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우선, 내가 글또를 참여하게 되었던 계기는 정리해보면 아래 세 가지였던 것 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;꾸준히 공부하며 내 생각을 잘 표현하는 방법을 배우는 것&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;6개월 전의 나와 현재의 나를 비교한다면, 위 세가지 참여 계기를 잘 지켜온 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;꾸준히 공부하며 내 생각을 잘 표현하는 방법을 배우는 것&lt;/h4&gt;
&lt;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;글또 활동 이후에도 글을 작성할 것이냐는 질문이 들어온다면, 나는 &quot;&lt;b&gt;기존 글또 프로세스와 동일하게 2주에 하나의 글을 작성하고 공유할 것&lt;/b&gt;&quot;이라고 말할 것이다. 이유는 몇년 전부터 미루던 개발 블로그 작성이라는 목표를 글또를 시작하며 이뤄냈기 때문이다. 그리고 한 번 작성하지 않기 시작하면 6개월 동안 습관들이기 위해 노력했던 시간이 굉장히 아쉬움으로 남을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;나와 비슷한 업무를 하는 사람들과 이야기를 나눠보며 성장하는 것&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참여 계기 중 가장 지키지 못한 부분이라고 생각한다. 다른 사람들이 작성하여 공유해주시는 내용을 많이 읽기는 했지만, 그러한 글을 읽으면서 스스로 생각하고 고민했던 부분들을 충분히 공유하지 못했던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅을 작성하면서 이유를 생각해보니,&amp;nbsp;&quot;&lt;b&gt;내가 말한 내용이 틀릴 수도 있을까봐 두려워했던 것&lt;/b&gt;&quot;이 가장 큰 원인이었던 것 같다.&amp;nbsp;다음 글또같은 활동이 있을 지 잘 모르겠지만, 다음 활동에서는 부끄러워하거나 두려워하지말고 채널 내/외 동료분들과 적극적으로 소통을 진행해보고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;글또의 장점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각하는 글또의 장점은 &quot;&lt;b&gt;좋은 커뮤니티&lt;/b&gt;&quot;와 &quot;&lt;b&gt;동기 부여&lt;/b&gt;&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;SNS나 링크드인 등 여러가지 커뮤니티가 존재하지만, 글또만큼 활성화되어 있고 편한 커뮤니티는 없다고 생각한다.&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;그리고, 다른 동료 개발자들이 꾸준히 글을 작성하는 것을 보고 &quot;나는 이번 주 어떤 글을 쓸까?&quot;하는 생각을 항상 가지고 살아왔던 것 같다. 미루고 싶었던 순간들도 굉장히 많이 존재했지만 채널에 올라오는 글을 하나씩 읽으며 동기부여를 받았고, 12회차 중 11회차 글을 작성할 수 있게 해줬기에 또 다른 글또의 장점으로 뽑았다.&lt;/p&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;&quot;&lt;b&gt;마지막 기수라 굉장히 아쉽지만, 꾸준하게 글쓰기를 하게 해준 운영진분들께 감사함을 표현하고 싶다&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/30</guid>
      <comments>https://binary-kim.tistory.com/30#entry30comment</comments>
      <pubDate>Sun, 23 Mar 2025 17:36:57 +0900</pubDate>
    </item>
    <item>
      <title>SAP 데이터를 추출하며..</title>
      <link>https://binary-kim.tistory.com/29</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 DE 직무로 근무하며 현재는 Data Hub를 구축하는 업무를 진행하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원천 시스템이 RDB (Oracle / MariaDB / Tibero / ...)가 아닌 SAP인 경우가 많이 존재했고, 이는 나에게 굉장한 혼란을 주었다.&lt;/p&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;나는 SAP이 뭔지 몰랐다. (&lt;s&gt;ASAP은 안다&lt;/s&gt;). SAP이라는 시스템이 뭔지 잘 모르는 상황에서, 데이터를 수집하여 Hub 구축을 진행해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅을 읽는 사람들 중, SAP을 개발하시는 분이라면 아래와 같이 생각할 수 있다.&lt;/p&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;SAP 솔루션 쓰면 모든게 해결되지 않나...???&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;회사에서 SAP 솔루션이나 SAP BW를 사용하면 데이터 추출 / 수정 등의 관리가 용이하지만, 현재 우리 회사는 안타깝게도 따로 어떠한 솔루션을 사용하고 있지 않다. 이에, PyRFC라는 라이브러리를 활용하여 SAP 내부의 Function Module을 호출하고, 이를 통해 SAP 시스템 내부의 테이블 / 컬럼 등의 정보를 추출하여 Hub 구축을 진행하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 게시글에선 SAP을 처음 사용해보며 유용하다고 느낀 기능들을 정리해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SAP GUI&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 SAP GUI를 들어가면 굉장히 옛날 시스템적인?? 디자인이 나를 맞이해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무거나 클릭해보고 싶지만, 관리자가 아닌 권한을 발급받아 접근하는 개발자 입장에선 조심히 사용해야 할 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 나는 MAC용을 사용하고 있고, 설치는 &lt;a title=&quot;링크&quot; href=&quot;https://www.sapvista.com/sap-gui-770-installation-guide-for-mac-ios&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;에서 진행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/conbbk/btsMNi6DAxw/oW9NNk1zQBm04bNycuyF60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/conbbk/btsMNi6DAxw/oW9NNk1zQBm04bNycuyF60/img.png&quot; data-alt=&quot;Topbar&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/conbbk/btsMNi6DAxw/oW9NNk1zQBm04bNycuyF60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fconbbk%2FbtsMNi6DAxw%2FoW9NNk1zQBm04bNycuyF60%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;500&quot; height=&quot;87&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Topbar&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Topbar&lt;/b&gt;를 유심히 보면, &lt;b&gt;좌측 상단&lt;/b&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;가장 실용적이면서 SAP 시스템을 사용할 때 필요한 트랜잭션 코드를 확인해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ABAP Dictionary&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1606&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccusF0/btsMLYO6AvO/6mhSIqVUWyQXZ2i3wYAvr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccusF0/btsMLYO6AvO/6mhSIqVUWyQXZ2i3wYAvr1/img.png&quot; data-alt=&quot;T-CODE: SE11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccusF0/btsMLYO6AvO/6mhSIqVUWyQXZ2i3wYAvr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccusF0%2FbtsMLYO6AvO%2F6mhSIqVUWyQXZ2i3wYAvr1%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;500&quot; height=&quot;296&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1606&quot; data-origin-height=&quot;891&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;T-CODE: SE11&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;&quot;&lt;b&gt;SE11&lt;/b&gt;&quot;을 검색하면, ABAP Dictionary가 나오게 된다. 해당 트랜잭션은 SAP에서 사용되는 데이터 구조 및 속성을 정리하여 관리할 수 있는 부분이다. 즉, 특정 테이블의 스키마를 세부적으로 분석하고 싶을 때 활용할 수 있는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SAP 시스템 내부에 존재하는 테이블 [ex) DD02L, DD03L, ...]을 검색하면 아래와 같은 정보를 얻을 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블 이름 및 설명 (어떤 역할의 테이블인지 Description)&lt;/li&gt;
&lt;li&gt;필드 이름 / 데이터 타입 / PK-FK 정보&lt;/li&gt;
&lt;li&gt;어떤 데이터 요소 (Data Element)를 사용하는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kC2jV/btsMMyWszll/lFSYq3KsRfZlvAbbZnaQKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kC2jV/btsMMyWszll/lFSYq3KsRfZlvAbbZnaQKK/img.png&quot; data-alt=&quot;Table 상세 Option&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kC2jV/btsMMyWszll/lFSYq3KsRfZlvAbbZnaQKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkC2jV%2FbtsMMyWszll%2FlFSYq3KsRfZlvAbbZnaQKK%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;500&quot; height=&quot;544&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Table 상세 Option&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;SAP 솔루션을 사용하면 테이블 스키마의 변경 사항을 자동으로 탐지하여 확인할 수 있지만, 그렇지 못한 경우에는 차선책이 필요하다. &quot;SE11&quot; 트랜잭션에서 Table 옵션 설정을 진행할 수 있는데, &quot;&lt;b&gt;Data Changes&lt;/b&gt;&quot;를 클릭하게 되면 &quot;&lt;b&gt;CDPOS&lt;/b&gt;&quot;, &quot;&lt;b&gt;CDHDR&lt;/b&gt;&quot;에 변경 사항에 대한 로그가 남는다고 한다. (해당 부분을 어떻게 분석하는 지는 추후에 공부해볼 예정이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Object Navigator&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;SE80&lt;/b&gt;&quot;을 검색하면, 객체 탐색기라는 부분이 나오게 된다. 해당 트랜잭션은 패키지 / 프로그램 / 클래스 / 함수 모듈 등을 통합적으로 관리할 수 있는 부분이다. &quot;&lt;b&gt;SE37&lt;/b&gt;&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;b&gt;Display / Change / Create&lt;/b&gt; 등의 옵션을 선택할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Display 옵션을 클릭하는 경우, 해당 Function Module이 어떤 로직으로 구현되어 있는지&amp;nbsp;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ABAP 언어로 확인할 수 있다.&amp;nbsp;&lt;/span&gt;실제 Change나 Create 작업을 진행하기 위해서는 &lt;b&gt;CTS&lt;/b&gt;(Change and Transport System) 번호가 필요하며, Git 시스템에서 일종의 Commit 번호라고 생각하면 된다. 해당 번호가 있어야 내가 변경한 이력이 남게 되고, 그 부분을 배포 요청하여 내가 개발한 함수 모듈을 시스템에서 활용할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 모듈 Interface는 아래와 같은 정보를 입력으로 받는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Import: 함수에 입력할 값&lt;/li&gt;
&lt;li&gt;Export: 함수에서 반환할 값&lt;/li&gt;
&lt;li&gt;Changing: 함수 실행 중 변경 가능한 변수&lt;/li&gt;
&lt;li&gt;Tables: 테이블 데이터 처리 시 활용&lt;/li&gt;
&lt;li&gt;Exceptions: 특정 오류 발생 시 예외 처리 로직 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 트랜잭션 페이지에서는 내가 개발한 함수 모듈을 테스트 및 디버깅할 수 있다는 장점도 존재한다.&amp;nbsp;우선, 개발한 함수 모듈을 디버깅 하기 위해서는 Activate (활성화) 상태로 변경되어야 하고, 그 후에 Execute (실행)를 진행하여 함수 모듈이 의도대로 동작하는지 파악할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Vhzn/btsMMz8Us7w/XbKquYOT4pNZjrjPBTsbx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Vhzn/btsMMz8Us7w/XbKquYOT4pNZjrjPBTsbx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Vhzn/btsMMz8Us7w/XbKquYOT4pNZjrjPBTsbx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Vhzn%2FbtsMMz8Us7w%2FXbKquYOT4pNZjrjPBTsbx0%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;500&quot; height=&quot;96&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRBZAJ/btsMLMOGJD6/ObbCaHvxssXFbkc7P4CxP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRBZAJ/btsMLMOGJD6/ObbCaHvxssXFbkc7P4CxP0/img.png&quot; data-alt=&quot;Activate / Test / Execute&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRBZAJ/btsMLMOGJD6/ObbCaHvxssXFbkc7P4CxP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRBZAJ%2FbtsMLMOGJD6%2FObbCaHvxssXFbkc7P4CxP0%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;500&quot; height=&quot;81&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Activate / Test / Execute&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Function Module&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python에서 내장 라이브러리가 있듯이, SAP에서도 비슷하게 사용자가 원하는 의도대로 동작하는 함수를 개발할 수 있으며 이를 함수 모듈 (Function Module) 이라 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 테이블에서 상위 5개의 컬럼 정보만 가져오는 로직을 구현하고자 하는 상황이라고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 가지 해결 방법이 있겠지만, 크게 두 가지로 비교를 해본다면 ...&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SAP -&amp;gt; Local 서버로 데이터를 다 가져온 다음, Python / PySpark / ... 등으로 처리하는 방법&lt;/li&gt;
&lt;li&gt;데이터를 가져올 때부터 원하는 컬럼만 추출해서 가져오는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 서비스를 운영할 때 가장 비용(Cost)이 많이 사용되는 부분은 &quot;&lt;b&gt;네트워크 간 데이터 이동&lt;/b&gt;&quot;이다. 그렇기 때문에, Function Module을 개발해서 RFC로 호출하는게 Local에 다 가지고 와서 처리하는 부분보다 효율적이지 않을까 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Function Module 배포&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;SE09&lt;/b&gt;&quot;를 검색하면, 특정 SAP 시스템에서 내가 개발한 Function Module / ... 의 이력을 확인할 수 있다. Function Module 배포는 Git에 Commit / Push / MR 날리는 부분과 굉장히 유사하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br6lFi/btsMMnOk1XO/23jftlCdTRhLk5JexJn5Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br6lFi/btsMMnOk1XO/23jftlCdTRhLk5JexJn5Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br6lFi/btsMMnOk1XO/23jftlCdTRhLk5JexJn5Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr6lFi%2FbtsMMnOk1XO%2F23jftlCdTRhLk5JexJn5Ck%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;500&quot; height=&quot;154&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Function Module 개발 및 테스트(&lt;b&gt;CTS 번호 생성)&lt;/b&gt; -&amp;gt; Commit 번호&lt;/li&gt;
&lt;li&gt;Function Module Release (&lt;b&gt;트럭 버튼&lt;/b&gt;) -&amp;gt; Git Push&lt;/li&gt;
&lt;li&gt;SAP 시스템 담당자에게 배포 요청 -&amp;gt; Merge Request&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시라도 Function Module을 배포해야 할 일이 존재한다면, 해당 과정을 참조하면 수월하게 진행할 수 있을 것이라 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;SQL Editor&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;DB02&lt;/b&gt;&quot;를 검색하면 아래와 같이 SQL 쿼리를 날리고 결과를 확인할 수 있는 부분이 존재한다.&amp;nbsp;Function Module을 호출하거나 SAP 솔루션을 통해 데이터를 확인하는 방법도 있지만, 누구에게는 이러한 방식이 굉장히 귀찮고 불필요한 과정이라고 생각이 들 수 있다. 이럴 때 굉장히 유용하게 사용할 수 있는 부분이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vCp1F/btsMNhUbo29/GMXffhvFCqhkn0NDTRkbkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vCp1F/btsMNhUbo29/GMXffhvFCqhkn0NDTRkbkk/img.png&quot; data-alt=&quot;SQL Editor&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vCp1F/btsMNhUbo29/GMXffhvFCqhkn0NDTRkbkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvCp1F%2FbtsMNhUbo29%2FGMXffhvFCqhkn0NDTRkbkk%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;500&quot; height=&quot;215&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1216&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SQL Editor&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;쿼리문을 작성할 때 중간에 수정하게 되면 한 칸씩 밀리게 되어 (word에서 insert 눌렀을 때 발생하는 현상) 불편함을 꽤 경험했던 기억이 난다. 혹시라고 해당 트랜잭션을 활용하시는 분은&amp;nbsp;중간 중간에 개행을 꼭 넣어줌으로써 쿼리 작성에 도움이 되었으면 좋겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;마무리하며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 게시글에서는 실제 회사에서 레거시 시스템의 원천인 SAP을 직접 다뤄보면서 초급자들에게 공유하면 좋을 이야기들을 위주로 정리하는 시간을 가져봤다.&amp;nbsp;다음 게시글은 PyRFC라는 라이브러리를 어떻게 적용하고 활용하고 있는지 기록해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;</description>
      <category>Function Module</category>
      <category>RFC</category>
      <category>sap</category>
      <category>SAP Gui</category>
      <category>T-CODE</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/29</guid>
      <comments>https://binary-kim.tistory.com/29#entry29comment</comments>
      <pubDate>Sun, 16 Mar 2025 16:00:00 +0900</pubDate>
    </item>
    <item>
      <title>[글또 챌린지 시즌2] 코드트리 이용 1달 후기</title>
      <link>https://binary-kim.tistory.com/28</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최근 글쓰기 모임 '글또'에서 진행하는 코드트리 챌린지에 참여하며, 코딩 학습에 대한 새로운 가능성을 발견했습니다. 코드트리가 제공하는 체계적인 커리큘럼과 풍부한 학습 콘텐츠는 저에게 깊은 인상을 남겼으며, 이에 대한 후기를 공유하고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[1] 체계적인 학습의 시작: Trail&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드트리 챌린지에서 가장 주목할 만한 기능은 'Trail'입니다. 이 기능은 알고리즘의 기초부터 심화까지, 단계별로 학습할 수 있도록 설계된 체계적인 커리큘럼을 제공합니다. 마치 잘 짜여진 학습 로드맵을 따라가는 듯한 느낌을 주며, 학습자가 혼란 없이 목표를 향해 나아갈 수 있도록 돕습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhZVwI/btsL4L4joxc/gq52aXlSWj6tBZmG6XvCC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhZVwI/btsL4L4joxc/gq52aXlSWj6tBZmG6XvCC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhZVwI/btsL4L4joxc/gq52aXlSWj6tBZmG6XvCC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhZVwI%2FbtsL4L4joxc%2Fgq52aXlSWj6tBZmG6XvCC0%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;500&quot; height=&quot;372&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;496&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각 섹션은 기본 개념, 문제, 해설, 토론 탭으로 구성되어 있어 학습의 효율성을 높입니다. 특히, 문제 풀이 중 어려움에 직면했을 때, 기본 개념 탭과 토론 탭을 통해 즉각적으로 궁금증을 해소하고 문제 해결 능력을 향상시킬 수 있었습니다. 또한, 난이도를 Novice Low부터 Intermediate High까지 6단계로 세분화하여 학습자 수준에 맞는 문제를 선택할 수 있도록 한 점은 매우 만족스러웠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FiWex/btsL4HgABgg/ZsufM09IJIV4q9ftWmInd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FiWex/btsL4HgABgg/ZsufM09IJIV4q9ftWmInd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FiWex/btsL4HgABgg/ZsufM09IJIV4q9ftWmInd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFiWex%2FbtsL4HgABgg%2FZsufM09IJIV4q9ftWmInd1%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;500&quot; height=&quot;397&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[2] 실력 점검의 기회: 실력 진단&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드트리에서 제공하는 '실력 진단' 기능은 단순한 모의 테스트를 넘어, 실제 코딩 테스트 환경을 완벽하게 재현한 경험을 제공합니다. 주 1회 응시 기회가 주어지며, 이 기회를 통해 학습자는 자신의 코딩 실력을 객관적으로 평가하고, 부족한 부분을 정확히 파악할 수 있습니다. 시험 환경은 실제 코딩 테스트와 매우 유사하게 구성되어 있어, 시간 제약 속에서 문제를 해결하는 연습을 할 수 있습니다. 이는 실제 시험에서 발생할 수 있는 긴장감을 미리 경험하고, 시간 관리 능력을 향상시키는 데 큰 도움이 됩니다. 또한, 시험 결과는 상세하게 분석되어 제공되므로, 어떤 유형의 문제에 약한지, 어떤 부분을 보완해야 하는지를 명확하게 알 수 있습니다. 특히, 실력 진단이 끝나면 평가 결과를 바탕으로 목표 기간 내 성과 달성을 위한 맞춤형 학습 커리큘럼을 제공해준다는 점이 매우 인상적이었습니다. 이러한 맞춤형 커리큘럼은 학습자가 효율적으로 학습 목표를 달성할 수 있도록 돕고, 학습 효과를 극대화하는 데 큰 역할을 합니다. '실력 진단'은 단순히 실력을 확인하는 것을 넘어, 학습 방향을 설정하고 실력 향상을 위한 구체적인 전략을 세우는 데 필수적인 도구라고 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckRPk6/btsL47y2xcY/mIsMDmXfYKlqpngH9Fgw2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckRPk6/btsL47y2xcY/mIsMDmXfYKlqpngH9Fgw2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckRPk6/btsL47y2xcY/mIsMDmXfYKlqpngH9Fgw2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckRPk6%2FbtsL47y2xcY%2FmIsMDmXfYKlqpngH9Fgw2k%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;500&quot; height=&quot;305&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[3] 실전 대비의 핵심: 기출 문제&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드트리는 삼성 SW 역량테스트의 실제 기출 문제를 제공하여, 실전 대비에 최적화된 학습 환경을 제공합니다. 단순히 문제를 나열하는 것이 아니라, 각 문제마다 난이도가 명확하게 표시되어 있어 학습자가 자신의 수준에 맞는 문제를 선택하여 풀이할 수 있도록 돕습니다. 이는 학습자가 무리하게 어려운 문제에 도전하여 좌절감을 느끼는 것을 방지하고, 단계적으로 실력을 향상시킬 수 있도록 설계된 배려입니다. 또한, 문제에 대한 이해를 돕는 이미지 자료들의 높은 퀄리티는 학습 효과를 극대화하는 데 큰 역할을 합니다. 복잡한 알고리즘이나 자료 구조를 시각적으로 표현하여, 학습자가 더욱 쉽게 이해하고 기억할 수 있도록 돕습니다. 뿐만 아니라, 각 문제에 대한 상세한 해설은 학습자가 스스로 문제를 해결하는 능력을 키우는 데 큰 도움이 됩니다. 단순히 정답을 알려주는 것이 아니라, 문제 해결 과정과 접근 방식을 설명하여, 학습자가 유사한 문제에 직면했을 때 스스로 해결할 수 있는 능력을 키울 수 있도록 돕습니다. 이러한 기출 문제 풀이 경험은 실제 시험에 대한 자신감을 높여줄 뿐만 아니라, 알고리즘 문제 풀이 실력을 한 단계 더 발전시키는 데 큰 도움이 될 것이라고 확신합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;( TMI : 2024 하반기 코딩테스트 문제 복원에 일부 기여했습니다 .. ㅎㅎ)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5db1i/btsL6KWWGAR/YK8c5jJG9qnoNNobXfY6I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5db1i/btsL6KWWGAR/YK8c5jJG9qnoNNobXfY6I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5db1i/btsL6KWWGAR/YK8c5jJG9qnoNNobXfY6I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5db1i%2FbtsL6KWWGAR%2FYK8c5jJG9qnoNNobXfY6I1%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;500&quot; height=&quot;419&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[4] 총평: 장점과 개선점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;매일 학습 목표를 자유롭게 설정할 수 있다는 점은 코드트리의 큰 장점 중 하나입니다. 고정된 학습 목표는 때로는 부담으로 작용할 수 있지만, 코드트리에서는 개인의 일정과 학습 속도에 맞춰 유연하게 목표를 설정할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;학습 흐름에 집중한 커리큘럼 구성은 학습 효과를 극대화합니다. Trail 구조를 통해 난이도에 따라 학습 단계를 설정하고, 문제 풀이 과정에서 기본 개념과 토론을 활용할 수 있도록 한 점은 학습 몰입도를 높이는 데 큰 역할을 했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개선점:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본 개념 탭의 설명이 때로는 명확하게 이해되지 않는 경우가 있었습니다. 하지만 이는 충분히 개선될 수 있는 부분이라고 생각하며, 코드트리의 지속적인 발전을 기대합니다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[5] 마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드트리는 체계적인 커리큘럼과 다양한 학습 콘텐츠를 통해 알고리즘 문제 풀이 실력 향상을 돕는 훌륭한 플랫폼입니다. 코드트리 챌린지 참여를 통해 얻은 긍정적인 경험을 바탕으로, 코딩 테스트 준비에 어려움을 느끼는 많은 분들에게 코드트리를 적극적으로 추천합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>CodeTree</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/28</guid>
      <comments>https://binary-kim.tistory.com/28#entry28comment</comments>
      <pubDate>Mon, 3 Feb 2025 19:03:00 +0900</pubDate>
    </item>
    <item>
      <title>[Apache Sqoop] Sqoop이란?</title>
      <link>https://binary-kim.tistory.com/26</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Sqoop이란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Apache Sqoop이란 RDBMS (MySQL, Oracle, ...)에서 Apache Hadoop 간 대용량 데이터 전송을 위해 설계된 도구이며, SQL-On-Hadoop의 약자라고 합니다. ETL / ELT 작업을 수행해야하는 상황에서 수집해야 하는 데이터의 크기가 대용량일 경우 Sqoop의 도입은 효율적인 파이프라인을 구성하는 데 고민해볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;간단한 예시로 DW (Data WareHouse)를 위한 파이프라인을 구성한다고 가정해보면...&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AwZF9/btsLJC7GH1r/OdwMuGJyJxppSYkcsD4GRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AwZF9/btsLJC7GH1r/OdwMuGJyJxppSYkcsD4GRK/img.png&quot; data-alt=&quot;DW 아키텍쳐 (https://parksuseong.blogspot.com/2019/08/data-warehouse.html)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AwZF9/btsLJC7GH1r/OdwMuGJyJxppSYkcsD4GRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAwZF9%2FbtsLJC7GH1r%2FOdwMuGJyJxppSYkcsD4GRK%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;503&quot; height=&quot;272&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DW 아키텍쳐 (https://parksuseong.blogspot.com/2019/08/data-warehouse.html)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 그림과 같이, 다양한 형태의 운영계 DB가 존재하는 상황에서 ETL을 통해 STG / ODS / DW / DM을 구성할 수 있습니다. 여기서&amp;nbsp; &lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;STG 영역은 운영계의 데이터를 그대로 복사하여 저장 / 관리를 진행하는 영역이며, 해당 작업을 진행할 때 대용량의 데이터를 가져와서 적재해야 할 수 있습니다. 이런 경우, Sqoop이라는 도구를 활용하게 되면 데이터를 효과적으로 수집할 수 있게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Sqoop은 아래와 같은 특징 및 장점을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CLI (Command Line Interface)를 통한 간단한 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다양한 RDBMS와 연동 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MapReduce를 활용한 병렬 처리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Hive / HBase 등 Hadoop Eco System과의 연동 편리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Sqoop에는 크게 Import / Export 작업으로 나뉘게 됩니다. 두 Task에 대해서 한 번 알아가보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Sqoop Import&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Import 작업은 &lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;RDBMS에서 Hadoop으로 데이터를 가져올 때의 작업을 의미합니다. 즉, 원천 데이터 (Oracle, Postgres, ...)에서 Hadoop으로 데이터를 가져오고자 할 때, Sqoop Import 명령어를 통해 작업을 수행할 수 있습니다. &lt;/span&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;대략적인 Import 작업 개요는 아래 사진과 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C0Veg/btsLJl58rbQ/FeQsvUCsJgV6VjPlhIlg60/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C0Veg/btsLJl58rbQ/FeQsvUCsJgV6VjPlhIlg60/img.jpg&quot; data-alt=&quot;Sqoop Import (http://hochul.net/blog/apache-sqoop-sql-to-hadoop/)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C0Veg/btsLJl58rbQ/FeQsvUCsJgV6VjPlhIlg60/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC0Veg%2FbtsLJl58rbQ%2FFeQsvUCsJgV6VjPlhIlg60%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;425&quot; height=&quot;411&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;485&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Sqoop Import (http://hochul.net/blog/apache-sqoop-sql-to-hadoop/)&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선, 작업을 수행하면 작업할 테이블의 Metadata를 수집하는 과정을 수행합니다. Metadata는 다양한 저장소에서 관리될 수 있으며, Hadoop Eco System 중 Apache Hive가 대표적입니다. 그 후로, Map-Only Job을 Submit하게 되어 MapReduce 중 Map 작업만 수행하게 됩니다. 왜 Map 작업만 수행할까요? 이는 Sqoop이라는 도구의 역할을 생각해보면 쉽게 해답을 얻을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Sqoop이라는 도구는 &quot;&lt;b&gt;대용량 데이터를 가져옴 / 내보냄&lt;/b&gt;&quot;이 주 기능이며, ETL에서 주로 Extract 영역에 속합니다. 데이터를 가공하는 Transform이 아닌 데이터 추출 / 전달에 좀 더 특화된 도구이기에, Map-Only 작업을 수행한다고 보시면 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Sqoop Export&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #222222; text-align: start;&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;Export 작업은 Import 작업 반대로, &lt;/span&gt;Hadoop에서 &lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;RDBMS로&amp;nbsp;&lt;/span&gt;데이터를 내보낼 때의 작업을 의미합니다. Hadoop에서 다양한 DB로 대용량 데이터를 전송할 때, Sqoop Export 작업을 수행할 수 있습니다. Export 작업 개요는 아래와 같습니다. Import 작업과 비슷한 듯 보이지만, 어디서 어디로 데이터를 보내는지에 따라 Import / Export가 나뉜다고 이해하시면 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0RpdK/btsLKuVox3V/K4KUXq4YAWdnKu4Bovgnn1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0RpdK/btsLKuVox3V/K4KUXq4YAWdnKu4Bovgnn1/img.jpg&quot; data-alt=&quot;Sqoop Export (http://hochul.net/blog/apache-sqoop-sql-to-hadoop/)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0RpdK/btsLKuVox3V/K4KUXq4YAWdnKu4Bovgnn1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0RpdK%2FbtsLKuVox3V%2FK4KUXq4YAWdnKu4Bovgnn1%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;427&quot; height=&quot;412&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;485&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Sqoop Export (http://hochul.net/blog/apache-sqoop-sql-to-hadoop/)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;병렬 처리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Sqoop Import / Export에는 기본적으로 &quot;&lt;b&gt;-m / --num-mappers&lt;/b&gt;&quot;라는 옵션이 존재합니다. 해당 옵션의 의미는 Sqoop 작업에서 활용할 mapper의 수를 지정하는 옵션이며, 설정한 값 만큼의 mapper가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;실제 Map-Only Job을 수행하게 됩니다. MapReduce 작업을 수행할 때 mapper가 1이면 데이터를 Count하는 사람이 한 명임을 의미하며, mapper가 8이면 사람이 8명임을 의미합니다. 이런 관점에서 보면, mapper를 높이는 것이 대용량 데이터를 처리하는 데 큰 효율을 가져다줄 수 있을 것으로 예상됩니다. &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;여기서, 한 가지 생각해보겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&quot;단순히 mapper를 크게하면, 작업의 효율성이 늘어날까?&quot;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;제 생각에는 해당 문장은 옳지 못한 표현이라 생각합니다. &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;mapper를 늘린다는 것은 결국엔 &quot;&lt;b&gt;하나의 Task를 수행하는 데 투입되는 리소스의 양이 늘어난다&lt;/b&gt;&quot;라는 것과 동일한 의미입니다. 리소스를 많이 투입한 상황인데,&amp;nbsp; 그에 준하는 효과를 보지 못한다면 비효율적인 상황이 아닐까 생각합니다. &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이러한 상황을 한 문장으로 정리해본다면, &quot;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;컨테이너 간 수집하는 데이터 건 수가 비슷한 경우 mapper 증가에 따른 이상적인 효과를 예상할 수 있으며, 그 반대로 컨테이너 간 &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Data Skew 현상이 존재하는 경우 리소스 투입 대비 비효율적인 작업을 수행할 수 있습니다.&quot;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt; 인 것 같습니다. 그렇다면 어떻게 이런 상황을 해결할 수 있을까요?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;num-mappers 옵션을 2 이상으로 설정하게 되면, &quot;&lt;b&gt;split-by&lt;/b&gt;&quot; 옵션을 함께 사용해야 합니다. split-by는 DB 내 어떤 컬럼을 기준으로 분할하여 Map 작업을 수행할지 기준 컬럼을 설정하는 옵션입니다. 해당 기준 컬럼의 데이터 분포를 바탕으로 여러 개의 컨테이너에 데이터를 분포시켜 병렬 처리를 수행하게 됩니다.&amp;nbsp;Sqoop 에서는 &lt;b&gt;MIN / MAX&lt;/b&gt; 값을 통해 설정한 mapper 수 만큼 구간을 분할하게 됩니다. 만약, 데이터가 1~8까지 존재하고 mapper가 4로 설정되어 있는 상황이면, 1번 컨테이너부터 4번 컨테이너까지 차례대로 &lt;b&gt;(1~2, 3~4, 5~6, 7~8)&lt;/b&gt; 의 데이터 값을 갖는 row들을 각각의 컨테이너에서 처리하는 작업을 수행할 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리에게 남은 숙제는 결국에는 ...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;Data Skew를 줄일 수 있는 적절한 컬럼을 추출하고, 이를 split-by에 활용하자&quot; &lt;/b&gt;인 것 같습니다. split-by에 어떤 컬럼의 값을 설정하는지에 따라, 작업 시간의 효율성을 결정할 수 있을 것으로 예상됩니다.&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;주의할 점&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;RDBMS와 Hadoop간 데이터가 전송되는 작업이다보니, 쉽게 적용가능하다는 장점이 존재합니다. 그렇지만, 모든 도구가 그렇듯이, 사용에 있어 주의해야 할 점이 존재합니다. 팀에서 겪었던 문제 중 하나는 &quot;&lt;b&gt;데이터 타입 변환&lt;/b&gt;&quot;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;-1&quot;이라는 숫자 데이터를 parquet(파케이) 테이블 내 Bigint 컬럼에 적재할 때, 음수 데이터 값이 BigInt가 아닌 String으로 인식되어 에러가 발생했었고, 이를 해결하고자 데이터를 받아올 때 String으로 변환하여 적재를 했던 경험이 있습니다. 이 외에도, 다양한 에러가 존재할 것이며, DW/DM 개발에 영향을 미치지 않도록 적절한 해결책을 찾는 것이 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;마무리하며&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이번 게시글에선 Sqoop에 대하여 간단하게 확인해보는 시간을 가져봤습니다. Sqoop이 2021년에 Apache Attic으로 이관되어, 현재는 개발이 멈춘 상태입니다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 대체할 수 있는 여러가지 도구들 (Apache Gobblin / NiFi)도 존재하니, 이를 알아두시면 나중에 어떤 기술을 도입할 지에 대한 고민에서 해답을 얻을 수 있을 것이라 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Apache Sqoop</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/26</guid>
      <comments>https://binary-kim.tistory.com/26#entry26comment</comments>
      <pubDate>Sat, 11 Jan 2025 14:53:27 +0900</pubDate>
    </item>
    <item>
      <title>[Spark 완벽 가이드] Adaptive Query Execution이란?</title>
      <link>https://binary-kim.tistory.com/25</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이번 포스팅에서는 Spark 3.0 버전부터 등장한 AQE(Adaptive Query Execution)에 대해서 알아가보는 시간을 가져보겠습니다. 이전 Spark 글에서 배경 및 기초 개념 / Catalyst Optimizer에 대한 내용을 공유드렸었는데, 혹여나 아직 보지 않으신 분들은 먼저 보고 오시는 것을 추천드립니다. 그 이유는 AQE의 배경이나 작동 방식 등을 이해하기 위해서는 어느 정도의 개념을 인지하고 있어야 하기 때문입니다. 아마도 보고오시면 해당 포스팅을&amp;nbsp;이해하는 데 도움이 될 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://binary-kim.tistory.com/22&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://binary-kim.tistory.com/22&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1735622241512&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;[Spark 완벽 가이드] Catalyst Optimizer란?&quot; data-og-description=&quot;서론저번 포스팅에서는 Spark가 나오게 된 배경 및 기본 개념을 위주로 정리해보는 시간을 가졌습니다. 이번 시간에는 Spark에서 Job을 제출했을 때 어떻게 최적화를 진행하는지를 시작으로 하여, &quot; data-og-host=&quot;binary-kim.tistory.com&quot; data-og-source-url=&quot;https://binary-kim.tistory.com/22&quot; data-og-url=&quot;https://binary-kim.tistory.com/22&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bE7Cki/hyXWnhwfbo/CMsW8DkCOifX9DqQv4Qmy1/img.png?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128,https://scrap.kakaocdn.net/dn/wPWpI/hyXWtWk5ev/9ze9eByJ85arDJbdmkuigK/img.png?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128,https://scrap.kakaocdn.net/dn/Q6LcP/hyXSry521P/OAsMHTfk8sKV1KxI1Cukm1/img.png?width=1024&amp;amp;height=235&amp;amp;face=0_0_1024_235&quot;&gt;&lt;a href=&quot;https://binary-kim.tistory.com/22&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://binary-kim.tistory.com/22&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bE7Cki/hyXWnhwfbo/CMsW8DkCOifX9DqQv4Qmy1/img.png?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128,https://scrap.kakaocdn.net/dn/wPWpI/hyXWtWk5ev/9ze9eByJ85arDJbdmkuigK/img.png?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128,https://scrap.kakaocdn.net/dn/Q6LcP/hyXSry521P/OAsMHTfk8sKV1KxI1Cukm1/img.png?width=1024&amp;amp;height=235&amp;amp;face=0_0_1024_235');&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;[Spark 완벽 가이드] Catalyst Optimizer란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;서론저번 포스팅에서는 Spark가 나오게 된 배경 및 기본 개념을 위주로 정리해보는 시간을 가졌습니다. 이번 시간에는 Spark에서 Job을 제출했을 때 어떻게 최적화를 진행하는지를 시작으로 하여,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;binary-kim.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;AQE (Adaptive Query Execution)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;탄생 배경&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark 2.xx 버전에서는 &lt;b&gt;Rule-Based&lt;/b&gt;로 Logical Plan을 최적화하고, &lt;b&gt;Cost-Based&lt;/b&gt;를 기반으로 Physical Plan을 최적화하여 사용자가 입력한 Spark Job의 효율적인 실행을 도왔습니다. 한 번 최적의 Physical Plan이 결정되면, 그 순서대로 쿼리가 수행되며 결과를 사용자에게 전달합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다면, 이런 경우도 한 번 생각해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예상했던 데이터의 분포와 실제 실행할 때의 &lt;b&gt;데이터 분포가 다른 경우&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;UDF(User Defined Function)에서 특정 조건을 활용하여 Spark가 정확한 데이터 분포에 대한 &lt;b&gt;정확한 예측을 할 수 없는 경우&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 두 가지 Case를 겪게 되면 어떤 결과를 얻을까요? 뭔가 최적의 결과를 얻을 것 같지 않다는 생각이 드시나요? 예상했던 데이터의 분포를 기반으로 최적의 Physical Plan을 생성했는데, 예상했던 분포와 다르면 연산에 있어 &lt;b&gt;지연 현상&lt;/b&gt;으로 이어지게 될 것입니다. Spark 2 버전에서 이러한 문제가 발생하는 것을 확인했고, 개선할 필요가 있다고 느꼈겟죠? Cost-Based Model 처럼&amp;nbsp;컴파일 시간이 아닌, 런타임에 사용자가 입력한 쿼리를 보다 효율적으로 변경시키는 방법론이 Spark 3버전부터 적용된 &quot;&lt;b&gt;AQE (Adaptive Query Execution)&lt;/b&gt;&quot;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;배경과는 상관 없는 내용이긴 하지만,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저는 Optimizer 개념을 처음 학습할 때, &quot;&lt;b&gt;그럼 실제 분포를 잘 예측할 수 있는 Optimizer를 만들면 되지 않을까?&lt;/b&gt;&quot; 하는 생각이 들었습니다. 매 상황에 맞는 Optimizer를 개발하여 활용하는 것이 성능에 좋을 수도 있지만, 매 작업에서 Optimizer를 만드는데 소요되는 시간과 인력이 투입되어야 합니다. 조금만 신중하게 생각해보면, Spark라는 Tool을 활용하는 개발자 입장에서 이런 부분들이 비효율적인 작업이라는 것을 깨닫는 데 오래 걸리지 않았던 것 같아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyvIGC/btsLBzbX0jU/LOBrg2IcRdcNwoDaAajZKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyvIGC/btsLBzbX0jU/LOBrg2IcRdcNwoDaAajZKK/img.png&quot; data-alt=&quot;https://blog.knoldus.com/adaptive-query-execution-aqe-in-spark-3-0/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyvIGC/btsLBzbX0jU/LOBrg2IcRdcNwoDaAajZKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyvIGC%2FbtsLBzbX0jU%2FLOBrg2IcRdcNwoDaAajZKK%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;676&quot; height=&quot;187&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://blog.knoldus.com/adaptive-query-execution-aqe-in-spark-3-0/&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AQE는 SparkSQL에 도입된 쿼리 최적화 엔진으로, 데이터의 런타임 통계를 기반으로 실제 실행 계획을 동적(Dynamic)으로 조정하여 쿼리 성능을 향상시키는 기능입니다. 즉, 데이터의 특성에 따라 런타임에 Logical Plan을 변경하는 작업을 수행하고, 이에 따라 Physical Plan 또한 변경시켜 최적화된 쿼리를 수행할 수 있도록 도와주는 기능입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기존에 생성했던 Physical Plan대로 작업을 수행하면서 런타임에 데이터의 분포를 바탕으로 최적화가 필요하다고 느꼈을 때, AQE가 실행되어 다시 Logical Plan 단계로 돌아가 실제 데이터 분포에 대한 최적의 Physical Plan을 추출하는 작업이 진행됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공식 문서에 따르면, AQE에서 지원하는 기능은 3가지가 존재합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Coalesce Post-Shuffle Partition&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Sort-Merge Join To Broadcast Join&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Skew Join Optimization&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 세 가지에 대해서 자세하게 알아가보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Coalesce Post-Shuffle Partition&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-02 오후 4.51.06.png&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEGa9e/btsLBuCjWfu/dpP1pa00kpcOcB2KHmpySK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEGa9e/btsLBuCjWfu/dpP1pa00kpcOcB2KHmpySK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEGa9e/btsLBuCjWfu/dpP1pa00kpcOcB2KHmpySK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEGa9e%2FbtsLBuCjWfu%2FdpP1pa00kpcOcB2KHmpySK%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;551&quot; height=&quot;428&quot; data-filename=&quot;스크린샷 2025-01-02 오후 4.51.06.png&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;첫 번째로, 셔플 작업 이후에 생성되는 Partition의 수를 동적으로 조정하는 방식입니다. 동적으로 조정한다는 방식이 텍스트를 읽었을 때 잘 와닿지 않을 수 있기에,&amp;nbsp;MapReduce 작업을 수행한다고 가정하며 해당 Case의 예시를 들어보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Reduce 작업을 수행할 때 Job의 수가 너무 작으면, 하나의 Partition의 크기가 매우 커져 부하가 걸리게 되고 실제 Executor의 메모리가 Out Of Memory에 빠질 수 있게 됩니다. &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Reduce 할 때 Job의 수가 너무 많은&amp;nbsp;&lt;/span&gt;반대의 경우는 어떨까요? Executor의 수보다 더 많은 Job이 존재한다고 할 때, 한 번에 Executor가 모든 Job을 수행하지 못하게 됩니다. 이 때 오버헤드 또한 발생하게 되어 성능 하락의 원인이 되는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 Partition의 수에 따른 장/단점들을 AQE에서는 동적으로 적절하게 조절함으로써, 하나의 Executor간 수행하는 작업의 균형을 이룰 수 있게 되고 I/O 작업 수가 감소하는 효과를 얻을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Sort-Merge Join To Broadcast Join&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UWYjz/btsLCGIwmhv/iiKyut3Jp9g97MqmKgU4J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UWYjz/btsLCGIwmhv/iiKyut3Jp9g97MqmKgU4J1/img.png&quot; data-alt=&quot;https://jeevan-madhur22.medium.com/spark-3-0-aqe-dynamically-choosing-join-strategy-explained-part-2-66d0cfb28c42&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UWYjz/btsLCGIwmhv/iiKyut3Jp9g97MqmKgU4J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUWYjz%2FbtsLCGIwmhv%2FiiKyut3Jp9g97MqmKgU4J1%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;718&quot; height=&quot;308&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://jeevan-madhur22.medium.com/spark-3-0-aqe-dynamically-choosing-join-strategy-explained-part-2-66d0cfb28c42&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark에서는 기본적으로 사용되는 조인 전략은 &quot;Sort-Merge Join&quot; 입니다. Sort-Merge Join은 Join할 두 Table을 Partition이 될 Key를 기준으로 각각 Sort 한 후, Merge하는 방식으로 대용량 데이터 처리에 적합합니다. 그렇지만, 모든 데이터가 셔플될 때 네트워크 이동이 필연적이며, 이에 비용이 많이 소요되는 작업입니다.&amp;nbsp;이러한 Join 전략을 사용하지 않고, 특정 Case에서 Broadcast Join을 사용하는 이유는 과연 무엇일까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Broadcast Join은 한쪽 데이터셋의 크기가 매우 작을 때 효율적으로 사용 가능한 조인 전략으로, 작은 데이터셋을 큰 데이터셋이 분포되어있는 모든 클러스터에 broadcast하여 셔플 작업을 최소화하는 방식입니다. Broadcast Join이 Sort-Merge Join보다 효율적인 이유는 한 테이블만 이동을 수행하면 되기 때문에, 네트워크 이동에서 소요되는 비용을 줄일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark에서는 작은 데이터셋의 크기가 평균적으로 &lt;b&gt;10MB ~ 100MB&lt;/b&gt;이하일 때 Sort-Merge Join을 Broadcast Join으로 변경하는 기준으로 삼고 있습니다. 내가 만약 Broadcast Join이 자동으로 일어나게 하는 기준을 정하고 임의로 정하고 싶다면, Spark Session을 생성할 때 &quot;spark.sql.autoBroadcastJoinThreshold&quot; 옵션에 적절한 값을 주면 적용 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Skew Join Optimization&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이전 포스팅에서도 반복적으로 언급했다싶이, Partition간 Data 분포가 불균형(Skew) 할 수록 셔플 작업이 일어나는 연산(Join)시 쿼리 성능을 저하시킬 수 있습니다. AQE는 런타임에 Data Skew를 감지해서 특정 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Partition&lt;/span&gt;의 데이터를 여러 작은 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Partition&lt;/span&gt;으로 분할하거나, 혹은 적절한 Join 전략을 적용하여 처리하는 방식을 의미합니다. 위에서 설명한 두 가지를 적절하게 섞어서 활용하다는 의미로 보입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;셔플 과정에서 발생하는 병목 현상을 줄이고, 이로써 전체 작업 성능을 향상시키는 것을 목표로 하는 것이 바로 AQE의 큰 특징이라고 알아두시면 좋을 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;활용&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark 3.0버전에서 AQE를 활용하려면 &quot;&lt;b&gt;spark.sql.adaptive.enabled=true&lt;/b&gt;&quot;로 Spark Session 생성 시에 설정하면 되며, Spark 3.2 버전 이후로는 AQE가 Default Option으로 설정되어 자동으로 적용된다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저는 프로젝트를 수행할 때 클러스터 작업 간 병목 현상이 발생하는지에 대한 여부를 &quot;Spark Web UI&quot;를 통해 인지했습니다. 당시, 100만 건 좀 안되는 데이터에 적절한 연산을 더하여 사용자들의 관심도를 측정하는 프로젝트를 수행했었는데, Data Skew로 인해 AWS EMR에서 평균 30분 정도의 시간이 소요됬습니다. 간혹 45분의 시간도 걸렸던 적이 있어 1시간을 주기로 돌아가는 파이프라인을 구축한 상황에서 난감했던 상황이 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;당시 해당 문제를 해결해보고자 여러가지 방법을 찾아보던 중,&amp;nbsp;&quot;어 나도 AQE 한 번 써볼까? 그러면 병목 현상을 좀 줄일 수 있겠네?&quot; 하는 생각에 바로 Google에 검색을 호다닥 진행했는데....&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;나도 모르게 이미 AQE를 쓰고있었군아... &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;였습니다 ㅎㅎ&lt;/span&gt;&quot;.&amp;nbsp;아마 프로젝트를 수행하던 시점에서 Spark 3.2버전보다 업그레이드 된 버전을 사용했기에, 저절로 적용되었던 것이었습니다. 그래서 &quot;머쓱타드&quot; 한 잔 적신 후에 다른 Optimizing 기법들 (Salting / Repartitioning ...)을 적절하게 활용하여 해결했던 경험이 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개인적인 생각&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;AQE를 무조건 사용하는 것이 좋은 판단일까요?&quot; 라는 질문에 어떻게 생각하시나요?&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;런타임에 실제 데이터 분포를 활용하여 Physical Plan을 다시 추출한다는 것은 &quot;그 만큼의 추가 시간 및 자원이 소요된다&quot;라는 의미와도 연결됩니다. Spark Tool을 연구/개발하시는 분들이 생각하시기에 추가적인 Cost가 발생한 것보다 그 이상의 훨씬 큰 장점을 가지고 있기에 AQE를 만들었다고 생각합니다. 또한, 최신 Spark 버전에서는 Default로 제공하는데는 이유가 있지 않을까 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(&lt;s&gt;킹리적 갓심&lt;/s&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇기 때문에 저는 .... 그냥 사용하겠습니다!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;&quot;&gt;&lt;b&gt;마무리하며&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;&quot;&gt;이번 글까지 작성하며 Spark에 대한 간단한 개념은 정리되었다고 생각합니다. 이론과 실습은 또 다른 영역이지만, 개념을 잘 알면 그만큼 활용할 수 있는 능력치가 증가할 수 있겠죠? ㅎㅎ&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;&quot;&gt;다음 기술 포스팅은 어떤 것을 진행해볼까요?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;아직 정해둔 것은 없지만, Hadoop 아니면 Trino 쪽을 정리해보지 않을까 생각합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;&quot;&gt;감사합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Apache Spark</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/25</guid>
      <comments>https://binary-kim.tistory.com/25#entry25comment</comments>
      <pubDate>Thu, 2 Jan 2025 17:02:34 +0900</pubDate>
    </item>
    <item>
      <title>2024년 회고</title>
      <link>https://binary-kim.tistory.com/24</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;안녕하세요. 어느덧 글 쓰는 시점은 현재 2024년 마지막 날이며, 내일이면 새로운 한 해를 맞이하게 되네요!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재 기술 블로그도 작성 중에 있지만, 올 한 해를 되돌아보고 어떤 부분이 좋았고 개선해야 할 지를 좀 되돌아고보고자 작성해봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추가로, 신년에는 무엇을 목표로 할 지도 목표를 세워보고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(글또라는 활동을 진행한지 벌써 3개월이 다되갑니다. ㅎㅎ)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회고&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;올해는 현재까지 살면서 가장 이벤트가 많았던 한 해였던 것 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1분기에는 졸업 및 네이버 부스트캠프를 수행하며 역량 향상을 위해 노력했던 시간이었습니다. 그 당시, 변성윤님의 스페셜 세션이 5차례 정도 있었던 것으로 기억하는데, &quot;&lt;b&gt;유익하면서도 잠시 쉬어가는 힐링 타임&lt;/b&gt;&quot;으로 현재까지도 기억에 남아 너무 좋았고, 글또라는 활동에 참가하게 된 큰 계기 중에 하나이기도 했던 것 같아요. 그리고, 현재의 제가 있게 해준 대외활동 중 하나이지 않을까 생각합니다. 몰입해서 결과물을 만들어나가며 성장할 수 있었고, 그 사이에서 좋은 동료들도 만날 수 있어 행복했습니다. 동료 분들과는 현재까지도 연락하거나 가끔 오프라인 만남을 가지고 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2분기에는 상반기 취업 준비에 몰입했던 시기였습니다. 많은 서류가 탈락했지만, 그 중에서도 가장 원했던 두 회사를 면접볼 수 있는 기회가 있었습니다. 면접을 준비하면서 특히나 &quot;이론과 실전은 많이 다르다&quot; 라는 부분을 많이 느꼈던 것 같아요. 부족한 부분은 확실하게 보였기에 이를 보완하면서도, 나의 강점을 부각시킬 수 있도록 많은 노력을 다했던 것 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;서류 -&amp;gt; 코딩테스트 -&amp;gt; 면접 (1/2차)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;간단하면서도 꽤나 오래걸리는 3단계의 채용 프로세스를 진행하며 &quot;&lt;b&gt;희노애락&lt;/b&gt;&quot;이 항상 공존했던 것 같아요. 약간 사람의 심정이... &lt;b&gt;&quot;서류만 붙여주세요&quot; -&amp;gt; &quot;면접 기회만 주세요&quot; -&amp;gt; &quot;합격시켜주세요&quot; &lt;/b&gt;이렇게 점점 고도화되는 느낌이었다.&amp;nbsp;상반기 채용 실패 후 굉장히 많은 스트레스와 힘듦이 함께했지만, 2주 간의 휴식을 거쳐 완전한 상태로 돌아올 수 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3분기에는 살면서 잠을 제일 안잤던 시기이기도 하며, 그만큼 열심히 살았던 시간이었습니다. 부트캠프를 한 차례 더 진행하면서 새로운 동료들과 새로운 분야를 학습하는 과정에서 재미를 느꼈고, 데이터 엔지니어의 커리어를 학습하며 AI를 새로 배웠을 때와는 또 다른 설렘이 있었던 것 같아요. 카페인으로 버텨가던 시기었기에, 사실 건강이 많이 안좋아졌던 시기이기도 합니다. 그래도... 값진 3달이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4분기는 설렘 반 두려움 반의 시간이었습니다. 가장 원하던 회사에 합격 소식을 받아 여행을 많이 다니면서 그동안의 스트레스와 힘들었던 감정을 사람들을 만나며 풀어가는 시간이었던 것 같아요. 데이터 엔지니어링을 생각보다 많이 경험해보지 못해서 그런지 한편으로는 걱정과 두려움이 한 가득 있었습니다. 그런데, 사실 저는 이렇게 생각해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;신입이면 닥치는 대로 다 경험해보면서, 최대한 많은 에러를 경험하자&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;처음부터 파이프라인을 잘 짜면, 구글같은 큰 기업에 이미 취업하지 않았을까요? ㅎㅎ. 최대한 많은 파이프라인을 경험해보면서 장애를 대응하는 경험을 반복적으로 수행하며, 동일한 장애를 일으키지 않는 방법을 학습하는 방향으로 성장해보고자 합니다. 많은 부분이 새로울 예정이기 때문에, 빠르게 적응하여 팀에 도움이 되는 개발자로 성장하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신년 목표&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주 3회 이상 운동 / 건강 관리 / 스트레스 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 엔지니어로써의 지속적인 자기개발 (CDC / Trino / Kubenetes ...)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저축&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신년 목표는 짧고 간단하게 기록해봤습니다!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 글을 읽는 분들도 올 한 해를 되돌아보며 마무리하는 시간을 꼭 가져보면 좋겠다는 생각이 듭니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>일상</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/24</guid>
      <comments>https://binary-kim.tistory.com/24#entry24comment</comments>
      <pubDate>Tue, 31 Dec 2024 09:07:59 +0900</pubDate>
    </item>
    <item>
      <title>[Hadoop 완벽 가이드] HDFS Federation 및 고가용성(HA)를 알아보자.</title>
      <link>https://binary-kim.tistory.com/23</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;안녕하세요. 본 게시물에서는 빅데이터 플랫폼인 Hadoop을 공부하면서, HDFS Federation이 어떤 역할을 위해 탄생했고 활용되는지를 알아보고자 글을 작성합니다. 최근 회사에 입사한 후 어떤 개념을 먼저 공부해볼 까 고민하던 중, 동료분께서 HDFS Federation의 개념에 대해서 말씀해주셨고, 이를 한 번 공부하며 기록해보고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이번 게시물은 HDFS Federation 배경 및 환경 구축에 필요한 개념들을 먼저 알아가 볼 것이며, 다음 게시물에서는 실제 Local Docker 환경에서 HA / Federation이 적용된 Multi Node Cluster를 구축하는 실습 관련하여 게시물을 작성해볼 예정입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한 번 시작해볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;HDFS Federation&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WtbIL/btsLiGWY2kd/d8cGudejhGATaRmrPbLJX1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WtbIL/btsLiGWY2kd/d8cGudejhGATaRmrPbLJX1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WtbIL/btsLiGWY2kd/d8cGudejhGATaRmrPbLJX1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/WtbIL/btsLiGWY2kd/d8cGudejhGATaRmrPbLJX1/img.gif&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;249&quot; height=&quot;202&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;202&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선, HDFS는 NameNode와 DataNode로 분리되어 있습니다. 이 두 핵심 구성 요소가 어떤 역할을 수행하는 지 먼저 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;NameNode&lt;/b&gt;는 HDFS에서의 &quot;두뇌 / 관리자&quot; 역할을 수행하는 중요한 구성 요소이며, 파일 시스템의 NameSpace 및 실제 파일이 어느 위치에 존재하는 지에 대한 Metadata를 저장하는 역할을 수행합니다. 실제로 사용자 / 클라이언트가 작업 요청했을 때 NameNode가 전달받아 내부에 저장된 Metadata 정보를 통해 원하는 정보가 어느 위치에 있는 지를 찾아내고, 이를 DataNode에 접근하여 제공하는 역할을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약, 단일 Cluster에서 NameNode에 장애가 발생할 경우 실제 파일이 위치한 Metadata에 대한 정보를 받아올 수 없습니다. 이 때, 클라이언트 요청을 처리할 수 없으며, 이는 곧 치명적인 문제로 연결될 수 있는 것이죠. 그렇기 때문에, 저는 NameNode를 &quot;두뇌&quot;라고 표현해봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DataNode&lt;/b&gt;는 HDFS에서의 &quot;일꾼&quot; 역할을 수행하는 요소이며, 실제 데이터를 작은 크기의 블록 단위로 저장하고 사용자의 요청에 따라 데이터를 읽기/쓰기 하는 작업을 수행합니다. DataNode를 많이 생성할수록 더 많은 데이터를 저장할 수 있으며. 실제 데이터를 저장하고 작업을 수행하는 역할을 담당하기 때문에 저는 DataNode를 &quot;일꾼&quot;으로 표현해봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;두뇌&quot;의 크기가 일정한데, &quot;일꾼&quot;이 마구마구 늘어나면, 당연히... 두뇌가 아파하겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;s&gt;(마치 제가 코딩할 때 저의 두뇌와 동일한 것 같네요 ㅎㅎ)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 정도의 개념을 숙지한 상태에서, HDFS Federation에 대해서 한 번 알아가보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAEuT9/btsLj9ciFiB/MAwcHYBRbKTXSho407GYT1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAEuT9/btsLj9ciFiB/MAwcHYBRbKTXSho407GYT1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAEuT9/btsLj9ciFiB/MAwcHYBRbKTXSho407GYT1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cAEuT9/btsLj9ciFiB/MAwcHYBRbKTXSho407GYT1/img.gif&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;461&quot; height=&quot;277&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;277&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;HDFS Federation&lt;/b&gt;이란 하나의 Hadoop Cluster 내에서 여러 개의 독립적인 NameSpace를 지원하는 기능입니다. 각 NameSpace는 자체적인 NameNode에 의해 관리가 되며, 이를 통해 단일 HDFS Cluster에서 여러 파일시스템을 운영할 수 있게 됩니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt;NameSpace는&lt;/span&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt;&amp;nbsp;자체적인 NameNode에&lt;/span&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt;&amp;nbsp;의해 관리가 되며, 이를 통해&lt;/span&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt;&amp;nbsp;단일 HDFS Cluster에서&lt;/span&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt;&amp;nbsp;여러 파일시스템을 운영할&lt;/span&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start;&quot;&gt;&amp;nbsp;수 있게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HDFS의 초기 버전 (1.xx)에서는 단일 NameNode가 전체 Cluster의 Metadata(어떤 DataNode에 데이터가 들어있는 지에 대한 정보)를 관리했습니다. 이로 인해, FaceBook과 같은 대규모 Cluster를 운영하는 서비스에서 메모리 관리 및 성능 병목 현상을 경험하게 됬죠. 이러한 문제를 해결하기 위해서 Hadoop Cluster에 도입한 것이 바로 HDFS Federation입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선, 하나의 NameNode가 파일 시스템 내 모든 NameSpace를 관리하는 것이 아닌, 각 NameNode가 각 NameSpace를 독립적으로 관리합니다. 즉, 여러 NameNode로 부하를 분산시킬 수 있기에 더 많은 파일과 더 큰 Cluster를 안정적으로 운영할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한, 독립적으로 NameSpace를 관리하기 때문에, 수평적으로 확장이 가능하다는 큰 장점이 있습니다. 이러한 개념을 잘 생각해보면, 뭔가&amp;nbsp;Hadoop의 큰 특징 중 하나인 &quot;&lt;b&gt;Commodity Hardware&lt;/b&gt;&quot;와 연관이 있다는 생각이 듭니다. 시스템 확장을 진행하고 싶을 때, 적절한 크기의 Hardware를 추가할 수 있다는 것과 연결될 수 있는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좀 더 확실하게 이해를 돕고자, 간단한 예시를 들어보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한 스타트업에서 &quot;운영팀 / 개발팀 / 홍보팀&quot; 총 3개의 팀이 생성하는 데이터를 관리해야 한다고 생각해봅시다. 하나의 NameNode로 관리하는 것 또한, 규모가 크지 않은 스타트업의 입장에서는 적절한 Hadoop Cluster 구조가 될 수 있습니다. 그러나, 만약에 회사가 많이 커져 NameNode의 부하가 커지는 상황이 온다면, 각 팀에서 발생하는 데이터를 따로 관리하는 것이 보다 적절할 수 있겠죠. 즉, 하나의 NameNode가 각 팀이 생성하고 관리하는 실제 데이터에 대한 Metadata를 각각 관리하도록 Hadoop Cluster 구조를 변경시킴으로서 NameNode의 부하를 줄일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추가로, &quot;디자인팀&quot;을 위한 시스템이 추가되어야 한다면, 하나의 NameNode일 때는 부하가 점점 더 커지게 됩니다. 그렇지만, HDFS Federation을 활용하게 된다면, 수평적으로 확장이 유연하게 가능하기 때문에 Hadoop Cluster 운영을 보다 손쉽게 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 특징으로 인해 HDFS Federation은 대규모 Hadoop Cluster에서 엄청 중요한 역할을 하며, 시스템의 전반적인 성능과 관리 효율성을 크게 향상시키는 장점이 있습니다.&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;High Availability&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;High Availability는 HDFS의 치명적인 단점 중 하나인 &lt;b&gt;SPOF(Single Point Of Failure)&lt;/b&gt;를 예방하고 해결하고자 도입되었습니다. SPOF라는 의미는 시스템 중 한 부분의 실패로 인해 시스템 장애가 발생한다는 것을 의미합니다. 즉, NameNode가 SPOF가 되며, 위에서도 설명했던 것과 동일하게 NameNode 장애는 큰 문제를 일으킬 수 있습니다. 안정적인 대규모 Hadoop Cluster를 도입하기 위해서는 HA가 결국에는 필수적으로 요구됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;High Availability를 적용하기 위해서는 NameNode를 최소 2개 이상 운영해야하며, &lt;b&gt;활성화(Active) / 보조(Standby)&lt;/b&gt; 구조를 통해 HA를 구현합니다. 평소에는 실제 Active Node가 사용자 / 클라이언트 요청을 처리하는 역할을 수행하다가, Active Node에서 장애가 발생했을 때 StandBy Node가 Active 역할을 대신합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Active와 Standby Node 간의 &lt;b&gt;동기화&lt;/b&gt;는 High Availability의 핵심 기능 역할이 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동기화 과정을 설명해보면...&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;편집 로그 공유&lt;/b&gt;: Active Node는 모든 NameSpace에서의 수정 사항을 편집 로그에 기록합니다. 이 로그는 이후 설명 할 QJM이나 공유 Storage 시스템에 저장하여 관리합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;실시간 동기화&lt;/b&gt;: StandBy Node는 지속적으로 공유된 편집 로그를 모니터링하고 변경 사항을 자신의 NameSpace에 적용합니다. 이를 통해 거의 실시간으로 동기화 상태를 지속할 수 있게 됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;블록 위치 정보 갱신&lt;/b&gt;: DataNode들은 Active / StandBy Node 모두에게 블록 위치 정보와 하트비트(정상적으로 운영되고 있다는 신호)를 전송합니다. 이를 통해, StandBy Node 또한 최신 블록 위치 정보를 유지할 수 있게 됩니다. (위 사진에서 Block Pool을 의미합니다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;체크포인트&lt;/b&gt;: 주기적으로 StandBy Node는 체크포인트를 생성해서 Metadata의 스냅샷을 기록합니다. 이를 통해 실제 서비스 장애가 발생했을 때, 해당 체크포인트를 활용하여 빠르게 복구할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Active Node가 StandBy Node로 대체되는 과정은 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Hadoop Cluster 내 Jookeeper가 Active Node의 &lt;b&gt;장애를 감지&lt;/b&gt;합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장애가 감지되면, StandBy Node에게 &quot;Active가 장애 상태니까, 너가 Active 대체 해&quot;라는 &lt;b&gt;신호&lt;/b&gt;를 보냅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;StandBy Node는 Active로의 전환을 진행하기 전, QJM에서 &lt;b&gt;미처리 된 편집 로그&lt;/b&gt;를 읽고 적용함으로써 최신 정보를 유지합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;펜싱&lt;/b&gt; 매커니즘을 실행함으로써, 기존의 Active Node가 더 이상 Active 역할을 수행하지 못하도록 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;StandBy Node가 Active 상태로 전환하며, 이후로부터 클라이언트 요청 처리는 &lt;b&gt;StandBy Node가 대신 수행&lt;/b&gt;합니다&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;** 펜싱 메커니즘이란 확실하게 Active Node를 죽이는 (Down 시키는) 과정이라 생각하면 됨.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: oklch(0.99 0.004 106.471); color: oklch(0.304 0.04 213.681); text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 High Availability 덕분에, 대규모 Hadoop Cluster에서 Active Node에 장애가 발생하더라도 무중단 서비스를 제공할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;QJM (Quorum Journal Manager)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;QJM은 HDFS에서 High Availability 구현을 위해 선호되는 방법이며, Active와 StandBy Node 간 편집 로그를 공유하는 역할을 수행합니다. Cluster를 구축할 때 JournalNode에서 작동하며, Active에서 편집한 로그를 기록하고, 이를 StandBy가 읽어 동기화를 유지할 수 있도록 도와줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 3개 이상의 JournalNode로 구성된다고 하는데, 이 부분에 대해서는 정확하게 왜 그러는지는 잘 모르겟습니다. 추후에 한 번 찾아보는 시간을 가져보겠습니다..!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Jookeeper&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jookeeper는 보편적으로 여러 서버 간 동기화, 구성 관리 등을 수행하기 위해 개발되었으며, HDFS에서는 HA구성을 위해 아래와 같은 핵심 역할을 수행합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Active Node를 선출하는 작업을 수행함으로써, Hadoop Cluster에서 단 하나의 Active Node만 존재하도록 보장하는 역할을 수행합니다. 또한,&amp;nbsp;클라이언트에게 현재 Active Node의 정보를 제공하며, 항상 Active Node에 연결할 수 있도록 합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Active Node 장애 시, StandBy Node로의 자동 전환을 진행합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;분산 락 메커니즘을 통해 두 NameNode가 동시에 Active 상태가 되는 것을 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 Jookeeper의 도입을 통해 HDFS의 High Availability를 크게 향상시킬 수 있으며, SPOF 문제를 해결하는 데 핵심 역할을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;&quot;&gt;&lt;b&gt;마무리하며&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 HDFS Federation 및 HA가 적용된 Cluster 구축에 필요한 개념들에 대해 알아봤습니다. 해당 포스팅을 읽으면서 &quot;왜 HDFS Federation을 쓸까?&quot;, &quot;왜 HA를 적용해야 할까?&quot; 등에 대한 궁금증이 해소되었길 바랍니다. 다음 게시물은 Docker 환경에서 어떻게 구축해나아가는지 한 번 알아가보는 시간을 가져보겠습니다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;&quot;&gt;&lt;b&gt;References&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[1]. &lt;a href=&quot;https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/Federation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/Federation.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[2]. &lt;a href=&quot;https://sungwookkang.com/entry/HDFS-Federation-%EB%8B%A4%EC%A4%91-%EB%84%A4%EC%9E%84%EB%85%B8%EB%93%9C%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%84%A4%EC%9E%84%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sungwookkang.com/entry/HDFS-Federation-%EB%8B%A4%EC%A4%91-%EB%84%A4%EC%9E%84%EB%85%B8%EB%93%9C%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%84%A4%EC%9E%84%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[3]. &lt;a href=&quot;https://haejun-kim.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://haejun-kim.tistory.com/64&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[4]. &lt;a href=&quot;https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>Apache Hadoop</category>
      <category>federation</category>
      <category>ha</category>
      <category>HADOOP</category>
      <category>Hdfs</category>
      <category>고가용성</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/23</guid>
      <comments>https://binary-kim.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 15 Dec 2024 20:44:05 +0900</pubDate>
    </item>
    <item>
      <title>[Spark 완벽 가이드] Catalyst Optimizer란?</title>
      <link>https://binary-kim.tistory.com/22</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ultra_fast_parrot (1).gif&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cptimF/btsKNptJryR/dU7Hyx16AgK4eCsYBVVrp1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cptimF/btsKNptJryR/dU7Hyx16AgK4eCsYBVVrp1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cptimF/btsKNptJryR/dU7Hyx16AgK4eCsYBVVrp1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cptimF/btsKNptJryR/dU7Hyx16AgK4eCsYBVVrp1/img.gif&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;128&quot; height=&quot;128&quot; data-filename=&quot;ultra_fast_parrot (1).gif&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저번 포스팅에서는 Spark가 나오게 된 배경 및 기본 개념을 위주로 정리해보는 시간을 가졌습니다. 이번 시간에는 Spark에서 Job을 제출했을 때 어떻게 최적화를 진행하는지를 시작으로 하여, 여러가지 성능 튜닝 기법들에 대해서 정리해보는 시간을 가져볼까 합니다. Spark에서 사용할 수 있는 여러가지 Method (map, filter, ...)들을 다루는 포스팅도 생각해봤지만, 해당 영역은 개념적인 부분보다 실습에 가까운 부분이기 때문에 생략을 해보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark Optimization이 중요한 이유는 뭘까요? 그리고 왜 필요할까요? 해당 질문에 대해 생각해보면 ...&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최적화라는 것은 &lt;b&gt;주어진 자원 내에서 성능을 최대한 끌어올려 원하는 작업을 더 빠르게, 더 효율적으로 수행&lt;/b&gt;하도록 만드는 과정입니다. Spark는 분산 처리 시스템으로 대용량 데이터를 병렬 처리할 수 있는 장점이 있지만, Hadoop의 MapReduce에 비해 기본적으로 많은 자원을 소비합니다. 따라서 자원을 효율적으로 사용하지 않으면 예상보다 긴 시간과 높은 비용이 소모될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여기서&lt;b&gt; Spark Optimization&lt;/b&gt;을 적용하면 처리 속도 및 비용 절감이라는 이점을 가지고 오게 되는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대용량 데이터를 다루는 데이터 파이프라인에서 비효율적인 처리는 시스템 부하를 증가시키고, 응답 시간을 늦추며, 비용을 크게 증가시킵니다. 빅데이터를 기반으로 서비스를 제공하는 기업 측면에서는 이러한 최적화 결과에 따라 서비스의 품질 및 경쟁력을 확보할 수 있게 되는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;본 게시물에서는 Catalyst Optimizer에 대해서 게시글을 작성해보고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없는 다이어그램.drawio.png&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NNomD/btsKt9dYwBd/RQOH4QKEYLpzLk2Z0KNaxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NNomD/btsKt9dYwBd/RQOH4QKEYLpzLk2Z0KNaxk/img.png&quot; data-alt=&quot;Spark, Spark, Spark Let's go!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NNomD/btsKt9dYwBd/RQOH4QKEYLpzLk2Z0KNaxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNNomD%2FbtsKt9dYwBd%2FRQOH4QKEYLpzLk2Z0KNaxk%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;324&quot; height=&quot;197&quot; data-filename=&quot;제목 없는 다이어그램.drawio.png&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;197&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Spark, Spark, Spark Let's go!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Catalyst Optimizer&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;Catalyst Optimizer는&lt;/span&gt; 사용자가 입력한 쿼리와 DataFrame 연산을 최적화하여 더 나은 성능을 제공하기 위해 사용되는 최적화 기법 중 하나입니다. Optimizer 단계는 크게 4단계로 구성되어 있으며, 각 단계에서는 분석, 최적화, 실행 및 코드 생성을 순차적으로 수행합니다. &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnPBVP/btsKNYPMlY3/K2eaJnxCwk0m65IA5H6VpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnPBVP/btsKNYPMlY3/K2eaJnxCwk0m65IA5H6VpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnPBVP/btsKNYPMlY3/K2eaJnxCwk0m65IA5H6VpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnPBVP%2FbtsKNYPMlY3%2FK2eaJnxCwk0m65IA5H6VpK%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;1024&quot; height=&quot;235&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전반적인 흐름은 위 그림과 같습니다. 각 단계를 순차적으로 알아보는 시간을 가져보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;분석 (Analysis)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자가 DataFrame이나 SQL Query를 입력하면, Spark 엔진은 이를 Unresolved Logical Plan으로 변환하여 처리합니다. Unresolved라는 의미는 데이터 소스나 테이블 정보가 명확하게 정의되지 않은 상태이며, 추가적인 검증 및 해석 등의 과정이 필요하다는 것을 의미하죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Unresolved Logical Plan을 활용하여 Resolved Logical Plan을 만드는 과정에서 Spark 엔진 내부의 Catalog를 활용합니다. Catalog는 메타데이터를 저장하는 저장소 역할을 수행하며, 테이블, 컬럼, 로우, 데이터 타입 등의 정보를 관리합니다. 결과적으로, 사용자가 입력한 쿼리에 대해 여러가지의 Resolved Logical Plan이 생성됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여기서 잠깐 생각해봅시다. Optimizing의 최종 목표는 동일한 작업에 대해 소모되는 Cost를 최대한으로 줄이는 것이 목표일 것입니다. 이 관점에서 생각해보면,&amp;nbsp;여러 가지 Resolved Logical Plan을 모두 실행시키는 것은 Cost적인 측면에서 상당히 비효율적이겠죠? 따라서, 가장 Optimized된 Logical Plan을 탐색하고 추출하는 과정을 추가로 수행하게 됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Logical Plan Optimization&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;본 단계에서는 표준화된 최적화 방법에 따라 &lt;b&gt;Rule-Based&lt;/b&gt;로 쿼리 최적화를 수행하며, 결과로 Optimized된 Logical Plan을 추출하는 작업을 수행합니다. 총 4가지의 기준을 바탕으로 Optimized된 Plan을 추출하는 작업을 수행하는데, 지금부터 알아가보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Constant Folding&lt;/b&gt;은 컴파일 시점에 상수 연산을 미리 계산하여 표현식을 단순화하는 방식입니다. 예를 들어, SELECT 2 + 3과 같은 쿼리는 실행 전에 SELECT 5로 변환되어 불필요한 연산을 방지합니다. 이를 통해 실행 시점의 불필요한 계산을 줄이고 성능을 높이는 데 기여할 수 있는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;b&gt;Predicate Pushdown&lt;/b&gt;은 필터링 조건을 데이터 소스와 최대한 가깝게 적용하여 데이터를 필터링하는 최적화 방법입니다. 이해를 돕기 위해 간단한 예를 들어보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 DataFrame을 불러온 후 특정 열의 값이 오늘 날짜와 일치하는 행만 추출한다고 가정해보겠습니다. DataFrame의 크기가 클수록 데이터 로드 및 필터링 과정에서 많은 부하가 발생할 수 있습니다. 그러나 필터링 조건을 데이터 소스에 가깝게 이동시켜 적용하면, 처리해야 할 데이터 양이 줄어들고, 네트워크 및 I/O 비용이 절감됩니다. 이러한 최적화는 Optimized Logical Plan을 생성하는 데 큰 역할을 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Join Reordering&lt;/b&gt;은 조인 순서를 최적화하여 중간 결과의 크기를 최소화하고 쿼리 처리 속도를 개선하는 기법입니다. Spark는 다양한 조인 전략을 고려하며, 데이터 크기와 분포에 따라 효율적인 순서를 선택하여 불필요한 리소스 사용을 줄일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Projection Pruning&lt;/b&gt;은 쿼리에서 필요하지 않은 열을 제거하여 처리량을 줄이는 최적화 방법입니다. 이로 인해 Spark는 메모리 사용량과 I/O 비용을 최소화하고, 필요한 데이터에만 집중할 수 있도록 최적화합니다. 예를 들어, 특정 열만 조회하는 쿼리에서는 불필요한 데이터를 무시하여 리소스를 절약합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Resolved Logical Plan에 위 4가지 과정을 적용하여 하나의 Optimized된 Logical Plan을 추출하는 과정을 Logical Plan Optimization이라고 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Physical Plan Optimization&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하나의 Optimized된 Logical Plan이 생성된 후에는 여러 개의 Physical Plan을 생성하는 과정과, 그 중 Optimized된 Physical Plan을 추출하는 과정을 수행합니다. Optimized한 Logical Plan을 추출하는 과정에서 Predicate Pushdown, ... 등이 활용되었다면, Optimized Physical Plan을 추출하는 과정에서는 Cost Model이 활용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Cost Model&lt;/b&gt;은 각 Physical Plan의 &quot;&lt;b&gt;CPU 사용, 메모리 사용, I/O 크기&lt;/b&gt;&quot; 등 연산을 수행할 때 소모되는 비용을 측정합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Join 전략&lt;/b&gt;을 선택한다고 가정해보죠. Spark에서 제공하는 Join 전략은 여러가지가 존재합니다. Sort-Merge Join / Broadcast Join / Hash Join 등 여러가지 Join 전략 중 어떤 전략이 가장 Cost를 적게 사용할 수 있을지를 본 과정에서 확인하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Data Skew (데이터 분포 편향)도 중요한 요소로 고려됩니다.&lt;/b&gt; 데이터가 일부 노드에 집중되거나 특정 파티션에만 존재하면 연산 부하가 집중되어 성능이 저하될 수 있습니다. Spark에서는 이를 방지하기 위해 데이터 분포를 최적화하거나 조인 전략을 변경하는 등 다양한 방법을 사용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이전 게시물에서 언급했던 것처럼, Spark에서는 &lt;b&gt;Shuffle&lt;/b&gt;을 줄이는 것이 연산 비용을 줄이는 핵심적인 방법 중 하나입니다. 네트워크 간 데이터 이동이 최소화될수록 연산 비용과 I/O 비용이 절감되기 때문에, Spark는 이러한 요소를 최적화하여 최적의 Physical Plan을 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결과적으로, Physical Plan Optimization 단계는 다양한 Physical Plan 중 가장 효율적인 계획을 선택함으로써 데이터 처리 성능을 극대화하고 자원을 효율적으로 사용할 수 있도록 합니다. 이를 통해 Spark는 대규모 데이터를 빠르고 효과적으로 처리할 수 있게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Code Generation&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Optimized된 Physical Plan은 &lt;b&gt;Java Bytecode&lt;/b&gt;로 변환됩니다. Spark는 JVM(자바 가상 머신) 위에서 실행되는 도구이기 때문에, 최적화된 실행 계획이 Java Bytecode로 컴파일되어 Spark의 런타임에서 효율적으로 실행됩니다. 이를 통해 Spark는 데이터를 처리하는 동안 높은 성능을 유지하고, 불필요한 연산을 줄이며 자원 활용을 최적화할 수 있게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Tungsten이라는 엔진&lt;/b&gt;과 함께 Physical Plan을 단일 Java 함수로 변환하는 과정을 거치며, 이를 Whole-Stage Code Generation이라고 합니다. 하나의 Java 함수로 변환했을 때 장점이 뭘까 궁금해서 검색해보니 ... 여러가지 장점이 있다고 합니다!! (&lt;s&gt;깊게 찾아보지는 않아 넘어가도록 하겠습니다&lt;/s&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;마무리하며&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Catalyst Optimizer는 현재 배포되어있는 Spark 3.xx 버전에서도 Optimization을 위해 활용되고 있습니다. 덕분에 분산 환경에서 데이터를 효율적으로 처리할 수 있게 됩니다. 근데, 여기서 한 가지 의문점이 들 수 있죠.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Catalyst Optimizer는 항상 Optimized된 Plan을 수행할까요?&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사실, Catalyst Optimizer가 모든 Case에서 최적의 실행 Plan을 보장하는 것은 아닙니다. 어떤 Optimizer든 Rule-Based + Cost-Based를 기반으로 최적화를 수행하지만, 실제 분산 환경에서 그렇지 않는 Case를 마주할 수도 있습니다. 이러한 문제를 해결하기 위해서 Spark 3.xx 버전부터는 &lt;b&gt;AQE (Adaptive Query Execution)&lt;/b&gt;와 같은 기능이 추가되어, 더욱 효율적으로 Spark Job을 수행할 수 있게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서, 다음 게시글은 AQE에 관련된 내용을 기술해보고자 합니다!!&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;긴 글 읽어주셔서 감사합니다. 다음 게시글에서 뵙겠습니다 :)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;References&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.databricks.com/glossary/catalyst-optimizer&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.databricks.com/glossary/catalyst-optimizer&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;a href=&quot;https://medium.com/@leeyh0216/spark-sql-6dc3d645cc31&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@leeyh0216/spark-sql-6dc3d645cc31&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Apache Spark</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/22</guid>
      <comments>https://binary-kim.tistory.com/22#entry22comment</comments>
      <pubDate>Mon, 18 Nov 2024 15:06:00 +0900</pubDate>
    </item>
    <item>
      <title>2024년 10월을 되돌아보며...</title>
      <link>https://binary-kim.tistory.com/21</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회고를 시작하며...&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이번 주에는 원래 Spark Optimizer와 Spark Job Tuning하는 방법에 대한 기술 블로그를 작성할 예정이었지만 ....!!&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재 거주하는 지역이 입사할 회사랑 거리가 꽤 있는 상황이라, 자취방을 구하고 다니느라 시간이 많이 없었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 게시물을 작성하는 날짜가 현재 참가하고 있는 &quot;글또&quot; 커뮤니티의 게시물 제출일인 상황에서, &quot;&lt;b&gt;패스할까 vs 10월 회고를 적어볼까&lt;/b&gt;&quot; 굉장히 고민을 많이 하다가, 친구와 해당 온라인 활동을 참가할 때 했던 다짐이 생각났다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20230420_163901781.webp&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Icf4/btsKCQy9FZu/JLTKdCPGQiikNLEXdaC6k1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Icf4/btsKCQy9FZu/JLTKdCPGQiikNLEXdaC6k1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Icf4/btsKCQy9FZu/JLTKdCPGQiikNLEXdaC6k1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Icf4%2FbtsKCQy9FZu%2FJLTKdCPGQiikNLEXdaC6k1%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;300&quot; height=&quot;394&quot; data-filename=&quot;KakaoTalk_20230420_163901781.webp&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;&lt;b&gt;우리에겐 Pass란 없다&lt;/b&gt;.&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;맞다. 나는 Pass를 쓰지 않을 것이다. 그래서, 10월을 한번 되돌아보는 시간을 가져볼 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;많은걸 했던 10월&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2024년 10월은 뭔가를 굉장히 부지런하게 했던 달이라 그런지, 살면서 가장 기억에 많이 남는 달이 될 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;취업&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;7~8월에 수강했던 교육 후 전환이 되어서 현재는 입사를 기다리는 중이다. (12월 입사 예정)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요즘 취업 시장이 엄청 힘들다고 이야기가 많이 들리고, 나 또한 체감을 많이 하고 있다. 2024 하반기 취업 시장을 돌아본다면, 우선 나에게는 &lt;b&gt;호재&lt;/b&gt;였던 것 같다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;2023 하반기나 2024 상반기 서류 합격률을 2024 하반기와 비교해봤을 때, &lt;b&gt;2024 하반기는 50% 이상을 달성했다 (8 / 12)&lt;/b&gt;.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나의 스펙에 있어서는 여름 방학에 &lt;b&gt;대기업 부트캠프 교육&lt;/b&gt;을 수강한 이력이 추가된 것을 제외하고는 사실 크게 변한게 없다.&amp;nbsp; 그렇지만, 이전 1년 간 지원했던 결과와는 큰 차이를 경험할 수 있었다. 결국에는 ...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;&lt;b&gt;표현의 변화&lt;/b&gt;&quot;로 인해 서류 합격률을 높일 수 있었다고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서류 탈락 통보를 받았던 지원서의 JD와 자기소개서를 2번 이상 다시 읽어보고, 그 이유를 찾기 위해 많은 노력을 진행했다. 다시 읽어보며, 나의 경험을 어떻게 표현하는 것이 내가 지원할 회사에 매력적일지 더 많이 고민하면서 자기소개서를 작성했던 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고, 운도 많이 따라준 것 같다. 밑에서도 이야기 할 것이지만, 등산하면서 기도를 드렸다. 기도를 드릴 때 나의 간절함이 뭔가 취업을 시켜준 것 같다. 현재도 항상 감사하게 생각하며 주변 사람들에게도 좋은 일이 일어나게 해달라고 함께 기도하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;근데, 2023 하반기와 2024 상반기에 지원했던 회사를 2024 하반기에 다시 지원해도 계속 떨어지는 회사도 있었다. 뭔가 그 회사랑 안맞는 부분이 있다보다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그런 회사는 그냥 지원하는게 시간 낭비인 것 같다는 생각이 들었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋게 좋게 생각해야 좀 덜 우울하고, 덜 스트레스 받고, 롱런할 수 있는 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20230318_130513332.png&quot; data-origin-width=&quot;232&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zsUVC/btsKDpHBAd4/kBNtlr5sSkB6VEkMRNSj20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zsUVC/btsKDpHBAd4/kBNtlr5sSkB6VEkMRNSj20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zsUVC/btsKDpHBAd4/kBNtlr5sSkB6VEkMRNSj20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzsUVC%2FbtsKDpHBAd4%2FkBNtlr5sSkB6VEkMRNSj20%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;400&quot; height=&quot;224&quot; data-filename=&quot;KakaoTalk_20230318_130513332.png&quot; data-origin-width=&quot;232&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;등산&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저는 거주지가 경기도 북부라, 집 근처에 산이 굉장히 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 10월부터 운동도 할 겸, 기도도 드릴 겸, 힐링도 할 겸 ..... 등산을 시작하게 되었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;산은 거의 격 일로 가고있다. 정상까지 가는가? 그건 아니다. 정상까지 간다기 보다는, 산의 좋은 공기와 분위기를 통해 힐링을 하는 것이 주 목적이었다. 주로 가는 코스는 왕복 1시간 30분 정도 코스고, 가는 길에 절이 있어 새벽? 기도를 드리고 내려온다. (사실 난 무교다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요즘 또 단풍 철이라 그런지, 굉장히 사람도 많고 분위기도 좋다.&amp;nbsp;눈으로 보는거랑, 사진으로 찍는거랑 느낌이 많이 달라 아쉽다. (내가 못 찍을 수도...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20241110_164409230.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKEbSC/btsKDV6YGQm/8j2keXVKurnTe4fWkzZxf0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKEbSC/btsKDV6YGQm/8j2keXVKurnTe4fWkzZxf0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKEbSC/btsKDV6YGQm/8j2keXVKurnTe4fWkzZxf0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKEbSC%2FbtsKDV6YGQm%2F8j2keXVKurnTe4fWkzZxf0%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;400&quot; height=&quot;300&quot; data-filename=&quot;KakaoTalk_20241110_164409230.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하루는 평소 올라가던 코스와 다른 곳으로 이동해봤는데, 신기한 체험을 하게 되었다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글쎄... 흑염소가 자연에서 풀을 뜯어먹으며 놀고 있었다. 사실 좀 당황했다. ㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20241110_164723713.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9aImO/btsKCxzSE7b/KERKQPoycyxLndVZWZpNAk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9aImO/btsKCxzSE7b/KERKQPoycyxLndVZWZpNAk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9aImO/btsKCxzSE7b/KERKQPoycyxLndVZWZpNAk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9aImO%2FbtsKCxzSE7b%2FKERKQPoycyxLndVZWZpNAk%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;400&quot; height=&quot;533&quot; data-filename=&quot;KakaoTalk_20241110_164723713.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;흑염소 한 번 만져보고.. 하산을 진행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기회가 된다면, &quot;산타또&quot; 채널 분들과 함께 등산을 진행해보고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Daliy Chilli Pepper Paste Class 참여&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;뭔지 모르시겠다구요? 네. &lt;b&gt;일일 고추장 담그기 체험&lt;/b&gt;을 진행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;매년 할머니께서 요맘때 쯤에 장을 담그시고 설날에 항상 나눠주셨는데, 연세가 많으셔서 이제 힘들다고 고추장 담으러 오라는 연락을 주셨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(할머니 댁으로 부랴부랴 ... 이동)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이미 재료를 다 구매하셔서 그런지, 생각보다 고추장 담그는게 재미있었다. 할머니의 비법 레시피를 제외하고는 사실상 휘젓는게 8할 이상이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(끓이면서 휘젓고 -&amp;gt; 식으면 또 재료넣고 휘젓고 -&amp;gt; ~~~~)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 대략 3시간? 정도 만에 고추장을 완성했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20241110_165357438.jpg&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAvHJ/btsKDYvRZbJ/hqBCxDl3UblYuGx4FM7UYk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAvHJ/btsKDYvRZbJ/hqBCxDl3UblYuGx4FM7UYk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAvHJ/btsKDYvRZbJ/hqBCxDl3UblYuGx4FM7UYk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAvHJ%2FbtsKDYvRZbJ%2FhqBCxDl3UblYuGx4FM7UYk%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;400&quot; height=&quot;711&quot; data-filename=&quot;KakaoTalk_20241110_165357438.jpg&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;설날에 얼른 맛보고 싶다~!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋사좋시&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그간 만나지 못했던 친구들과, 형님들과, 교수님들도 한 번씩 찾아가서 인사를 드렸다. 그냥 뭐 ... 취업한 기념으로 밥을 많이 사줬다. 덕분에 현재 내 통장은 텅텅 비게되었다. 하지만 그런 말이 있지 않은가?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;쓸 때는 확실하게 쓰고, 모을때는 확실하게 모으자&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;감사했던 사람들에게 밥 한끼 대접한다는 느낌이어서 그런지, 돈이 하나도 아깝지 않았다. 취업하면 이제 또 자주 못 볼텐데 .... 지금 많이 봐둬야지.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리하며&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;더 많은 이벤트가 10월에 함께했지만, 제일 좋았던 부분은 &quot;가족과의 행복한 시간&quot; 이었다. 취업 기간동안 알게 모르게 매일 도와줬던 가족에게 가장 감사함을 많이 느끼고 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;친구도 좋지만, 역시 가족이 최고다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음 게시물에 Spark Optimizer에 대하여 좀 더 정리된 게시물로 찾아뵙겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kanghodong.jpg&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wsjnx/btsKDCzU6V9/TjoDE31oHwa8OVx2kC9wxk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wsjnx/btsKDCzU6V9/TjoDE31oHwa8OVx2kC9wxk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wsjnx/btsKDCzU6V9/TjoDE31oHwa8OVx2kC9wxk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwsjnx%2FbtsKDCzU6V9%2FTjoDE31oHwa8OVx2kC9wxk%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;400&quot; height=&quot;259&quot; data-filename=&quot;kanghodong.jpg&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>일상</category>
      <category>글또</category>
      <category>일상</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/21</guid>
      <comments>https://binary-kim.tistory.com/21#entry21comment</comments>
      <pubDate>Sun, 10 Nov 2024 17:09:56 +0900</pubDate>
    </item>
    <item>
      <title>[Spark 완벽 가이드] Spark 정의 및 API 둘러보기</title>
      <link>https://binary-kim.tistory.com/20</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재 저는 Hadoop / Spark / Airflow / Kafka를 공부하고 있습니다!! 이번 포스팅부터는 현재 공부 중인 &quot;&lt;b&gt;스파크 완벽 가이드&lt;/b&gt;&quot;라는 도서를 읽고 Spark라는 Tool이 무엇인지, 어떻게 작동되는지, 어떤 Data Type이 있고 어떤 특징들을 가지고 있는지 3~4차례에 나눠서 기록해보고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대략적인 Keyword는 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;Spark 정의&quot; -&amp;gt; &quot;Spark 최적화&quot; -&amp;gt; &quot;Spark Streaming&quot; (-&amp;gt; &quot;Spark ML&quot;)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선, Spark를 공부함에 있어 해당 책을 고른 이유는 딥러닝을 공부하면서 &quot;&lt;b&gt;ORELLY&lt;/b&gt;&quot; 출판사 책을 굉장히 많이 읽었었는데 내용이 너무 좋았었던 기억이 있어서 이번에도 믿고 구매를 해봤습니다. 그리고, 소프티어 교육을 들으면서 같이 공부하시던 분 중 한 분이 저 책으로 공부하시던 기억이 나서 저도 구매를 해버렸습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구매 후 느낀 점은.... &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;책이 굉장히 두껍네요 (&lt;s&gt;다 읽을 수 있을려나&lt;/s&gt;)&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;시작이 반이라는 말이 있듯이, Spark를 정복하는 그날까지! 화이팅 해보겠습니다!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Spark가 나오게 된 배경&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빅데이터하면 가장 먼저 떠오르는 두 가지 도구를 선택하라고 하면, 저는 Hadoop과 Spark라고 생각합니다. 분산 환경에서 데이터를 저장하고 처리하는 도구가 나오게 된 가장 핵심 요인은 &quot;&lt;b&gt;데이터를 저장하는 비용이 저렴해졌다&lt;/b&gt;&quot;라는 부분입니다. 과거에는 데이터를 저장하는 비용이 굉장히 비쌌기 때문에, 데이터 저장 및 처리 방식에 좀 더 신중할 수 밖에 없었던 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만, Cloud 기술의 발전과 더불어 Storage 저장 비용이 급격하게 하락하면서 대량의 데이터를 저장하는 것이 가능해졌고, 궁극적으로 데이터를 처리하는 비용보다 저렴해졌습니다. 다양한 기업에서는 이러한 이점으로 인하여 더 많은 데이터를 수집하고 분석하려는 수요가 많아지게 되었고, 이에 맞게 데이터를 효율적으로 빠르게 처리할 수 있는 도구가 필요해진 상황에 직면했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;데이터 저장 비용이 저렴하다 보니 아마도 &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&quot;xxx님, 일단 그냥 다 저장하고 처리는 나중에 생각해요~&quot;로 이어졌을 것입니다. 근데, 데이터를 모아두고 보니 &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&quot;&lt;b&gt;어떻게 처리하지&lt;/b&gt;?&quot;라는 관점이 생겼고, 이러한 상황에서 Spark라는 Tool이 개발되지 않았나 생각합니다.&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;s&gt;(그래서 Spark가 뭔데 씹덕아?)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Spark란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark를 설명하기에 앞서, Hadoop의 개념을 잠시 정리하고 가보겠습니다. Hadoop은 크게 &lt;b&gt;Storage Layer / Resource Management Layer / Application Layer&lt;/b&gt; 총 3단계로 나뉩니다. 이 3가지 Layer 중 Spark는 &lt;b&gt;Application Layer&lt;/b&gt;에 속하게 됩니다. Application Layer는 데이터를 처리하는 단계를 의미합니다. 즉, 분산되어있는 대량의 데이터를 병렬로 처리함으로써 데이터의 효율성을 극대화할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 관점에서 Spark를 바라본다면...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark는 대규모 데이터 처리 및 분석을 위해 설계된 오픈 소스 분산 컴퓨팅 시스템입니다. 기본적으로, 컴퓨팅 기능 (&lt;b&gt;In-Memory Caching&lt;/b&gt;)을 활용하여 빠른 데이터 처리 속도를 제공하며, 대규모 데이터셋에 대해 복잡한 쿼리 / 분석을 효율적으로 수행할 수 있도록 도와줍니다.&amp;nbsp;여기서 한 가지 의문이 들 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Hadoop에도 데이터를 처리 / 집계하는 MapReduce가 있는데, 왜 굳이 Spark를 사용해야 할까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해당 질문에 대한 답변은 MapReduce와 Spark의 데이터 처리 방식을 이해하면 납득이 갑니다. &quot;A-&amp;gt;B-&amp;gt;C-&amp;gt;D&quot; 작업을 순차적으로 수행하며, 이전 작업이 현재 작업에 영향을 미치는 상황이라고 가정해보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Hadoop의 MapReduce는 한 번의 작업이 수행될 때마다 HDFS에서 &lt;b&gt;File I/O&lt;/b&gt;를 수행해야한다. File I/O는 물리적인 Storage에 읽기 / 쓰기 하는 작업이기에, 상당히 느리다. 매 단계에서의 결과를 HDFS에 다시 기록하고, 다음 단계에서 이를 활용해야 한다. 이로 인하여 대규모 데이터 처리에선 적합하지만, 실시간으로 데이터를 처리하는 관점에선 한계점이 존재하게 되는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반면, Spark는 MapReduce와 다르게 중간 결과를 HDFS에 저장하지 않고 &lt;b&gt;메모리에 저장&lt;/b&gt;하는 방식을 활용하여 빠르게 데이터를 처리할 수 있다는 장점이 있습니다. 물론, 메모리에 캐싱 느낌으로 저장해서 관리하기 때문에 MapReduce에 비해 빠르지만 Cost가 높은 연산입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결국 핵심은...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;Spark가 메모리 기반의 빠른 데이터 처리를 가능하게 하여, 실시간 데이터 처리 및 복잡한 분석 작업에서 더 뛰어난 성능을 발휘한다&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Spark는 어떻게 작동할까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Driver 생성 및 리소스 요청&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark 애플리케이션이 시작되면 가장 먼저 Cluster 노드 중 하나에 &lt;b&gt;Spark Driver&lt;/b&gt;가 생성됩니다. 그 후에, Yarn / Mesos / Kubenetes 등과 같은 Cluster Manager와 통신하며 작업에 필요한 리소스를 요청합니다. 그 후, Cluster Manager는 CPU / RAM / Executor 수 등 작업에 필요한 리소스를 할당해줍니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여기서 Cluster Manager는 Hadoop에서의 Resource Management Layer 역할을 수행하고, Spark Driver가 설치된 Cluster는 Hadoop에서 Application Layer 역할을 수행합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Spark Context 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark Driver는 Cluster와의 연결을 관리하고, 애플리케이션 실행에 필요한 환경을 설정하는 &lt;b&gt;Spark Context&lt;/b&gt;를 생성합니다. Spark Context는 사용자가 입력한 코드에서 Transformation 연산을 수행하며, 해당 연산은 &lt;b&gt;RDD Lineage&lt;/b&gt;하게 표현됩니다. Action이 호출되기 전까지 Spark Context는 데이터를 실제로 처리하지 않는다는 부분이 제일 중요한 Key Point 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Action 호출 (연산 수행)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Action이 호출되면, Spark Context는 이때까지 생성된 RDD Lineage를 기반으로 DAG를 생성합니다. Spark Context는 DAG를 분석해서 Spark Job을 생성합니다. 하나의 Job은 Wide Tranformation 연산에 따라 여러 Stage로 나뉠 수 있으며, 각 Stage는 여러 Task로 나뉠 수 있습니다. 여기서 주목할 만한 부분은 &quot;&lt;b&gt;Stage가 나뉜다&lt;/b&gt;&quot;입니다. 그 이유는 ...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;Stage가 나뉜다&quot; = &quot;하나의 Executor에서 데이터를 처리한 결과가 2개 이상이다&quot; = &quot;Cluster 간 Shuffle이 발생한다.&quot; =&amp;nbsp;&quot;데이터의 네트워크 이동이 필요하다&quot; = &quot;연산 비용이 증가한다&quot;로 이어질 수 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결국엔, count()나 collect()와 같은 Wide Transformation 작업을 얼마나 적게 수행하는지는 실제 Spark Job 연산에 큰 영향을 미칠 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;뭔가 작업을 처리해야하는 상황에서 최적화를 할려면 .... 중요하겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;데이터는 어떻게 저장될까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark는 다양한 데이터 형식으로 데이터를 저장하고 활용할 수 있습니다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;JSON(JavaScript Object Notation)&lt;/b&gt;은 가독성이 좋고, 구조화된 데이터를 표현하는 데 적합한 자료구조입니다. 특히, CSV에서는 표현이 불가능한 &quot;&lt;b&gt;데이터 간 계층적인 구조&lt;/b&gt;&quot;를 표현하기에 매우 적합합니다. JSON은 주로 비정형 데이터 저장에 많이 활용하는데, 저장 공간이 상대적으로 크다는 단점을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;CSV(Comma Seperated Values)&lt;/b&gt;는 텍스트 파일 형식으로, 쉼표(,)를 기준으로 구분되어 저장된 구조를 의미합니다. CSV는 간단한 데이터 저장 및 전송에 적합하며, 대부분의 데이터 처리 도구에서 지원하기 때문에 널리 사용됩니다. 그러나 데이터 타입을 명시할 수 없고, 대규모 데이터셋에서는 성능이 저하될 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;b&gt;Parquet&lt;/b&gt;는 컬럼 기반 저장 형식으로, 대규모 데이터 처리에 최적화되어 있습니다. Apache &lt;b&gt;Hadoop&lt;/b&gt;과의 호환성이 뛰어나며, 스키마를 명확하게 정의할 수 있어 대량의 데이터를 효율적으로 처리할 수 있습니다. Parquet는 데이터 압축과 효율적인 I/O를 지원하여 성능이 우수합니다. AWS Redshift가 컬럼 기반 저장 형식의 예시입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Spark에서 메모리는 어떻게 관리하는가?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;657&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx34XC/btsKhKfnDCo/NrkftyWKAbWJqpv5DUp0t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx34XC/btsKhKfnDCo/NrkftyWKAbWJqpv5DUp0t0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx34XC/btsKhKfnDCo/NrkftyWKAbWJqpv5DUp0t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx34XC%2FbtsKhKfnDCo%2FNrkftyWKAbWJqpv5DUp0t0%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;400&quot; height=&quot;420&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;657&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spark는 크게 Reserved Memory / User Memory / Spark Memory 총 3개로 나뉩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Reserved Memory&lt;/b&gt;는 말 그대로 &quot;예약 메모리&quot;입니다. OS를 설치할 때 기본적으로 잡아먹는 메모리가 존재하듯이, Spark를 작동시키기 위한 시스템 프로세스나 기타 메모리 관련 Overhead를 처리하는데 사용되는 메모리입니다. Default로는 300MB로 설정되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;User Memory&lt;/b&gt;는 Java Heap에서 Reserved Memory를 제외한 영역 중 일부를 차지하며, Default는 25%로 설정되어 있습니다. 사용자 정의 객체(User Defined Function)나 사용자가 정의한 변수, 외부 라이브러리를 사용할 때 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;해당 메모리 영역을 사용하게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;Spark Memory&lt;/b&gt;는 User Memory를 제외한 나머지 영역을 의미합니다. 해당 메모리는 Execution Memory와 Storage Memory로 나뉘어 활용됩니다. Execution Memory에서는 Spark Job 실행 중에 사용되는 메모리로써, Shuffle / Join / Aggregation 연산으로 인해 생성된 중간 결과를 저장하는데 사용되는 메모리입니다. 작업 실행 중 &quot;Java Heap에서 Out Of Memory&quot;가 발생하면, 해당 메모리 영역이 부족하다는 것을 의미합니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Storage Memory에서는 RDD나 DataFrame 등을 저장하는 데 사용하는 메모리로, Spark Session에서 &lt;b&gt;.cache()&lt;/b&gt;나 &lt;b&gt;.persist()&lt;/b&gt;를 사용할 때 활용되는 메모리입니다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 메모리 영역은 Spark Session을 생성할 때 config로써 변경하여 활용할 수 있습니다. 특정 사용자가 Spark를 사용할 때 처리해야 할 데이터의 규모나 연산량을 예측할 수 있다면, 그에 맞게 메모리를 변경하여 사용하는 것 또한 최적화의 일부이지 않을까 하는 생각이 듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Dataset vs DataFrame&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Dataset과 DataFrame은 Spark에서 고수준 API를 통해 제공되는 데이터 구조로, 대규모 데이터를 처리하고 분석하기 위한 최적의 방식을 제공합니다. 두 데이터 구조를 분석해보자면 ...&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Dataset는 RDD와 DataFrame의 장점을 결합한 구조라고 합니다. DataFrame과의 큰 차이점은 &quot;&lt;b&gt;타입 안정성&lt;/b&gt;&quot; 측면입니다. DataFrame은 실제 데이터를 활용할 때(RunTime) 저장된 데이터의 Type을 확인하는 반면, Dataset은 &lt;b&gt;컴파일 단계&lt;/b&gt;에서 데이터의 Type읠 확인하기 때문에 상대적으로 안정성이 높습니다. 그렇지만, Dataset은 Java나 Scala에서만 활용이 가능하고, Python과 R에서는 지원하지 않는다는 특징을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DataFrame은 데이터가 행/열로 구조화 된 형태이며, 비정형 및 반정형 데이터를 처리할 때도 효율적으로 활용할 수 있습니다. 그리고, RDD보다 좀 더 높은 수준의 API로 데이터에 대한 추상화를 제공한다는 장점을 가지고 있습니다. DataFrame은 Java / Scala / Python / R에서 모두 제공한다는 특징을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;고수준 API의 공통적인 특징은 &quot;빠르고 편리하다&quot;라고 생각합니다. SQL 쿼리와 같이 친숙한 방식으로써 데이터에 접근할 수 있으며, Spark 내부의 Catalyst Optimizer와 Tungsten을 통해 최적화된 Spark Job을 실행할 수 있다는 장점이 있습니다. 그래서인지, 실습할 때 RDD보다는 DataFrame을 많이 사용했던 것 같네요 ㅎㅎ.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;RDD (Resilient Distributed Data)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;RDD는 Spark에서 사용되는 저수준 API로써, 탄력적인 분산 데이터셋이라는 이름을 가지고 있습니다. 다수의 서버(Cluster, Node)에 걸쳐 분산 형태로 저장된 요소들의 집합을 RDD라고 이야기합니다. RDD는 크게 3가지 특징을 가지고 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;첫 번째로, RDD는 &lt;b&gt;추상화된 형태&lt;/b&gt;로 제공됩니다. 실제로는 여러 Cluster에 분산되어 데이터가 존재하지만, 사용자가 데이터를 활용할 때는 하나의 통합된 데이터로 생각하여 사용할 수 있습니다. 두 번째로, RDD는 &lt;b&gt;탄력적이며 불변성&lt;/b&gt;을 가지고 있습니다. 즉, 네트워크 장애로 인해 연산을 정상적으로 종료하지 못했을 때, 이전 RDD 연산으로 이동하여 스스로 복구할 수 있는 내성을 가지고 있습니다.&amp;nbsp;마지막으로, RDD를 포함한 Spark 연산은&lt;b&gt; Lazy Evaluation&lt;/b&gt;을 제공합니다. Transformation 연산이 사용자에 의해 호출되더라도, count(), collect() 등의 Action 연산이 호출되기 전까지 작업을 수행하지 않습니다. Action 연산이 호출되었을 때 비로소 RDD Lineage하게 구성된 DAG 형태의 Spark Job이 각 Executor에서 수행됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;RDD는 고수준 API인 DataFrame에 비해 연산 속도가 많이 느립니다. 그 이유는, Dataset이나 DataFrame은 Spark 내부의 &lt;b&gt;Catalyst Optimizer&lt;/b&gt;에 의해 최적화된 상태로 작업을 수행하게 되지만 RDD는 그렇지 않습니다. 여기서도 한 가지 의문이 생길 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;DataFrame보다 느린데, 왜 써야되죠?&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최적화가 되어 있지 않지만, RDD를 사용해야하는 혹은 사용할 수 있는 상황이 몇가지 존재합니다. 예를 들어, 처리하고자 하는 데이터의 형태가 Text / Binary와 같은 &lt;b&gt;비정형 데이터&lt;/b&gt;일 때는, DataFrame에 비해 효율적일 수 있습니다. 웹 서버 로그 파일에서 특정 IP 주소에서만 발생한 요청 수를 계산하는 상황에서는 오히려 RDD가 빠를 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결국엔, 처리하고자하는 상황에 맞는 방법을 선택하여 활용하는 것이 중요해 보입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;마무리하며&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오늘은 Spark가 나오게 된 배경과 더불어, 데이터 저장 방식 및 API에 대해서 정리하는 글을 작성해봤습니다. 저 또한 Spark를 배워나가는 입장이고, 앞으로도 Spark를 사용할 일이 굉장히 많을 것으로 예상되는데요. 그러한 입장에서, 새로 Spark를 공부하시는 분들이 제 게시물을 읽고&amp;nbsp;많은 도움이 되었으면 좋겠다는 생각이 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음 게시글은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Spark 최적화와 관련된 내용으로 다시 오겠습니다!!&amp;nbsp;&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;긴 글 읽어주셔서 감사합니다. :)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Reference&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[스파크 완벽 가이드]&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[스파크 메모리 정리] &lt;a href=&quot;https://0x0fff.com/spark-memory-management/&quot;&gt;https://0x0fff.com/spark-memory-management/&lt;/a&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Apache Spark</category>
      <author>binary-kim</author>
      <guid isPermaLink="true">https://binary-kim.tistory.com/20</guid>
      <comments>https://binary-kim.tistory.com/20#entry20comment</comments>
      <pubDate>Fri, 25 Oct 2024 16:16:04 +0900</pubDate>
    </item>
  </channel>
</rss>