<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://ggoals.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ggoals.github.io/" rel="alternate" type="text/html" /><updated>2020-03-30T17:29:05+00:00</updated><id>https://ggoals.github.io/feed.xml</id><title type="html">Ggoals</title><subtitle>wanna be full-stack developer ( + Data Eng + ML... LOL :) )</subtitle><entry><title type="html">Druid..!!</title><link href="https://ggoals.github.io/Druid/" rel="alternate" type="text/html" title="Druid..!!" /><published>2018-09-20T00:00:00+00:00</published><updated>2018-09-20T00:00:00+00:00</updated><id>https://ggoals.github.io/Druid</id><content type="html" xml:base="https://ggoals.github.io/Druid/">&lt;h1 id=&quot;druid-components-in-design&quot;&gt;Druid Components in Design&lt;/h1&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;ㅁ-when-should-i-use-druid&quot;&gt;ㅁ When should I use Druid?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Insert rates are very high, but updates are less common. &lt;br /&gt;
 ( 사실 Insert 만 있어야함. update 는 안됌. 모든 Data 는 immutable 한 상태라 보는 것이 맞음 )&lt;/li&gt;
  &lt;li&gt;Most of your queries are aggregation and reporting queries (“group by” queries). You may also have searching and scanning queries. &lt;br /&gt;
 group by, filtering 을 구현하기에 좋다&lt;/li&gt;
  &lt;li&gt;You are targeting query latencies of 100ms to a few seconds. &lt;br /&gt;
( 100ms ~ 수초 이내에 query response 가 요구될 때 )&lt;/li&gt;
  &lt;li&gt;Your data has a time component &lt;br /&gt;
 ( 이것도 필수임 )&lt;/li&gt;
  &lt;li&gt;You have high cardinality data columns (e.g. URLs, user IDs) and need fast counting and ranking over them. &lt;br /&gt; ( Counting, Ranking 같은 연산은 참 빠름 )&lt;/li&gt;
  &lt;li&gt;You want to load data from Kafka, HDFS, flat files, or object storage like Amazon S3. ( 나름 유명한 데이터 오픈소스와의 integration 을 잘 지원해줌 )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;ㅁ-그렇다면-쓰지-말아야-할때는&quot;&gt;ㅁ 그렇다면 쓰지 말아야 할때는??&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;참 아이러니 하게도(?) Druid 는 쓰지 말아야 할때를 공식문서에 잘 정리해 두었다. ( 뭔가 믿음직 스러운… +_+ ㅎㅎ )&lt;/li&gt;
  &lt;li&gt;primary key 를 통한 update&lt;/li&gt;
  &lt;li&gt;query latency 가 중요한 reporting 시스템&lt;/li&gt;
  &lt;li&gt;“big” join 이 필요한 query ( 20만건 이내는 lookup 으로 해결 가능하긴 함, Infra 성능에 따라 다릅니다. )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;ㅁ-druids-main-features&quot;&gt;ㅁ Druid’s main features&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Columnar storage format&lt;/li&gt;
  &lt;li&gt;Scalable distributed system&lt;/li&gt;
  &lt;li&gt;Massively parallel processing&lt;/li&gt;
  &lt;li&gt;Realtime or batch ingestion&lt;/li&gt;
  &lt;li&gt;Self-healing, self-balancing, easy to operate&lt;/li&gt;
  &lt;li&gt;Cloud-native, fault-tolerant architecture that won’t lose data&lt;/li&gt;
  &lt;li&gt;Indexes for quick filtering&lt;/li&gt;
  &lt;li&gt;Approximate algorithms&lt;/li&gt;
  &lt;li&gt;Automatic summarization at ingest time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;ㅁ-architecture&quot;&gt;ㅁ Architecture&lt;/h2&gt;
&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/druid/architecture_1.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;storage&quot;&gt;Storage&lt;/h3&gt;
&lt;h4 id=&quot;-segments&quot;&gt;   Segments&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;segment file’s data structure : Timestamp, Demensions, Metrics&lt;/li&gt;
  &lt;li&gt;Multi-value Columns 도 가능함 ( 여러개 들어가도 Bitmap indexing 이 가능하기 때문)
``` javascript
1: Dictionary that encodes column values
  {
 “Justin Bieber”: 0,
 “Ke$ha”:         1
  }&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2: Column data
  [0,
   [0,1],  &amp;lt;–Row value of multi-value column can have array of values
   1,
   1]&lt;/p&gt;

&lt;p&gt;3: Bitmaps - one for each unique value
  value=”Justin Bieber”: [1,1,0,0]
  value=”Ke$ha”:         [0,1,1,1]
                            ^
                            |
                            |
    Multi-value column has multiple non-zero entries&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;br/&amp;gt;
##### &amp;amp;nbsp;&amp;amp;nbsp; Data Structures
![_config.yml](/images/druid/data_structure.png) &amp;lt;br/&amp;gt;
 
 - 기본적으로 Timestamp, Dimensions, Metrics 가 있음
 - Dimensioons 컬럼에 의해 group-by, filter operation 이 일어남

&amp;lt;br/&amp;gt;
##### Segment Components
 - `version.bin` : 4bytes 로 버전을 나타냄
 - `meta.smoosh` : meta data ( 다른 smoosh 파일에 대한 )
 - `XXXXX.smoosh` : 데이터의 minimized 된 파일. 데이터의 각 열에 대한 개별 파일과 Segment 에 대한 extra metadata 가 있는 index.drd 파일이 있음

&amp;lt;br/&amp;gt;
##### Format of a column
```text
    1. A Jackson-serialized ColumnDescriptor
    2. The rest of the binary for the column
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;sharding&quot;&gt;Sharding&lt;/h5&gt;
&lt;p&gt;Segment 의 form 은 interval 별 block 이다. 이 block 은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shardSpec&lt;/code&gt;에 의존하고 druid의 queries 는 이 block 이 완성되어야만 완료된다. ( 즉, block 이 만들어 지기 전까지는 해당 interval 에 대해선 query 가 안날라 간다는 의미인듯 함 )&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//example block files
sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_0
sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_1
sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;ㅁ-nodes-types&quot;&gt;ㅁ Nodes Types&lt;/h3&gt;
&lt;h4 id=&quot;historical&quot;&gt;Historical&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Running
    &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;io.druid.cli.Main server historical
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;&lt;br /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;역할
    &lt;ul&gt;
      &lt;li&gt;Segments 를 로딩하고 서빙하는 역할, 캐시에 저장해놓는 역할&lt;/li&gt;
      &lt;li&gt;Segments 에 대해서 querying 하는 역할도 담당 ( groupBy, topN 등 쿼리의 경우 historical nodes 에서 부분적으로 먼저 처리하고 처리한 결과를 전달 )&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;broker&quot;&gt;Broker&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;역할
    &lt;ul&gt;
      &lt;li&gt;query 라우팅 역할 ( 주키퍼를 통해 쿼리할 대상의 노드를 알아냄.)&lt;/li&gt;
      &lt;li&gt;Historical Nodes 로부터 받은 결과를 merge 한다.&lt;/li&gt;
      &lt;li&gt;Realtime Nodes 로부터도 결과를 같이 받아 merge 한다.&lt;/li&gt;
      &lt;li&gt;LRU caching per-segment results&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;coordinator&quot;&gt;Coordinator&lt;/h4&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;io.druid.cli.Main server coordinator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;HTTP endpoints supported : 리더 정보, 세그먼트 로딩, 데이터소스 정보 GET, 데이터 소스 POST, 리텐션 룰 GET 등&lt;/li&gt;
  &lt;li&gt;primarily responsible for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;segment management and distribution&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;주기적으로 돌면서 적절한 action 을 취함.&lt;/li&gt;
  &lt;li&gt;broker / historical nodes 와 비슷하게 zookeeper 와 연결되어 현재 클러스터의 정보를 얻는다.&lt;/li&gt;
  &lt;li&gt;또한 available segments 와 rules 정보를 위해 metastore 와도 connection을 맺고 있다.&lt;/li&gt;
  &lt;li&gt;역할 : Cleaning Up Segments, Historical Nodes 로 로딩되는 Segments 의 밸런싱을 담당.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;indexing-service&quot;&gt;Indexing Service&lt;/h4&gt;
