<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>호호홍얍얍</title>
    <link>https://bibapditura.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 9 May 2026 14:30:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>호호홍얍얍</managingEditor>
    <item>
      <title>카프카 살펴보기(1부)</title>
      <link>https://bibapditura.tistory.com/99</link>
      <description>&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;panel&quot; data-prosemirror-content-type=&quot;node&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;blockquote data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-style=&quot;style3&quot;&gt;본 글에서는 메시지의 저장과 소비만을 다룬다.&lt;br /&gt;- keyword: topic, partition, offset, partitioner, segment, clean-up policy&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot; data-prosemirror-content-type=&quot;node&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-node-block=&quot;true&quot;&gt;들어가며&lt;/h1&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;annotation&quot; data-prosemirror-content-type=&quot;mark&quot; data-id=&quot;f27ef7e7-a9b7-4479-8171-091347bd29b6&quot; data-mark-annotation-type=&quot;inlineComment&quot; data-mark-type=&quot;annotation&quot;&gt;이벤트&lt;/span&gt;&lt;/b&gt;는 키-밸류 구조로 되어있는, 무슨 일이 일어났는지에 대한 사건의 기록이다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;사건을 기록하고 꺼내어봄으로써 각 어플리케이션의 요구에 맞게 특정한 행동을 수행할 수 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;키는 기록에 대한 구분자로, 어떤 user 가 될 수도 있고, 번호가 될 수도 있다. 하나의 키에 여러 가지 사건이 발생될 수 있으므로 유니크할 필요도 없고 반드시 있어야만 하는 것도 아니다. 이 키에 대한 내용을 밸류로 갖고, 이벤트 메시지는 사실 키-밸류와 함께 타임스탬프, 메타정보인 헤더를 갖는다. 이벤트는 하나의 기록이므로 당연히 변경되지 않는다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;카프카는 실시간 데이터를 처리한다. 우리가 일기를 쓰듯이 하루에 한 번 지나간 사건에 대해 기록하는 것이 아니다. 상시 특정 대상에 대한 변화 지점을 계속해서 포착하는 것이다. 카프카는 이러한 실시간 이벤트를 수집하고, 그것들을 받아서 바로 처리할 수 있게끔, 또는 나중에 찾아볼 수 있게끔 잘 구성해서 저장한다. 각 이벤트들은 기록 자체로는 서로 상관 없는 개별적인 사건이 될 뻔했지만, 이를 잘 구성함으로써, 데이터의 지속적인 흐름과 해석을 보장해주고 있다. 실시간 정보를 주고 받는 상시 접속 시대에, 자동화된 메시징 처리를 가능하게 하는 이벤트 스트리밍이 카프카의 기본 컨셉이다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;그럼 어떻게 잘 구성해서 저장하길래 다양한 애플리케이션이 필요에 따라 효과적으로 데이터를 찾고 처리할 수 있게 하는가?&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;h1 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot;&gt;데이터의 저장&lt;/h1&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size23&quot;&gt;메시지 저장 순서 보장&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;이벤트는 &lt;span data-prosemirror-mark-name=&quot;annotation&quot; data-prosemirror-content-type=&quot;mark&quot; data-id=&quot;f8b6a18a-d66a-4c61-bead-3126172e76ae&quot; data-mark-annotation-type=&quot;inlineComment&quot; data-mark-type=&quot;annotation&quot;&gt;토픽에&lt;/span&gt; 저장된다.&lt;b&gt; 토픽&lt;/b&gt;은 말 그대로 특정 주제인데, 그 주제에 해당하는 메시지들을 저장한다. 카프카는 메시지를 저장, 관리, 분산 처리를 하는 카프카 서버(브로커)와 이 메시지를 발행하고 수신하는 클라이언트인 프로듀서, 컨수머로 구성된다. 프로듀서가 발행한 메시지는 브로커에 쌓인다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;실제로 데이터가 저장되는 곳은 &lt;/span&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;파티션&lt;/span&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;이다.&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-pm-slice=&quot;0 0 []&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-pm-slice=&quot;0 0 []&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-pm-slice=&quot;0 0 []&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1196&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKYP1d/btsL2ddMiXX/JIkI3sRFSbLURrhIzR8H40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKYP1d/btsL2ddMiXX/JIkI3sRFSbLURrhIzR8H40/img.png&quot; data-alt=&quot;https://curiousjinan.tistory.com/entry/understand-kafka-partitions&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKYP1d/btsL2ddMiXX/JIkI3sRFSbLURrhIzR8H40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKYP1d%2FbtsL2ddMiXX%2FJIkI3sRFSbLURrhIzR8H40%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;1196&quot; height=&quot;546&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://curiousjinan.tistory.com/entry/understand-kafka-partitions&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;하나의 토픽은 여러 개의 파티션을 가질 수 있다. 각 파티션에는 특정 컨수머가 동적으로 할당되는데, 파티션이라는 개념이 없었다면, 여러 개의 메시지 발행자, 소비자가 메시지 읽기/쓰기를 하기 위해 계속 줄서있어야 했을 것이다. 파티션은 특정 주제 내에서의 분산을 가능하게 한다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;그렇다면 메시지 순서는 어떻게 보장되지?&lt;/span&gt;&lt;/b&gt;&lt;/u&gt; 이걸 이해하기 위해 필요한 개념은 오프셋이다. 오프셋은 파티션에 저장되는 메시지의 위치이다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오프셋은 파티션 내에서 고유하다.&lt;/b&gt; 즉, 파티션이 달라지면 오프셋은 달라진다. 각 메시지는 토픽과 파티션, 오프셋을 가짐으로써 저장 순서가 보장된다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;530&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;530&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AltWE/btsL1f4Y1OY/2wK0Op0qjJKJpKmWMEBdq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AltWE/btsL1f4Y1OY/2wK0Op0qjJKJpKmWMEBdq1/img.png&quot; data-alt=&quot;https://www.geeksforgeeks.org/topics-partitions-and-offsets-in-apache-kafka/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AltWE/btsL1f4Y1OY/2wK0Op0qjJKJpKmWMEBdq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAltWE%2FbtsL1f4Y1OY%2F2wK0Op0qjJKJpKmWMEBdq1%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;1060&quot; height=&quot;361&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.geeksforgeeks.org/topics-partitions-and-offsets-in-apache-kafka/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;다시 말하면, 파티션 밖에서의 오프셋은 의미가 없다. 위 그림에서 7번 메시지는 파티션 0, 1, 2 에서 모두 다른 메시지이다. 메시지를 저장된 순서에 따라 처리하려면, 같은 파티션으로 배치해야 한다.&lt;/p&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size23&quot;&gt;파티셔닝&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;카프카는 이를 위해 &lt;u&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;파티셔닝이라는 개념을 가지고 있다. 어떤 파티션에 배치할 것인가를 결정하는 전략&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;인데, 총 세 가지의 방식이 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째로, &lt;b&gt;키 기반 파티셔닝&lt;/b&gt;은 메시지가 키를 가지고 있을 때, 같은 키는 같은 파티션에 할당하는 전략이다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;두 번째로, &lt;b&gt;스티키 파티셔닝&lt;/b&gt;은 배치 사이즈 또는 시간으로 결정된다. 배치 설정에 따라 크기가 꽉 차면 / 시간이 되면 그 묶음은 한 파티션에 할당한다. 만약 배치가 차지 않았다면, 이전 레코드와 동일한 파티션에 발행되고, 새로 생성된 배치는 무작위로 할당된다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;세 번째는 &lt;b&gt;라운드 로빈&lt;/b&gt; 방식이다. 카프카 2.4 이전까지는 키가 없을 때의 기본 전략이었다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;위 동작을 수행하는 것이 &lt;b&gt;파티셔너&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;파티셔너는 프로듀서의 영역이다. 메시지가 발행될 때 어떤 파티션에 배치될지가 결정된다. 필요하다면 개별 어플리케이션에서 Partitioner 를 구현하여 커스텀 파티셔너를 만들어도 된다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;키 기반 파티셔닝을 데이터 스트림 관점에서 보자면, 파티션은 주제별로 묶인 이벤트를 또 한 번 묶은 최후의 데이터 단위인 셈이다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;381&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3J0LQ/btsL1qE8ydz/u8PQcwKEcqEuPZNtVREPkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3J0LQ/btsL1qE8ydz/u8PQcwKEcqEuPZNtVREPkk/img.png&quot; data-alt=&quot;https://www.youtube.com/watch?v=kj9JH3ZdsBQ&amp;amp;amp;t=22s&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3J0LQ/btsL1qE8ydz/u8PQcwKEcqEuPZNtVREPkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3J0LQ%2FbtsL1qE8ydz%2Fu8PQcwKEcqEuPZNtVREPkk%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;761&quot; height=&quot;258&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;258&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.youtube.com/watch?v=kj9JH3ZdsBQ&amp;amp;t=22s&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size23&quot;&gt;파티션의 구성&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;앞서 언급했듯, 예상되는 부하에 따라 토픽 별로 파티션 개수를 정할 수 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;몇 개가 적절할까? 우선 &lt;b&gt;파티션은 늘리는 건 가능해도, 줄일 수는 없다&lt;/b&gt;. 그렇다면 최초에 넉넉하게 만들되, 지나치게 많지 않게 해야 한다. 또, &lt;b&gt;키 기반 파티셔닝을 사용할 때, 파티션의 개수를 늘리면 파티셔닝 계산이 깨진다&lt;/b&gt;. 순서 보장이 안 될 수 있다. 때문에 늘리는 것도 신중하게 해야 한다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;어차피 파티션 수가 더 적으면 특정 컨수머는 유휴 상태에 들어간다. 반대로 지나치게 많으면 하나의 컨수머가 처리해야 하는 파티션 수가 너무 늘어나게 된다. 쓰기 속도, 파티션 키 분산도 신경 써야 한다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;결국 잘, 해야 한다는 건데, &lt;span data-prosemirror-node-inline=&quot;true&quot; data-prosemirror-node-name=&quot;inlineCard&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://docs.cloudera.com/runtime/7.2.18/kafka-performance-tuning/topics/kafka-tune-sizing-partition-number.html&quot;&gt;https://docs.cloudera.com/runtime/7.2.18/kafka-performance-tuning/topics/kafka-tune-sizing-partition-number.html&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; 에 따르면 &lt;b&gt;파티션 수 = max(목표 처리량 / 프로듀서 처리량, 목표 처리량 / 컨슈머 처리량)&lt;/b&gt; 이런 공식을 제공하고 있긴 하다.&lt;/p&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size26&quot;&gt;메시지의 삭제&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;메시지는 최대 저장 한도가 있다. 기본적으로 7일, 무제한이 최대 한도이다. 하지만 서버에 메시지가 쌓이기만 한다면 문제가 생길 것이다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;어떤 메시지를 어떻게 삭제할 것인가? 카프카의 메시지의 삭제 정책은 두 가지가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;cleanup.policy=delete(default)&lt;/b&gt;: 정해진 용량이나 시간을 초과하면 삭제
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;retention.ms / log.retention.ms&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;retention.bytes / log.retention.bytes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;cleanup.policy=compact:&lt;/b&gt; key 기준 최신 메시지만 남기고 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;296&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oTBmJ/btsL1XPX7Ln/bvUKZvj3KJFCqkkxL6oMjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oTBmJ/btsL1XPX7Ln/bvUKZvj3KJFCqkkxL6oMjk/img.png&quot; data-alt=&quot;https://kafka.apache.org/documentation&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oTBmJ/btsL1XPX7Ln/bvUKZvj3KJFCqkkxL6oMjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoTBmJ%2FbtsL1XPX7Ln%2FbvUKZvj3KJFCqkkxL6oMjk%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;592&quot; height=&quot;399&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://kafka.apache.org/documentation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;cleanup.policy=delete,compact:&lt;/b&gt; delete 와 compact 를 조합&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;다만 &lt;u&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;backgroundColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-background-custom-color=&quot;#fdd0ec&quot;&gt;메시지 삭제는 개별 메시지 단위가 아닌 &amp;lsquo;세그먼트&amp;rsquo; 단위로 이루어진다&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;. 따라서 실제 메시지 보존 기간은 설정값보다 길어질 수 있음에 유의해야 한다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;자세한 얘기를 하기 전에, 세그먼트가 뭔지부터 보자.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size23&quot;&gt;세그먼트&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;세그먼트는 메시지가 저장되는 묶음이다. 아까 메시지는 파티션에 저장되고, 파티션 내에서만 순서가 유지된다고 했는데, 이건 또 무슨 소리일까?&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;메시지가 파티션에 저장된다고 하면, 파티션에 차곡차곡 순서대로 쌓을 것 같지만, &lt;b&gt;사실은 세그먼트 단위로 만들어진 파일&lt;/b&gt;을 차곡차곡 쌓게 된다. 아래의 그림과 같이, 설정된 크기 또는 시간(segment.ms / segment.bytes)에 따라 세그먼트가 생성된다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;484&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W9Vl3/btsL19bwzdl/NbmNqPkD4lj6mPzSoWqpSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W9Vl3/btsL19bwzdl/NbmNqPkD4lj6mPzSoWqpSk/img.png&quot; data-alt=&quot;https://rohithsankepally.github.io/Kafka-Storage-Internals/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W9Vl3/btsL19bwzdl/NbmNqPkD4lj6mPzSoWqpSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW9Vl3%2FbtsL19bwzdl%2FNbmNqPkD4lj6mPzSoWqpSk%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;968&quot; height=&quot;546&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://rohithsankepally.github.io/Kafka-Storage-Internals/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;토픽 내 파티션에 메시지를 발행한다면, 실제 세그먼트는 아래와 같이 생긴다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;메시지는 .log 라는 하나의 파일에 쌓인다. (*.index, *.timeindex 파일도 생긴다)&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span data-prosemirror-mark-name=&quot;annotation&quot; data-prosemirror-content-type=&quot;mark&quot; data-id=&quot;838359d3-0659-4f13-8a7b-062940995a55&quot; data-mark-annotation-type=&quot;inlineComment&quot; data-mark-type=&quot;annotation&quot;&gt;파일명은 시작 offset 을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;codeBlock&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;code&gt;00000000000000000000.* - Capture storage of messages with 0 &amp;lt;= offset &amp;lt;35.
00000000000000000035.* - Capture storage of messages with offset &amp;gt;=35
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;자세한 내용은 &lt;span data-prosemirror-node-inline=&quot;true&quot; data-prosemirror-node-name=&quot;inlineCard&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://rohithsankepally.github.io/Kafka-Storage-Internals/&quot;&gt;https://rohithsankepally.github.io/Kafka-Storage-Internals/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; 이 글을 보라.&lt;/p&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size23&quot;&gt;삭제의 대상&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;log 파일을 통해 우리는 delete 를 하든, compact 를 하든 삭제가 세그먼트 단위로 이뤄지는 이유에 대해 알 수 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;데이터는 로그의 헤드 부분에 쌓인다. 자연히 오래된 메시지는 테일 부분에 오래된 순으로 쌓여 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;세그먼트는 크기 또는 시간에 따라 구분된다고 했다. &lt;b&gt;이미 크기 또는 시간이 꽉 찬 테일 부분은, 여러 개의 세그먼트로 나뉘어져 있을 것이다. 반면 헤드의 세그먼트에는 계속해서 새로운 데이터가 쌓이게 된다&lt;/b&gt;.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;665&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s66o5/btsL1FotcQH/qnzpbaIjomsP7B9PX3417k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s66o5/btsL1FotcQH/qnzpbaIjomsP7B9PX3417k/img.png&quot; data-alt=&quot;https://docs.confluent.io/kafka/design/log_compaction.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s66o5/btsL1FotcQH/qnzpbaIjomsP7B9PX3417k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs66o5%2FbtsL1FotcQH%2FqnzpbaIjomsP7B9PX3417k%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;665&quot; height=&quot;209&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.confluent.io/kafka/design/log_compaction.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;아래의 그림이 있을 때, 삭제 후보는 활성화된 세그먼트를 제외하고, 아래의 1, 2, N-1 이다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;680&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;605&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVAEzu/btsL1C6mYLr/3JbcFmTRxfdqOosFy19iY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVAEzu/btsL1C6mYLr/3JbcFmTRxfdqOosFy19iY0/img.png&quot; data-alt=&quot;https://docs.cloudera.com/runtime/7.2.10/kafka-overview/topics/kafka-overview-logs-and-log-segments.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVAEzu/btsL1C6mYLr/3JbcFmTRxfdqOosFy19iY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVAEzu%2FbtsL1C6mYLr%2F3JbcFmTRxfdqOosFy19iY0%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;680&quot; height=&quot;605&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;605&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.cloudera.com/runtime/7.2.10/kafka-overview/topics/kafka-overview-logs-and-log-segments.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;실제 삭제 대상은 delete 이냐, compact 이냐에 따라 다르다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;611&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl1ywG/btsL05uh51Q/LIUIgTTEmZJ6VaArXwkcg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl1ywG/btsL05uh51Q/LIUIgTTEmZJ6VaArXwkcg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl1ywG/btsL05uh51Q/LIUIgTTEmZJ6VaArXwkcg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl1ywG%2FbtsL05uh51Q%2FLIUIgTTEmZJ6VaArXwkcg0%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;611&quot; height=&quot;204&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;delete 정책은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;보존 기간이나 크기&lt;/b&gt;를 초과한 &lt;b&gt;닫힌&lt;/b&gt; 세그먼트를 대상으로 한다.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;오래된 세그먼트부터 순차적으로 삭제한다.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;설정된 보존 기준을 초과하지 않는 세그먼트는 그대로 유지된다.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;위의 그림에서, Segment N 이 활성화된 세그먼트이고, 보존 기준을 초과한 세그먼트가 Segement 1 뿐이라면, 2, N-1, N 은 그대로 유지된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;세그먼트가 생기는 시간 / 사이즈가 있고, 보존 기간 / 사이즈가 있기 때문에 어떤 메시지가 삭제되느냐는 예상과는 조금 다를 수 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;아래의 그림을 보면, 세그먼트 사이즈가 보존 기간보다 크고, 체크 스레드가 보존 기간을 초과한 세그먼트를 삭제하고 있다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1600&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;865&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9pBjz/btsL1XCqxG1/8V13G4xAZSqgOSh49oV181/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9pBjz/btsL1XCqxG1/8V13G4xAZSqgOSh49oV181/img.png&quot; data-alt=&quot;https://www.redpanda.com/guides/kafka-performance-kafka-logs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9pBjz/btsL1XCqxG1/8V13G4xAZSqgOSh49oV181/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9pBjz%2FbtsL1XCqxG1%2F8V13G4xAZSqgOSh49oV181%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;1600&quot; height=&quot;865&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;865&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.redpanda.com/guides/kafka-performance-kafka-logs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;compact 정책은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;닫힌 세그먼트를 대상으로 한다.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;각 키에 대해 가장 최신 값만을 유지하고, 이전 버전의 데이터는 제거한다.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;압축 과정에서 새로운 세그먼트가 생성되며, 이 세그먼트에는 각 키의 최신 값만 포함된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;compact 방식일 때의 대상은 보존 기간의 초과가 아니라, 아래 세 가지 설정에 의해 결정된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;log.cleaner.delete.retention.ms&lt;/span&gt;&lt;/b&gt; controls how long the records are retained after they are confirmed for deletion.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;log.cleaner.min.compaction.lag.ms&lt;/span&gt;&lt;/b&gt; defines the minimum age of the records that are subject to compaction.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;log.cleaner.max.compaction.lg.ms&lt;/span&gt;&lt;/b&gt; defines the maximum age of records that can remain in the system without compaction.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot;&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;1800&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvfvvA/btsL0ZBlAII/Na8hr5hLkJePZNSfKKpvmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvfvvA/btsL0ZBlAII/Na8hr5hLkJePZNSfKKpvmK/img.png&quot; data-alt=&quot;https://developer.confluent.io/courses/architecture/compaction/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvfvvA/btsL0ZBlAII/Na8hr5hLkJePZNSfKKpvmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvfvvA%2FbtsL0ZBlAII%2FNa8hr5hLkJePZNSfKKpvmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;942&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://developer.confluent.io/courses/architecture/compaction/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;만약 compact 방식인데 키가 null 이면 어떻게 될까?&lt;span data-prosemirror-mark-name=&quot;annotation&quot; data-prosemirror-content-type=&quot;mark&quot; data-id=&quot;b1175bdf-64e7-4ea3-b475-60fc53db9dbf&quot; data-mark-annotation-type=&quot;inlineComment&quot; data-mark-type=&quot;annotation&quot;&gt; 키가 null 인 레코드는 전송되지 않는다&lt;/span&gt;(&lt;span data-prosemirror-node-inline=&quot;true&quot; data-prosemirror-node-name=&quot;inlineCard&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://blog.voidmainvoid.net/505&quot;&gt;https://blog.voidmainvoid.net/505&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; ).&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;더 자세하게 알고 싶으면 &lt;span data-prosemirror-node-inline=&quot;true&quot; data-prosemirror-node-name=&quot;inlineCard&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://developer.confluent.io/courses/architecture/compaction/&quot;&gt;https://developer.confluent.io/courses/architecture/compaction/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; 여기에 아주 잘 설명돼 있다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot; data-prosemirror-content-type=&quot;node&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-node-block=&quot;true&quot;&gt;1부를 마치며&lt;/h1&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;카프카는 로그 기반 구조를 취함으로써, 한 번 쓰여진 데이터는 변경이 불가능하게 한다. 또한 테일 영역의 데이터만 삭제함으로써 삭제를 용이하게 하며, 끝에만 저장하니까 속도도 빠르다(&lt;span data-prosemirror-node-inline=&quot;true&quot; data-prosemirror-node-name=&quot;inlineCard&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://docs.confluent.io/kafka/design/file-system-constant-time.html&quot;&gt;https://docs.confluent.io/kafka/design/file-system-constant-time.html&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; ).&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;카프카는 이러한 방식으로 데이터를 저장함으로써, 이벤트 스트리밍이라는 컨셉을 구현했다. 또, 이 글에서 다루지는 않았지만, 파티션의 복제를 통해 분산 처리를 지원하는데, 로그 기반의 순차적인 시스템이 이것을 가능하게 한다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;여기까지, 실시간으로 변화하는 현재의 사건들을 여러 클라이언트가 대응할 수 있도록 한 카프카의 컨셉이 어떻게 실현되었는지 살펴봤다.&lt;/p&gt;
&lt;h1 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot;&gt;메시지 소비&lt;/h1&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;to be continued&lt;/p&gt;</description>
      <category>개발</category>
      <category>clean-up policy</category>
      <category>kafka</category>
      <category>offset</category>
      <category>Partition</category>
      <category>partitioner</category>
      <category>segment</category>
      <category>Topic</category>
      <category>카프카</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/99</guid>
      <comments>https://bibapditura.tistory.com/99#entry99comment</comments>
      <pubDate>Fri, 24 Jan 2025 22:01:12 +0900</pubDate>
    </item>
    <item>
      <title>[누구나 자료구조와 알고리즘] 3장. 빅오표기법</title>
      <link>https://bibapditura.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빅오표기법: 시간 복잡도를 효율적으로 나타내기 위한 표기법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;탄생배경&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;어떤 알고리즘을 &quot;22단계의 알고리즘&quot;과 같은 식으로 표기하는 방식은 원소수가 달라질 때마다 몇 단계가 필요한지 달라지기 때문에 부적절하다.&lt;/li&gt;