&lt;h5 id=&quot;overlord&quot;&gt;Overlord&lt;/h5&gt;
&lt;ul&gt;
  &lt;li&gt;역할 : Task 를 받고, Task 를 분배하는 역할을 한다. 그리고 caller 에게 Task 에 대한 결과를 return 해준다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5 id=&quot;middlemanager&quot;&gt;MiddleManager&lt;/h5&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;io.druid.cli.Main server middleManager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;역할 : submitted 된 task 를 처리하는 worker node다. peon 앞에서 task 를 전달해주는 역할을 한다.
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;ㅁ-dependencis&quot;&gt;ㅁ Dependencis&lt;/h3&gt;
&lt;h4 id=&quot;deep-storage&quot;&gt;Deep Storage&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Types : Local Mount, S3-compatible, HDFS, etc..
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;metadata-storage&quot;&gt;Metadata Storage&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Types : derby ( for not production), MySQL, PostgreSQL&lt;/li&gt;
  &lt;li&gt;Metadata Storage Tables
    &lt;ul&gt;
      &lt;li&gt;Segments Table
        &lt;ul&gt;
          &lt;li&gt;used column : 사용 여부&lt;/li&gt;
          &lt;li&gt;payload column :
            &lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dataSource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;wikipedia&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;interval&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-05-23T00:00:00.000Z/2012-05-24T00:00:00.000Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-05-24T00:10:00.046Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;loadSpec&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3_zip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;bucket&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bucket_for_segment&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/segment/on/s3&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dimensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;comma-delimited-list-of-dimension-names&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;metrics&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;comma-delimited-list-of-metric-names&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;shardSpec&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;binaryVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;size_of_segment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;identifier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;wikipedia_2012-05-23T00:00:00.000Z_2012-05-24T00:00:00.000Z_2012-05-23T00:10:00.046Z&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;            &lt;/div&gt;
          &lt;/li&gt;
          &lt;li&gt;Druid cluster 의 segement 관리는 MySQL 을 통해 저장된다. 그렇기에 Segments 를 Delete 후 Reload 할때에도 API 를 통해서도 되지만 MySQL Segment 테이블의 Used 를 1 로 하는 방법도 있다. ( 단!! 주의!! Overwirte 된 Segment 의 경우 version 이 높은 것만 골라서 1로 바꿔줘야 한다.)
            &lt;h4 id=&quot;zookeeper&quot;&gt;Zookeeper&lt;/h4&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;역할
    &lt;ul&gt;
      &lt;li&gt;Coordinator leader election&lt;/li&gt;
      &lt;li&gt;Segment “publishing” protocol from Historical and Realtime&lt;/li&gt;
      &lt;li&gt;Segment load/drop protocol between Coordinator and Historical&lt;/li&gt;
      &lt;li&gt;Overlord leader election&lt;/li&gt;
      &lt;li&gt;Indexing Service task management&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><summary type="html">Druid Components in Design</summary></entry><entry><title type="html">Streaming System A-Z</title><link href="https://ggoals.github.io/Streaming_System_A-Z/" rel="alternate" type="text/html" title="Streaming System A-Z" /><published>2018-03-21T00:00:00+00:00</published><updated>2018-03-21T00:00:00+00:00</updated><id>https://ggoals.github.io/Streaming_System_A-Z</id><content type="html" xml:base="https://ggoals.github.io/Streaming_System_A-Z/">&lt;h2 id=&quot;slide&quot;&gt;Slide&lt;/h2&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/HwFOBG9pZ3flYC&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen=&quot;&quot;&gt; &lt;/iframe&gt;
&lt;div style=&quot;margin-bottom:5px&quot;&gt; &lt;strong&gt; &lt;a href=&quot;//www.slideshare.net/ssusera7e5ca/sk-planet-streaming-system&quot; title=&quot;SK planet Streaming system&quot; target=&quot;_blank&quot;&gt;SK planet Streaming system&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;https://www.slideshare.net/ssusera7e5ca&quot; target=&quot;_blank&quot;&gt;용휘 김&lt;/a&gt;&lt;/strong&gt; &lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;링크 : &lt;a href=&quot;https://www.slideshare.net/ssusera7e5ca/sk-planet-streaming-system&quot;&gt;Slide Share 링크&lt;/a&gt;
&lt;br /&gt;
SK planet 의 개인화 추천팀에서 스트리밍 시스템에 대한 고민과 회고성 내용을 담은 얘기 입니다.
&lt;br /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">Slide SK planet Streaming system from 용휘 김</summary></entry><entry><title type="html">Personalization Recommend in SK planet</title><link href="https://ggoals.github.io/About_Personalization_Recommend_Platform_Colloseo/" rel="alternate" type="text/html" title="Personalization Recommend in SK planet" /><published>2018-03-19T00:00:00+00:00</published><updated>2018-03-19T00:00:00+00:00</updated><id>https://ggoals.github.io/About_Personalization_Recommend_Platform_Colloseo</id><content type="html" xml:base="https://ggoals.github.io/About_Personalization_Recommend_Platform_Colloseo/">&lt;h2 id=&quot;slide&quot;&gt;Slide&lt;/h2&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/lF7fii80fQoC5M&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen=&quot;&quot;&gt; &lt;/iframe&gt;
&lt;div style=&quot;margin-bottom:5px&quot;&gt; &lt;strong&gt; &lt;a href=&quot;//www.slideshare.net/JaehoonJung/skplanet-sk-ict-tech-summit-2017-skplanet-sk-ict-tech-summit-2017&quot; title=&quot;SKPlanet 추천 플랫폼 콜로세오 - SK ICT Tech Summit 2017 SKPlanet 추천 플랫폼 콜로세오 - SK ICT Tech Summit 2017 &quot; target=&quot;_blank&quot;&gt;SKPlanet 추천 플랫폼 콜로세오 - SK ICT Tech Summit 2017 SKPlanet 추천 플랫폼 콜로세오 - SK ICT Tech Summit 2017 &lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;https://www.slideshare.net/JaehoonJung&quot; target=&quot;_blank&quot;&gt;Jaehoon Jung&lt;/a&gt;&lt;/strong&gt; &lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;링크 : &lt;a href=&quot;https://www.slideshare.net/JaehoonJung/skplanet-sk-ict-tech-summit-2017-skplanet-sk-ict-tech-summit-2017&quot;&gt;Slide Share 링크&lt;/a&gt;
&lt;br /&gt;
2016 ~ 2017년 동안 구축한 SK planet 의 개인화 추천 플랫폼 Colloseo 에 대한 내용입니다.
&lt;br /&gt;
정말 열심히 한 프로젝트이기도 하고, 스스로 자부심을 갖게 해준 프로젝트 이기도 하네요. 정치적으로 탈도 많고 말도 많았지만, 분명히 눈에 띄는 성과를 이뤄냈고, 제 커리어에 큰 자부심이 되어줄 프로젝트입니다. 함께해 주신 기획자, 개발자, 분석가 그리고 도와주신 타팀 여러분들께 이자리를 빌어 모두 감사드립니다. 특히 고생하신 팀장님께 다시 한번 감사드릴게요 ㅎㅎ&lt;/p&gt;

&lt;h2 id=&quot;more-important-who-than-what&quot;&gt;More Important “Who” than “What”&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;무엇을 만드느냐 보다 누가 그리고 누구와 함께 만드냐가 중요함을 알게해준 프로젝트 입니다. &lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;Ownership 을 가진 개발자들이 모여 제품을 만들 때, 얼마나 멋진 퍼포먼스가 나는지 알게된 프로젝트네요 :) &lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><summary type="html">Slide SKPlanet 추천 플랫폼 콜로세오 - SK ICT Tech Summit 2017 SKPlanet 추천 플랫폼 콜로세오 - SK ICT Tech Summit 2017 from Jaehoon Jung</summary></entry><entry><title type="html">Spark ALS Tuning By Intel …</title><link href="https://ggoals.github.io/Spark_ALS_Algorithm_tuning/" rel="alternate" type="text/html" title="Spark ALS Tuning By Intel ..." /><published>2018-01-22T00:00:00+00:00</published><updated>2018-01-22T00:00:00+00:00</updated><id>https://ggoals.github.io/Spark_ALS_Algorithm_tuning</id><content type="html" xml:base="https://ggoals.github.io/Spark_ALS_Algorithm_tuning/">&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;오늘 다룰 내용은 Spark 에서 추천 서비스를 위해 제공하는 ALS 알고리즘에서 있었던 문제들과 이를 어떻게 튜닝했고, 얼마나 성능이 좋아졌는지에 대해 발표한 내용을 공유하는 자리입니다. ( Intel 이 튜닝한 내용을 참조했습니다. )&lt;/p&gt;

&lt;p&gt;사실 이 부분에 대해서 공부하고, 발표를 준비 하면서 많이 든 생각은 “스파크 정도 되는 오픈소스를 하시는 분들도 이런 실수를 하는구나…” 를 느끼면서 대용량 데이터를 이용하여 추천 서비스를 하는게 얼마나 어려운지와 “과연 AI 에서는 알고리즘이 다 일까? 빅데이터를 넘어서 AI 의 시대로 가고 있는 이 상황에서 엔지니어들이 positioning, contribute 할 수 있는 부분은 어떤 부분이 있을까?”에 대한 어느정도 방향 제시가 되었다 생각하여 정말 기쁩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/als-algorithm-tuning/1.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
링크 : &lt;a href=&quot;https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf&quot;&gt;Google’s Hidden Technical Debt in Machine Learning Systems&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;구글에서 2015년에 발표한 문서입니다. 대략적인 내용은 “Machine Learning 은 우리에게 판타스틱한 기능을 제공함은 분명하지만 대충대충 빠르게 만든 ML 서비스는 매우 비싸고 힘든 유지비용이 들것이다.” 라는 것입니다.&lt;/p&gt;

&lt;p&gt;으잉?? 왠 갑자기 ALS 알고리즘 튜닝 얘기한다 하시고 이런 걸 설명하죠?? +_+??&lt;br /&gt;
Intel 에서 Spark 의 ALS 알고리즘을 튜닝한게, 과연 단순 알고리즘의 문제였을까요?&lt;br /&gt;
&lt;br /&gt;
오늘의 얘기는 제가 보여드린 이 그림을 마음속 한켠에 간직하고 보시면 어떨까 싶습니다 :)&lt;/p&gt;

&lt;h2 id=&quot;spark-recommendation-system&quot;&gt;Spark Recommendation System&lt;/h2&gt;
&lt;p&gt;당연히 Spark 문서에도 잘 나와있구요 :)
링크 : &lt;a href=&quot;http://spark.apache.org/docs/latest/ml-collaborative-filtering.html&quot;&gt;Spark Collaborative Filtering&lt;/a&gt;
&lt;br /&gt;
알고리즘에 대해서는 많은 분들이 잘 설명해주셨습니다. ㅎㅎ
특히 아래 slide share 가 깔끔하게 잘 설명 되어 있더라구요.
링크 : &lt;a href=&quot;https://www.slideshare.net/madvirus/als-ws&quot;&gt;ALS WS에 대한 이해 자료&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;als-summary&quot;&gt;ALS summary&lt;/h2&gt;
&lt;p&gt;사실 오늘 얘기는 ALS 알고리즘에 대해 다루진 않을 겁니다. 설명이 잘되어 있는 블로그도 많고 오래된(?) 알고리즘 이라 저보다 더 많은 고수들이 많으실 것이기에… +_+… ( 절대 귀찮아서 아닙니다… ㅋㅋ )
&lt;br /&gt;
Spark ALS example 코드는 spark github 에서 보실수 있습니다 ㅎㅎ &lt;br /&gt;
링크 : &lt;a href=&quot;https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/ml/ALSExample.scala&quot;&gt; Spark ALS Example &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/als-algorithm-tuning/2.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
CF 의 한 종류인 MF 를 하는 방법중 하나 인데요. User to Item 의 Score 을 ( 이때 스코어가 explicit 일수도 implicit 일수도 있습니다. ) 표현되어진 Matrix 가 있다면 이를 적당한 Rank 를 가진 User Latent Feature Matrix 와 Item Latent Feature Matrix 로 분해하는 것입니다. 보통 Rank 를 구하는 방법도 여러가지 있지만 Spark 의 ALS 알고리즘 에서는 이를 하나의 하이퍼 파리미터로 생각하고 User 가 Rank 값을 적절하게 정해주도록 되어 있습니다. ( Convex Relaxation 을 통해 최적의 Rank 구하는 방법도 있는거로 압니다. 😃 )&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/als-algorithm-tuning/3.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
이때 Iteration 한번에 User Vector 를 고정시킨 후 Item Vector 를 변경하고, Item Vector 를 고정시키고 User Vector 값을 변경하고 … 이렇게 여러번 하다보면 상당히 그럴싸한(?) User Vector 와 Item Vector 가 나옵니다~~ 이런 얘기 입니다. ㅎㅎ 
&lt;br /&gt;
사실 앞 수식이 제일 critical 하고, 뒤에는 Overfitting 을 방지하기 위한 Tikhonov regularization 입니다. 또 Feature 의 성향에 따라 negative 한 값을 줘도 되는지 아니면 all positive 한 값으로 Feature 를 구해야 하는 지 등 변형해서 쓸 수 있습니다. ( Spark 에서는 nonnegative 는 false 가 default 입니다 ㅎㅎ )
&lt;br /&gt;
참고로 Nonnegative 와 negative 는 Latent Feature 를 Optimization 하는 방식이 다릅니다. 앞에껀 NNLS 를 사용하고 뒤에껀 Cholskey decomposition 을 사용합니다. 둘마다 특징이 있으니 이점 참고하세요 :)&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;/h2&gt;
&lt;h3 id=&quot;ㅁ-gc-problem-and-oom-frequently-in-recommendforall-method&quot;&gt;ㅁ GC Problem and OOM frequently in recommendForAll method&lt;/h3&gt;
&lt;p&gt;링크 : &lt;a href=&quot;https://issues.apache.org/jira/browse/SPARK-20446&quot;&gt;SPARK-20446&lt;/a&gt;
&lt;br /&gt;
내용은 간단합니다. User Vector * Item Vector 계산 시에 Top Item 을 뽑아오는 로직에서 계산된 모든 결과를 저장하지 않고 가져올 Top N 의 갯수만 저장하겠다는 것입니다. 이전에는 User 별로 Item Prediction Score 를 전부 저장하고 그 걸 sorting 해서 top N 을 가져오는 것이였는데, Item 갯수가 많을 경우 당연히 시스템이 뻗겠죠 ^^;
&lt;br /&gt;
 ㅁ mllib/src/main/scala/org/apache/spark/mllib/recommendation/MatrixFactorizationModel.scala