&lt;li&gt;또한 &quot;N개의 원소가 있을 때 선형 검색에 N단계가 필요하다&quot;와 같은 표기는 너무 길다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;O(N): 데이터 원소가 N개일 때 알고리즘에 몇 단계가 필요한지 표기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빅오표기법은 최악의 경우를 상정해 표기한다.&lt;/li&gt;
&lt;li&gt;위의 표기는 선형검색에서 최악의 경우를 고려하여 표현한 것이다.&lt;/li&gt;
&lt;li&gt;빅오표기법은 &quot;데이터 원소가 N개일 때 알고리즘에 몇 단계가 필요할까?&quot;에 대한 답을 표현한 것이다.&lt;/li&gt;
&lt;li&gt;그에 대한 답은 &quot;알고리즘에 N단계가 필요하다&quot;는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;O(1): 가장 빠른 알고리즘 유형 = 상수 시간을 갖는 알고리즘&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;읽기는 배열에 원소가 몇 개든, 항상 1단계만 소요된다.&lt;/li&gt;
&lt;li&gt;데이터가 늘어나도 알고리즘의 단계수는 증가하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빅오로 구분하는 알고리즘 유형&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;빅오의 본질은 데이터가 늘어날 때 알고리즘의 성능이 어떻게 바뀌는지를 의미한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;1) O(1)이든, O(3)이든 데이터 증가에 영향을 받지 않는 유형이므로, 둘을 구분할 필요가 없다. 즉, O(3)이라 표기하지 않고 O(1)로 표기한다.&lt;/li&gt;
&lt;li&gt;2) O(N)은 데이터 증가가 성능에 영향을 미치므로, O(1)과는 다른 유형이다.&lt;/li&gt;
&lt;li&gt;이러한 내용은 아래 그래프로 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvoHAa/btrOP1jnx8a/cuoGN8EsRjAonVNDnkIDOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvoHAa/btrOP1jnx8a/cuoGN8EsRjAonVNDnkIDOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvoHAa/btrOP1jnx8a/cuoGN8EsRjAonVNDnkIDOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvoHAa%2FbtrOP1jnx8a%2FcuoGN8EsRjAonVNDnkIDOK%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;1388&quot; height=&quot;744&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;744&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;b&gt;O(N)과 항상 100단계가 걸리는 알고리즘의 효율성 비교&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 그래프를 보면, 특정 원소수를 기준으로, 100 미만은 O(N)이, 100 초과는 100단계 알고리즘이 더 낫다고 볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z9XSW/btrOHTsmbFW/PkyhQD8r3hrAb7BNszdb70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z9XSW/btrOHTsmbFW/PkyhQD8r3hrAb7BNszdb70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z9XSW/btrOHTsmbFW/PkyhQD8r3hrAb7BNszdb70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz9XSW%2FbtrOHTsmbFW%2FPkyhQD8r3hrAb7BNszdb70%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;1274&quot; height=&quot;722&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;722&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;b&gt;이진검색의 빅오표기: O(logN) - 데이터가 두 배로 증가할 때마다 한 단계씩 늘어나는 알고리즘&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;'로그 시간의 시간 복잡도'의 유형&lt;/li&gt;
&lt;li&gt;O(logN)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(log2(N))에서 2를 생략한 것&lt;/li&gt;
&lt;li&gt;데이터 원소가 N개 있을 때 알고리즘에 log2(N) 단계가 걸린다는 의미이다.&lt;/li&gt;
&lt;li&gt;즉, O(logN)은 원소가 하나가 될 때까지 데이터 원소를 계속해서 반으로 줄이는 만큼의 단계 수가 걸린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;알고리즘의 효율성 비교: O(1) &amp;gt; O(logN) &amp;gt; O(N)&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;1274&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbdCQA/btrOTiXQQB0/EAilN4ekc2KG1OiM11VXV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbdCQA/btrOTiXQQB0/EAilN4ekc2KG1OiM11VXV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbdCQA/btrOTiXQQB0/EAilN4ekc2KG1OiM11VXV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbdCQA%2FbtrOTiXQQB0%2FEAilN4ekc2KG1OiM11VXV1%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;1274&quot; height=&quot;722&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 로가리즘(로그)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로가리즘은 지수와 역의 관계다.&lt;/li&gt;
&lt;li&gt;log2(8) = 3
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2의 3제곱의 역으로, 2를 3번 곱해야 8을 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;1이 나올 때까지 8을 2로 몇 번 나눠야 하는지 계산하면 구할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;O(logN) VS O(N)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) O(logN): 데이터 원소가 두 배로 늘어날 때마다 딱 한 단계만 더 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) O(N): 데이터 원소 수만큼의 단계가 필요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V13Js/btrOQfvmAsq/AjaKhThUWGwov8eirJk90k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V13Js/btrOQfvmAsq/AjaKhThUWGwov8eirJk90k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V13Js/btrOQfvmAsq/AjaKhThUWGwov8eirJk90k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV13Js%2FbtrOQfvmAsq%2FAjaKhThUWGwov8eirJk90k%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;1572&quot; height=&quot;616&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연습문제 - 각 함수의 시간복잡도 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666002569091&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function isLeapYear(year) {
	return (year % 100 === 0) ? (year % 400 === 0) : (year % 4 === 0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 수가 들어오든 항상 한 단계만 수행하므로(데이터가 늘어남에 따라 영향을 받지 않으므로) 상수 시간의 알고리즘이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;/p&gt;
&lt;pre id=&quot;code_1666002821629&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function arraySum(array) {
	let sum = 0;
    
    for(let i = 0; i &amp;lt; array.length; i++) {
    	sum += array[i];
    }
    
    return sum;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배열의 길이에 따라 단계가 달라지므로 O(N)이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666003201301&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function chessboardSpace(numberOfGrains) {
	let chessboardSpaces = 1;
    let placedGrains = 1;
    
    while (placedGrains &amp;lt; numberOfGrains) {
    	placedGrains *= 2;
        chessboardSpaces += 1;
    }
    
    return chessboardSpaces;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(logN)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- N이 두 배 늘어날 때마다 루프를 한 번 더 실행하므로 O(logN)이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666003619649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function selectAStrings(array) {
	let newArray = [];
    
    for(let i=0; i &amp;lt; array.length; i++) {
    	if (array[i].startsWith(&quot;a&quot;)) {
        	newArray.push(array[i]);
        }
    }
    
    return newArray;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 배열이 오든, 배열의 모든 자리수를 검사해야 하므로 O(N)이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;pre id=&quot;code_1666003810835&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function median(array) {
	const middle = Math.floor(array.length / 2);
    
    if (array.length % 2 === 0) {
    	return (array[middle - 1] + array[middle]) / 2;
    } else {
    	return array[middle];
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한 번만 수행한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>개발</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/83</guid>
      <comments>https://bibapditura.tistory.com/83#entry83comment</comments>
      <pubDate>Mon, 17 Oct 2022 19:55:02 +0900</pubDate>
    </item>
    <item>
      <title>[오늘 한 것 &amp;amp; 배운 것]</title>
      <link>https://bibapditura.tistory.com/81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘 한 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 면접준비&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 모의면접&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 코딩테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;배운 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. stream 내에서 if 문 사용하는 방법: 중괄호 활용&lt;/p&gt;
&lt;pre id=&quot;code_1662204426122&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; nameList = Arrays.stream(split)
                .map(name -&amp;gt; {
                    String[] nameArr = name.split(&quot; &quot;);
                    if (nameArr.length &amp;gt; 2) {
                        return nameArr[0].substring(0, 1) + nameArr[1].substring(0, 1);
                    } else {
                        return nameArr[0].substring(0, 1);
                    }
                })
                .collect(Collectors.toList());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 필터와 인터셉터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘 모의면접 중, 필터와 인터셉터의 차이에 대해 질문했는데 이 질문에 대답을 못했다. 간단히 아래와 같이 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필터: 스프링에 들어오기 전(디스패처 서블릿 앞단)에 동작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인터셉터: 디스패처 서블릿 호출 후 컨트롤러 호출 전/후로 동작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AOP: 메소드의 실행 전/후로 동작&lt;/p&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>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/81</guid>
      <comments>https://bibapditura.tistory.com/81#entry81comment</comments>
      <pubDate>Sat, 3 Sep 2022 20:30:43 +0900</pubDate>
    </item>
    <item>
      <title>[오늘 한 것 &amp;amp; 배운 것]</title>
      <link>https://bibapditura.tistory.com/80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘 한 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 코딩테스트 연습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;배운 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Array, List&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 프로세스, 스레드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Wrapper 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 컬렉션 프레임웤&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 집단을 저장하는 클래스들을 표준화한 설계&lt;/li&gt;
&lt;li&gt;컬렉션 인터페이스: Collection(List, Set), Map&lt;/li&gt;
&lt;li&gt;컬렉션 클래스: ArrayList, HashMap, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- List&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순서가 있는 데이터의 집합&lt;/li&gt;
&lt;li&gt;데이터의 중복을 허용한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-- ArrayList&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 저장공간을 처음부터 지정해야 한다&lt;/li&gt;
&lt;li&gt;더 큰 공간이 필요하면 새로운 더 큰 배열을 생성해서 기존 배열의 내용을 복사하여 새로운 배열에 저장한다&lt;/li&gt;
&lt;li&gt;메모리 상에 연달아 공간을 확보한다&lt;/li&gt;
&lt;li&gt;첫 번째 위치만 알면, index로 상대적 위치를 빠르게 찾을 수 있다&lt;/li&gt;
&lt;li&gt;Vector는 스레드 세이프하기 때문에 멀티 스레드 환경이 필요하면 Vector를 사용한다 - 하지만 예전과의 호환을 위해서만 남아 있는 것이기 때문에 안 쓰는 게 좋음&lt;/li&gt;
&lt;li&gt;중간 데이터를 추가/삭제할 때는 데이터를 복사 후에 집어 넣는 방식이므로 효율이 좋지 않다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-- LinkedList&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 노드가 다음 노드의 주소를 저장하여, 불연속적으로 존재하는 데이터를 서로 연결한 형태&lt;/li&gt;
&lt;li&gt;자바에서는 이전 노드도 저장하는 더블 링크드 리스트로 구현되어 있다&lt;/li&gt;
&lt;li&gt;중간 데이터를 추가/삭제할 때는 참조를 변경하기만 하면 되서 처리속도가 매우 빠르다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;--- 순차적으로 추가/삭제하는 경우에는 ArrayList가 LinkedList보다 빠르지만, 중간데이터를 추가/삭제하는 경우에는 LinkedList가 더 빠르다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-- Stack&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마지막에 저장한 데이터를 가장 먼저 꺼내는 LIFO 구조&lt;/li&gt;
&lt;li&gt;순차적으로 데이터를 추가하고 삭제하기 때문에 ArrayList와 같은 배열 기반의 컬렉션 클래스가 적합하다&lt;/li&gt;
&lt;li&gt;자바에서는 클래스로 구현되어 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-- Queue&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음에 저장한 데이터를 가장 먼저 꺼내는 FIFO 구조&lt;/li&gt;
&lt;li&gt;데이터의 추가/삭제가 쉬운(데이터의 복사가 발생하지 않는) LinkedList로 구현하는 것이 적합하다 - 자바에는 LinkedList가 구현되어 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--- PriorityQueue&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Queue의 구현체, 저장한 순서에 관계없이 우선순위가 높은 것부터 꺼낸다&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Set&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순서를 유지하지 않는 데이터의 집합&lt;/li&gt;
&lt;li&gt;데이터의 중복을 허용하지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Map&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키와 값의 쌍으로 이루어진 데이터의 집합&lt;/li&gt;
&lt;li&gt;순서는 유지되지 않는다&lt;/li&gt;
&lt;li&gt;키는 중복을 허용하지 않고 값은 중복을 허용한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 프로세스와 스레드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Wrapper 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bibapditura.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bibapditura.tistory.com/79&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/80</guid>
      <comments>https://bibapditura.tistory.com/80#entry80comment</comments>
      <pubDate>Thu, 1 Sep 2022 18:27:26 +0900</pubDate>
    </item>
    <item>
      <title>Wrapper 클래스</title>
      <link>https://bibapditura.tistory.com/79</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Wrapper 클래스란?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본형을 객체로 포장하는 것&lt;/li&gt;
&lt;li&gt;기본형: char, boolean, int, byte, short, double, float, long&lt;/li&gt;
&lt;li&gt;참조타입으로 변환되므로, 주소를 저장하게 된다(equals 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;언제 사용되는가?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메소드의 파라미터로 객체 타입만이 요구되는 경우&lt;/li&gt;
&lt;li&gt;클래스의 장점 - 클래스에 포함된 메소드를 활용하는 경우&lt;/li&gt;
&lt;li&gt;제네릭의 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;박싱 &amp;amp; 언박싱&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;박싱: 기본형을 Wrapper 클래스로 변환할 때 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Integer num = new Integer(1);&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;언박싱: Wrapper 클래스를 기본형으로 변환할 때 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int n = num.intValue();&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오토박싱 &amp;amp; 오토언박싱&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위처럼 직접 쓰지 않고 바로 대입해도 박싱/언박싱이 이뤄진다&lt;/li&gt;
&lt;li&gt;오토박싱: Integer num = 1;&lt;/li&gt;
&lt;li&gt;오토언박싱: int n = num;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/79</guid>
      <comments>https://bibapditura.tistory.com/79#entry79comment</comments>
      <pubDate>Thu, 1 Sep 2022 09:50:20 +0900</pubDate>
    </item>
    <item>
      <title>SQL문 - Join, Case when, Datetime</title>
      <link>https://bibapditura.tistory.com/78</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Join&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- inner join: 교집합&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: A, B 테이블에 모두 존재하는 데이터 중, A 테이블 기준 기간이 긴 데이터 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1661933030995&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
from animal_ins A 
left join animal_outs B on A.animal_id=B.animal_id
where A.datetime &amp;gt; B.datetime
order by A.datetime&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- outer join: 합집합&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: A, B 테이블 중 B 테이블에만 존재하는 데이터 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1661932984035&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT B.animal_id, B.name
from animal_ins A right outer join animal_outs B on A.animal_id=B.animal_id
where A.animal_id is null&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;If / case when&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- If: 특정 조건에 따라 분기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: A인 경우에는 X, 아닌 경우에는 O로 표기하기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1661933379421&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ANIMAL_ID, NAME, IF(SEX_UPON_INTAKE LIKE 'Intact%', 'X', 'O') AS '중성화'
FROM ANIMAL_INS
ORDER BY ANIMAL_ID;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Case When End: 특정 조건에 따라 분기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: A인 경우에는 X, 아닌 경우에는 O로 표기하기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1661933326196&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT animal_id, name,
case when sex_upon_intake like 'intact%' then 'X'
else 'O'
end as '중성화'
from animal_ins&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Datetime&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- datediff: 두 날짜의 기간 일수로 비교하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661933207030&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT B.animal_id, B.name
from animal_outs B
join animal_ins A
on A.animal_id=B.animal_id
where B.animal_id is not null
order by datediff(A.datetime, B.datetime)
limit 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 날짜 포맷&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661936121205&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT animal_id, name, date_format(datetime, '%Y-%m-%d') as '날짜'
from animal_ins 
order by animal_id&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/78</guid>
      <comments>https://bibapditura.tistory.com/78#entry78comment</comments>
      <pubDate>Wed, 31 Aug 2022 17:10:59 +0900</pubDate>
    </item>
    <item>
      <title>[오늘 한 것 &amp;amp; 배운 것]</title>
      <link>https://bibapditura.tistory.com/77</link>
      <description>&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;티끌 ver.2 - 네이버 쇼핑 API 붙이기&amp;nbsp;&lt;/li&gt;
&lt;li&gt;모의 면접
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레디스를 사용한 이유는?&lt;/li&gt;
&lt;li&gt;레디스 말고 다른 것도 있는데 레디스를 사용한 이유는 무엇인가?&lt;/li&gt;
&lt;li&gt;pub/sub란 무엇인가?&lt;/li&gt;
&lt;li&gt;OAuth2가 작동하는 프로세스에 대해 설명해보라&lt;/li&gt;
&lt;li&gt;구글 토큰을 별도로 저장하지 않았는지? - 별도 저장을 통해 자동 로그인을 구현할 수 있다&lt;/li&gt;
&lt;li&gt;@Autowired 어노테이션에 대해 설명해보라&lt;/li&gt;
&lt;li&gt;스프링의 기본 동작 프로세스에 대해 설명해보라&lt;/li&gt;
&lt;li&gt;싱글톤은 어떻게 유지되는지? - 인스턴스를 static으로 만들어서 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배운 것&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 UserService에서 BoardRepository를 참조해야 할 일이 생긴다. 이것은 옳은 방식일까?
&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;한 번만 호출하는 경우: Repository를 바로 호출하는 편이 효율적임&lt;/li&gt;
&lt;li&gt;여러 군데서 활용하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스별로 파라미터를 걸어서 호출&lt;/li&gt;
&lt;li&gt;팩토리 패턴: 임플과 서비스를 나누어라&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/77</guid>
      <comments>https://bibapditura.tistory.com/77#entry77comment</comments>
      <pubDate>Fri, 26 Aug 2022 23:12:16 +0900</pubDate>
    </item>
    <item>
      <title>[스프링 핵심 기본 원리] SOLID 원칙</title>
      <link>https://bibapditura.tistory.com/75</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. SRP 단일책임원칙 Single Responsibility Principle&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; -&amp;gt; 변경이 있을 때 파급효과가 적어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. OCP 개방-폐쇄원칙 Open/Closed Principle&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 확장에는 열려 있으나, 변경에는 닫혀 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 다형성을 활용하여, 인터페이스를 구현한 새로운 클래스를 만들어서 새로운 기능을 구현했다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이때, 서비스 단에서는 아래와 같은 코드를 작성하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MemberRepository mp = new MemoryMemberRepository();&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 그런데, mp를 new JdbcMemberRepository();로 바꾸어야 한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; DIP를 위반하게 되고, 변경에 열려 있는 것이 되어 버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;gt; 이것을 해결하려면 빈 컨테이너를 활용하여 DI를 하는 것이 필요하다.&lt;/p&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. LSP 리스코프 치환원칙 Liskov Substitution Principle&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; - 자동차 인터페이스의 엑셀: 앞으로 간다는 규약 -&amp;gt; 뒤로 간다는 기능을 만들어서는 안 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. ISP 인터페이스 분리 원칙 Interface Segregation Principle&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 자동차 인터페이스를 정비사/운전으로 쪼개라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. DIP 의존관계 역전 원칙 Dependency Inversion Principle&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;- 의존성 주입은 이 원칙을 따르는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 역할에 대해서만 알아야 하는 것. 구현에 의존하면 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=====&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 다형성만으로는 OCP, DIP를 지킬 수 없다 -&amp;gt; 스프링 프레임워크를 사용한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 객체지향: 객체들의 모임. 객체는 메시지를 주고 받고 데이터를 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 다형성: 역할과 구현으로 구분할 수 있다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/75</guid>
      <comments>https://bibapditura.tistory.com/75#entry75comment</comments>
      <pubDate>Wed, 10 Aug 2022 11:28:02 +0900</pubDate>
    </item>
    <item>
      <title>20220713</title>
      <link>https://bibapditura.tistory.com/72</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;통계 스케쥴러 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 내가 아낀 이력 월별 통계 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Scheduler 선정 이유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 일정 시간에 정해진 일을 수행하는 데는 batch, quartz, scheduler가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- batch: 여러 job을 순차적으로 처리. 보다 규모가 큰 경우 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- quartz, scheduler: 특정 job을 특정 시간에 처리. 단, quartz는 클러스트링 등 세부적인 조작이 가능하지만 구현이 복잡하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 통계만을 위한 작업이므로, scheduler를 사용하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* scheduler는 스프링부트 스타터에 기본적으로 포함되어 있어 새로 주입할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고려해야할 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 서버 시간과 로컬 시간이 다를 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* cron 표현 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 사람이 없는 시간대에 작동시켜야 함(ex. 새벽 5시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* queryDSL 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 프론트에서 요청하는 api, 정해진 시간에 맞춰 저장시킬 api 두 개가 필요하다.&lt;/p&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;* 통계테이블에 userid를 연관관계를 맺어야 한다?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- yes: user별 데이터를 객체로 다루기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- no: 양방향 매핑을 한다면, 불필요한 데이터까지 꺼내와야 한다. 단방향 매핑을 한다면 되지만, 역시 userid 외 불필요한 데이터를 가져오게 된다. 번거롭더라도 where 절을 통해 구현하는 게 맞을 거라는 생각&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*  db에서 갖고 와서 sum/count를 계산할 것인가? 아니면 아예 갖고 와서 계산할 것인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;queryDSL&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자가 아닌 코드로 쿼리를 작성함으로써, 컴파일 시점에 문법 오류를 쉽게 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;자동 완성 등 IDE의 도움을 받을 수 있다.&lt;/li&gt;
&lt;li&gt;동적인 쿼리 작성이 편리하다.&lt;/li&gt;
&lt;li&gt;쿼리 작성 시 제약 조건 등을 메서드 추출을 통해 재사용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속성 종류&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cron : cron표현식을 지원한다. &quot;초 분 시 일 월 요일 (년)&quot;으로 표현한다. cron표현식에 쓸 수 있는 것들(특수문자 활용 포함)이 많은데 해당 내용이 핵심이 아니므로 다른 블로그에서 확인해보기를 바란다.&lt;/li&gt;
&lt;li&gt;fixedDelay : milliseconds 단위로, 이전 작업이 끝난 시점으로 부터 고정된 시간을 설정한다. ex) fixedDelay = 5000&lt;/li&gt;
&lt;li&gt;fixedDelayString : fixedDelay와 같은데 property의 value만 문자열로 넣는 것이다. ex) fixedDelay = &quot;5000&quot;&lt;/li&gt;
&lt;li&gt;fixedRate : milliseconds 단위로, 이전 작업이 수행되기 시작한 시점으로 부터 고정된 시간을 설정한다. ex) fixedRate = 3000&lt;/li&gt;
&lt;li&gt;fixedRateString : fixedDelay와 같은데 property의 value만 문자열로 넣는 것이다. ex) fixedRate = &quot;3000&quot;&lt;/li&gt;
&lt;li&gt;initialDelay : 스케줄러에서 메서드가 등록되자마자 수행하는 것이 아닌 초기 지연시간을 설정하는 것이다.&lt;/li&gt;
&lt;li&gt;initialDelayString : 위와 마찬가지로 문자열로 값을 표현하겠다는 의미다.&lt;/li&gt;
&lt;li&gt;zone : cron표현식을 사용했을 때 사용할 time zone으로 따로 설정하지 않으면 기본적으로 서버의 time zone이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/72</guid>
      <comments>https://bibapditura.tistory.com/72#entry72comment</comments>
      <pubDate>Wed, 13 Jul 2022 21:38:39 +0900</pubDate>
    </item>
    <item>
      <title>목표</title>
      <link>https://bibapditura.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이번 주차 목표&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메서드 분리하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 깃 협업툴로 활용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기획 똑띠 하기!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컨플루언스로 정책 정의 &amp;amp; 지라로 이슈 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 예외처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지난 주차에 한 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- MySQL 연결(select / update / insert / delete / drop 등 기본 sql문 작성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터베이스 설계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 영속성 약간 건드림...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 람다식 써봄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- jwt 약간 이해&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호호홍얍얍</author>
      <guid isPermaLink="true">https://bibapditura.tistory.com/71</guid>
      <comments>https://bibapditura.tistory.com/71#entry71comment</comments>
      <pubDate>Thu, 23 Jun 2022 23:12:43 +0900</pubDate>
    </item>
  </channel>
</rss>