&lt;strong&gt;변경전&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcBlocks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blockify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rank&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srcFeatures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dstBlocks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blockify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rank&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dstFeatures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ratings&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcBlocks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;cartesian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dstBlocks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;flatMap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;srcIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srcFactors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dstIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dstFactors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;length&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dstIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;length&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ratings&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcFactors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;transpose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dstFactors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;ratings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;foreachActive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nf&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;srcIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dstIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;변경후&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcBlocks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blockify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;srcFeatures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dstBlocks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blockify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dstFeatures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ratings&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcBlocks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;cartesian&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dstBlocks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;flatMap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;srcIter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dstIter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;srcIter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;size&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dstIter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pq&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BoundedPriorityQueue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Ordering&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;_2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;srcIter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;srcId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srcFactor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;dstIter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dstId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dstFactor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
Spark 을 튜닝할때 가장 키포인트가 뭘까요? &lt;br /&gt;
본인이 만든 프로그램이 겁나 느려져서 빡세게 고생 해보신 분들(?) 이라면 아실겁니다. 바로 shuffle 을 줄이고, memory 사용을 줄여라 입니다. ( 아! 너무 당연한 얘기인가요…? ㅋㅋ )
&lt;br /&gt;
&lt;img src=&quot;/images/als-algorithm-tuning/5.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
혹시 위에 그림을 보기 전에 source change 결과만 보시고 이 모든 결과를 예상하셨다면 당신은 Spark 를 꽤(?) 잘하는 것입니다 :) ㅎㅎ top n 을 뽑는건 단순히 memory 에만 영향을 주는 것이 아닌 shuffle 의 양을 줄여주기 때문에 엄청나게 빠른 결과를 줄것 같아! 라는 예상을 할수 있을 겁니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/als-algorithm-tuning/6.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
&lt;img src=&quot;/images/als-algorithm-tuning/7.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
&lt;img src=&quot;/images/als-algorithm-tuning/8.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
&lt;br /&gt;
위에는 밴치마크 결과 입니다. 참고 하세요. ㅎㅎ&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;ㅁ-block-size-is-static&quot;&gt;ㅁ Block-Size is static&lt;/h3&gt;
&lt;p&gt;링크 : &lt;a href=&quot;https://issues.apache.org/jira/browse/SPARK-20443&quot;&gt;SPARK-20443&lt;/a&gt;
&lt;br /&gt;
&lt;img src=&quot;/images/als-algorithm-tuning/4.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
Spark 에서는 Matrix 계산을 할때 cell(?) 단위로 하지 않고 Block Manager 를 거쳐 계산됩니다. 즉, Spark 에서 Data shuffle 의 기준을 이 Block Matrix 로 잡게 되죠. 다만, recommendForAll method 에서 기본적인 block size 가 4096으로 고정되어 있는게 문제였는데요.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;mllib/src/main/scala/org/apache/spark/mllib/recommendation/MatrixFactorizationModel.scala
&lt;strong&gt;변경전&lt;/strong&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blockify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rank&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;RDD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])])&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;RDD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;DenseMatrix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;blockSize&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4096&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// TODO: tune the block size
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;blockStorage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rank&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blockSize&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
&lt;strong&gt;변경후&lt;/strong&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blockify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;RDD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])],&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;blockSize&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;RDD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])]]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
user, item matrix 를 inner product 할때 block 의 size 를 조절할 수 없도록 고정시켜놨습니다. executor 가 몇개인지 한 executor, core 당 할당 받을 수 있는 메모리가 몇인지 cpu 의 register, cache, memory 에 따라 computing 시간은 천차 만별일 것입니다. 
&lt;br /&gt;
&lt;strong&gt;1차&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;BlockSize(recommendationForAll time)
128(124s), 256(160s), 512(184s), 1024(244s), 2048(332s), 4096(488s), 8192(OOM)

The Test Environment:
3 workers: each work 10 core, each work 30G memory, each work 1 executor.
The Data: User 480,000, and Item 17,000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
&lt;strong&gt;2차&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-test&quot;&gt;3 workers: each work 40 core, each worker 180G memory, each worker 1 executor.
The Data: user 3,290,000, and item 208,000
The results are:
blockSize rank=10 rank = 100
128 67.32min 127.66min 
256 46.68min 87.67min 
512 35.66min 63.46min
1024  28.49min 41.61min
2048  22.83min  34.76min
4096  22.39min 54.43min
8192  23.35min 71.09min
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
어떨 때는 block size 를 크게 하면 좋고, 어떨때는 작게 하면 좋고, 어떨때는 적당히 큰값으로 하는게 좋습니다. 사실 이건 저도 고민을 해봤는데 테스트를 통해서 밖에 알 수 없을거 같네요 ^^; 위에서 살짝 언급 드렸다 싶이 computing 이라는게 단순하게 cpu, RAM 을 늘린다고 좋아지는게 아닙니다. cpu 와 RAM 중간에서 memory 가 왔다갔다 하는 것도 고려를 해야지요. ( 혹시 이런거 계산해서 block size 정할 수 있는 방법 아시는 재야의 고수님들 있으면 쪽지 좀 주세용 ㅎㅎ)&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;ㅁ-optimize-the-cartesian-rdd&quot;&gt;ㅁ Optimize the Cartesian RDD&lt;/h3&gt;
&lt;p&gt;링크 : &lt;a href=&quot;https://issues.apache.org/jira/browse/SPARK-20638&quot;&gt;SPARK-20638&lt;/a&gt;
&lt;br /&gt;
core/src/main/scala/org/apache/spark/rdd/CartesianRDD.scala
&lt;strong&gt;변경전&lt;/strong&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Partition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TaskContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;T&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;currSplit&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;asInstanceOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;CartesianPartition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rdd1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;currSplit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rdd2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;currSplit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;s2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
&lt;strong&gt;변경후&lt;/strong&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-scala highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Partition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TaskContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;T&lt;/span&gt;, &lt;span class=&quot;kt&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;resultIter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rdd1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;currSplit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getOrElseCache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rdd2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;currSplit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;s2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;StorageLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;MEMORY_AND_DISK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
Cartesian RDD ( Spark core ) 에 문제가 쫌 있습니다. Large size 한 RDD 를 cartesian join 할 경우 곱해져야 할 RDD 가 중복되어서 계속 전송하게 됩니다. 사실 한번 전송 받은 RDD ( 여기서는 block 이라고 할까요? matrix 연산을 block 단위로 하고 있으니까요 ㅎㅎ ). block 은 전송할 필요가 없습니다. 그래서 RDD 의 저장 방식을 변경하고 local ( excecutor ) 에 저장하고 있다고 없을때만 전송받고 있을 땐 memory or disk 에서 꺼내서 계산합니다.
&lt;br /&gt;
링크 : 소스 참조 (https://github.com/apache/spark/pull/17936/files) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
아.. DF 를 쓰는 spark 2.x 에서는 내부적으로 cross join 이 구현 되어 잇어 key optimazation 을 탑니다. 크게 성능 저하가 없습니다. 이미 테스트도 완료했으니 2.x 를 쓰시는 분들은 그냥 쓰셔도 괜찮아요 ^^ (참고로 이 부분은 spark core 부분이라 그런지 아직 fixed 되지 않은 부분입니다.)
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;ㅁ-the-bkm-best-known-methods-of-using-native-blas-to-improvement-mlmllib-performance&quot;&gt;ㅁ The BKM (best known methods) of using native BLAS to improvement ML/MLLIB performance&lt;/h3&gt;
&lt;p&gt;링크 : &lt;a href=&quot;https://issues.apache.org/jira/browse/SPARK-21305&quot;&gt;SPARK-21305&lt;/a&gt;
&lt;br /&gt;
&lt;strong&gt;추가&lt;/strong&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
+# Options &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;native BLAS, like Intel MKL, OpenBLAS, and so on.
 +# You might get better performance to &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;these options &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;using native BLAS &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;see SPARK-21305&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
 +# - &lt;span class=&quot;nv&quot;&gt;MKL_NUM_THREADS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1        Disable multi-threading of Intel MKL
 +# - &lt;span class=&quot;nv&quot;&gt;OPENBLAS_NUM_THREADS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1   Disable multi-threading of OpenBLAS
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
Spark ML, MLLIB 에서 사용하는 BLAS 라는 library 에서 multi threading 을 쓰는 설정이 이상하다고 하네요. 위와 같이 수정하고 쓰면 좀 더 나은 성능을 볼 수 있다고 합니다. (아, 물론 MKL, BLAS 를 잘 쓰시려면 빌드단계부터 운영 환경과 맞춰 잘 해줘야 합니다. )&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;result&quot;&gt;Result&lt;/h2&gt;
&lt;p&gt;음… 일단은 위에 수정된 내용들이 전부 Master Branch 에 적용된 상태는 아닙니다. 결국 RDD 기반의 mllib 을 쓸거면 반영이 안된 부분은 본인이 수정해서 쓰던지… DF기반의 ml 을 써도 마찬가지 입니다. cartesianRDD 만 crossjoin 으로 대체 가능한 거지 나머지 부분은 수정해서 써야 한다는 것이지요. 하지만 작은 사이즈는 문제가 없습니다. ^^ 그래도 역시 Spark 이니까요 ㅎㅎ &lt;del&gt;이것저것 다 귀찮으시면… 2.3rc-1 으로 해보셔도 괜찮을 듯 싶습니다 ㅎㅎ ( 해보진 않았습니다. ) 2.3 이 latest stable 로 빨리 올라오길 기원합니다.&lt;/del&gt; ( 이 글의 초안을 쓴지도 어엿 2~3달이 지났네요 ^^; ㅎㅎ 이제는 2.3 이 latest stable 입니다. )
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;부흥하라-데이터-엔지니어여&quot;&gt;부흥하라! 데이터 엔지니어여&lt;/h2&gt;
&lt;p&gt;자! 이제 다시 돌아와서 ㅎㅎ 
&lt;br /&gt;
사실 최근에 굉장히 고민이 많았습니다. 최근에 워낙 분석이나 ML/DL이 각광받다보니 서버나 엔지니어링 쪽 공부보단 분석이나 모델링 공부를 많이 해야겠다고 많이 느꼈습니다. 하지만 하면서 고민되었던게 내 커리어는 엔지니어로 계속 가고 싶은데 이렇게 공부하고 일을 하면서 과연 내가 2~3년 뒤에는 내 커리어는 뭐가 되어 있을까? 라는 고민을 많이 하게 되었죠.
&lt;br /&gt;
&lt;br /&gt;
 근데 이 발표를 준비하면서 많이 느꼈습니다. 그렇게 common 하고 쉽다고 느끼던 ALS 알고리즘 조차 대용량으로 가면 하기 어렵다는 걸요. 날고 긴다는 Spark 커미터들 조차도 이 버그를 수정하는데 버전 2.3까지 끌었습니다. 예전에 @권혁진 님께서 스사모에서 발표해주실때 Spark 에 ML 관련된 커미터가 다른 component에 비해 많이 부족하다고 하셨습니다. 그 이유는 Modeling 과 Engineer 를 둘다 할 줄 아는 개발자가 많이 없기 때문이라고 하셨죠. 
&lt;br /&gt;
&lt;br /&gt;
추천 서비스를 해보면서 느낀 점은 저희가 만든 알고리즘을 서비스에 올려서 돌려보면 “기가 막힌 모델”이 이길 때도 있지만 “빠른 training/inference 되는 모델”이 이길때도 있습니다. 그때 그때 다르겠죠. 그냥 간단히 생각해보면 번역이나 이미지 인식은 정교하게 잘 짜여진 모델이 이길겁니다. 근데 시시각각 바뀌는 상황에선 오히려 새로운 데이터로 계속 모델을 바꿔쳐 주는게 이길 수도 있겠죠.
&lt;br /&gt;
&lt;br /&gt;
데이터 엔지니어, 분석가, 모델링. 이를 잘 융합하는 기업이 이길거란 생각이 듭니다. ( 너무 당연한 건가요? ^^; ㅎㅎ )
&lt;br /&gt;
&lt;br /&gt;
이제는 엔지니어도 같이 이러한 모델이 좋을까? 학습하려면 어떻게 networking 해야 할까? 분산 training 은 가능할까? 모델은 어떻게 serving &amp;amp; deploy 하지? 그때 무중단을 해야할까? 할수 있을까? F/W 은 뭘 선택하지? 등등 ML 서비스를 위해 시스템을 어떻게 설계할지 함께 고민해봐야 하는 시대가 아닌가 생각합니다. :)&lt;/p&gt;</content><author><name></name></author><summary type="html">Overview 오늘 다룰 내용은 Spark 에서 추천 서비스를 위해 제공하는 ALS 알고리즘에서 있었던 문제들과 이를 어떻게 튜닝했고, 얼마나 성능이 좋아졌는지에 대해 발표한 내용을 공유하는 자리입니다. ( Intel 이 튜닝한 내용을 참조했습니다. )</summary></entry><entry><title type="html">Spark, Flink, Kafka Streaming …</title><link href="https://ggoals.github.io/About_Streaming_Spark_Kafka_Flink/" rel="alternate" type="text/html" title="Spark, Flink, Kafka Streaming ..." /><published>2017-11-19T00:00:00+00:00</published><updated>2017-11-19T00:00:00+00:00</updated><id>https://ggoals.github.io/About_Streaming_Spark_Kafka_Flink</id><content type="html" xml:base="https://ggoals.github.io/About_Streaming_Spark_Kafka_Flink/">&lt;h2 id=&quot;streaming-101&quot;&gt;Streaming 101&lt;/h2&gt;
&lt;p&gt;ㅁ Latency &amp;amp; Throughput &lt;br /&gt;
&lt;img src=&quot;/images/1/latency1.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
&lt;img src=&quot;/images/1/latency2.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Latency : Processing 완료 시간 - Event 발생 시간 &lt;br /&gt;
 보통 이와 같이 정의됩니다. 하지만 이렇게 정의할 경우 위 그림처럼 사용자가 인터넷이 되지 않는 터널등의 구간에서의 Event 발생 ( = 엔지니어들이 해결해 줄수 없는 영역으로 인한 Latency ) 등이 있기에 보통 Latency 는 Event 발생 시간 대신 Log Collector 역할을 하는 서버가 로그를 받은 시간으로 대신하는 경우가 많습니다.
 &lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/1/Throughput.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Throughput : Streaming 서버의 시간당 처리량 &lt;br /&gt;
 &lt;img src=&quot;/images/1/throughput1.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
메시지가 적을땐 Streaming Service 의 Throughput 이 시스템에 큰 영향을 주지 않습니다. 하지만 위처럼 유입되는 메시지가 많아지면 Streaming Service 의 Throughput 은 서비스의 품질을 결정짓는 중요한 요소가 됩니다. 서버가 시간당 처리하는 메시지 양이 적으면 처리 속도가 느려질테고, Latency 는 점점 증가하겠죠. 이럴땐 Scale out 을 하건 더 빠른 처리가 가능하도록 로직을 수정하는 등의 운영을 해줘야 합니다. &lt;br /&gt;
  Latency 와 Throughput 은 보통 대략적으로 반비례 관계에 있다는 말을 합니다. Streaming 서비스의 Throughput 이 유입되는 Input 량보다 현저히 떨어지면 당연히 Latency 가 올라갈 것이고, Throughput 이  높으면 유입되는 Input 들을 빨리 빨리 처리할테니 Latency 는 줄어들 것입니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-sql-streaming&quot;&gt;ㅁ SQL Streaming&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Spark’s Structured Streaming&lt;/li&gt;
  &lt;li&gt;Flink’s Data Stream SQL&lt;/li&gt;
  &lt;li&gt;Kafka’s kSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-그-이외에-streaming-에서-중요한-개념들&quot;&gt;ㅁ 그 이외에 Streaming 에서 중요한 개념들!&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Exactly Once, At most once, At least once&lt;/li&gt;
  &lt;li&gt;Time Windowed&lt;/li&gt;
  &lt;li&gt;How to manage State! ( in Stateful Streaming )&lt;/li&gt;
  &lt;li&gt;How to manage log&lt;/li&gt;
  &lt;li&gt;How to Fail-over, Alert, Restart&lt;/li&gt;
  &lt;li&gt;How to Scale out&lt;/li&gt;
  &lt;li&gt;How to Monitoring Metric
&lt;br /&gt;
&lt;br /&gt;
 결국 어려운건 운영입니다… Streaming 시스템에서 Latency &amp;amp; Throughput 도 
 매우 중요한 요소이지만 “어떻게 운영할 것인가? 운영포인트를 줄여갈 것인가?”도
 매우매우 중요한 요소입니다. 이게 없으면 Streaming F/W 이라 할 수 없죠.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-위에서-한-얘기들-실제-streaming-시스템에서-어떻게-처리하는지가-궁금하시다면-&quot;&gt;ㅁ 위에서 한 얘기들 실제 Streaming 시스템에서 어떻게 처리하는지가 궁금하시다면! :)&lt;/h4&gt;
&lt;p&gt;링크 : &lt;a href=&quot;http://slides.com/yonghweekim/streaming-system#&quot;&gt;Spark Streaming 운영 및 회고&lt;/a&gt; &lt;br /&gt;
오늘 얘기에서는 위에 내용들을 어떻게 처리하고 관리하는지를 보기 위함은 아니라 패스 하겠습니다!&lt;br /&gt;
나중에 기회가 되면 Spark Streaming 운영과 회고 발표 슬라이드도 글로 옮겨야 겠네요 ^^;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;streaming-service&quot;&gt;Streaming Service&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;오늘은 Kafka, Spark, Flink :) 이 3개의 서비스를 한번 
비교해볼까 합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;kafka-streaming&quot;&gt;Kafka streaming&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/Kafka_github.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
Kafka 0.9 부터 Kafka Streaming Client 를 지원합니다.&lt;br /&gt;
현재는 1.0 버전을 드디어! 런칭하면서 그 발전속도가 세상을 깜짝 놀라게 합니다.&lt;/p&gt;

&lt;p&gt;Streaming 이 나온지 얼마 되지 않아 ksql 이라는 어마 무시한 kafka sql streaming 오픈소스가 나옵니다. &lt;br /&gt;
(링크 : &lt;a href=&quot;https://github.com/confluentinc/ksql&quot;&gt;ksql Github Repository&lt;/a&gt; ) &lt;br /&gt;
최근에는 LINE Corperation 에서 상용서비스에 Kafka Streams 를 적용했고, 덕분에 Kafka 개발자들은 신이납니다. &lt;br /&gt;
( 보통 상용에 대한 검증을 큰 회사에서 한번 해주면 믿고 가면 되거든요 ㅋㅋ ) &lt;br /&gt;
(링크 : &lt;a href=&quot;https://engineering.linecorp.com/ko/blog/detail/80&quot;&gt;내부 데이터 파이프라인에 Kafka Streams 적용하기&lt;/a&gt; ) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-resource-manager&quot;&gt;ㅁ Resource Manager&lt;/h4&gt;
&lt;p&gt;카프카 스트림즈는 yarn 이나 mesus 같은 리소스 매니저를 통해 띄우지 않습니다. &lt;br /&gt;
( 물론 apache slider 나 다른 방법을 통해 띄우는 것들은 제외 하겠습니다. 기본 docs 에 없음을 말할 뿐 입니다) &lt;br /&gt;
&lt;img src=&quot;/images/1/yarn_stupid_developer.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
그게 꼭 나쁜걸까요? Yarn 이나 Mesus 나 Network Resource Managing 은 하지 못합니다. &lt;br /&gt;
누군가 큰 쿼리를 돌리면 Streaming 서비스가 정상적으로 돌지 않는 ( 클러스터 전체가 정상적으로 돌지 않는 )
상태가 발생하기도 합니다
 Streaming 서비스 같은 Long Running Service 들은 Stand Alone 형태로 띄울때가 ( = 네트워크 사용이나 리소스 사용이
 예측이 안되는 클러스터와는 별도의 존에서 ) 나을 수도 있다는 생각이 듭니다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-clients-service-discovery&quot;&gt;ㅁ Client’s Service Discovery&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/infra_book.jpeg&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
이 책을 인용하자면 “인프라에서 동작중인 애플리케이션과 서비스는 종종 다른 애플리케이션이나 서비스를 찾는 방법을 알아야한다”
동일 토픽의 동일 group id 로 컨슘하고 있는 서버를 찾는 방법이 명령어 한줄에 뽝! 되는 그런 클린한 방법이 없습니다.
즉, 관리하던사람이 아닌 잘 모르는 사람, 인수인계 받아야 하는 사람이 오면 문서 없이는 꽤 고생하겠죠 &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-monitoring&quot;&gt;ㅁ Monitoring&lt;/h4&gt;
&lt;p&gt;Kafka Streams Client 에 대한 모니터링이 존재하지 않습니다. ( = 별도로 붙여야 합니다. ) &lt;br /&gt;
요샌 APM 이 쩌는게 워낙 많아서리… ㅎㅎ 
VM 이나 Application 에 대한 모니터링이 워낙 잘 되어 있어 그런 부분의 솔루션이 회사에 존재한다면
이부분도 해결은 가능합니다 :)
Kafka Cluster 의 상태를 살펴 볼수 있는 Cruise Control for Apache Kafka 과 함께 쓰면 더 좋을것 같기도 하네요 :) &lt;br /&gt;
( 링크 : &lt;a href=&quot;https://engineering.linkedin.com/blog/2017/08/open-sourcing-kafka-cruise-control&quot;&gt;open-sourcing-kafka-cruise-control&lt;/a&gt; ) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-streaming-sql-engine&quot;&gt;ㅁ Streaming SQL Engine&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/ksql_query.png&quot; alt=&quot;_config.yml&quot; /&gt;
&lt;img src=&quot;/images/1/ksql_graph.png&quot; alt=&quot;_config.yml&quot; /&gt;
Data Streaming 을 SQL 을 이용해서 Table 처럼 정의하고 Window 크기 만큼
빼서 사용이 가능하도록 만든 Kafka 만의 SQL Engine 입니다.
InfluxDB + Grafana 를 사용해서 Visualization 쉽게 가능하도록 되어 있네요!
자세한 설명은 아래 링크에서 튜토리얼 영상을 보세요 :) &lt;br /&gt;
( 링크 : &lt;a href=&quot;https://github.com/confluentinc/ksql&quot;&gt;KSQL github repository&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;spark-streaming&quot;&gt;Spark Streaming&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/spark_github.png&quot; alt=&quot;_config.yml&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-this-is-not-native-streaming-just-micro-batch&quot;&gt;ㅁ This is not native streaming. Just “Micro Batch”&lt;/h4&gt;
&lt;p&gt;스팍 스트리밍은 스트리밍이 아니죠. 마이크로 배치 입니다.
event loop 가 돌며 batch job 을 계속 submit 하는 식으로 구현되어져 있습니다.
그래서 느리죠. 느려요. 느립니다 &lt;br /&gt;
&lt;img src=&quot;/images/1/goksung.jpg&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
근데 서비스하면서 많이 느끼는게 정말 님들의 서비스는 &lt;br /&gt;
“1초도 못 기다림.”&lt;br /&gt;
“2초도 못 기다림.”&lt;br /&gt;
“3초도 못 기다림.”&lt;br /&gt;
수 초도 지연되면 안되는 서비스 인가요? 물론 그런 서비스이실수도 있고,
아닐수도 있습니다. 수초도 지연되선 안된다면 Spark Streaming 은 절대 쓰시면 안됩니다.
단 그 부분만 Okay 된다면 Spark Streaming 만큼 괜찮은 서비스가 없습니다.
그 이유는 Micro Batch 특성 때문인데요. Native Streaming 과 Micro Batch 를 둘다 코딩해보신 분들은
왜 Micro Batch 가 좋은지 느낄 수도 있을것 같아요 ( 아! 물론 개인차가 있을순 있습니다 ㅎㅎ ) &lt;br /&gt;
이렇게 Micro Batch 로 나눠져 있다는게 코딩할때 생각보다 생각을 덜 하게 해줍니다. :)&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-spark-ui&quot;&gt;ㅁ Spark UI&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/spark_dashboard.jpg&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
거의… 이거때문에 Spark 쓴다고 해도 과언이 아닐 정도로 잘 되어 있습니다.
이거 없이 Spark 운영한다고 하는 사람은 Spark 운영을 하지 않은 사람일 것입니다.
근데 이 부분 때문에 많은 오해가 생기기도 하더라구요.
그 예로 하나가 Delay Time 입니다. &lt;br /&gt;
Dealy Time 과 Streaming Latency 는 같은 값일까요? 또는 서로 비슷한 추세라도 보일까요?
답은 아닙니다.&lt;/p&gt;

&lt;p&gt;Streaming Latency 는 보통( 살짝 다르게 쓰기도 하지만 ) &lt;br /&gt;
Streaming Latency = 메시지(로그)의 Processing 처리 완료 시간 - Event 발생 시간 &lt;br /&gt;
입니다.&lt;br /&gt;
Spark UI 에 나오는 Delay Time 은&lt;br /&gt;
Delay Time = Real Processing Time(실제 배치를 프로세싱 하는데 걸린 시간 ) - Micro Batch’s duration &lt;br /&gt;
입니다. :)&lt;br /&gt;
잘 만들어진 UI 는 편하긴 하지만 그 의미를 잘 모르면 오해를 불러일으키기 쉽습니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;flink&quot;&gt;Flink&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/flink_github.png&quot; alt=&quot;_config.yml&quot; /&gt;
Streaming에 이상할 만큼 특화된(=잘만들어진) F/W Flink 입니다. &lt;br /&gt;
Flink… 정말 Streaming 분야에서는 짱입니다.. &lt;br /&gt;
&lt;br /&gt;
그리고 로고가 동물인게 마음에 듭니다. 역사적으로 로고가 동물인게 잘 되더라구요.&lt;br /&gt;
Docker, Go, Linux 다 동물입니다 :) &lt;br /&gt;
&lt;img src=&quot;/images/1/docker_linux_go_img.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;아래에서 Flink 특징들 보면서 기능상 장단점을 한번 볼게요. :) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-flink-dashboard-&quot;&gt;ㅁ Flink Dashboard &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/flink_running_job_dashboard.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
&lt;img src=&quot;/images/1/flink_task_mager_dashboard.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Flink Dashboard 를 이용해보신 분들이라면 Flink 의 매력에 푹 빠지실 겁니다.&lt;br /&gt;
기본적인 모니터링 기능 제공 ( Job 의 상태, Task manager 별 Latency, Source/Sink Msg 수 등 ) 뿐 아니라 Log finder 기능 ( 진짜 이게 판타스틱! ), Job Submit/Cancel 등의 기능을 제공하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-log-finder-&quot;&gt;ㅁ Log finder &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/flink_task_dashboard.png&quot; alt=&quot;_config.yml&quot; /&gt; &lt;br /&gt;
위 사진에서 보안상… :) 어쩔수 없이 삭제했만 Task Manager 를 보시면 내 job 이 실행되고 있는 Task Manager ( = Spark 의 executor 와 비슷한 개념 )
들이 보입니다. Error 가 난 Task Manager 의 Hostname( or IP ) 도 뜨고 해당 Task Manager 의 Error 로그만, 전체로그만 따로 볼수 있습니다. &lt;br /&gt;
운영해 보신 분들이라면 로그를 잘 적재하고, 에러가 났을 때 쉽게 에러난 부분을 찾는게 얼마나 귀찮고 짜증나는지 알 것입니다. 이거 때문에 로그 설정을 잘해야 하기도 하고, 더 나아가서는 yarn 설정 자체를 건드려줘야 하는 경우가 있을 수 있죠. 근데 Flink 는 정말정말 기본 설정이 잘 되어 있습니다. 에러가 나면 에러가 난 Task Manager 의 로그만 따로 볼 수 있도록 한점. 또 Error Stack Trace 로그만 따로 볼 수 있는 기능을 Dashboard 에서 제공해 줍니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-job-start--cancel-&quot;&gt;ㅁ Job Start &amp;amp; Cancel &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;역시 Dashboard에서 Job 을 Start 및 Stop 을 할수 있습니다. ( 몇가지 제약 조건이 있지만요 ^^; )&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-docs-good-&quot;&gt;ㅁ Docs….. good… &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;Flink 는 정말 책을 읽는 다는 느낌이 들정도로 책이 자세합니다. 예를들어 &lt;br /&gt;
Best Practice : &lt;a href=&quot;https://ci.apache.org/projects/flink/flink-docs-release-1.3/dev/best_practices.html&quot;&gt;Flink’s Best practice&lt;/a&gt; &lt;br /&gt;
운영을 할때 이런부분을 조절해서 써라… 하는 가이드가 있습니다.&lt;br /&gt;
&lt;br /&gt;
그리고 왜 그러지 싶을 정도로 책들도 Flink 책들이 자세히 써 있습니다 ^^; (물론 제 개인적인 생각 ㅋㅋ )
(링크 : &lt;a href=&quot;http://shop.oreilly.com/product/0636920057321.do&quot;&gt;OREILLY Flink books&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;마지막으로&quot;&gt;마지막으로…&lt;/h2&gt;
&lt;p&gt;아래는 개인적인 의견을 한번 정리해보았습니다.&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-꼭-resource-manager-가-필요하다고는-생각-안합니다-&quot;&gt;ㅁ 꼭 Resource manager 가 필요하다고는 생각 안합니다. &lt;br /&gt;&lt;/h4&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-스트림즈만-하고-싶다면-flink-를-&quot;&gt;ㅁ 스트림즈만 하고 싶다면 Flink 를! &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;/images/1/Flink_forward_sk.png&quot; alt=&quot;_config.yml&quot; /&gt;&lt;/p&gt;

&lt;p&gt;아래 영상을 보시면 Spark 은 Streaming Join 이 불가능하지만,
Flink 는 가능하다는 설명이 나옵니다. 그만큼 스트리밍 관련되서 많이 발전된건 아직 Flink 인것 같네요. 그리고 Spark 의 Micro batch 또한 Streaming 에서는 그 한계를 보이는것 같습니다. &lt;br /&gt;
( 링크 : &lt;a href=&quot;https://www.youtube.com/watch?v=ZZevulsXp0g&quot;&gt;Predictive Maintenance with Apache Flink - Dongwon Kim (SK telecom)&lt;/a&gt; )
&lt;br /&gt;&lt;br /&gt;
Data Strata 2017 in Singapore 에 다녀왔습니다. ( 생생한 후기는 다음 글에서 적을게요 ㅎㅎ ) 거기서 있던 &lt;a href=&quot;https://conferences.oreilly.com/strata/strata-sg/public/schedule/detail/62907&quot;&gt;Top five mistakes when writing streaming applications&lt;/a&gt; 발표에서 발표자가 Flink 를 제외한 다른 Streaming System 돌려까기를 시전했습니다. 보통 Streaming 시스템에서는 이런 부분을 이렇게 처리해야 해요… 아 근데 Flink 는 그냥 됩니다. 뭐 이런 말투로 말이죠… ㅎㅎ 국내에선 Flink 가 많이 인기가 없어보이지만 해외에선 사뭇 다른 느낌을 많이 받았습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-수초의-latency-도-견딜수-없다면-kafka-or-flink-를-&quot;&gt;ㅁ 수초의 Latency 도 견딜수 없다면 Kafka or Flink 를! &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;위에서 설명했듯이 Spark 의 Micro Batch 구조상 1초 아래로 Duration 을 내리는게 거의 불가능하다 보시면 됩니다 :) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-쫌-더-세분화된-windowed-기능을-이용하고-싶다면-flink-kafka-를-&quot;&gt;ㅁ 쫌 더 세분화된 Windowed 기능을 이용하고 싶다면 Flink, Kafka 를! &lt;br /&gt;&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Session Windowed 기능은 Flink, Kafka 만 &lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;Count Windowed 기능은 Flink 만&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-딥러닝과의-integration-을-고민한다면-현재시점에선-spark-일듯-&quot;&gt;ㅁ 딥러닝과의 Integration 을 고민한다면… 현재시점에선 Spark 일듯! &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;Spark Summit 2017 의 키노트 영상을 보면 Streaming 과 Deep Leaning 가장 핫한 키워드로 제시합니다. 이미 이 두 영역을 결합하려는 시도가 Spark 진형에서는 많이 일어나고 있습니다. 그 예로 Tensorflowonspark 가 현재로썬 그나마 커밋수가 올라가는 중입니다… ㅎㅎ( 그나마 입니다… ㅠㅠ ) 물론 Flink 도 지원을 하려는 시도가 있긴 합니다. Flinkonspark 라고 Flink Forward 2017 에서 발표 된 프로젝트인데.. 이유는 모르겠지만 커밋이 멈췄습니다 ㅠㅠ ( Flink 힘내… )&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-flink-빨리-14-가-stable-로-올라가길-ㅠㅠ-&quot;&gt;ㅁ Flink… 빨리 1.4 가 stable 로 올라가길… ㅠㅠ &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;회사에 Flink 를 적용하려 했을 때 제일 당황스러웠던 문제가 1.3.2 Stable 버전이 회사 Yarn Cluster 에서 작동하지 않는 문제였습니다. 이유는 Job 을 컨트롤 할때 consitent hostname normalization 이 안된 탓인데요. 자세한 내용은 &lt;a href=&quot;https://issues.apache.org/jira/browse/FLINK-7540&quot;&gt;Akka hostnames are not normalised consistently&lt;/a&gt; 이곳을 참고해 주세요 :) &lt;br /&gt;
TFServing(Tensorflow serving) 과의 연동 등에서도 아직 1.3.2 는 문제가 있다고 합니다. 여튼 1.4 branch 에는 해당 내용도 같이 수정되어 
merge 되었다고 하니 한번 기대해 보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 id=&quot;ㅁ-난-하나밖에-못하오-라고-한다면-spark-를-&quot;&gt;ㅁ 난 하나밖에 못하오…. 라고 한다면 Spark 를?! &lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;오늘은 Streaming Service 의 글을 다뤄서 Kafka 와 Flink 도 같이 다뤘습니다. 그리고 실제 업계에서 Streaming 만을 위한다면 그래도 Flink 가… 라는 말이 많이 있습니다. Project Scafolding 부터 Source, sink 의 개념을 이용한 connector 는 그 코드 또한 너무 간결하여 아름다워 보이기까지 하니까요. 하지만 Spark 의 강점은 위에만 있는 것이 아닙니다. 수많은 Commiter, Star 수. Databricks 의 지원, 분석/ML/Batch/Python 호환, Deep Learning Integration 등 많은 영역의 범주를 포함하려 하는 방향성이 Spark 의 인기를 만든 것이라 생각합니다. 본인의 업무가 Streaming 만 하는게 아니라면 좀더 Full Framework 에 가까운 Spark 이 낫지 않을까 생각합니다.&lt;/p&gt;</content><author><name></name></author><summary type="html">Streaming 101 ㅁ Latency &amp;amp; Throughput Latency : Processing 완료 시간 - Event 발생 시간 보통 이와 같이 정의됩니다. 하지만 이렇게 정의할 경우 위 그림처럼 사용자가 인터넷이 되지 않는 터널등의 구간에서의 Event 발생 ( = 엔지니어들이 해결해 줄수 없는 영역으로 인한 Latency ) 등이 있기에 보통 Latency 는 Event 발생 시간 대신 Log Collector 역할을 하는 서버가 로그를 받은 시간으로 대신하는 경우가 많습니다. Throughput : Streaming 서버의 시간당 처리량 메시지가 적을땐 Streaming Service 의 Throughput 이 시스템에 큰 영향을 주지 않습니다. 하지만 위처럼 유입되는 메시지가 많아지면 Streaming Service 의 Throughput 은 서비스의 품질을 결정짓는 중요한 요소가 됩니다. 서버가 시간당 처리하는 메시지 양이 적으면 처리 속도가 느려질테고, Latency 는 점점 증가하겠죠. 이럴땐 Scale out 을 하건 더 빠른 처리가 가능하도록 로직을 수정하는 등의 운영을 해줘야 합니다.  Latency 와 Throughput 은 보통 대략적으로 반비례 관계에 있다는 말을 합니다. Streaming 서비스의 Throughput 이 유입되는 Input 량보다 현저히 떨어지면 당연히 Latency 가 올라갈 것이고, Throughput 이  높으면 유입되는 Input 들을 빨리 빨리 처리할테니 Latency 는 줄어들 것입니다.</summary></entry></feed>