<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>데브원영</title>
    <link>https://voidmainvoid.tistory.com/</link>
    <description>life is short</description>
    <language>ko</language>
    <pubDate>Mon, 13 Apr 2026 04:14:39 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>AndersonChoi</managingEditor>
    <image>
      <title>데브원영</title>
      <url>https://t1.daumcdn.net/cfile/tistory/271A0A43595393E907</url>
      <link>https://voidmainvoid.tistory.com</link>
    </image>
    <item>
      <title>카프카 source connector가 exactly-once를 지원하는 방법</title>
      <link>https://voidmainvoid.tistory.com/537</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;KIP-618에서 Source connector의 exactly-once(일부)&lt;/b&gt; 지원을 건의하였고 이 내용은 &lt;b&gt;3.3.0&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;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-618%3A+Exactly-Once+Support+for+Source+Connectors&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-618%3A+Exactly-Once+Support+for+Source+Connectors&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763870484212&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-618: Exactly-Once Support for Source Connectors - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Status Current state: Accepted Discussion thread:&amp;nbsp;here Voting thread:&amp;nbsp;here JIRA: KAFKA-10000 - 이슈 세부사항 가져오는 중... 상태 ,&amp;nbsp; KAFKA-6080 - 이슈 세부사항 가져오는 중... 상태 Please keep the discussion on the mailing list r&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-618%3A+Exactly-Once+Support+for+Source+Connectors&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-618%3A+Exactly-Once+Support+for+Source+Connectors&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-618%3A+Exactly-Once+Support+for+Source+Connectors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-618%3A+Exactly-Once+Support+for+Source+Connectors&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-618: Exactly-Once Support for Source Connectors - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Status Current state: Accepted Discussion thread:&amp;nbsp;here Voting thread:&amp;nbsp;here JIRA: KAFKA-10000 - 이슈 세부사항 가져오는 중... 상태 ,&amp;nbsp; KAFKA-6080 - 이슈 세부사항 가져오는 중... 상태 Please keep the discussion on the mailing list r&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기존에는 source connector의 EOS를 지원하지 않았던 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 다음과 같은 방식으로 데이터를 처리하고 오프셋을 저장했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 소스 DB로 부터 데이터를 읽어서 토픽으로 send()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. __connect-offsets에 읽은 오프셋까지 따로 커밋(저장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 방식은 별도의 처리로 이루어졌기 때문에 만약 워커가 죽어서 오프셋 저장이 되지 않으면 send()는 수행했지만 다시금 실행하는 즉, 두번의 처리(at-least-once)가 수행되었습니다. 그리고 추가적으로 좀비 태스크의 문제가 있었는데, 같은 소스 파티션에서 태스크가 어떠한 이유로 두번 이상 읽어서 중복이 발생하는 부분이 있어서 이를 다음과 같은 방식으로 해결하려고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 소스 레코드 전송 + 오프셋 저장을 '원자적'으로 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 좀비 태스크 팬싱(fencing)으로 중복 처리 하지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 관련 메커니즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 트랜잭션(원자적 처리)안에 소스 레코드 전송과 오프셋 커밋을 동시에 하는 것이 중요하다. 결과적으로 완벽하게 동시에 반영되어야지만 중복이나 누락없이 정확한 위치에서 읽기가 가능해지기 때문이다. 그렇기에 source connector로 전송되는 레코드는 'transaction record'로 전송되고 이에 따라 commit 또는 abort되어 처리된다. 즉&lt;b&gt;, &lt;/b&gt;consumer 입장에서 topic을 읽기위해서는 isolation.level을 read_committed로 해야지만 정확히 한번처리된 데이터만 읽을 수 있게 된다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 설정하는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exactly.once.source.support 옵션을 통해 이제 source connector는 exactly-once 전송을 수행할 수 있게 되었습니다. 관련 옵션의 설명은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- exactly.once.source.supprt : DISABLED(기본값), ENABLED, PREPARING&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/39/documentation.html#connectconfigs_exactly.once.source.support&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/39/documentation.html#connectconfigs_exactly.once.source.support&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Whether to enable exactly once support for source connectors in the cluster by using transactions to write source records and their source offsets, and by proactively fencing out old task generations before bringing up new ones. To enable exactly-once source support on a new cluster, set this property to 'enabled'. To enable support on an existing cluster, first set to 'preparing' on every worker in the cluster, then set to 'enabled'. A rolling upgrade may be used for both changes. For more information on this feature, see the exactly-once source support documentation.&lt;br /&gt;&lt;b&gt;소스 커넥터에서 생성된 레코드와 해당 소스 오프셋을 트랜잭션으로 함께 기록하고, 새로운 태스크를 시작하기 전에 이전 세대의 태스크들을 적극적으로 펜싱하여 비활성화함으로써, 클러스터에서 소스 커넥터의 exactly-once 지원을 활성화할지 여부를 설정하는 옵션이다. 새로운 클러스터에서 처음부터 exactly-once 소스 지원을 사용하려면 이 값을 &amp;lsquo;enabled&amp;rsquo;로 설정하면 된다. 이미 운영 중인 클러스터에서는, 모든 워커에 대해 먼저 &amp;lsquo;preparing&amp;rsquo;으로 설정한 뒤, 그다음 단계에서 &amp;lsquo;enabled&amp;rsquo;로 설정해야 한다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스 커넥터 자체에서 exactly-once 처리를 지원하더라도 결과적으로 connect 클러스터 전체가 exactly-once 모드를 사용할 수 있도록 프레임워크 레벨에서 설정을 활성화 해야만 하고, 이 기능은 오직 distributed 모드(분산 커넥트)에서만 사용 가능하다.&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;특이한 점은 '처음' 커넥트 클러스터를 실행한다면 해당 옵션을 'enabled'로 설정하면 되고, 만약에 롤링 업그레이드 등을 통해 기존에는 'disabled(default)'로 되어 있다면 'preparing'으로 설정한 뒤에 'enabled'로 다시 변경해야만 한다.&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/537</guid>
      <comments>https://voidmainvoid.tistory.com/537#entry537comment</comments>
      <pubDate>Sun, 23 Nov 2025 13:22:24 +0900</pubDate>
    </item>
    <item>
      <title>카프카는 복제본(replica)를 자동으로 다른 브로커로 재배치하지 않습니다</title>
      <link>https://voidmainvoid.tistory.com/536</link>
      <description>&lt;p data-end=&quot;332&quot; data-start=&quot;174&quot; data-ke-size=&quot;size16&quot;&gt;브로커가 0, 1, 2, 3, 4번으로 구성된 클러스터가 있고, 특정 토픽의 파티션은 0번이 리더이며 1번과 2번에 복제본이 있다고 가정합니다.&lt;/p&gt;
&lt;p data-end=&quot;332&quot; data-start=&quot;174&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;332&quot; data-start=&quot;174&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 브로커 : 0,1,2,3,4&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;332&quot; data-start=&quot;174&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 토픽의 파티션 : 0(리더), 1(팔로워), 2(팔로워)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;332&quot; data-start=&quot;174&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;332&quot; data-start=&quot;174&quot; data-ke-size=&quot;size16&quot;&gt;이후 브로커 2번을 graceful shutdown하거나 예상치 못한 장애로 인해 오래 오프라인 상태가 되는 상황을 떠올려볼 수 있습니다.&lt;/p&gt;
&lt;blockquote data-end=&quot;428&quot; data-start=&quot;369&quot; data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;브로커 2번이 장시간 오프라인이면, 카프카가 자동으로 복제본을 3번이나 4번 브로커로 옮겨주지 않을까?&amp;rdquo;&lt;/blockquote&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;369&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;494&quot; data-start=&quot;430&quot; data-ke-size=&quot;size16&quot;&gt;복제본이 자동으로 이동한다면 가용성과 내구성이 유지될 것처럼 보입니다. 그러나 실제 Kafka는 어떻게 동작할까요.&lt;/p&gt;
&lt;hr data-end=&quot;499&quot; data-start=&quot;496&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;534&quot; data-start=&quot;501&quot; data-ke-size=&quot;size26&quot;&gt;카프카의 동작&lt;/h2&gt;
&lt;p data-end=&quot;699&quot; data-start=&quot;536&quot; data-ke-size=&quot;size16&quot;&gt;브로커 2번이 1분, 10분, 1시간, 그 이상을 오프라인 상태로 유지하더라도 Kafka는 오직 두 가지 동작만 수행합니다.&lt;/p&gt;
&lt;p data-end=&quot;699&quot; data-start=&quot;536&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;699&quot; data-start=&quot;536&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;첫째, 브로커 2번이 일정 시간 동안 리더를 따라잡지 못하면 ISR(In-Sync Replicas)에서 제외합니다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;둘째, 필요한 경우 리더 교체만 처리합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;881&quot; data-start=&quot;701&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;881&quot; data-start=&quot;701&quot; data-ke-size=&quot;size16&quot;&gt;그러나 Kafka는 복제본을 다른 브로커로 이동하지 않습니다. 즉, &lt;b&gt;replica 목록은 그대로 [0,1,2] 상태로 유지&lt;/b&gt;되며, 복제본 불일치 문제는 운영자가 직접 조치하지 않는 이상 해결되지 않습니다. 이로 인해 replication.factor가 3이라도 실질적으로는 2개의 replica만 운영되는 결과가 일어납니다. 이런 현상을 &lt;b&gt;Under replicated partition 상태라고 부릅니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;881&quot; data-start=&quot;701&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;881&quot; data-start=&quot;701&quot; data-ke-size=&quot;size26&quot;&gt;관련 문서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/documentation/#basic_ops_decommissioning_brokers&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/documentation/#basic_ops_decommissioning_brokers&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://kafka.apache.org/documentation/#basic_ops_decommissioning_brokers&quot;&gt;Decommissioning brokers&lt;/a&gt;&lt;/h4&gt;
&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;The partition reassignment tool does not have the ability to automatically generate a reassignment plan for decommissioning brokers yet. As such, the admin has to come up with a reassignment plan to move the replica for all partitions hosted on the broker to be decommissioned, to the rest of the brokers. This can be relatively tedious as the reassignment needs to ensure that all the replicas are not moved from the decommissioned broker to only one other broker. To make this process effortless, we plan to add tooling support for decommissioning brokers in the future.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p data-end=&quot;224&quot; data-start=&quot;59&quot; data-ke-size=&quot;size16&quot;&gt;브로커를 폐지(decommission)할 때, 현재의 파티션 재할당 도구는 이를 위한 &lt;b&gt;자동 재할당 계획을 생성하는 기능을 제공하지 않습니다&lt;/b&gt;. 따라서 관리자는 폐지하려는 브로커가 가지고 있는 모든 파티션의 복제본을 나머지 브로커로 옮기기 위한 재할당 계획을 &lt;b&gt;직접&lt;/b&gt; 만들어야 합니다. 이 작업은 상당히 번거로울 수 있습니다. 왜냐하면 재할당 과정에서 복제본이 폐지되는 브로커에서 &lt;b&gt;단일 브로커로만 몰려 이동하지 않도록&lt;/b&gt; 신경 써야 하기 때문입니다. 이 과정을 보다 수월하게 만들기 위해, Kafka는 향후 브로커 폐지를 위한 자동화된 도구 지원을 추가할 계획입니다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1372&quot; data-start=&quot;1343&quot; data-ke-size=&quot;size26&quot;&gt;그렇다면 운영에서는 어떻게 대응해야 하는가&lt;/h2&gt;
&lt;p data-end=&quot;1501&quot; data-start=&quot;1374&quot; data-ke-size=&quot;size16&quot;&gt;브로커가 단기간 오프라인인 경우에는 ISR에서 빠졌다가 복구 시 다시 합류하면 문제는 자연스럽게 해결됩니다. 그러나 브로커가 장기간 복구되지 않거나 아예 폐지할 예정이라면 운영자가 직접 복제본 재배치 작업을 실행해야 합니다. Kafka는 kafka-reassign-partitions.sh와 같은 관리 도구를 통해 명시적으로 원하는 replica 구성을 지정하도록 설계되어 있습니다. 관리자가 &amp;ldquo;파티션 0의 복제본을 0, 1, 3으로 옮기겠다&amp;rdquo;라고 지시해야만 Kafka는 이에 따라 실제 복제 작업을 수행합니다.&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/536</guid>
      <comments>https://voidmainvoid.tistory.com/536#entry536comment</comments>
      <pubDate>Fri, 21 Nov 2025 00:13:36 +0900</pubDate>
    </item>
    <item>
      <title>KIP-932 Queues for Kafka 사용해보기(KafkaShareConsumer)</title>
      <link>https://voidmainvoid.tistory.com/535</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 사용되는 아파치 카프카는 이벤트 스트림으로 파티션단위로 데이터를 처리하기 때문에 컨슈머 개수를 파티션 개수만큼 실행시켜 운영하는 것이 일반적이다. Queues for Kafka는 이와 다르게 파티션 개수보다 더 많은 컨슈머를 운영하기 위한 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757648633593&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-932: Queues for Kafka - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Status Current state:&amp;nbsp;Accepted Discussion thread: https://lists.apache.org/thread/9wdxthfsbm5xf01y4xvq6qtlg0gq96lq JIRA:&amp;nbsp;https://issues.apache.org/jira/browse/KAFKA-16092 Please keep the discussion on the mailing list rather than commenting on the wiki (&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-932: Queues for Kafka - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Status Current state:&amp;nbsp;Accepted Discussion thread: https://lists.apache.org/thread/9wdxthfsbm5xf01y4xvq6qtlg0gq96lq JIRA:&amp;nbsp;https://issues.apache.org/jira/browse/KAFKA-16092 Please keep the discussion on the mailing list rather than commenting on the wiki (&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Queues+for+Kafka+%28KIP-932%29+-+Preview+Release+Notes&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/Queues+for+Kafka+%28KIP-932%29+-+Preview+Release+Notes&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757650440947&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Queues for Kafka (KIP-932) - Preview Release Notes - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Apache Kafka 4.1.0 is shipped with a preview release of KIP-932: Queues for Kafka. This feature is not yet recommended for use on production clusters, but it is ready for evaluation and testing. This KIP introduces the concept of a share group as a way of &quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Queues+for+Kafka+%28KIP-932%29+-+Preview+Release+Notes&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Queues+for+Kafka+%28KIP-932%29+-+Preview+Release+Notes&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Queues+for+Kafka+%28KIP-932%29+-+Preview+Release+Notes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Queues+for+Kafka+%28KIP-932%29+-+Preview+Release+Notes&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Queues for Kafka (KIP-932) - Preview Release Notes - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka 4.1.0 is shipped with a preview release of KIP-932: Queues for Kafka. This feature is not yet recommended for use on production clusters, but it is ready for evaluation and testing. This KIP introduces the concept of a share group as a way of&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.1.0이 릴리즈되면서 Queues for Kafka는 이제 early access에서 preview로 바뀌었고, 상용환경에서도 위험을 감수하고 사용할만큼 보완되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;KafkaShareConsumer 사용 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) cluster 실행 및 설정&lt;/h3&gt;
&lt;pre id=&quot;code_1767056847542&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3.8&quot;

services:
  kafka:
    image: apache/kafka:4.1.0
    container_name: kafka41
    ports:
      - &quot;9092:9092&quot;
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENERS: INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9091,CONTROLLER://0.0.0.0:9093
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://127.0.0.1:9092,EXTERNAL://host.docker.internal:9091
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_NUM_PARTITIONS: 1

      # Share Coordinator 내부 상태 토픽 생성 조건 완화
      KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR: &quot;1&quot;
      KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR: &quot;1&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상기와 같이 설정하고 docker-compose up 으로 실행&lt;/p&gt;
&lt;pre id=&quot;code_1757650768379&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-features.sh --bootstrap-server localhost:9092 upgrade --feature share.version=1
share.version was upgraded to 1.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행중인 브로커에 피쳐를 on 하기 위해 상기 명령어를 실행한다.&lt;/p&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;pre id=&quot;code_1757650846184&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Exception in thread &quot;main&quot; org.apache.kafka.common.errors.UnsupportedVersionException: The cluster does not support the share group protocol. To use share groups, the cluster must have the share group protocol enabled.&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) consumer code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-1) ImplicitAck mode&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757651635806&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.example;

import org.apache.kafka.clients.consumer.AcknowledgeType;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaShareConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.util.List;
import java.util.Properties;

public class Main {
    private final static Logger log = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(&quot;bootstrap.servers&quot;, &quot;localhost:9092&quot;);
        props.put(&quot;group.id&quot;, &quot;test-group&quot;); // 공유 그룹 ID

        KafkaShareConsumer&amp;lt;String, String&amp;gt; consumer =
                new KafkaShareConsumer&amp;lt;&amp;gt;(props, new StringDeserializer(), new StringDeserializer());

        consumer.subscribe(List.of(&quot;test&quot;));

        while (true) {
            ConsumerRecords&amp;lt;String, String&amp;gt; records = consumer.poll(Duration.ofMillis(500));
            records.forEach(record -&amp;gt; {
                log.info(&quot;Processed: &quot; + record.value());
            });
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도로 모드를 지정하지 않고 KafkaShareConsumer를 사용할 경우 암시적인 ack 모드로 사용된다.&amp;nbsp; poll()로 가져온 배치는 자동으로 성공된것으로 간주되어 ACK가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1757651749014&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[main] INFO org.apache.kafka.common.config.AbstractConfig - ShareConsumerConfig values: 
	allow.auto.create.topics = true
	auto.commit.interval.ms = 5000
	auto.offset.reset = latest
	bootstrap.servers = [localhost:9092]
	group.id = test-group
	share.acknowledgement.mode = implicit  // 기본으로 설정된 mode 
    
    ... 생략
[main] WARN org.apache.kafka.clients.consumer.internals.ShareConsumerDelegateCreator - Share groups and KafkaShareConsumer are part of a preview feature introduced by KIP-932, and are not recommended for use in production.
[main] INFO org.apache.kafka.common.telemetry.internals.KafkaMetricsCollector - initializing Kafka metrics collector
[main] INFO org.apache.kafka.common.utils.AppInfoParser - Kafka version: 4.1.0
[main] INFO org.apache.kafka.common.utils.AppInfoParser - Kafka commitId: 13f70256db3c994c
[main] INFO org.apache.kafka.common.utils.AppInfoParser - Kafka startTimeMs: 1757651562780
[main] INFO org.apache.kafka.clients.consumer.internals.ShareConsumerImpl - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Subscribed to topics: test
[consumer_background_thread] INFO org.apache.kafka.clients.consumer.internals.ShareMembershipManager - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Member Hq3kzUZhQ4mt3l6afzGrVg with epoch 0 transitioned from UNSUBSCRIBED to JOINING.
[consumer_background_thread] INFO org.apache.kafka.clients.Metadata - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Cluster ID: 5L6g3nShT-eMCtK--X86sw
[consumer_background_thread] INFO org.apache.kafka.clients.consumer.internals.CoordinatorRequestManager - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Discovered group coordinator Coordinator(key='test-group', nodeId=1, host='127.0.0.1', port=9092, errorCode=0, errorMessage='')
[consumer_background_thread] INFO org.apache.kafka.clients.consumer.internals.ShareMembershipManager - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Member Hq3kzUZhQ4mt3l6afzGrVg with epoch 10 transitioned from JOINING to RECONCILING.
[consumer_background_thread] INFO org.apache.kafka.clients.consumer.internals.ShareMembershipManager - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Reconciling assignment with local epoch 0
	Member:                                    Hq3kzUZhQ4mt3l6afzGrVg
	Assigned partitions:                       [test-0]
	Current owned partitions:                  []
	Added partitions (assigned - owned):       [test-0]
	Revoked partitions (owned - assigned):     []

[consumer_background_thread] INFO org.apache.kafka.clients.consumer.internals.ShareMembershipManager - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Member Hq3kzUZhQ4mt3l6afzGrVg with epoch 10 transitioned from RECONCILING to ACKNOWLEDGING.
[consumer_background_thread] INFO org.apache.kafka.clients.consumer.internals.ShareMembershipManager - [ShareConsumer clientId=consumer-test-group-1, groupId=test-group] Member Hq3kzUZhQ4mt3l6afzGrVg with epoch 10 transitioned from ACKNOWLEDGING to STABLE.&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;2-2) ExplicitAck mode&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757651976939&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.example;

import org.apache.kafka.clients.consumer.AcknowledgeType;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaShareConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.util.List;
import java.util.Properties;

public class Main {
    private final static Logger log = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(&quot;bootstrap.servers&quot;, &quot;localhost:9092&quot;);
        props.put(&quot;group.id&quot;, &quot;test-group&quot;); // 공유 그룹 ID
        props.put(&quot;share.acknowledgement.mode&quot;, &quot;explicit&quot;); // ACK 모드

        KafkaShareConsumer&amp;lt;String, String&amp;gt; consumer =
                new KafkaShareConsumer&amp;lt;&amp;gt;(props, new StringDeserializer(), new StringDeserializer());

        consumer.subscribe(List.of(&quot;test&quot;));

        while (true) {
            ConsumerRecords&amp;lt;String, String&amp;gt; records = consumer.poll(Duration.ofMillis(500));
            records.forEach(record -&amp;gt; {
                try {
                    doProcessing(record.value());

                    // 성공적으로 처리 &amp;rarr; ACK
                    consumer.acknowledge(record, AcknowledgeType.ACCEPT);

                } catch (RetryableException e) {
                    // 재시도 가능한 오류 &amp;rarr; RELEASE
                    consumer.acknowledge(record, AcknowledgeType.RELEASE);

                } catch (Exception e) {
                    // 복구 불가능 오류 &amp;rarr; REJECT
                    consumer.acknowledge(record, AcknowledgeType.REJECT);
                }
            });

            // 메시지 단위 ACK을 브로커에 커밋
            consumer.commitSync();
        }
    }

    private static void doProcessing(String task) throws Exception {
        // 예: 이미지 처리, API 호출 등
        if (task.contains(&quot;fail&quot;)) {
            throw new RetryableException(&quot;Temporary failure&quot;);
        }
        log.info(&quot;Processed: &quot; + task);
    }

    static class RetryableException extends Exception {
        public RetryableException(String msg) {
            super(msg);
        }
    }
}&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;명시적 모드인 경우 commit을 수행해야 한다. AcknowledgeType은 총 3가지가 있으며 각 특징은 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1757652066124&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * The acknowledge type is used with {@link KafkaShareConsumer#acknowledge(ConsumerRecord, AcknowledgeType)} to indicate
 * whether the record was consumed successfully.
 */
@InterfaceStability.Evolving
public enum AcknowledgeType {
    /** The record was consumed successfully. */
    ACCEPT((byte) 1),

    /** The record was not consumed successfully. Release it for another delivery attempt. */
    RELEASE((byte) 2),

    /** The record was not consumed successfully. Reject it and do not release it for another delivery attempt. */
    REJECT((byte) 3);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1727&quot; data-start=&quot;1401&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AcknowledgeType&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;사용 상황&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;브로커 동작&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1559&quot; data-start=&quot;1495&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1508&quot; data-start=&quot;1495&quot;&gt;&lt;b&gt;ACCEPT&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1520&quot; data-start=&quot;1508&quot;&gt;성공적으로 처리됨&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1531&quot; data-start=&quot;1520&quot;&gt;정상 처리 완료&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1559&quot; data-start=&quot;1531&quot;&gt;Archived(완료)로 이동, 재전달 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1655&quot; data-start=&quot;1560&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1574&quot; data-start=&quot;1560&quot;&gt;&lt;b&gt;RELEASE&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1591&quot; data-start=&quot;1574&quot;&gt;일시적 실패, 재시도 필요&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1612&quot; data-start=&quot;1591&quot;&gt;네트워크/DB 오류, 일시적 장애&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1655&quot; data-start=&quot;1612&quot;&gt;다시 Available 상태로 이동, deliveryCount +1, &lt;b&gt;동일 컨슈머 또는 다른 컨슈머가 재시도&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1727&quot; data-start=&quot;1656&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1669&quot; data-start=&quot;1656&quot;&gt;&lt;b&gt;REJECT&lt;/b&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1682&quot; data-start=&quot;1669&quot;&gt;처리 불가능한 오류&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1701&quot; data-start=&quot;1682&quot;&gt;포이즌 메시지, 스키마 불일치&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1727&quot; data-start=&quot;1701&quot;&gt;즉시 Archived 상태, 재전달 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;deliveryCount란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Share Group(KIP-932)에서 각 레코드가 컨슈머에게 획득(acquire) 될 때마다 증가하는 카운터. 즉, 이 메시지가 몇 번 재시도되었는가를 추적하는 값임. 메시지가 무한정 재시도되는 것을 막기 위함. 잘못된 메시지(포이즌 레코드)가 무한 루프에 빠지지 않도록 최대 횟수 제한을 둠. &lt;a href=&quot;https://kafka.apache.org/documentation/#brokerconfigs_group.share.delivery.count.limit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;group.share.delivery.count.limit(기본값 5) 설정&lt;/a&gt;에 의해 limit 제어됨. 기본값(5)이라면 한 레코드는&amp;nbsp;최대 5회까지 poll &amp;rarr; acquire&amp;nbsp;될 수 있음. &lt;b&gt;6&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;번째부터는 더 이상 Available로 돌아가지 않고&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;Archived(폐기)&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;b&gt;상태&lt;/b&gt;로 전환됨.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757652533863&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────────┐
│                          Share Group State Machine                   │
└──────────────────────────────────────────────────────────────────────┘

[Produced]
    │  (레코드가 토픽에 기록됨)
    ▼
[Available]
    │  poll() 시 컨슈머가 획득(acquire)
    ▼
[Acquired / In-Flight]  ── 처리 시도 (process)
    │
    ├─ acknowledge(..., ACCEPT)
    │        │
    │        ▼
    │   [Acknowledged]  ──(commitSync/Async)──► __share_group_state 반영
    │                      (완료 상태. 재전달되지 않음)
    │
    ├─ acknowledge(..., RELEASE)
    │        │
    │        ├─ deliveryCount &amp;lt; maxDeliveries
    │        │        │
    │        │        ▼
    │        │   [Available] 로 복귀
    │        │   (같은 컨슈머 또는 다른 컨슈머가 재시도 가능,
    │        │    deliveryCount += 1)
    │        │
    │        └─ deliveryCount &amp;ge; maxDeliveries
    │                 │
    │                 ▼
    │            [Archived]  (더 이상 배달하지 않음)
    │
    ├─ acknowledge(..., REJECT)
    │        │
    │        ▼
    │   [Archived]  (즉시 보관/차단. 재전달 없음)
    │   (보통 DLQ로 복사 후 REJECT)
    │
    └─ (명시적 ACK 없이 루프 종료)
             │
             ├─ share.acknowledgement.mode = explicit
             │     &amp;rarr; ACK 안 한 레코드들은 같은 acquisition으로 재제공
             │       (다음 poll에서 다시 처리, deliveryCount 증가 없음)
             │
             └─ share.acknowledgement.mode = implicit
                   &amp;rarr; 다음 poll() 시 이전 배치가 암시적 ACK 처리됨
                     (실패 레코드도 성공으로 간주될 수 있으므로 주의)

[Archived] / [Acknowledged]
    └─ 단말 상태(terminal). 컨슈머에게 더 이상 전달되지 않음.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5개 인스턴스(컨슈머) 실행해보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- test 토픽, 파티션0개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- intellij에서 multi instance run&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3240&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck4cL2/btsQunYWzL4/nkwYOtE2hTXQhWbO8lLXbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck4cL2/btsQunYWzL4/nkwYOtE2hTXQhWbO8lLXbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck4cL2/btsQunYWzL4/nkwYOtE2hTXQhWbO8lLXbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck4cL2%2FbtsQunYWzL4%2FnkwYOtE2hTXQhWbO8lLXbk%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;3240&quot; height=&quot;618&quot; data-origin-width=&quot;3240&quot; data-origin-height=&quot;618&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;쉘스크립트로 상태 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757652950441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-groups.sh --bootstrap-server localhost:9092 --list
GROUP                TYPE                 PROTOCOL
test-group           Share                share

$ ./kafka-share-groups.sh --bootstrap-server localhost:9092 --list
test-group

$ ./kafka-share-groups.sh --bootstrap-server localhost:9092 --describe --group test-group
GROUP           TOPIC           PARTITION  START-OFFSET
test-group      test            0          13

$ ./kafka-share-groups.sh --bootstrap-server localhost:9092 --describe --group test-group --members
GROUP           CONSUMER-ID            HOST            CLIENT-ID             #PARTITIONS  ASSIGNMENT
test-group      531rie8GTeGXgr4mT0jViw /192.168.65.1   consumer-test-group-1 1            test:0
test-group      GMGiDkymRLqmH2sA_Py4yw /192.168.65.1   consumer-test-group-1 1            test:0
test-group      Wq1DHTFSRQWTH5m1-AA_-A /192.168.65.1   consumer-test-group-1 1            test:0
test-group      WyCVBVNBQsyeAFHMeYJCKw /192.168.65.1   consumer-test-group-1 1            test:0
test-group      aaeOrPSiQC-r69sdvoIsOQ /192.168.65.1   consumer-test-group-1 1            test:0

$ ./kafka-share-groups.sh --bootstrap-server localhost:9092 --describe --group test-group --state

GROUP           COORDINATOR (ID)          STATE           #MEMBERS
test-group      127.0.0.1:9092  (1)       Stable          5&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_1757653121897&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-topics.sh --bootstrap-server localhost:9092 \
  --alter --topic test --partitions 2

$ ./kafka-share-groups.sh --bootstrap-server localhost:9092 --describe --group test-group
GROUP           TOPIC           PARTITION  START-OFFSET
test-group      test            0          13
test-group      test            1          -

$ bin ./kafka-share-groups.sh --bootstrap-server localhost:9092 --describe --group test-group --members
GROUP           CONSUMER-ID            HOST            CLIENT-ID             #PARTITIONS  ASSIGNMENT
test-group      531rie8GTeGXgr4mT0jViw /192.168.65.1   consumer-test-group-1 1            test:0
test-group      GMGiDkymRLqmH2sA_Py4yw /192.168.65.1   consumer-test-group-1 1            test:1
test-group      Wq1DHTFSRQWTH5m1-AA_-A /192.168.65.1   consumer-test-group-1 1            test:1
test-group      WyCVBVNBQsyeAFHMeYJCKw /192.168.65.1   consumer-test-group-1 1            test:0
test-group      aaeOrPSiQC-r69sdvoIsOQ /192.168.65.1   consumer-test-group-1 1            test:0&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;kafka-share-groups.sh에 partitions는 해당 컨슈머가 점유중인 파티션 개수를 뜻함. 그리고 assignment는 해당 컨슈머가 할당된 토픽+파티션의 조합을 나타냄. kafkaShareConsumer인 경우 assignment는 기존 방식과 다름. Share Coordinator가 가용상태에 따라 동적으로 정함.&lt;/p&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>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/535</guid>
      <comments>https://voidmainvoid.tistory.com/535#entry535comment</comments>
      <pubDate>Fri, 12 Sep 2025 13:49:38 +0900</pubDate>
    </item>
    <item>
      <title>Apache Kafka 4.1.0 docker-compose.yaml 실행</title>
      <link>https://voidmainvoid.tistory.com/534</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757648416583&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3.8&quot;

services:
  kafka:
    image: apache/kafka:4.1.0
    container_name: kafka41
    ports:
      - &quot;9092:9092&quot;
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENERS: INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9091,CONTROLLER://0.0.0.0:9093
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://127.0.0.1:9092,EXTERNAL://host.docker.internal:9091
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_NUM_PARTITIONS: 1&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;/p&gt;
&lt;pre id=&quot;code_1757648444655&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker-compose up&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;/p&gt;
&lt;pre id=&quot;code_1757648462207&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;➜  kafka cd kafka_2.13-4.1.0
➜  kafka_2.13-4.1.0 ls
bin       config    libs      LICENSE   licenses  NOTICE    site-docs
➜  kafka_2.13-4.1.0 cd bin
➜  bin ./kafka-topics.sh --bootstrap-server localhost:9092 --topic test --create
Created topic test.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;카프카 바이너리 다운로드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/downloads&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757648475637&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apache Kafka&quot; data-og-description=&quot;Apache Kafka: A Distributed Streaming Platform.&quot; data-og-host=&quot;kafka.apache.org&quot; data-og-source-url=&quot;https://kafka.apache.org/downloads&quot; data-og-url=&quot;https://kafka.apache.org/downloads&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CqBQO/hyZI6rXogx/82Ak1qSKhWPQpKighxc0z1/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kafka.apache.org/downloads&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CqBQO/hyZI6rXogx/82Ak1qSKhWPQpKighxc0z1/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka: A Distributed Streaming Platform.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kafka.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/534</guid>
      <comments>https://voidmainvoid.tistory.com/534#entry534comment</comments>
      <pubDate>Fri, 12 Sep 2025 12:42:05 +0900</pubDate>
    </item>
    <item>
      <title>Openapi API 사용시 ⚠️선결제하면 안되는 이유.. - 돈낭비..</title>
      <link>https://voidmainvoid.tistory.com/533</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2024년 8월에 개인 프로젝트도 할겸 겸사겸사 openapi platform에서 선결제를 했었다. 그 당시 생각으로는 당장 사용하지 않더라도 차차 api key를 활용하면서 안전하게 돈이 빠져나가면 되겠다는 생각에 50달러(당시 7만원 정도)를 결제했었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1900&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcEJOZ/btsQrrHkpn1/KQJ9poyYu7nKeavNkSd7EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcEJOZ/btsQrrHkpn1/KQJ9poyYu7nKeavNkSd7EK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcEJOZ/btsQrrHkpn1/KQJ9poyYu7nKeavNkSd7EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcEJOZ%2FbtsQrrHkpn1%2FKQJ9poyYu7nKeavNkSd7EK%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;1900&quot; height=&quot;496&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1900&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 어쩌다저쩌다 하다보니 2025년이 되었고, 다시 프로젝트를 할 일이 생겨서 &lt;b&gt;예전에 충전했던 50달러 사용해야지~&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;왠걸~ 내가 사용할 수 있는 금액이 0.00 달러로 찍혀있는게 아닌가;;;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mq3kb/btsQtNCrTBV/9voChBWkqikdkfgHQ70tdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mq3kb/btsQtNCrTBV/9voChBWkqikdkfgHQ70tdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mq3kb/btsQtNCrTBV/9voChBWkqikdkfgHQ70tdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmq3kb%2FbtsQtNCrTBV%2F9voChBWkqikdkfgHQ70tdk%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;482&quot; height=&quot;295&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 내가 이걸 어디 낭비해서 다썻나..? 하고 payment history 내역을 찾아봐도 아무리 쓴 내역이 없다. 그러다가 들어간 곳은 credit grants. 여기서 수상한 state를 볼 수 있었는데 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;EXPIRE&lt;/b&gt;&lt;/span&gt; 라는 글자가 있는게 아닌가;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZuawx/btsQrJajjCP/q548nsfSSObfneO5ZkglJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZuawx/btsQrJajjCP/q548nsfSSObfneO5ZkglJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZuawx/btsQrJajjCP/q548nsfSSObfneO5ZkglJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZuawx%2FbtsQrJajjCP%2Fq548nsfSSObfneO5ZkglJ0%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;1970&quot; height=&quot;692&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9월 1일에 expire 되었다는 충격적인 이야기 선결제한 금액이 다 쓰지 않으면 소멸되는 이런 듣도 보도 못한 정책에 화가 나서 구글링해보니 일부 레딧 사용자들도 빡쳐서 글을 올린 내용을 확인할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://community.openai.com/t/are-openai-credits-expiring/511215&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://community.openai.com/t/are-openai-credits-expiring/511215&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757495767568&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Are OpenAI credits expiring?&quot; data-og-description=&quot;Since dashboard change, I see no warning about credit expiration date. They forgot to put it, they placed it somewhere else or credits are not expiring any more?&quot; data-og-host=&quot;community.openai.com&quot; data-og-source-url=&quot;https://community.openai.com/t/are-openai-credits-expiring/511215&quot; data-og-url=&quot;https://community.openai.com/t/are-openai-credits-expiring/511215&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gqaw0/hyZGW5l7m1/8RV8WjEtetH2zRHE41RmAK/img.png?width=463&amp;amp;height=500&amp;amp;face=0_0_463_500,https://scrap.kakaocdn.net/dn/bdcZx4/hyZIMgq6vI/jh3I5D9UTf1Mtzj3INXSj0/img.png?width=463&amp;amp;height=500&amp;amp;face=0_0_463_500,https://scrap.kakaocdn.net/dn/tjTMD/hyZJeDhAqd/5T9qdmIU2FE2xPdI1urFkK/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500&quot;&gt;&lt;a href=&quot;https://community.openai.com/t/are-openai-credits-expiring/511215&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://community.openai.com/t/are-openai-credits-expiring/511215&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gqaw0/hyZGW5l7m1/8RV8WjEtetH2zRHE41RmAK/img.png?width=463&amp;amp;height=500&amp;amp;face=0_0_463_500,https://scrap.kakaocdn.net/dn/bdcZx4/hyZIMgq6vI/jh3I5D9UTf1Mtzj3INXSj0/img.png?width=463&amp;amp;height=500&amp;amp;face=0_0_463_500,https://scrap.kakaocdn.net/dn/tjTMD/hyZJeDhAqd/5T9qdmIU2FE2xPdI1urFkK/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Are OpenAI credits expiring?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Since dashboard change, I see no warning about credit expiration date. They forgot to put it, they placed it somewhere else or credits are not expiring any more?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;community.openai.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;1532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lFCdR/btsQsOBOf7U/MYtom8e4ZCMJyAo9i0jHx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lFCdR/btsQsOBOf7U/MYtom8e4ZCMJyAo9i0jHx0/img.png&quot; data-alt=&quot;레딧에서 성토하는 댓글들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lFCdR/btsQsOBOf7U/MYtom8e4ZCMJyAo9i0jHx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlFCdR%2FbtsQsOBOf7U%2FMYtom8e4ZCMJyAo9i0jHx0%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;517&quot; height=&quot;498&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;1532&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;레딧에서 성토하는 댓글들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;약관을 찾아봤더니&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://openai.com/ko-KR/policies/service-credit-terms/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://openai.com/ko-KR/policies/service-credit-terms/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u8DyS/btsQt44Yb4y/tw32yloSKq8bPtd50YnLbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u8DyS/btsQt44Yb4y/tw32yloSKq8bPtd50YnLbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u8DyS/btsQt44Yb4y/tw32yloSKq8bPtd50YnLbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu8DyS%2FbtsQt44Yb4y%2Ftw32yloSKq8bPtd50YnLbK%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;515&quot; height=&quot;317&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;682&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;아니 선결제하면서 누가 약관을 찾아보겠냐구용.. 실제로 4번 항목에 선불 서비스(선결제) 시 환불도 안될 뿐만 아니라 크래딧 구매 이후 1년 안에 소진을 못하면 소멸되는 특이한 정책을 사용하고 있었다. 이런 약관은 결제 페이지에서 쉽게 찾아볼 수 없으며, 수십장의 문서가 난무하는 약관을 찾아봐야 알 수 있다는 사실 ㅜㅜ 화난다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발이야기</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/533</guid>
      <comments>https://voidmainvoid.tistory.com/533#entry533comment</comments>
      <pubDate>Wed, 10 Sep 2025 18:18:50 +0900</pubDate>
    </item>
    <item>
      <title>Ubuntu에서 JDK11 설치 후 기본값으로 설정하기</title>
      <link>https://voidmainvoid.tistory.com/532</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1) JDK 버전 확인&lt;/p&gt;
&lt;pre id=&quot;code_1748155677076&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ java -version&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;2) apt 업데이트, jdk11 설치&lt;/p&gt;
&lt;pre id=&quot;code_1748155689877&quot; class=&quot;r&quot; data-ke-language=&quot;r&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt update
$ sudo apt install openjdk-11-jdk -y&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;3) 버전 확인&lt;/p&gt;
&lt;pre id=&quot;code_1748155711291&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ java -version
openjdk version &quot;11.0.27&quot; 2025-04-15
OpenJDK Runtime Environment (build 11.0.27+6-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.27+6-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tQgZQ/btsObYlPf6a/9H8n78PxKVAOtIpAbtbbn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tQgZQ/btsObYlPf6a/9H8n78PxKVAOtIpAbtbbn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tQgZQ/btsObYlPf6a/9H8n78PxKVAOtIpAbtbbn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtQgZQ%2FbtsObYlPf6a%2F9H8n78PxKVAOtIpAbtbbn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;76&quot; data-origin-width=&quot;503&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발이야기</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/532</guid>
      <comments>https://voidmainvoid.tistory.com/532#entry532comment</comments>
      <pubDate>Sun, 25 May 2025 15:48:53 +0900</pubDate>
    </item>
    <item>
      <title>윈도우즈 wsl2 환경에서 로컬 카프카 브로커 연동하기</title>
      <link>https://voidmainvoid.tistory.com/531</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우즈 wsl 환경에서 ipv6를 사용할 경우 localhost 또는 127.0.0.1 접근이 안될 경우가 있습니다. 이 경우 접근을 위해 다음과 같이 셋팅을 할 경우 접근이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;준비물&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- wsl2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Ubuntu&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Apache kafka 3.9.0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Intellij CE&lt;/p&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) Apache kafka 3.9.0 다운로드 및 압축 풀기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/downloads&lt;/a&gt; 에서 3.9.0 바이너리를 다운로드 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1511&quot; data-origin-height=&quot;671&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BtU1w/btsOaEhVQ8E/kzeZloKdku0KIefSoDiSt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BtU1w/btsOaEhVQ8E/kzeZloKdku0KIefSoDiSt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BtU1w/btsOaEhVQ8E/kzeZloKdku0KIefSoDiSt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBtU1w%2FbtsOaEhVQ8E%2FkzeZloKdku0KIefSoDiSt0%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;1511&quot; height=&quot;671&quot; data-origin-width=&quot;1511&quot; data-origin-height=&quot;671&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDeXlK/btsObKOWwLX/NsslqsTu1ReI8dCukIKi61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDeXlK/btsObKOWwLX/NsslqsTu1ReI8dCukIKi61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDeXlK/btsObKOWwLX/NsslqsTu1ReI8dCukIKi61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDeXlK%2FbtsObKOWwLX%2FNsslqsTu1ReI8dCukIKi61%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;532&quot; height=&quot;334&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 다운로드 받은 압축파일을 푼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) Ubuntu 터미널 실행 및 다운로드 환경 접근&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748151821149&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dvwy@dvwy:~$ cd /mnt/c/Users/choco/Downloads/kafka_2.12-3.9.0/kafka_2.12-3.9.0
dvwy@dvwy:/mnt/c/Users/choco/Downloads/kafka_2.12-3.9.0/kafka_2.12-3.9.0$&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WSL 우분투 환경에서 윈도우즈 다운로드 디렉토리에 접근하기 위해서는 &lt;b&gt;/mnt/c/Users/사용자이름/Downloads&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) config/server.properties 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748151955675&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vi config/server.properties
broker.id=0
listeners=PLAINTEXT://[::1]:9092&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wsl 환경에 접근하기 위해 IPv6 기준 로컬호스트인 [::1] 을 입력한다. 이후 카프카 브로커를 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1748152016582&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1) 주키퍼 실행
$ bin/zookeeper-server-start.sh config/zookeeper.properties

2) 카프카 실행
$ bin/kafka-server-start.sh config/server.properties&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;4) kafka-console-producer.sh확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748152062948&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/kafka-console-producer.sh --bootstrap-server [::1]:9092 --topic test
&amp;gt;a
&amp;gt;b
&amp;gt;c&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[::1]:9092&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;5) /etc/hosts 수정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우분투 내에서 해당 host로 접근을 하는 추가 호스트를 만들기 위해 다음과 같이 수정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1748152125182&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo vi /etc/hosts
[::1] my-kafka

// 이후 부터는 my-kafka:9092 로 접근 가능
$ bin/kafka-console-producer.sh --bootstrap-server my-kafka:9092 --topic test
&amp;gt;a
&amp;gt;b
&amp;gt;c&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;6) intellij CE 에서 접근 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748152241510&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SimpleProducer {
    private final static Logger logger = LoggerFactory.getLogger(SimpleProducer.class);
    private final static String TOPIC_NAME = &quot;test&quot;;
    private final static String BOOTSTRAP_SERVERS = &quot;[::1]:9092&quot;;

    public static void main(String[] args) {

        Properties configs = new Properties();
        configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
        configs.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());

        KafkaProducer&amp;lt;String, String&amp;gt; producer = new KafkaProducer&amp;lt;&amp;gt;(configs);

        String messageValue = &quot;testMessage&quot;;
        ProducerRecord&amp;lt;String, String&amp;gt; record = new ProducerRecord&amp;lt;&amp;gt;(TOPIC_NAME, messageValue);
        producer.send(record);
        logger.info(&quot;{}&quot;, record);
        producer.flush();
        producer.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bootstrap-server에 [::1]:9092 로 설정했을 경우 정상 접근됨을 확인합니다.&lt;/p&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;7) hosts 설정 수정 및 확인&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;581&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qPoOc/btsObEVr8a6/ceA9AJ6QvRvytq1atuY8e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qPoOc/btsObEVr8a6/ceA9AJ6QvRvytq1atuY8e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qPoOc/btsObEVr8a6/ceA9AJ6QvRvytq1atuY8e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqPoOc%2FbtsObEVr8a6%2FceA9AJ6QvRvytq1atuY8e1%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;346&quot; height=&quot;274&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;581&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모장을 '관리자 권한으로 실행' 으로 실행합니다. 이후, &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;b&gt;\Windows\System32\drivers\etc\hosts&lt;/b&gt;&lt;span&gt; 파일을 실행하여 다음과 같이 수정합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKWE1k/btsOcazMkUm/BwS7wv5XpJgJpjZtxk6v5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKWE1k/btsOcazMkUm/BwS7wv5XpJgJpjZtxk6v5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKWE1k/btsOcazMkUm/BwS7wv5XpJgJpjZtxk6v5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKWE1k%2FbtsOcazMkUm%2FBwS7wv5XpJgJpjZtxk6v5k%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;537&quot; height=&quot;232&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이후 intellij CE에서 &lt;b&gt;my-kafka:9092&lt;/b&gt; 로 접근해서 브로커와 연동되는지 확인합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748152474127&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SimpleProducer {
    private final static Logger logger = LoggerFactory.getLogger(SimpleProducer.class);
    private final static String TOPIC_NAME = &quot;test&quot;;
    private final static String BOOTSTRAP_SERVERS = &quot;my-kafka:9092&quot;; // 변경된 호스트

    public static void main(String[] args) {

... 생략&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;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/531</guid>
      <comments>https://voidmainvoid.tistory.com/531#entry531comment</comments>
      <pubDate>Sun, 25 May 2025 14:55:01 +0900</pubDate>
    </item>
    <item>
      <title>Sent auto-creation request for Set(__consumer_offsets) to the active controller 에러 해결 방법</title>
      <link>https://voidmainvoid.tistory.com/530</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에서 테스트 도중에.. 발생한 에러이다.&lt;/p&gt;
&lt;pre id=&quot;code_1744948096522&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller
Sent auto-creation request for Set(__consumer_offsets) to the active controller&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겨우 찾아낸 링크 &lt;a href=&quot;https://github.com/bitnami/charts/issues/19522#issuecomment-2341364442&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/bitnami/charts/issues/19522#issuecomment-2341364442&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744948153940&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;[bitnami/kafka] messages are not getting generated in topics from producer to consumer &amp;middot; Issue #19522 &amp;middot; bitnami/charts&quot; data-og-description=&quot;Name and Version bitnami/kafka What architecture are you using? amd64 What steps will reproduce the bug? I have no name!@kafka-controller-0:/$ kafka-topics.sh --bootstrap-server localhost:9092 --cr...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/bitnami/charts/issues/19522#issuecomment-2341364442&quot; data-og-url=&quot;https://github.com/bitnami/charts/issues/19522&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/bitnami/charts/issues/19522#issuecomment-2341364442&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/bitnami/charts/issues/19522#issuecomment-2341364442&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[bitnami/kafka] messages are not getting generated in topics from producer to consumer &amp;middot; Issue #19522 &amp;middot; bitnami/charts&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Name and Version bitnami/kafka What architecture are you using? amd64 What steps will reproduce the bug? I have no name!@kafka-controller-0:/$ kafka-topics.sh --bootstrap-server localhost:9092 --cr...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 broker 셋팅시에 다음과 같이 설정을 안해서 그렇다&lt;/p&gt;
&lt;pre id=&quot;code_1744948167863&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;offsets.topic.replication.factor=1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 기본값이 3이라서 그런데, 로컬에서 브로커1개로 띄웠을때는 3개 rf로 만들 수 없기 때문에 무한반복 나는 것 ㅜㅜ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFjqG9/btsNpM1rpTn/feKY5o04gki7ToWnwK0EL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFjqG9/btsNpM1rpTn/feKY5o04gki7ToWnwK0EL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFjqG9/btsNpM1rpTn/feKY5o04gki7ToWnwK0EL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFjqG9%2FbtsNpM1rpTn%2FfeKY5o04gki7ToWnwK0EL1%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;1296&quot; height=&quot;466&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 상황과 유사하게 transaction rf도 마찬가지로 로컬에서는 수정해줘야 한다;;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRWeF3/btsNqEnOSYv/NtDWByylm0CBzhDekYtmsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRWeF3/btsNqEnOSYv/NtDWByylm0CBzhDekYtmsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRWeF3/btsNqEnOSYv/NtDWByylm0CBzhDekYtmsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRWeF3%2FbtsNqEnOSYv%2FNtDWByylm0CBzhDekYtmsK%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;1244&quot; height=&quot;472&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/530</guid>
      <comments>https://voidmainvoid.tistory.com/530#entry530comment</comments>
      <pubDate>Fri, 18 Apr 2025 12:49:50 +0900</pubDate>
    </item>
    <item>
      <title>카프카4.0 부터는 eager rebalancing protocol이 삭제됩니다.</title>
      <link>https://voidmainvoid.tistory.com/529</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://issues.apache.org/jira/browse/KAFKA-18839&quot;&gt;https://issues.apache.org/jira/browse/KAFKA-18839&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1740724050351&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[KAFKA-18839] Drop support for eager rebalancing in Streams - ASF JIRA&quot; data-og-description=&quot;In 3.1 we deprecated the EAGER protocol in Kafka Streams (see KAFKA-13439). This ticket covers actually dropping this protocol in 4.0. Note that KAFKA-8575 covers the actual task cleanup we can do once we no longer have to support eager rebalancing, which &quot; data-og-host=&quot;issues.apache.org&quot; data-og-source-url=&quot;https://issues.apache.org/jira/browse/KAFKA-18839&quot; data-og-url=&quot;https://issues.apache.org/jira/browse/KAFKA-18839&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://issues.apache.org/jira/browse/KAFKA-18839&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://issues.apache.org/jira/browse/KAFKA-18839&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[KAFKA-18839] Drop support for eager rebalancing in Streams - ASF JIRA&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In 3.1 we deprecated the EAGER protocol in Kafka Streams (see KAFKA-13439). This ticket covers actually dropping this protocol in 4.0. Note that KAFKA-8575 covers the actual task cleanup we can do once we no longer have to support eager rebalancing, which&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;issues.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이슈(KAFKA-18839)는 Kafka Streams에서 기존에 사용되던&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;EAGER 재분배(eager rebalancing) 프로토콜&lt;/b&gt;에 대한 지원을 완전히 제거하는 작업입니다. Kafka Streams는 버전 3.1부터 EAGER 프로토콜을 사용 중단(deprecated)했고, 4.0 버전부터는 이 프로토콜을 아예 제거하기로 결정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Why drop?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EAGER 프로토콜은 오래된 방식으로, 유지보수와 코드 복잡성을 증가시키는 요인이었습니다. 더 나은 성능과 안정성을 제공하는 COOPERATIVE 재분배 프로토콜로 전환하면서, EAGER 프로토콜은 불필요한 잔재물이 되었습니다. 단일 재분배 프로토콜에 집중하여 스트림즈 개선을 할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;이후 버전에서는?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;1492&quot; data-end=&quot;1545&quot;&gt;이제부터 Kafka Streams는 오직&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;COOPERATIVE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;재분배 프로토콜만 지원합니다.&lt;/li&gt;
&lt;li data-start=&quot;1548&quot; data-end=&quot;1630&quot;&gt;기존에 EAGER 프로토콜을 사용하던 설정은 더 이상 유효하지 않으며, 시스템 구성 시 반드시 COOPERATIVE 프로토콜로 전환해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;EAGER 리밸런싱 프로토콜이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨슈머가 그룹에 합류/실패/종료 할 경우 그룹 코디네이터가 이를 감지하고 전체 파티션에 대해 Revoke(할당 취소 또는 연결 해제)를 수행. 이후, 그룹 코디네이터는 사전에 할당된 알고리즘(range, roundrobin 등)을 통해 재분배 수행합니다. 로직이 단순하지만 전체 파티션에 대해 재분배가 이루어져서 전체적으로 리밸런싱에 시간이 많이 소요되게 됩니다.&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;반면, COOPERATIVE는 부분적으로 파티션을 재분배하기 때문에 점진적 리밸런싱을 통해 컨슈머들에게 끼치는 영향을 최소화 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;코드로 설정하는 방법?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐 별도로 있는 것은 아니고 Cooperative가 붙어있는 Rebalancing 을 선택하면 됨. CooperativeStickyAssignor가 대표적입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740724109298&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CooperativeStickyAssignorExample {
    public static void main(String[] args) {
    
        Properties props = new Properties();
        props.put(&quot;bootstrap.servers&quot;, &quot;localhost:9092&quot;);
        props.put(&quot;group.id&quot;, &quot;cooperative-sticky-group&quot;);

        props.put(&quot;key.deserializer&quot;, &quot;org.apache.kafka.common.serialization.StringDeserializer&quot;);
        props.put(&quot;value.deserializer&quot;, &quot;org.apache.kafka.common.serialization.StringDeserializer&quot;);

        // cooperative rebalancing을 사용하기 위한 assignor 지정
        props.put(&quot;partition.assignment.strategy&quot;, 
            &quot;org.apache.kafka.clients.consumer.CooperativeStickyAssignor&quot;);&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;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/529</guid>
      <comments>https://voidmainvoid.tistory.com/529#entry529comment</comments>
      <pubDate>Fri, 28 Feb 2025 15:28:04 +0900</pubDate>
    </item>
    <item>
      <title>[local macOS 환경] apache kafka(3.5.0기준) + redpanda/console 로 편하게 테스트 하기</title>
      <link>https://voidmainvoid.tistory.com/527</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;[local 환경] apache kafka + redpanda:console.png&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDfC7k/btsMxFhnm5D/T3hClAfvpwr8jdZPGKPSVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDfC7k/btsMxFhnm5D/T3hClAfvpwr8jdZPGKPSVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDfC7k/btsMxFhnm5D/T3hClAfvpwr8jdZPGKPSVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDfC7k%2FbtsMxFhnm5D%2FT3hClAfvpwr8jdZPGKPSVK%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;227&quot; height=&quot;95&quot; data-filename=&quot;[local 환경] apache kafka + redpanda:console.png&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 환경에서 개발을 하다보면 항상 shell script로 사용하지만 좀 불편할때가 많습니다. redpanda에서는 console을 통해 apache kafka와 연동하는 웹 콘솔을 오픈소스로 제공하고 있습니다.&lt;/p&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;a href=&quot;https://github.com/redpanda-data/console&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/redpanda-data/console&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1740557339901&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - redpanda-data/console: Redpanda Console is a developer-friendly UI for managing your Kafka/Redpanda workloads. Console &quot; data-og-description=&quot;Redpanda Console is a developer-friendly UI for managing your Kafka/Redpanda workloads. Console gives you a simple, interactive approach for gaining visibility into your topics, masking data, manag...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/redpanda-data/console&quot; data-og-url=&quot;https://github.com/redpanda-data/console&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xEYlL/hyYjkMQann/GdsQeByT6f0TcMVd0eXZs0/img.png?width=1279&amp;amp;height=640&amp;amp;face=0_0_1279_640,https://scrap.kakaocdn.net/dn/D2LxR/hyYjohqGbE/dLDyPNSnFFbCLgsxj8MTBK/img.png?width=1279&amp;amp;height=640&amp;amp;face=0_0_1279_640&quot;&gt;&lt;a href=&quot;https://github.com/redpanda-data/console&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/redpanda-data/console&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xEYlL/hyYjkMQann/GdsQeByT6f0TcMVd0eXZs0/img.png?width=1279&amp;amp;height=640&amp;amp;face=0_0_1279_640,https://scrap.kakaocdn.net/dn/D2LxR/hyYjohqGbE/dLDyPNSnFFbCLgsxj8MTBK/img.png?width=1279&amp;amp;height=640&amp;amp;face=0_0_1279_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - redpanda-data/console: Redpanda Console is a developer-friendly UI for managing your Kafka/Redpanda workloads. Console&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Redpanda Console is a developer-friendly UI for managing your Kafka/Redpanda workloads. Console gives you a simple, interactive approach for gaining visibility into your topics, masking data, manag...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 사용하여 로컬에서 테스트하기 용이하도록 설정하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Apache kafka binary setting &amp;amp; start&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config/kraft/server.properties&lt;/p&gt;
&lt;pre id=&quot;code_1740557980004&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 소켓 서버가 수신할 주소와 포트를 설정합니다.
# 여기서 Kafka 브로커는 세 가지 리스너(INTERNAL, EXTERNAL, CONTROLLER)를 통해 외부와 내부의 연결 요청을 받게 됩니다.
# - INTERNAL: 내부 통신용으로, 모든 네트워크 인터페이스(0.0.0.0)에서 포트 9092로 수신합니다.
# - EXTERNAL: 외부 접속용으로, 모든 네트워크 인터페이스(0.0.0.0)에서 포트 9091로 수신합니다.
# - CONTROLLER: Kafka 클러스터의 컨트롤러 전용 리스너로, 주로 KRaft 모드에서 사용하며 포트 9093으로 수신합니다.
listeners=INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9091,CONTROLLER://:9093

# 브로커 간 통신에 사용할 리스너의 이름을 지정합니다.
# 이 설정은 Kafka 브로커들끼리 데이터 복제나 메타데이터 교환 등 내부 통신에 사용됩니다.
# 위의 예제에서는 INTERNAL 리스너를 사용하도록 지정되어 있습니다.
inter.broker.listener.name=INTERNAL

# 클라이언트에게 브로커의 접속 정보를 알릴 때 사용할 리스너 이름, 호스트명 및 포트를 지정합니다.
# 만약 이 설정을 지정하지 않으면, 기본적으로 listeners에 설정된 값이 사용됩니다.
# 예제에서는 다음과 같이 설정되어 있습니다:
# - INTERNAL 리스너는 127.0.0.1:9092로 광고되어 로컬 클라이언트(예: 로컬 셸 스크립트)에서 사용됩니다.
# - EXTERNAL 리스너는 host.docker.internal:9091로 광고되어 Docker 등 외부 환경에서 사용됩니다.
advertised.listeners=INTERNAL://127.0.0.1:9092,EXTERNAL://host.docker.internal:9091

# 리스너 이름과 보안 프로토콜 간의 매핑을 설정합니다.
# 각 리스너는 지정된 보안 프로토콜(예: PLAINTEXT, SSL 등)을 사용하게 되며,
# 이 설정을 통해 리스너별로 사용할 프로토콜을 명시할 수 있습니다.
# 위 예제에서는 다음과 같이 설정되어 있습니다:
# - CONTROLLER, INTERNAL, EXTERNAL 리스너는 모두 PLAINTEXT(암호화 없이 평문 통신)로 사용됩니다.
# - 그 외 SSL, SASL_PLAINTEXT, SASL_SSL 등 다른 프로토콜에 대한 매핑도 포함되어 있습니다.
listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT&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;기본설정과 다르게 추가로 INTERNAL, EXTERNAL 이라는 리스너를 별도로 선언했고, 각각 PLAINTEXT의 특징을 가진다. 그리고 advertised.listeners를 통해 외부 환경에서 접근을 하게 되면 통신이 가능하도록 설정하였다.&lt;/p&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;pre id=&quot;code_1740558065230&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/kafka-server-start.sh config/kraft/server.properties&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;/p&gt;
&lt;pre id=&quot;code_1740558143740&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo lsof -iTCP -sTCP:LISTEN -n -P | grep java

java       1935 cory  114u  IPv6 0xb5d56fea76ceb187      0t0  TCP *:50654 (LISTEN)
java       1935 cory  138u  IPv6 0x120b860a979e4dc8      0t0  TCP *:9093 (LISTEN)
java       1935 cory  179u  IPv6 0x694fc65154f5a4d6      0t0  TCP *:9091 (LISTEN)
java       1935 cory  180u  IPv6 0xbaf49a6f1b8ea763      0t0  TCP *:9092 (LISTEN)&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;/p&gt;
&lt;pre id=&quot;code_1740558182205&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/kafka-topics.sh --bootstrap-server localhost:9092 --list&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Redpanda console start&lt;/h3&gt;
&lt;pre id=&quot;code_1740558204640&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker run -p 8080:8080 -e KAFKA_BROKERS=host.docker.internal:9091 docker.redpanda.com/redpandadata/console:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) Result&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;1962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIFleJ/btsMyFuaUhn/jnkgNCNzpHa1h4aK3k4wL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIFleJ/btsMyFuaUhn/jnkgNCNzpHa1h4aK3k4wL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIFleJ/btsMyFuaUhn/jnkgNCNzpHa1h4aK3k4wL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIFleJ%2FbtsMyFuaUhn%2FjnkgNCNzpHa1h4aK3k4wL0%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;2706&quot; height=&quot;1962&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;1962&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;1962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cahaLY/btsMx9bqq2p/v559L0qr9NJaYK495WIW6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cahaLY/btsMx9bqq2p/v559L0qr9NJaYK495WIW6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cahaLY/btsMx9bqq2p/v559L0qr9NJaYK495WIW6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcahaLY%2FbtsMx9bqq2p%2Fv559L0qr9NJaYK495WIW6K%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;2706&quot; height=&quot;1962&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;1962&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;1962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cajt1a/btsMyTFM6EI/ltLh5DtLjXIgl3N9701vOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cajt1a/btsMyTFM6EI/ltLh5DtLjXIgl3N9701vOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cajt1a/btsMyTFM6EI/ltLh5DtLjXIgl3N9701vOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcajt1a%2FbtsMyTFM6EI%2FltLh5DtLjXIgl3N9701vOk%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;2706&quot; height=&quot;1962&quot; data-origin-width=&quot;2706&quot; data-origin-height=&quot;1962&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/527</guid>
      <comments>https://voidmainvoid.tistory.com/527#entry527comment</comments>
      <pubDate>Wed, 26 Feb 2025 17:24:31 +0900</pubDate>
    </item>
    <item>
      <title>카프카에서 데이터 삭제는 어떻게 이루어 지는가&amp;gt;</title>
      <link>https://voidmainvoid.tistory.com/526</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;카프카에서 데이터 삭제는 어떻게 이루어 지는가.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjXOCV/btsMgH8HpQX/hfrEWyuNEAd4bI6uptpYxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjXOCV/btsMgH8HpQX/hfrEWyuNEAd4bI6uptpYxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjXOCV/btsMgH8HpQX/hfrEWyuNEAd4bI6uptpYxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjXOCV%2FbtsMgH8HpQX%2FhfrEWyuNEAd4bI6uptpYxK%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;119&quot; height=&quot;130&quot; data-filename=&quot;카프카에서 데이터 삭제는 어떻게 이루어 지는가.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카의 데이터의 삭제는 로그 세그먼트 단위로 삭제가 이루어진다. 노드(구 브로커)의 로그매니저는 시간(time) 또는 용량(size)에 따라 삭제여부를 결정한다. 시간 기반 정책에서는 레코드의 timestamp에 따라 달라진다. 해당 세그먼트 파일에 존재하는 가장 큰 timestamp 값(레코드 순서와는 무관)을 토대로 찾아낸다. 용량 기반 정책은 기본적으로 설정되지 않는다. 만약 설정된다면, 로그매니저는 가장 오래된 세그먼트 파일을 용량이 다 찼을때 부터 차례 대로 삭제하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 시간과 용량 두개의 설정이 동시에 설정된다면 먼저 도달하는 정책의 기준에 따라 삭제가 이루어진다. 언제든지 삭제가 될 수 있도록 copy-on-wirte 방식으로 세그먼트 목록을 사용한다. 이를 통해 삭제가 되는 동안에도  데이터 목록이 갑자기 변경되지 않아서 일관된 데이터 검색이 가능하다. 즉, 데이터 처리를 수행하면서도 안정적으로 삭제를 할 수 있다는 뜻~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/documentation/#impl_deletes&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/documentation/#impl_deletes&lt;/a&gt;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/526</guid>
      <comments>https://voidmainvoid.tistory.com/526#entry526comment</comments>
      <pubDate>Thu, 13 Feb 2025 19:55:35 +0900</pubDate>
    </item>
    <item>
      <title>kafka 4.0부터는 스칼라 2.12가 더 이상 사용되지 않습니다.</title>
      <link>https://voidmainvoid.tistory.com/525</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=181308218&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=181308218&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739439426149&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-751: Drop support for Scala 2.12 in Kafka 4.0 (deprecate in 3.0) - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Status Current state: Adopted Discussion thread:&amp;nbsp;link Vote thread:&amp;nbsp;link JIRA:&amp;nbsp; KAFKA-12930 - 이슈 세부사항 가져오는 중... 상태 &amp;nbsp;(3.0) KAFKA-12895 - 이슈 세부사항 가져오는 중... 상태 &amp;nbsp;(4.0) Please keep the discussion on the ma&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=181308218&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=181308218&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=181308218&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=181308218&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-751: Drop support for Scala 2.12 in Kafka 4.0 (deprecate in 3.0) - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Status Current state: Adopted Discussion thread:&amp;nbsp;link Vote thread:&amp;nbsp;link JIRA:&amp;nbsp; KAFKA-12930 - 이슈 세부사항 가져오는 중... 상태 &amp;nbsp;(3.0) KAFKA-12895 - 이슈 세부사항 가져오는 중... 상태 &amp;nbsp;(4.0) Please keep the discussion on the ma&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kafka 4.0부터는 스칼라 2.12가 더 이상 사용되지 않습니다.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LkQhE/btsMhcUxKES/YGbiOdriGNcPK1jxVoqMN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LkQhE/btsMhcUxKES/YGbiOdriGNcPK1jxVoqMN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LkQhE/btsMhcUxKES/YGbiOdriGNcPK1jxVoqMN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLkQhE%2FbtsMhcUxKES%2FYGbiOdriGNcPK1jxVoqMN0%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;83&quot; height=&quot;90&quot; data-filename=&quot;kafka 4.0부터는 스칼라 2.12가 더 이상 사용되지 않습니다.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;516&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 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Kafka는 현재 Scala 2.12와 2.13 버전에서 빌드되고 있지만, &lt;b&gt;Scala 3.0&lt;/b&gt; 출시 이후 사용자들이 해당 버전 지원을 요청할 가능성이 큼. 여러 버전을 지원하는 것은 개발과 테스트 측면에서 비용이 크므로, Kafka 3.0에서 Scala 2.12 지원을 deprecate하고, &lt;b&gt;Kafka 4.0에서 완전히 제거할 것을 제안함.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;Kafka 3.0에서는 Scala 2.12 빌드 지원을 비권장하고 관련 문서를 업데이트할 예정이며, Kafka 4.0에서는 build.gradle과 dependencies.gradle에서 Scala 2.12 관련 코드를 삭제하고, README에서도 지원 여부를 제거하는 등의 변경을 수행할 계획임. Scala 2.12를 계속 사용해야 하는 사용자들은 Kafka 3.x에서 머물러야 하며, 최신 Scala 버전으로 업그레이드할 수 있을 때 Kafka 4.0을 사용할 수 있음. 다만, kafka core module 내 클래스들은 공식적인 공개 API는 아니지만 많은 프로젝트가 통합 테스트에서 이를 활용하고 있음.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://issues.apache.org/jira/browse/KAFKA-12895&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://issues.apache.org/jira/browse/KAFKA-12895&lt;/a&gt; 에서 본격적으로 삭제하는 작업이 이루어졌고 현재 모든 티켓이 머지 완료되었음.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size23&quot;&gt;그럼 스칼라3은 언제 배포되나?&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;스칼라 3은 이미 2021년 5월 14일에 배포되었음.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-end=&quot;371&quot; data-start=&quot;199&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.scala-lang.org/download/3.0.0.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.scala-lang.org/download/3.0.0.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739439621626&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Scala 3.0.0&quot; data-og-description=&quot;Other Releases You can find the links to prior versions or the latest development version below. To see a detailed list of changes for each version of Scala please refer to the changelog. Note that different major releases of Scala 2 (e.g. Scala 2.11.x and&quot; data-og-host=&quot;www.scala-lang.org&quot; data-og-source-url=&quot;https://www.scala-lang.org/download/3.0.0.html&quot; data-og-url=&quot;https://www.scala-lang.org/download/3.0.0.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fVcPr/hyYfPZmKQi/gDb1Zi4iZmptkZcF9itj70/img.png?width=399&amp;amp;height=648&amp;amp;face=0_0_399_648&quot;&gt;&lt;a href=&quot;https://www.scala-lang.org/download/3.0.0.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.scala-lang.org/download/3.0.0.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fVcPr/hyYfPZmKQi/gDb1Zi4iZmptkZcF9itj70/img.png?width=399&amp;amp;height=648&amp;amp;face=0_0_399_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Scala 3.0.0&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Other Releases You can find the links to prior versions or the latest development version below. To see a detailed list of changes for each version of Scala please refer to the changelog. Note that different major releases of Scala 2 (e.g. Scala 2.11.x and&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.scala-lang.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025년 1월 20일 3.6.3 릴리즈됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.scala-lang.org/download/3.6.3.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.scala-lang.org/download/3.6.3.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739439637416&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Scala 3.6.3&quot; data-og-description=&quot;Other Releases You can find the links to prior versions or the latest development version below. To see a detailed list of changes for each version of Scala please refer to the changelog. Note that different major releases of Scala 2 (e.g. Scala 2.11.x and&quot; data-og-host=&quot;www.scala-lang.org&quot; data-og-source-url=&quot;https://www.scala-lang.org/download/3.6.3.html&quot; data-og-url=&quot;https://www.scala-lang.org/download/3.6.3.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DRyed/hyYfDq6II5/ovmlslrFhEnZK91C9AEti1/img.png?width=399&amp;amp;height=648&amp;amp;face=0_0_399_648&quot;&gt;&lt;a href=&quot;https://www.scala-lang.org/download/3.6.3.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.scala-lang.org/download/3.6.3.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DRyed/hyYfDq6II5/ovmlslrFhEnZK91C9AEti1/img.png?width=399&amp;amp;height=648&amp;amp;face=0_0_399_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Scala 3.6.3&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Other Releases You can find the links to prior versions or the latest development version below. To see a detailed list of changes for each version of Scala please refer to the changelog. Note that different major releases of Scala 2 (e.g. Scala 2.11.x and&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.scala-lang.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/525</guid>
      <comments>https://voidmainvoid.tistory.com/525#entry525comment</comments>
      <pubDate>Thu, 13 Feb 2025 18:39:24 +0900</pubDate>
    </item>
    <item>
      <title>standalone 카프카(kraft모드 in local) 실행 스크립트(1줄)</title>
      <link>https://voidmainvoid.tistory.com/524</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1739248339826&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;standalone 카프카(kraft모드 in local) 실행을 위한 준비와 실행&quot; data-og-description=&quot;$ bin/kafka-storage.sh random-uuidcKUMbEGERui8cHUhwdc6XA$ bin/kafka-storage.sh format -t cKUMbEGERui8cHUhwdc6XA -c config/kraft/server.propertiesFormatting /tmp/kraft-combined-logs with metadata.version 3.6-IV2.$ bin/kafka-server-start.sh config/kraft/serv&quot; data-og-host=&quot;blog.voidmainvoid.net&quot; data-og-source-url=&quot;https://blog.voidmainvoid.net/518&quot; data-og-url=&quot;https://blog.voidmainvoid.net/518&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c2Ncw0/hyYfYPenI4/Mdg9bRl5k1MTw9LiJSWKK1/img.png?width=484&amp;amp;height=300&amp;amp;face=0_0_484_300,https://scrap.kakaocdn.net/dn/etRGPb/hyYb9dPUQX/2kNMqdaYlCcK2hyJfp8dm1/img.png?width=484&amp;amp;height=300&amp;amp;face=0_0_484_300,https://scrap.kakaocdn.net/dn/dPNrnj/hyYfYBGOzG/mKMhF5r8JDUYZs63i28ZVK/img.png?width=264&amp;amp;height=200&amp;amp;face=0_0_264_200&quot;&gt;&lt;a href=&quot;https://blog.voidmainvoid.net/518&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.voidmainvoid.net/518&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c2Ncw0/hyYfYPenI4/Mdg9bRl5k1MTw9LiJSWKK1/img.png?width=484&amp;amp;height=300&amp;amp;face=0_0_484_300,https://scrap.kakaocdn.net/dn/etRGPb/hyYb9dPUQX/2kNMqdaYlCcK2hyJfp8dm1/img.png?width=484&amp;amp;height=300&amp;amp;face=0_0_484_300,https://scrap.kakaocdn.net/dn/dPNrnj/hyYfYBGOzG/mKMhF5r8JDUYZs63i28ZVK/img.png?width=264&amp;amp;height=200&amp;amp;face=0_0_264_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;standalone 카프카(kraft모드 in local) 실행을 위한 준비와 실행&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;$ bin/kafka-storage.sh random-uuidcKUMbEGERui8cHUhwdc6XA$ bin/kafka-storage.sh format -t cKUMbEGERui8cHUhwdc6XA -c config/kraft/server.propertiesFormatting /tmp/kraft-combined-logs with metadata.version 3.6-IV2.$ bin/kafka-server-start.sh config/kraft/serv&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.voidmainvoid.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스팅에서 kraft모드를 로컬에서 실행할 때 차례대로 실행해야 하는 코드를 올린적이 있었는데, 불편해서 한줄로 요약한 버전을 올려봄!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739248375617&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ UUID=$(bin/kafka-storage.sh random-uuid | tr -d '\n') &amp;amp;&amp;amp; echo &quot;Generated UUID: ${UUID}&quot; &amp;amp;&amp;amp; bin/kafka-storage.sh format -t &quot;${UUID}&quot; -c config/kraft/server.properties &amp;amp;&amp;amp; bin/kafka-server-start.sh config/kraft/server.properties&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;bin/kafka-storage.sh random-uuid로 UUID를 생성하고 변수 UUID에 저장합니다.&lt;/li&gt;
&lt;li&gt;생성된 UUID를 출력합니다.&lt;/li&gt;
&lt;li&gt;해당 UUID를 사용하여 Kafka storage를 format 합니다.&lt;/li&gt;
&lt;li&gt;마지막으로 Kafka 서버를 시작합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;standalone 카프카.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOvC24/btsMfcFKCFb/mUIUsAiOSKcGBMlaE1ZmN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOvC24/btsMfcFKCFb/mUIUsAiOSKcGBMlaE1ZmN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOvC24/btsMfcFKCFb/mUIUsAiOSKcGBMlaE1ZmN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOvC24%2FbtsMfcFKCFb%2FmUIUsAiOSKcGBMlaE1ZmN0%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;86&quot; height=&quot;94&quot; data-filename=&quot;standalone 카프카.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.0.0에서는?&lt;/h3&gt;
&lt;pre id=&quot;code_1744873408115&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ UUID=$(bin/kafka-storage.sh random-uuid | tr -d '\n') &amp;amp;&amp;amp; echo &quot;Generated UUID: ${UUID}&quot; &amp;amp;&amp;amp; bin/kafka-storage.sh format  --standalone -t &quot;${UUID}&quot; -c config/server.properties &amp;amp;&amp;amp; bin/kafka-server-start.sh config/server.properties&lt;/code&gt;&lt;/pre&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/524</guid>
      <comments>https://voidmainvoid.tistory.com/524#entry524comment</comments>
      <pubDate>Tue, 11 Feb 2025 13:33:45 +0900</pubDate>
    </item>
    <item>
      <title>KIP-932: Queues for Kafka 조사</title>
      <link>https://voidmainvoid.tistory.com/523</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1736662235633&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-932: Queues for Kafka - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Status Current state:&amp;nbsp;Accepted Discussion thread: https://lists.apache.org/thread/9wdxthfsbm5xf01y4xvq6qtlg0gq96lq JIRA:&amp;nbsp;https://issues.apache.org/jira/browse/KAFKA-16092 Please keep the discussion on the mailing list rather than commenting on the wiki (&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-932: Queues for Kafka - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Status Current state:&amp;nbsp;Accepted Discussion thread: https://lists.apache.org/thread/9wdxthfsbm5xf01y4xvq6qtlg0gq96lq JIRA:&amp;nbsp;https://issues.apache.org/jira/browse/KAFKA-16092 Please keep the discussion on the mailing list rather than commenting on the wiki (&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n9m4V/btsLJxepCSL/vmYgiIwV9Z5nuCkMPDI1a1/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n9m4V/btsLJxepCSL/vmYgiIwV9Z5nuCkMPDI1a1/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n9m4V/btsLJxepCSL/vmYgiIwV9Z5nuCkMPDI1a1/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn9m4V%2FbtsLJxepCSL%2FvmYgiIwV9Z5nuCkMPDI1a1%2Ftfile.dat&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;617&quot; height=&quot;318&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;852&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KIP-932는 Kafka에 새로운 Queue Topic을 도입하여 기존 Topic/Partition 모델의 한계를 보완하고, 메시지를 단일 Consumer에 할당하는 Single-Consumer Semantics를 제공하려는 제안임. Queue Topic은 기존 Kafka Topic과 달리 &lt;b&gt;FIFO(First-In-First-Out) 메시지 순서를 보장하며, 메시지 처리의 동적 확장성을 제공&lt;/b&gt;함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로듀서는 어떻게 다르게 동작하나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로듀서의 동작은 기존과 거의 동일하지만, 파티션 키가 불필요하다. Queue Topic이라고 불리는 이 토픽은 전체에서 순서를 유지하도록 설계되어 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Queue 토픽&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- QUEUE 모드라는 것을 명시적으로 선언하지 않아도 됨. 이런 동작을 위해서&lt;b&gt; 컨슈머측에서만 따로 그룹 설정시 정의&lt;/b&gt;하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- FIFO 순서보장 : 전체 Queue에 대해 FIFO 유지. 파티션들을 단일 파티션으로 보이게 하는 것.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨슈머가 동작하게 하는 방법?&lt;/h3&gt;
&lt;pre id=&quot;code_1736662629573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kafka-console-consumer.sh --bootstrap-server &amp;lt;broker-address&amp;gt; \
    --topic &amp;lt;topic-name&amp;gt; \
    --group &amp;lt;share-group-name&amp;gt; \
    --consumer-property group.type=share&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GroupType에 &quot;share&quot;라는 ENUM이 새로 만들어지게됨. 그리고 &lt;b&gt;kafka-console-share-consumer.sh&lt;/b&gt;라는 새로운 쉘 명령어가 만들어질듯함.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;&lt;b&gt;Option&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--bootstrap-server &amp;lt;String: server to connect to&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;REQUIRED: The server(s) to connect to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--consumer-config &amp;lt;String: config file&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;Consumer config properties file. Note that [consumer-property]&amp;nbsp;takes precedence over this config.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--consumer-property &amp;lt;String: consumer_prop&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;Consumer property in the form key=value.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--enable-systest-events&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;Log lifecycle events of the consumer in addition to logging consumed messages. (This is specific for system tests.)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--formatter &amp;lt;String: class&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;The name of a class to use for formatting Kafka messages for display. (default: kafka.tools.DefaultMessageFormatter)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--formatter-config &amp;lt;String: config file&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;Config properties file to initialize the message formatter. Note that [property] takes precedence of this config.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--group &amp;lt;String: share groud id&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;The share group id of the consumer. (default:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;console-share-consumer&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--help&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;Print usage information.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--key-deserializer &amp;lt;String: deserializer for keys&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;The name of the class to use for deserializing keys.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--max-messages &amp;lt;Integer: num_messages&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;The maximum number of messages to consume before exiting. If not set, consumption is continual.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--property &amp;lt;String: prop&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;The properties to initialize the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;message formatter. Default&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;properties include:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;print.timestamp=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;print.key=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;print.offset=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;print.delivery=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;print.partition=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;print.headers=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;print.value=true|false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;key.separator=&amp;lt;key.separator&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;line.separator=&amp;lt;line.separator&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;headers.separator=&amp;lt;line.separator&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;null.literal=&amp;lt;null.literal&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;key.deserializer=&amp;lt;key.deserializer&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;value.deserializer=&amp;lt;value.&lt;/span&gt;&lt;span&gt;deserializer&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;header.deserializer=&amp;lt;header.&lt;/span&gt;&lt;span&gt;deserializer&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;Users can also pass in customized&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;properties for their formatter; more&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;specifically, users can pass in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;properties keyed with 'key.&lt;/span&gt;&lt;span&gt;deserializer.', 'value.&lt;/span&gt;&lt;span&gt;deserializer.' and 'headers.&lt;/span&gt;&lt;span&gt;deserializer.' prefixes to configure&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;their deserializers.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--reject&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;If specified, messages are rejected as they are consumed.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--reject-message-on-error&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;If there is an error when processing a message, reject it instead of halting.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--release&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;If specified, messages are released as they are consumed.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--timeout-ms &amp;lt;Integer: timeout_ms&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;If specified, exit if no message is available for consumption for the specific interval.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--topic &amp;lt;String: topic&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;REQUIRED: The topic to consume from.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--value-deserializer &amp;lt;String: deserializer for values&amp;gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;The name of the class to use for deserializing values.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left; width: 45%;&quot;&gt;--version&lt;/td&gt;
&lt;td style=&quot;text-align: left; width: 54.8837%;&quot;&gt;&lt;span&gt;&lt;span&gt;Display Kafka version.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제 코드는 어떻게 될까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 모든게 만들어지지 않아서 앞으로 변화될 여지는 있지만, 아래와 같이 설정될 것으로 추정됨.&lt;/p&gt;
&lt;pre id=&quot;code_1736663185890&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.apache.kafka.clients.consumer.KafkaShareConsumer;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.ShareConsumerConfig;

import java.time.Duration;
import java.util.Collections;

public class SharedGroupConsumer {
    public static void main(String[] args) {
        // Kafka Share Consumer 설정
        ShareConsumerConfig config = new ShareConsumerConfig();
        config.setBootstrapServers(&quot;localhost:9092&quot;);
        config.setGroupId(&quot;my-shared-group&quot;);
        config.setTopic(&quot;my-queue-topic&quot;);

        // KafkaShareConsumer 생성
        try (KafkaShareConsumer&amp;lt;String, String&amp;gt; consumer = new KafkaShareConsumer&amp;lt;&amp;gt;(config)) {
            // 메시지 처리 루프
            while (true) {
                ConsumerRecords&amp;lt;String, String&amp;gt; records = consumer.poll(Duration.ofMillis(100));
                records.forEach(record -&amp;gt; {
                    System.out.printf(&quot;Consumed record: key = %s, value = %s, offset = %d%n&quot;,
                            record.key(), record.value(), record.offset());
                    // 메시지 처리 후 Ack 전송
                    consumer.ack(record);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}&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;관련 PR&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://github.com/apache/kafka/pull/16461/files&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/apache/kafka/pull/16461/files&lt;/a&gt;&lt;br /&gt;- &lt;a href=&quot;https://github.com/apache/kafka/pull/16134/files#diff-d1ccc49e6566a37e558ff2cecc49d1d984465b2b26d0d676f4a2f143fe3b3d86&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/apache/kafka/pull/16134/files#diff-d1ccc49e6566a37e558ff2cecc49d1d984465b2b26d0d676f4a2f143fe3b3d86&lt;/a&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;trunk branch에 merge되고 있으므로 trunk에서 확인 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/apache/kafka/tree/trunk&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/apache/kafka/tree/trunk&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1736663227621&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - apache/kafka: Mirror of Apache Kafka&quot; data-og-description=&quot;Mirror of Apache Kafka. Contribute to apache/kafka development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/apache/kafka/tree/trunk&quot; data-og-url=&quot;https://github.com/apache/kafka&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/osIkQ/hyX0xrh9qY/PKj870lTIP228qJf3ffgV1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/HkolX/hyX0qy2hmr/EMVVksKrJsAEDCo3tFLkv1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/apache/kafka/tree/trunk&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/apache/kafka/tree/trunk&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/osIkQ/hyX0xrh9qY/PKj870lTIP228qJf3ffgV1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/HkolX/hyX0qy2hmr/EMVVksKrJsAEDCo3tFLkv1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - apache/kafka: Mirror of Apache Kafka&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Mirror of Apache Kafka. Contribute to apache/kafka development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/523</guid>
      <comments>https://voidmainvoid.tistory.com/523#entry523comment</comments>
      <pubDate>Sun, 12 Jan 2025 15:27:46 +0900</pubDate>
    </item>
    <item>
      <title>trino에서 java.sql.SQLException: Unrecognized connection property 'url' 에러가 나는 이유와 해결 방법</title>
      <link>https://voidmainvoid.tistory.com/520</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;spark jdbc를 통해 trino를 접근하기 위해 아래와 같은 코드를 짤 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1729077041863&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.apache.spark.sql.{DataFrame, SparkSession}
import java.util.Properties

// Spark 세션 생성
val spark = SparkSession.builder()
  .appName(&quot;Spark Trino JDBC Example&quot;)
  .getOrCreate()

// JDBC URL 설정
val jdbcUrl = &quot;jdbc:trino://&amp;lt;trino-host&amp;gt;:&amp;lt;port&amp;gt;/&amp;lt;catalog&amp;gt;/&amp;lt;schema&amp;gt;&quot;

// Trino JDBC 속성 설정
val connectionProperties = new Properties()
connectionProperties.setProperty(&quot;user&quot;, &quot;&amp;lt;your-user&amp;gt;&quot;)
connectionProperties.setProperty(&quot;password&quot;, &quot;&amp;lt;your-password&amp;gt;&quot;)
connectionProperties.setProperty(&quot;driver&quot;, &quot;io.trino.jdbc.TrinoDriver&quot;)
connectionProperties.setProperty(&quot;SSL&quot;, &quot;true&quot;) // 필요 시 SSL 활성화

// Trino 테이블 또는 SQL 쿼리 설정
val hiveTable = &quot;(SELECT * FROM your_table LIMIT 10) AS tmp&quot;

// DataFrame 생성 및 데이터 로드
val dfJdbc: DataFrame = spark.read
  .jdbc(jdbcUrl, hiveTable, connectionProperties)

// 결과 출력
dfJdbc.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 실행했을 때 아래와 같은 에러가 발생할 경우이다.&lt;/p&gt;
&lt;pre id=&quot;code_1729077066187&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.sql.SQLException: Unrecognized connection property 'url'.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 에러는 url이라는 key가 trino에 인입되어 발생하는 에러인데, trino에서는 용인되지 않는 설정값이 추가되면 warning도 아니고 에러로 뱉어버린다.......&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spark에서는 url이라는 key에 value를 jdbc:trino:// 로 시작되는 값을 강제 주입하기 때문인데, 이는 3.2.x대 버전까지 이어져 왔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;a href=&quot;https://issues.apache.org/jira/browse/SPARK-36163&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://issues.apache.org/jira/browse/SPARK-36163&lt;/a&gt; 에서 해당 문제를 해결하고자 했고, 그 결과로 3.3.x 이상 버전에서는 해당 에러는 더이상 발생하지 않는다 ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/520</guid>
      <comments>https://voidmainvoid.tistory.com/520#entry520comment</comments>
      <pubDate>Wed, 16 Oct 2024 20:12:36 +0900</pubDate>
    </item>
    <item>
      <title>Spark 개발시, main/resources 패키지에 hdfs-site.xml, core-site.xml 등을 넣는 이유</title>
      <link>https://voidmainvoid.tistory.com/519</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmRG9P/btsI2ETNhqe/v92gee6IgxlEkPeGZm1AD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmRG9P/btsI2ETNhqe/v92gee6IgxlEkPeGZm1AD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmRG9P/btsI2ETNhqe/v92gee6IgxlEkPeGZm1AD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmRG9P%2FbtsI2ETNhqe%2Fv92gee6IgxlEkPeGZm1AD1%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;309&quot; height=&quot;221&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;main/resources&lt;/b&gt; 디렉터리는 Apache Maven이나 SBT와 같은 빌드 도구를 사용하는 프로젝트에서 애플리케이션의 리소스 파일을 저장하는 표준 위치이다. 이 디렉터리에 배치된 파일들은 컴파일된 클래스와 함께 JAR 파일에 포함되며, 런타임에 애플리케이션에서 사용될 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div data-message-id=&quot;dd63d1ed-988f-4cc4-b1cb-630374906689&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HDFS 설정 파일 (hdfs-site.xml)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hdfs-site.xml 파일은 Hadoop 분산 파일 시스템(HDFS)의 설정을 정의한다. 이 파일에는 HDFS 클러스터의 동작을 제어하는 다양한 구성 옵션이 포함되어 있다. 예를 들어, 네임노드의 주소, 데이터 디렉터리, 복제 수 등의 정보가 포함될 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;main/resources 디렉터리에 배치하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main/resources는 애플리케이션의 &lt;b&gt;모든 리소스 파일(예: 설정 파일, 정적 파일, 템플릿 등)을 저장하는 표준 위치다. 이러한 파일들은 컴파일된 애플리케이션의 클래스패스에 자동으로 포함&lt;/b&gt;되므로, 애플리케이션 코드에서 손쉽게 접근할 수 있다. Spark 애플리케이션이 실행될 때, main/resources에 있는 hdfs-site.xml 파일이 자동으로 클래스패스에 포함되므로, 별도의 설정 없이도 Spark 애플리케이션이 해당 파일을 로드하고 사용할 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/하둡</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/519</guid>
      <comments>https://voidmainvoid.tistory.com/519#entry519comment</comments>
      <pubDate>Tue, 13 Aug 2024 13:42:17 +0900</pubDate>
    </item>
    <item>
      <title>standalone 카프카(kraft모드 in local) 실행을 위한 준비와 실행</title>
      <link>https://voidmainvoid.tistory.com/518</link>
      <description>&lt;pre id=&quot;code_1719153722039&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/kafka-storage.sh random-uuid
cKUMbEGERui8cHUhwdc6XA

$ bin/kafka-storage.sh format -t cKUMbEGERui8cHUhwdc6XA -c config/kraft/server.properties
Formatting /tmp/kraft-combined-logs with metadata.version 3.6-IV2.

$ bin/kafka-server-start.sh config/kraft/server.properties
$ bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 --version
3.6.2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카프카 바이너리 다운로드 링크 : &lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kafka.apache.org/downloads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1719153749786&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apache Kafka&quot; data-og-description=&quot;Apache Kafka: A Distributed Streaming Platform.&quot; data-og-host=&quot;kafka.apache.org&quot; data-og-source-url=&quot;https://kafka.apache.org/downloads&quot; data-og-url=&quot;https://kafka.apache.org/downloads&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qL0Ql/hyWoLFNjSf/pikJK0pFsjEktE9ZDSFL7k/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kafka.apache.org/downloads&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qL0Ql/hyWoLFNjSf/pikJK0pFsjEktE9ZDSFL7k/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka: A Distributed Streaming Platform.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kafka.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;standalone 카프카(kraft모드) 실행을 위한 준비와 실행.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGfiba/btsH86DPNLK/ez32R3PgwCXxI6puI7QhyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGfiba/btsH86DPNLK/ez32R3PgwCXxI6puI7QhyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGfiba/btsH86DPNLK/ez32R3PgwCXxI6puI7QhyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGfiba%2FbtsH86DPNLK%2Fez32R3PgwCXxI6puI7QhyK%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;277&quot; height=&quot;172&quot; data-filename=&quot;standalone 카프카(kraft모드) 실행을 위한 준비와 실행.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;bin/kafka-storage.sh 로 따로 파일과 디렉토리를 만들어야 하는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;bin/kafka-storage.sh&lt;/b&gt; 스크립트를 사용하여 별도의 파일과 디렉토리를 만드는 이유는 성능 최적화, 데이터 관리 용이성, 안정성 및 복구 편의성을 확보하기 위함.&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/518</guid>
      <comments>https://voidmainvoid.tistory.com/518#entry518comment</comments>
      <pubDate>Sun, 23 Jun 2024 23:44:20 +0900</pubDate>
    </item>
    <item>
      <title>scala에러 Unable to make private java.nio.DirectByteBuffer 해결 방법</title>
      <link>https://voidmainvoid.tistory.com/517</link>
      <description>&lt;pre id=&quot;code_1717411951044&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to make private java.nio.DirectByteBuffer(long,int) accessible: module java.base does not &quot;opens java.nio&quot;&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;와 같은 코드가 떠서 놀랬다. intellij에서 sbt로 빌드한 스칼라코드가 실행되지 않을 때가 있는데, 이 오류는 jvm컴파일 버전 때문에 생기는 이슈이다.&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;a href=&quot;https://stackoverflow.com/questions/70153343/unable-to-make-private-java-nio-directbytebufferlong-int-accessible&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/70153343/unable-to-make-private-java-nio-directbytebufferlong-int-accessible&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717411989562&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Unable to make private java.nio.DirectByteBuffer(long,int) accessible&quot; data-og-description=&quot;I'm using Python to access Databricks through databricks-connect. Behind the wall, this uses spark which is indeed java based so in order to use this, I need java. The JDK has been downloaded (vers...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/70153343/unable-to-make-private-java-nio-directbytebufferlong-int-accessible&quot; data-og-url=&quot;https://stackoverflow.com/questions/70153343/unable-to-make-private-java-nio-directbytebufferlong-int-accessible&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bSzXdD/hyWg0uTvu1/CqRLyhH6Vkcw8CXE2icFh1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/70153343/unable-to-make-private-java-nio-directbytebufferlong-int-accessible&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/70153343/unable-to-make-private-java-nio-directbytebufferlong-int-accessible&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bSzXdD/hyWg0uTvu1/CqRLyhH6Vkcw8CXE2icFh1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Unable to make private java.nio.DirectByteBuffer(long,int) accessible&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I'm using Python to access Databricks through databricks-connect. Behind the wall, this uses spark which is indeed java based so in order to use this, I need java. The JDK has been downloaded (vers...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결방법&lt;/h3&gt;
&lt;pre id=&quot;code_1717412001386&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew install --cask adoptopenjdk/openjdk/adoptopenjdk8&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;와 같이 jdk8을 깔고 해당 버전을 빌드버전으로 설정하면 된다. 또는 Intellij에서는 project structure에서 다음과 같이 변경하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XDnPI/btsHL4tkpGr/jR6xWTlvjUCND9S8EfAp5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XDnPI/btsHL4tkpGr/jR6xWTlvjUCND9S8EfAp5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XDnPI/btsHL4tkpGr/jR6xWTlvjUCND9S8EfAp5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXDnPI%2FbtsHL4tkpGr%2FjR6xWTlvjUCND9S8EfAp5K%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;878&quot; height=&quot;408&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;408&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;</description>
      <category>Programming Language/Java &amp;amp; Scala</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/517</guid>
      <comments>https://voidmainvoid.tistory.com/517#entry517comment</comments>
      <pubDate>Mon, 3 Jun 2024 19:54:14 +0900</pubDate>
    </item>
    <item>
      <title>아파치 플링크는 2.0 버전부터는 더이상 scala API를 지원하지 않습니다.</title>
      <link>https://voidmainvoid.tistory.com/516</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;아파치 플링크는 2.0 버전부터는 더이상 scala API를 지원하지 않습니다..png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y3Cza/btsHms7ZsWk/ekHEOhwOisbkKZQSrbz6nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y3Cza/btsHms7ZsWk/ekHEOhwOisbkKZQSrbz6nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y3Cza/btsHms7ZsWk/ekHEOhwOisbkKZQSrbz6nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy3Cza%2FbtsHms7ZsWk%2FekHEOhwOisbkKZQSrbz6nk%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;111&quot; height=&quot;111&quot; data-filename=&quot;아파치 플링크는 2.0 버전부터는 더이상 scala API를 지원하지 않습니다..png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&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;a href=&quot;https://cwiki.apache.org/confluence/display/FLINK/FLIP-265+Deprecate+and+remove+Scala+API+support&quot;&gt;https://cwiki.apache.org/confluence/display/FLINK/FLIP-265+Deprecate+and+remove+Scala+API+support&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715317482396&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;FLIP-265 Deprecate and remove Scala API support - Apache Flink - Apache Software Foundation&quot; data-og-description=&quot;Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast). Motivation Apache Flink offers APIs for building your Flink application using the DataStream and Table API. These are offered in Java an&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/FLINK/FLIP-265+Deprecate+and+remove+Scala+API+support&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/FLINK/FLIP-265+Deprecate+and+remove+Scala+API+support&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/FLINK/FLIP-265+Deprecate+and+remove+Scala+API+support&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/FLINK/FLIP-265+Deprecate+and+remove+Scala+API+support&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;FLIP-265 Deprecate and remove Scala API support - Apache Flink - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast). Motivation Apache Flink offers APIs for building your Flink application using the DataStream and Table API. These are offered in Java an&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플링크1.15버전까지는 스칼라와 강결합되어 있는 코드를 제공했습니다. 그러나 점차 스칼라 관련 기여가 적어지고 있는 상황에서 더 이상 스칼라에 대한 직접적인 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;이에 따라 플링크 PMC(Project Management Committee)의 투표를 받았고, 거의 만장일치로 승인이 떨어졌습니다. vote 관련 링크는 다음에서 볼 수 있습니다. &lt;a href=&quot;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715321141909&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&quot; data-og-description=&quot;&quot; data-og-host=&quot;lists.apache.org&quot; data-og-source-url=&quot;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&quot; data-og-url=&quot;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;https://lists.apache.org/thread/qfz4opcbc2p59fhmymncxyzxb70cn098&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lists.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;1450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqCeay/btsHl5L3bfU/itudzkb2BkEdGk6xbWGXXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqCeay/btsHl5L3bfU/itudzkb2BkEdGk6xbWGXXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqCeay/btsHl5L3bfU/itudzkb2BkEdGk6xbWGXXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqCeay%2FbtsHl5L3bfU%2Fitudzkb2BkEdGk6xbWGXXK%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;634&quot; height=&quot;589&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;1450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플링크 프로젝트 운영 규칙(Flink Bylaws)에 따라 PMC는 이런 사안에 대해 투표를 해야만 합니다. 투표에 대한 상세한 사항은 &lt;a href=&quot;https://cwiki.apache.org/confluence/display/FLINK/Flink+Bylaws&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/FLINK/Flink+Bylaws&lt;/a&gt;&amp;nbsp;에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무엇이 바뀌나?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 크게 바뀌는 부분은 직접적인 scala api가 없어진다는 부분입니다. scala는 tuple, 간결한 문법, collection 등 다양한 장점을 가진 언어이고 이를 지원함으로써 스칼라를 사용하는 유저들은 플링크를 더욱 scala 친화적으로 사용할 수 있었습니다. 동일한 jvm 라이브러리라고 하더라도 언어가 다르면 지저분해지기 때문에 이런 부분은 스칼라 유저들에게 친숙하게 다가왔습니다. 스파크를 사용하던 스칼라 유저는 이런 점이 반가웠으리라 생각됩니다.&lt;/p&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;Flink Scala API를 활용한 예제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715321306887&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.apache.flink.api.scala._

object WordCountScala {
  case class WordWithCount(word: String, count: Int)

  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment

    val text = env.fromElements(
      &quot;Who's there?&quot;,
      &quot;I think I hear them. Stand, ho! Who's there?&quot;
    )

    val counts = text
      .flatMap(_.toLowerCase.split(&quot;\\W+&quot;))
      .filter(_.nonEmpty)
      .map(word =&amp;gt; WordWithCount(word, 1))
      .groupBy(_.word)
      .reduce { (a, b) =&amp;gt; WordWithCount(a.word, a.count + b.count) }

    counts.print()
  }
}&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;위와 같이 scala flink로 사용한 구문은 무척이나 간결합니다. 그럼 자바 라이브러리로 구현하면 어떻게 될까요?&lt;/p&gt;
&lt;pre id=&quot;code_1715321346740&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Java Tuple2를 사용하는 예제
import org.apache.flink.api.common.functions.FlatMapFunction
import org.apache.flink.api.java.tuple.Tuple2
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.util.Collector

object JavaStyleWordCount {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    val text = env.socketTextStream(&quot;localhost&quot;, 9999)

    val counts = text
      .flatMap(new FlatMapFunction[String, Tuple2[String, Integer]] {
        override def flatMap(value: String, out: Collector[Tuple2[String, Integer]]): Unit = {
          for (word &amp;lt;- value.toLowerCase.split(&quot;\\W+&quot;)) {
            if (word.nonEmpty) out.collect(new Tuple2(word, 1))
          }
        }
      })
      .keyBy(0)
      .sum(1)

    counts.print()
    env.execute(&quot;Java Style Word Count in Scala&quot;)
  }
}&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;JAVA api를 그대로 사용하면 코드의 &lt;b&gt;구조 자체가 자바에 의존적이기 때문에 상대적으로 읽기 어렵고 장황&lt;/b&gt;해집니다. 예를 들자면, Java의 Tuple 클래스를 사용하거나, Collector를 사용한 사용자 정의 함수 정의가 필요할 때 코드가 더 복잡해집니다. 그리고 Java POJO를 사용하면 타입 정보가 감소되고 간결한 코드 작성이 어려워집니다.&lt;b&gt; Scala에서는 케이스 클래스를 사용하여 더욱 타입 안전하고 간결한 코드&lt;/b&gt;를 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/516</guid>
      <comments>https://voidmainvoid.tistory.com/516#entry516comment</comments>
      <pubDate>Fri, 10 May 2024 22:10:18 +0900</pubDate>
    </item>
    <item>
      <title>Redis-go를 interface화 하여 사용하기</title>
      <link>https://voidmainvoid.tistory.com/515</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Redis-go를 interface화 하여 사용하기.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2hvKx/btsFkJKURUi/2e2C0TGpNxuh8e9IEwwGy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2hvKx/btsFkJKURUi/2e2C0TGpNxuh8e9IEwwGy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2hvKx/btsFkJKURUi/2e2C0TGpNxuh8e9IEwwGy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2hvKx%2FbtsFkJKURUi%2F2e2C0TGpNxuh8e9IEwwGy0%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;348&quot; height=&quot;188&quot; data-filename=&quot;Redis-go를 interface화 하여 사용하기.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;golang에서 Redis를 사용할 때는 보통 go-redis 라이브러리를 많이 사용합니다. 이 때, 바로 메서드를 사용하기 보다는 내부 비즈니스 로직이 포함된 RedisClient 인터페이스를 만들어 사용하곤 하는데요. 아래는 그 예시 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;redis.go&lt;/h3&gt;
&lt;pre id=&quot;code_1708944745670&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;github.com/go-redis/redis/v8&quot; // go-redis import
)

// RedisClientInterface 인터페이스 정의
type RedisClientInterface interface {
    Set(key string, value interface{}) error
    Get(key string) (string, error)
}

// RedisClient 구조체 정의
type RedisClient struct {
    client *redis.Client
}

// NewRedisClient 함수는 RedisClient 인스턴스를 초기화합니다.
func NewRedisClient(addr string) *RedisClient {
    return &amp;amp;RedisClient{
        client: redis.NewClient(&amp;amp;redis.Options{
            Addr: addr, // Redis 서버 주소
        }),
    }
}

// Get 메서드는 주어진 키에 대한 값을 Redis에서 검색합니다.
func (c *RedisClient) Get(key string) (string, error) {
    ctx := context.Background()
    result, err := c.client.Get(ctx, key).Result()
    if err != nil {
        return &quot;&quot;, err
    }
    return result, nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;main.go&lt;/h3&gt;
&lt;pre id=&quot;code_1708944766269&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func main() {
    // RedisClient 인스턴스 생성
    redisClient := NewRedisClient(&quot;localhost:6379&quot;)

    // Set 예시
    err := redisClient.Set(&quot;key&quot;, &quot;value&quot;)
    if err != nil {
        fmt.Println(&quot;Set error:&quot;, err)
        return
    }

    // Get 예시
    result, err := redisClient.Get(&quot;key&quot;)
    if err != nil {
        fmt.Println(&quot;Get error:&quot;, err)
        return
    }

    fmt.Println(&quot;Get result:&quot;, result)
}&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;위와 같은 방식은 일반적으로 많이 사용되는 Struct 선언 구문입니다. 하지만, Testify와 같은 도구로 테스트를 할 때는 RedisClient를 Interface화 해야하는데, 이 때는 RedisClientInterface를 따로 정의해야 합니다. 아래는 그 예시입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708944851949&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// RedisClientInterface 정의
type RedisClientInterface interface {
    Get(key string) (string, error)
}&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;단순히 위와 같이 정의만 하더라도 interface를 사용할 수 있습니다. 다만, main.go에서 사용할 때는 RedisClient를 파라미터로 받되, 형을 RedisClientInterface로 받아야만 인터페이스로 사용할 수 있습니다. 아래는 그 예시입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708944941402&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// CacheOperation 함수는 RedisClientInterface를 사용하여 캐시 작업을 수행합니다.
func CacheOperation(redisClientInterface를 RedisClientInterface, key string, value string) error {
    if err := redisClientInterface를.Set(key, value); err != nil {
        return fmt.Errorf(&quot;failed to set value: %w&quot;, err)
    }
    return nil
}

func main() {
    // RedisClient 인스턴스 생성
    redisClient := NewRedisClient(&quot;localhost:6379&quot;)

    // CacheOperation 함수를 사용하여 캐시 작업 수행
    key := &quot;sampleKey&quot;
    value := &quot;sampleValue&quot;
    if err := CacheOperation(redisClient, key, value); err != nil {
        fmt.Println(&quot;Cache operation error:&quot;, err)
    }
}&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;위와 같이 CachOperation은 RedisClientInterface를 받아서 사용하게 됩니다. 이렇게 사용할 경우, 상위 레벨 로직으로 부터 분리하고 코드의 유연성과 테스트의 용이성이 향상될 수 있습니다.&lt;/p&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>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/515</guid>
      <comments>https://voidmainvoid.tistory.com/515#entry515comment</comments>
      <pubDate>Mon, 26 Feb 2024 23:57:05 +0900</pubDate>
    </item>
    <item>
      <title>카프카 컨슈머의 auto.offset.reset 옵션을 반드시 earliest로 변경해야 하는 이유</title>
      <link>https://voidmainvoid.tistory.com/514</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;auto.offset.reset는 카프카 컨슈머를 다루는데 있어 아주 중요한 부분입니다.&amp;nbsp; 해당 옵션이 가질 수 있는 값은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;earliest : 마지막 커밋 기록이 없을 경우, 가장 예전(낮은 번호 오프셋) 레코드부터 처리&amp;nbsp;&lt;/li&gt;
&lt;li&gt;latest : 마지막 커밋 기록이 없을 경우, 가장 최근(높은 번호 오프셋) 레코드부터 처리&lt;/li&gt;
&lt;li&gt;none : 커밋 기록이 없을 경우 throws Exception&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 옵션은 필수 옵션이 아닌 선택 옵션으로서 입력을 하지 않으면 자동으로 &lt;b&gt;latest&lt;/b&gt;로 설정됩니다. 일반적으로 컨슈머를 운영할 때 이 옵션을 건드리는 경우는 거의 드문데요. 그러다보니 기본값인 latest로 설정할 경우  우리도 모르게 운영 중 데이터의 유실이 발생할 수 있다는 사실을 놓치기도 합니다.&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;blockquote data-ke-style=&quot;style2&quot;&gt;Note that altering partition numbers while setting this config to latest may cause message delivery loss since producers could start to send messages to newly added partitions (i.e. no initial offsets exist yet) before consumers reset their offsets.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 데이터가 유실 될까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티션의 개수가 변경될 경우 컨슈머는 metadata.max.age.ms 만큼 메타데이터 리프래시 기간 이후 리밸런싱이 일어나면서 파티션 할당과정을 거치게 됩니다. 문제는 메타데이터 리프레시(파티션 변경 여부를 알아차리는 시간) 기간동안 새로운 파티션에 데이터가 들어올 수 있다는 사실입니다. 다음 그림은 컨슈머의 auto.offset.reset이 latest일 경우 데이터가 일부 유실되는 모습을 그렸습니다.&lt;/p&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) 파티션2개인 토픽에 컨슈머 2개가 연동되어 있는 그림&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0A1L9/btsEtswcmQZ/VMBMx5pH8NK1uc2IJzuMeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0A1L9/btsEtswcmQZ/VMBMx5pH8NK1uc2IJzuMeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0A1L9/btsEtswcmQZ/VMBMx5pH8NK1uc2IJzuMeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0A1L9%2FbtsEtswcmQZ%2FVMBMx5pH8NK1uc2IJzuMeK%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;1136&quot; height=&quot;408&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 파티션을 3개로 늘린 그림&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oHfCY/btsEuPdAqUH/7hgIHfRp2mdU8EuIFDnlmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oHfCY/btsEuPdAqUH/7hgIHfRp2mdU8EuIFDnlmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oHfCY/btsEuPdAqUH/7hgIHfRp2mdU8EuIFDnlmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoHfCY%2FbtsEuPdAqUH%2F7hgIHfRp2mdU8EuIFDnlmK%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;1160&quot; height=&quot;576&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 새로운 파티션에 데이터가 들어가는 그림&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJRDLk/btsEmTCbWp6/d0Y9e4e9CTdGK27akKaej1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJRDLk/btsEmTCbWp6/d0Y9e4e9CTdGK27akKaej1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJRDLk/btsEmTCbWp6/d0Y9e4e9CTdGK27akKaej1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJRDLk%2FbtsEmTCbWp6%2Fd0Y9e4e9CTdGK27akKaej1%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;1172&quot; height=&quot;700&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 메타데이터가 리프래시 되고 리밸런싱이 일어나는 그림&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmTqoQ/btsEpmXFMIa/Y5mVh8W2Dz800x3Nat3TaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmTqoQ/btsEpmXFMIa/Y5mVh8W2Dz800x3Nat3TaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmTqoQ/btsEpmXFMIa/Y5mVh8W2Dz800x3Nat3TaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmTqoQ%2FbtsEpmXFMIa%2FY5mVh8W2Dz800x3Nat3TaK%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;1150&quot; height=&quot;698&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) 리밸런싱이 완료되고 가장 최근 데이터(오프셋 2번)부터 컨슈머가 가져가는 그림&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M0f1o/btsEmq003o3/0nWjGKPwLH8nIONM2UruK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M0f1o/btsEmq003o3/0nWjGKPwLH8nIONM2UruK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M0f1o/btsEmq003o3/0nWjGKPwLH8nIONM2UruK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM0f1o%2FbtsEmq003o3%2F0nWjGKPwLH8nIONM2UruK0%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;1156&quot; height=&quot;746&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;746&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;위와 같은 상황에서 1,2 오프셋에 해당하는 레코드들이 컨슈머에서 처리되지 않고 지나간 것을 알 수 있습니다. 이는 데이터 양이 적을때는 유실량이 겨우 2개 밖에 안되? 라고 생각할 수도있겠지만, 초당 1억건 이상 들어올 때는 이 데이터양이 매우 많을 수 있습니다. 또한 metadata의 리프래시 주기에 따라서도 유실량이 달라 질 수 있습니다.&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;사실상 컨슈머가 알 수 있는 warning 구문 조차 없기 때문에 많은 개발자들은 유실이 되었는지도 모르고 지나갈 때가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;유실을 막기 위 해서 어떻게 해야 하나&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파티션 증설에 따른 유실을 막기 위해서는 단순히 컨슈머의 옵션을 auto.offset.reset earliest로 설정하는 것이 가장 손쉬운 방법입니다. 그러나 개발자가 컨슈머를 운영하는 상황에서 offset reset을 다 챙기지 못하는 상황이 많고, 파티션을 늘리면 당연히 처음 데이터부터 가져간다고 이해하는 경우가 많기 때문에 오해를 일으키기 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이에 대해 많은 카프카 개발자들은 우려를 표했고 카프카 3.6(23년 10월)이 되어서야 드디어 경고 문구를 DOCS에 추가하는 수준에 끝나게 되었습니다. 관련 PR은 다음과 같습니다. DOCS에 추가된지 6개월도 안되었으니  이미 많은 카프카 컨슈머 개발자들은 이를 놓쳤을거라 생각됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/apache/kafka/pull/10167/files&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/apache/kafka/pull/10167/files&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707110894901&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;KAFKA-12261: Mention about potential delivery loss on increasing partition when auto.offset.reset = latest by ocadaruma &amp;middot; Pull &quot; data-og-description=&quot;Splitting partitions while setting auto.offset.reset to latest may cause message delivery loss, but users might not be aware about that since currently it isn't documented anywhere. Committer Check...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/apache/kafka/pull/10167/files&quot; data-og-url=&quot;https://github.com/apache/kafka/pull/10167&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb8KXO/hyVf1B9WSV/4oa3P45G78DMHE286C6kYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/apache/kafka/pull/10167/files&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/apache/kafka/pull/10167/files&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb8KXO/hyVf1B9WSV/4oa3P45G78DMHE286C6kYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KAFKA-12261: Mention about potential delivery loss on increasing partition when auto.offset.reset = latest by ocadaruma &amp;middot; Pull&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Splitting partitions while setting auto.offset.reset to latest may cause message delivery loss, but users might not be aware about that since currently it isn't documented anywhere. Committer Check...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대한 대응 책으로 &lt;a href=&quot;https://github.com/hudeqi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;텐센트 개발자 hudeqi&lt;/a&gt;는 기존 컨슈머 그룹의 auto.offset.reset을 기존 earliest, latest, none에서 더 세분화하여 개발자로 하여금 오해가 없이 운영할 수 있도록 하는 방안을 KIP-842에서 제안했고 이는 현재도 논의 진행 중에 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-842%3A+Add+richer+group+offset+reset+mechanisms&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-842%3A+Add+richer+group+offset+reset+mechanisms&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707110999759&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-842: Add richer group offset reset mechanisms - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Status Current state: Under Discuss JIRA: here&amp;nbsp; Pull&amp;nbsp;Request:&amp;nbsp;here Discussing thread: here Vote thread: here Motivation When the server expands partitions for a topic, the producer firstly perceives the expansion, and some data is written in the newly e&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-842%3A+Add+richer+group+offset+reset+mechanisms&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-842%3A+Add+richer+group+offset+reset+mechanisms&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-842%3A+Add+richer+group+offset+reset+mechanisms&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-842%3A+Add+richer+group+offset+reset+mechanisms&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-842: Add richer group offset reset mechanisms - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Status Current state: Under Discuss JIRA: here&amp;nbsp; Pull&amp;nbsp;Request:&amp;nbsp;here Discussing thread: here Vote thread: here Motivation When the server expands partitions for a topic, the producer firstly perceives the expansion, and some data is written in the newly e&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애석하게도 이런 논의가 진행되는 &lt;a href=&quot;https://lists.apache.org/thread/dhy4xjb1d5olbn5njho54df4n5om29fz&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;discusstion thread&lt;/a&gt;를 살펴보면 이렇게 변경하는 안에 대해 그다지 호의적이지는 않은 것 같습니다. latset, earliest, none 외에 추가하는 것이 개발자로 하여금 더 어렵게 만들고, seekToEnd()와 같은 컨슈머에서 다룰 수 있는 오프셋 지정 메서드들이 제공되기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;For the original use-case you mentioned, that you want to start from &quot;latest&quot; when the app starts, but if a new partition is added you want to start from &quot;earliest&quot; it seem that the right approach would be to actually configure &quot;earliest&quot;, and when the app is deployed for the first time, use a `seekToEnd()` to avoid triggering auto-offset-reset?&lt;br /&gt;- Matthias J. Sax&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무쪼록 해당 기능에 대해 잘 이해하고 예상치 못한 데이터 유실을 경험하지 않길 바라는 마음에 작성해 보았습니다.&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/514</guid>
      <comments>https://voidmainvoid.tistory.com/514#entry514comment</comments>
      <pubDate>Mon, 5 Feb 2024 14:34:32 +0900</pubDate>
    </item>
    <item>
      <title>json value가 null일때 golang은 Unmarshal을 잘 할 수 있을까?</title>
      <link>https://voidmainvoid.tistory.com/513</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;json value가 null일때 golang은 Unmarshal을 잘 할 수 있을까?.png&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPK5tp/btsDGscELCh/X06WJvuNy2NMJE5AMFRXk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPK5tp/btsDGscELCh/X06WJvuNy2NMJE5AMFRXk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPK5tp/btsDGscELCh/X06WJvuNy2NMJE5AMFRXk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPK5tp%2FbtsDGscELCh%2FX06WJvuNy2NMJE5AMFRXk1%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;108&quot; height=&quot;101&quot; data-filename=&quot;json value가 null일때 golang은 Unmarshal을 잘 할 수 있을까?.png&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;golang은 JSON Format 데이터를 struct로 변환할 수 있는데 이것을 Unmarshal이라고 부릅니다. 예를 들어 다음과 같은 함수로 구현될 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705564055861&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func getStructFromJSON(jsonData string, valuePtr interface{}) error {
	return json.Unmarshal([]byte(jsonData), valuePtr)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;jsonData&lt;/b&gt; : json포맷으로된 String 데이터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;valuePtr&lt;/b&gt; : struct타입&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같이 호출할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705564240854&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type SampleStruct struct {
	A int32 `json:&quot;a&quot;`
	B int32 `json:&quot;b&quot;`
}

func main() {

	var valuePtr SampleStruct
	err := getStructFromJSON(&quot;{\&quot;a\&quot;: 13,\&quot;b\&quot;: 11}&quot;, &amp;amp;valuePtr)
	if err != nil {
		log.Print(err)
	}
	log.Print(valuePtr.A)
	log.Print(valuePtr.B)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705564262708&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2024/01/01 16:50:25 13
2024/01/01 16:50:25 11&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;그런데 만약에 숫자 대신에 null이 들어가 있으면 어떻게 될까요?&lt;/p&gt;
&lt;pre id=&quot;code_1705564309834&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;a&quot;: 13,&quot;b&quot;: null}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상기 데이터가 들어갈 경우 결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705564325015&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2024/01/01 16:51:28 13
2024/01/01 16:51:28 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0으로 초기화 되는 것을 알 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;만약 0으로 초기화가 아니라 null로 초기화 하고 싶다면?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;golang에서 int32는 nil 표현이 불가능합니다. 만약 nil을 표현하고 싶다면 pointer 타입으로 정의해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705564414661&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type SampleStruct struct {
	A int32  `json:&quot;a&quot;`
	B *int32 `json:&quot;b&quot;`
}
func main() {

	var valuePtr SampleStruct
	err := getStructFromJSON(&quot;{\&quot;a\&quot;: 13,\&quot;b\&quot;: null}&quot;, &amp;amp;valuePtr)
	if err != nil {
		log.Print(err)
	}
	log.Print(valuePtr.A)
	log.Print(valuePtr.B)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행시 결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705564425338&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2024/01/01 16:53:08 13
2024/01/01 16:53:08 &amp;lt;nil&amp;gt;&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;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/513</guid>
      <comments>https://voidmainvoid.tistory.com/513#entry513comment</comments>
      <pubDate>Thu, 18 Jan 2024 16:54:44 +0900</pubDate>
    </item>
    <item>
      <title>JSON은 null을 키값으로 가질 수 있을까?</title>
      <link>https://voidmainvoid.tistory.com/512</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;JSON을 정의할 때 null을 키로 가질 수 있을지 궁금해서 jsonlint.com을 사용하여 테스트를 진행했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jsonlint.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jsonlint.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705558701474&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JSON Online Validator and Formatter - JSON Lint&quot; data-og-description=&quot;Loading... About the JSONLint Editor JSONLint is a validator and reformatter for JSON, a lightweight data-interchange format. Copy and paste, directly type, or input a URL in the editor above and let JSONLint tidy and validate your messy JSON code. What Is&quot; data-og-host=&quot;jsonlint.com&quot; data-og-source-url=&quot;https://jsonlint.com/&quot; data-og-url=&quot;https://jsonlint.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://jsonlint.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jsonlint.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JSON Online Validator and Formatter - JSON Lint&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Loading... About the JSONLint Editor JSONLint is a validator and reformatter for JSON, a lightweight data-interchange format. Copy and paste, directly type, or input a URL in the editor above and let JSONLint tidy and validate your messy JSON code. What Is&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jsonlint.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상기 사이트는 valid한 JSON 데이터인지 확인해 줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트용 데이터는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705558723604&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  null:&quot;&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BqZOD/btsDFXDOWkX/OZ72QaXbnMKZ5YhT3xxti1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BqZOD/btsDFXDOWkX/OZ72QaXbnMKZ5YhT3xxti1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BqZOD/btsDFXDOWkX/OZ72QaXbnMKZ5YhT3xxti1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBqZOD%2FbtsDFXDOWkX%2FOZ72QaXbnMKZ5YhT3xxti1%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;1844&quot; height=&quot;286&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON의 key로 STRING이 있어야 하는데 NULL이 있어서 invalid json으로 결과값이 나왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜그럴까요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.json.org/json-ko.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.json.org/json-ko.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705558769624&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JSON&quot; data-og-description=&quot;JSON (JavaScript Object Notation)은 경량의 DATA-교환 형식이다. 이 형식은 사람이 읽고 쓰기에 용이하며, 기계가 분석하고 생성함에도 용이하다. JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1&quot; data-og-host=&quot;www.json.org&quot; data-og-source-url=&quot;https://www.json.org/json-ko.html&quot; data-og-url=&quot;https://www.json.org/json-ko.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.json.org/json-ko.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.json.org/json-ko.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JSON&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JSON (JavaScript Object Notation)은 경량의 DATA-교환 형식이다. 이 형식은 사람이 읽고 쓰기에 용이하며, 기계가 분석하고 생성함에도 용이하다. JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.json.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;json은 name/value 형태의 쌍으로 collection 타입의 element로 ㄱ성되어 있고 이 element는 string으로 이루어져야 합니다. Value에는 null이 들어갈 수 있지만 name에는 반드시 string이 들어가야만 합니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JSON은 null을 키값으로 가질 수 있을까?.png&quot; data-origin-width=&quot;2010&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rp42U/btsDC5vQAxh/GWU6a8iAwhelAXiGnKyRs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rp42U/btsDC5vQAxh/GWU6a8iAwhelAXiGnKyRs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rp42U/btsDC5vQAxh/GWU6a8iAwhelAXiGnKyRs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRp42U%2FbtsDC5vQAxh%2FGWU6a8iAwhelAXiGnKyRs1%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;2010&quot; height=&quot;934&quot; data-filename=&quot;JSON은 null을 키값으로 가질 수 있을까?.png&quot; data-origin-width=&quot;2010&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>빅데이터</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/512</guid>
      <comments>https://voidmainvoid.tistory.com/512#entry512comment</comments>
      <pubDate>Thu, 18 Jan 2024 15:21:40 +0900</pubDate>
    </item>
    <item>
      <title>You aren't going to Need it(YAGNI). 그 기능이 필요할 때 만들어라!</title>
      <link>https://voidmainvoid.tistory.com/511</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1704357639963&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;You aren't gonna need it - Wikipedia&quot; data-og-description=&quot;From Wikipedia, the free encyclopedia Software engineering principle &amp;quot;You aren't gonna need it&amp;quot;[1][2] (YAGNI)[3] is a principle which arose from extreme programming (XP) that states a programmer should not add functionality until deemed necessary.[4] Other&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;You aren't gonna need it - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;From Wikipedia, the free encyclopedia Software engineering principle &quot;You aren't gonna need it&quot;[1][2] (YAGNI)[3] is a principle which arose from extreme programming (XP) that states a programmer should not add functionality until deemed necessary.[4] Other&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Always implement things when you actually need them, never when you just foresee that you [will] need them. - Ron Jeffries&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;1376&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OEvzQ/btsC6Ve7aie/I9MCWmdUj5meKsoJ8HV6Z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OEvzQ/btsC6Ve7aie/I9MCWmdUj5meKsoJ8HV6Z0/img.png&quot; data-alt=&quot;간단한 작업임에도 불구하고 거대한 개발로 인해 지연되고 있음.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OEvzQ/btsC6Ve7aie/I9MCWmdUj5meKsoJ8HV6Z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOEvzQ%2FbtsC6Ve7aie%2FI9MCWmdUj5meKsoJ8HV6Z0%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;1376&quot; height=&quot;588&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;간단한 작업임에도 불구하고 거대한 개발로 인해 지연되고 있음.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;You Aren't Gonna Need It&quot; (YAGNI) 원칙은 소프트웨어 개발에서 중요한 개념으로, 개발자들이 실제 필요하지 않은 기능을 미리 구현하지 않도록 하는 것이 기본 원칙입니다. 특히 애자일 개발 방법론에서 강조되는데, 애자일 방식으로 개발을 할 때 현재의 요구사항에 집중하고 불필요한 작업을 피하는 것이 핵심아라 볼 수 있습니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;원칙&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;현재 필요한가?&lt;/b&gt;: YAGNI는 개발자가 현재의 요구사항에만 집중하도록 도와줍니다. 이는 추측에 의한 기능 개발을 방지하고, 현재 사용자의 필요에 직접적으로 대응하는 기능에 집중하게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발로 인해 시간과 자원의 효율적으로 변하는가?&lt;/b&gt;: 불필요한 기능을 개발하는 것은 시간과 자원의 낭비를 의미합니다. YAGNI를 따름으로써, 개발 팀은 더 중요하고 긴급한 작업에 집중할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지보수의 용이성이 커지는가? &lt;/b&gt;: 덜 복잡한 코드는 유지보수하기가 더 쉽습니다. 불필요한 코드가 없으면 버그 발생 가능성이 줄어들고, 코드에 대한 이해와 수정이 더 간단해집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반응성과 유연성이 좋아지는가? &lt;/b&gt;: 미래의 변화에 더 잘 대응할 수 있습니다. 불필요한 기능을 구현하지 않음으로써, 나중에 요구사항이 변경되었을 때 이에 더 빠르게 반응하고 필요한 기능을 추가할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;한계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장기적 비전 부족&lt;/b&gt;: 때때로 YAGNI는 장기적인 시스템 설계나 아키텍처의 발전을 간과할 수 있습니다. 이는 추후 시스템이 확장될 때 문제가 될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;과도한 단순화&lt;/b&gt;: 일부 경우에는 YAGNI가 너무 강조되어 시스템의 확장성이나 유연성이 무시될 수 있습니다. 이는 장기적으로 더 많은 작업을 초래할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;고려사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;균형 잡힌 접근&lt;/b&gt;: YAGNI 원칙은 상황에 따라 다르게 적용되어야 합니다. 현재의 필요와 미래의 가능성 사이에 균형을 찾는 것이 중요합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팀과의 의사소통&lt;/b&gt;: 개발 팀 내에서 YAGNI 원칙에 대한 명확한 이해와 합의가 필요합니다. 이를 통해 과도한 기능 개발을 방지하고 프로젝트의 방향성을 유지할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;맥킨지 연구에 의하면 기업들은 프로덕트 개발비를 50%초과 지출하면 세후 이익을 3.5% 손실하는 반면, 6개월 늦게 출시하면 33%를 잃는다고 한다. - 찰스 H. 하우스, 레이먼드&amp;nbsp; L. 프라이스&lt;/blockquote&gt;</description>
      <category>DevOps/소프트웨어공학</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/511</guid>
      <comments>https://voidmainvoid.tistory.com/511#entry511comment</comments>
      <pubDate>Thu, 4 Jan 2024 17:46:22 +0900</pubDate>
    </item>
    <item>
      <title>map[string]interface 데이터를 avro 포맷으로 파일 저장하는 방법</title>
      <link>https://voidmainvoid.tistory.com/510</link>
      <description>&lt;pre id=&quot;code_1701142064325&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;github.com/linkedin/goavro&quot;
	&quot;os&quot;
	&quot;time&quot;
)

func main() {
	// Avro 스키마 정의
	schemaJSON := `{
	   &quot;type&quot;: &quot;record&quot;,
	   &quot;name&quot;: &quot;Example&quot;,
	   &quot;fields&quot;: [
	       {&quot;name&quot;: &quot;username&quot;, &quot;type&quot;: &quot;string&quot;},
	       {&quot;name&quot;: &quot;age&quot;, &quot;type&quot;: &quot;int&quot;}
	   ]
	}`

	codec, err := goavro.NewCodec(schemaJSON)
	if err != nil {
		panic(err)
	}

	// 파일 생성
	file, err := os.Create(&quot;avro_data.avro&quot;)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// Avro 데이터 생성 및 파일에 적재
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	for range ticker.C {
		// 예시 데이터 생성
		data := map[string]interface{}{
			&quot;username&quot;: &quot;JohnDoe&quot;,
			&quot;age&quot;:      30,
		}

		b, err := json.Marshal(data)
		if err != nil {
			panic(err)
		}
		fmt.Println(string(b))

		//Avro 데이터 생성
		native, _, err := codec.NativeFromTextual(b)
		if err != nil {
			panic(err)
		}

		binaryData, err := codec.BinaryFromNative(nil, native)
		if err != nil {
			panic(err)
		}

		// 파일에 Avro 데이터 쓰기
		if _, err := file.Write(binaryData); err != nil {
			panic(err)
		}

		// 줄 바꿈
		if _, err := file.WriteString(&quot;\n&quot;); err != nil {
			panic(err)
		}

		fmt.Println(&quot;Avro 데이터를 파일에 적재했습니다.&quot;)
	}
}&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;NativeFromTextual&lt;/b&gt; 메서드와 &lt;b&gt;json.Marshal&lt;/b&gt;을 통해 byte로 변환하는 부분입니다. &lt;b&gt;NativeFromTextual&lt;/b&gt;는 Avro 데이터를 지정한 포맷을 기반으로 데이터를 저장하는데 사용됩니다. 그런데 이 메서드를 받는 파라미터는 byte이므로 반드시 byte로 변환해야만 합니다.&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;이를 위한 json.Marshal을 사용하여 데이터를 byte로 변환하여 avro 형태에 맞는 codec을 통해 변환시키는데 사용됩니다.&lt;/p&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;map[string]interface 데이터를 avro 포맷으로 파일 저장하는 방법.png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGMajw/btsA2vcAW6d/RBRm1SyLnu0xiospzfp4YK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGMajw/btsA2vcAW6d/RBRm1SyLnu0xiospzfp4YK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGMajw/btsA2vcAW6d/RBRm1SyLnu0xiospzfp4YK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGMajw%2FbtsA2vcAW6d%2FRBRm1SyLnu0xiospzfp4YK%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;336&quot; height=&quot;88&quot; data-filename=&quot;map[string]interface 데이터를 avro 포맷으로 파일 저장하는 방법.png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&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;a href=&quot;https://pkg.go.dev/github.com/linkedin/goavro/v2#section-readme&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pkg.go.dev/github.com/linkedin/goavro/v2#section-readme&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701142204876&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;goavro package - github.com/linkedin/goavro/v2 - Go Packages&quot; data-og-description=&quot;Discover Packages github.com/linkedin/goavro/v2 Version: v2.12.0 Opens a new window with list of versions in this module. Published: Aug 19, 2022 License: Apache-2.0 Opens a new window with license information. Imports: 23 Opens a new window with list of i&quot; data-og-host=&quot;pkg.go.dev&quot; data-og-source-url=&quot;https://pkg.go.dev/github.com/linkedin/goavro/v2#section-readme&quot; data-og-url=&quot;https://pkg.go.dev/github.com/linkedin/goavro/v2#section-readme&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://pkg.go.dev/github.com/linkedin/goavro/v2#section-readme&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pkg.go.dev/github.com/linkedin/goavro/v2#section-readme&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;goavro package - github.com/linkedin/goavro/v2 - Go Packages&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Discover Packages github.com/linkedin/goavro/v2 Version: v2.12.0 Opens a new window with list of versions in this module. Published: Aug 19, 2022 License: Apache-2.0 Opens a new window with license information. Imports: 23 Opens a new window with list of i&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pkg.go.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/510</guid>
      <comments>https://voidmainvoid.tistory.com/510#entry510comment</comments>
      <pubDate>Tue, 28 Nov 2023 12:30:29 +0900</pubDate>
    </item>
    <item>
      <title>카프카에서 계층 저장소(Tiered storage)가 필요한 이유</title>
      <link>https://voidmainvoid.tistory.com/509</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;카프카 계층 저장소(Tiered storage) 알아보기.png&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sjSTY/btsyTsvBzNY/OqkehMoSWrddWv5kta9fVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sjSTY/btsyTsvBzNY/OqkehMoSWrddWv5kta9fVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sjSTY/btsyTsvBzNY/OqkehMoSWrddWv5kta9fVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsjSTY%2FbtsyTsvBzNY%2FOqkehMoSWrddWv5kta9fVK%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;185&quot; height=&quot;103&quot; data-filename=&quot;카프카 계층 저장소(Tiered storage) 알아보기.png&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2020년 11월 Cofluent Platform 6.0이 릴리즈&lt;/a&gt;되면서 카프카의 계층 저장소가 처음으로 대중에게 소개되었습니다. 이전까지 카프카 오픈소스 진영에서 많이 논의 되었지만 실제로 개발자가 사용 가능한 형태로 나온 것은 이때가 처음입니다. 컨플루언트를 사용하는 많은 개발자와 회사에서는  카프카의 계층 저장소를 사용해왔습니다. 이후 &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023년 10월, 오픈소스 카프카 3.6.0이 릴리즈&lt;/a&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;핵심은 비용 절감&lt;/b&gt;이라고 생각합니다. 비용 절감에는 크게 두가지가 있는데&lt;b&gt; 컴퓨팅&amp;nbsp;리소스 비용과&lt;/b&gt;&amp;nbsp;&lt;b&gt;휴먼&amp;nbsp;리소스 비용&lt;/b&gt;입니다. 이 2가지 측면에서 카프카의 계층 저장소가 어떤 역할을 하는지 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 컴퓨팅 리소스 감소&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재의 카프카는 여러대의 브로커(서버)에 로컬의 파일시스템에 레코드를 세그먼트 단위로 저장하고 있습니다. 프로듀서가 토픽에 데이터를 전달할 때 마다 세그먼트에 레코드를 추가, 저장함으로써 파일시스템의 크기가 계속해서 늘어나는 구조를 가지고 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 이 데이터의 양이 많아지고 리텐션(Retention)기간을 길게 가져가야할 때 입니다. 파일시스템이 저장되는 공간인 로컬 디스크가 아무리 램에 비해 저렴하다고 하더라도 100TB, 1000TB 혹은 그 이상으로 구성하기는 매우 어렵고 비용이 많이 발생합니다. 카프카의 분산 이벤트 스트리밍 플랫폼 특성상 모든 토픽의 리텐션을 3일, 3시간 이내로 가져가는 것은 카프카의 특징을 오히려 상쇄 시키는 역효과로 가져옵니다. 그렇기 때문에&lt;b&gt; 더 긴 리텐션을 만족시키기 위해서는 로컬 저장소 저장 방식이 아니라 리모트 저장소가&amp;nbsp;필요&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;카프카에서 제공하는 계층 저장소는 S3, HDFS, Azure storage 등 우리에게 익숙한 저장소를 지원합니다. &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;리모트 저장소와 로컬 저장소로 설정한 토픽 둘 다 최근 데이터 읽기/쓰기는 거의 비슷합니다. 다만, 리모트 저장소에 저장된 토픽의 레코드 중 브로커의 페이지 캐시에 존재하지 않는 데이터를 읽을 때(컨슈머)는 약간의 지연이 발생할 수 있습니다. 일반적으로 우리가 스트림 데이터를 다룰 때 가장 최신의 데이터를 자주 접근하고&lt;b&gt; 오래된 데이터를 다시 가져오는 리플레이 상황은 빈번히 일어나지 않기 때문에 리모트 저장소로 설정된 토픽의 지연은 일반적인 상황에서 크게 문제되지 않는다고 볼 수 있습니다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 휴먼 리소스 감소&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜기간 동안 카프카를 운영하면서 많은 카프카 운영자들은 브로커를 운영하기 위해 많은 피땀을 흘려왔습니다. 운영을 지속함에 따라 토픽의 개수가 계속해서 늘어나고 토픽의 파티션 개수는 각양 각색이며, 토픽별 데이터양도 모두 다르기 때문입니다. 그렇기 때문에 브로커의 디스크 용량 불균등 현상으로 인해 특정 토픽의 파티션 개수를 배수로 늘리거나 파티션 재설정(partition reassign)을 수행해야만 했습니다. &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;리모트 저장소는 카프카 클러스터 운영자가 들이는 수고를 한층 줄여줄 수 있습니다. 리모트 저장소로 설정된 토픽은 로컬 디스크에 저장되는 것이 아니라 외부 저장소에 저장되기 때문에 각 브로커별 로컬 디스크의 데이터양을 이전만큼 민감하게 모니터링할 필요가 없습니다. 또한 브로커 업그레이드와 같은 롤링 리스타트 상황에서도 각 브로커의 영향도가 한층 적어진다는 장점이 있습니다. 이전 만큼 대규모로 비싼 비용의 브로커를 운영할 필요가 없어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, &lt;b&gt;리모트 저장소를 사용한다고 모든게 해결되는 것은 아닙니다.&lt;/b&gt; 리모트 저장소와 연결된 토픽을 따로 관리해야할 것입니다. 예를 들어&lt;b&gt; 카프카와 리모트 저장소의 연결 상태, 데이터 크기, 네트워크 속도 등 다양한 부분을 인프라 관점에서 고민이 필요합니다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카가 제공하는 계층 저장소는 아직 얼리 엑세스 모드로서 많은 기능들이 제한적으로 제공됩니다. 한번 리모트 저장소로 저장한 토픽은 다시 로컬 저장소로 변경이 불가능, 카프카 클라이언트와 호환성 부족 등이 대표적이며 이외에도 안정성 측면에서 프로덕션 레벨에서 사용하기에는 아직 부적합 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 카프카의 계층 저장소는 상당히 가치있기 때문에 빠르게 프로뎍션 레벨로 제공될 것이라 생각됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고문서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800064884&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kafka Tiered Storage Early Access Release Notes - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;This is an early access release for tiered storage feature(KIP-405), and it is not recommended for use in production environments. Instead, we advise users to create new clusters with version 3.6.0 and test the feature there. Alternatively, you can try the&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Tiered+Storage+Early+Access+Release+Notes&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kafka Tiered Storage Early Access Release Notes - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This is an early access release for tiered storage feature(KIP-405), and it is not recommended for use in production environments. Instead, we advise users to create new clusters with version 3.6.0 and test the feature there. Alternatively, you can try the&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-950%3A++Tiered+Storage+Disablement&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-950%3A++Tiered+Storage+Disablement&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800070872&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-950:  Tiered Storage Disablement - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;This page is meant as a template for writing a KIP. To create a KIP choose Tools-&amp;gt;Copy on this page and modify with your content and replace the heading with the next KIP number and a description of your issue. Replace anything in italics with your own des&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-950%3A++Tiered+Storage+Disablement&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-950%3A++Tiered+Storage+Disablement&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-950%3A++Tiered+Storage+Disablement&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-950%3A++Tiered+Storage+Disablement&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-950: Tiered Storage Disablement - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page is meant as a template for writing a KIP. To create a KIP choose Tools-&amp;gt;Copy on this page and modify with your content and replace the heading with the next KIP number and a description of your issue. Replace anything in italics with your own des&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://dzone.com/articles/the-stairway-to-apache-kafka-tiered-storage&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dzone.com/articles/the-stairway-to-apache-kafka-tiered-storage&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800079112&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;The Stairway to Apache Kafka&amp;reg; Tiered Storage - DZone&quot; data-og-description=&quot;Tiered Storage, a feature of Apache Kafka that allows the offloading of data to object storage in the cloud, was developed in the open by the community.&quot; data-og-host=&quot;dzone.com&quot; data-og-source-url=&quot;https://dzone.com/articles/the-stairway-to-apache-kafka-tiered-storage&quot; data-og-url=&quot;https://dzone.com/articles/the-stairway-to-apache-kafka-tiered-storage&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bHo4xV/hyUgTZtsUh/EOG1NZpKPmI4NkTSXEXJ1K/img.jpg?width=2737&amp;amp;height=1711&amp;amp;face=0_0_2737_1711,https://scrap.kakaocdn.net/dn/EzTX5/hyUgHrcEsL/VDamrstMeu1GdmuJ9ioj2K/img.jpg?width=2737&amp;amp;height=1711&amp;amp;face=0_0_2737_1711&quot;&gt;&lt;a href=&quot;https://dzone.com/articles/the-stairway-to-apache-kafka-tiered-storage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dzone.com/articles/the-stairway-to-apache-kafka-tiered-storage&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bHo4xV/hyUgTZtsUh/EOG1NZpKPmI4NkTSXEXJ1K/img.jpg?width=2737&amp;amp;height=1711&amp;amp;face=0_0_2737_1711,https://scrap.kakaocdn.net/dn/EzTX5/hyUgHrcEsL/VDamrstMeu1GdmuJ9ioj2K/img.jpg?width=2737&amp;amp;height=1711&amp;amp;face=0_0_2737_1711');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The Stairway to Apache Kafka&amp;reg; Tiered Storage - DZone&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Tiered Storage, a feature of Apache Kafka that allows the offloading of data to object storage in the cloud, was developed in the open by the community.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dzone.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://joshua-robinson.medium.com/simplify-kafka-at-scale-with-confluent-tiered-storage-ae8c1a2c9c80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://joshua-robinson.medium.com/simplify-kafka-at-scale-with-confluent-tiered-storage-ae8c1a2c9c80&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800084835&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Simplify Kafka at Scale with Confluent Tiered Storage&quot; data-og-description=&quot;Confluent recently announced the general availability of Tiered Storage in the Confluent Platform 6.0 release, a new feature for managing&amp;hellip;&quot; data-og-host=&quot;joshua-robinson.medium.com&quot; data-og-source-url=&quot;https://joshua-robinson.medium.com/simplify-kafka-at-scale-with-confluent-tiered-storage-ae8c1a2c9c80&quot; data-og-url=&quot;https://joshua-robinson.medium.com/simplify-kafka-at-scale-with-confluent-tiered-storage-ae8c1a2c9c80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bUYk43/hyUgQuVpQj/0Da1byPPisbySbqM0CnbHK/img.png?width=423&amp;amp;height=268&amp;amp;face=0_0_423_268&quot;&gt;&lt;a href=&quot;https://joshua-robinson.medium.com/simplify-kafka-at-scale-with-confluent-tiered-storage-ae8c1a2c9c80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://joshua-robinson.medium.com/simplify-kafka-at-scale-with-confluent-tiered-storage-ae8c1a2c9c80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bUYk43/hyUgQuVpQj/0Da1byPPisbySbqM0CnbHK/img.png?width=423&amp;amp;height=268&amp;amp;face=0_0_423_268');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Simplify Kafka at Scale with Confluent Tiered Storage&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Confluent recently announced the general availability of Tiered Storage in the Confluent Platform 6.0 release, a new feature for managing&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;joshua-robinson.medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800090812&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Confluent 6.0 Delivers the Most Powerful Event Streaming Platform to Date&quot; data-og-description=&quot;Confluent Platform 6.0 delivers all phases of Project Metamorphosis for the most powerful, cost-efficient Kafka with infinite data retention, scale, and global availability.&quot; data-og-host=&quot;www.confluent.io&quot; data-og-source-url=&quot;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&quot; data-og-url=&quot;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bpbDi7/hyUgIXXAjf/BLliexIU4uZ9nAMxDOi3RK/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/ujEb5/hyUgPCLwI1/6sEB8ullWNkA07aGubP4YK/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/5nFj5/hyUgRghIXh/pQkws7HlKz5D2ZieIRvE5k/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540&quot;&gt;&lt;a href=&quot;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.confluent.io/blog/confluent-platform-6-0-delivers-the-most-powerful-event-streaming-platform-to-date/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bpbDi7/hyUgIXXAjf/BLliexIU4uZ9nAMxDOi3RK/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/ujEb5/hyUgPCLwI1/6sEB8ullWNkA07aGubP4YK/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/5nFj5/hyUgRghIXh/pQkws7HlKz5D2ZieIRvE5k/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Confluent 6.0 Delivers the Most Powerful Event Streaming Platform to Date&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Confluent Platform 6.0 delivers all phases of Project Metamorphosis for the most powerful, cost-efficient Kafka with infinite data retention, scale, and global availability.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.confluent.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800134896&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-405: Kafka Tiered Storage - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Authors Satish Duggana, Sriharsha Chintalapani, Ying Zheng, Suresh Srinivas Status Current State:&amp;nbsp;&amp;quot;Accepted&amp;quot; Discussion Thread: here JIRA:&amp;nbsp; KAFKA-7739 - 이슈 세부사항 가져오는 중... 상태 Motivation Kafka is an important part of data infrastr&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-405: Kafka Tiered Storage - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Authors Satish Duggana, Sriharsha Chintalapani, Ying Zheng, Suresh Srinivas Status Current State:&amp;nbsp;&quot;Accepted&quot; Discussion Thread: here JIRA:&amp;nbsp; KAFKA-7739 - 이슈 세부사항 가져오는 중... 상태 Motivation Kafka is an important part of data infrastr&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://www.confluent.io/blog/introducing-apache-kafka-3-6/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.confluent.io/blog/introducing-apache-kafka-3-6/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697800144402&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introducing Apache Kafka 3.6&quot; data-og-description=&quot;Apache Kafka 3.6 brings Tiered Storage Early Access, migrating clusters from ZooKeeper to KRaft with no downtime, a grace period for stream-table joins, and more!&quot; data-og-host=&quot;www.confluent.io&quot; data-og-source-url=&quot;https://www.confluent.io/blog/introducing-apache-kafka-3-6/&quot; data-og-url=&quot;https://www.confluent.io/blog/introducing-apache-kafka-3-6/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/thgn3/hyUgNZeUSH/XGK6SdjGtoKUmrSYkNUQF0/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/ZWfqY/hyUgP3OU9x/RDDDrmRlGWAJX4ZvNLWDT0/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748&quot;&gt;&lt;a href=&quot;https://www.confluent.io/blog/introducing-apache-kafka-3-6/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.confluent.io/blog/introducing-apache-kafka-3-6/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/thgn3/hyUgNZeUSH/XGK6SdjGtoKUmrSYkNUQF0/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/ZWfqY/hyUgP3OU9x/RDDDrmRlGWAJX4ZvNLWDT0/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Introducing Apache Kafka 3.6&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka 3.6 brings Tiered Storage Early Access, migrating clusters from ZooKeeper to KRaft with no downtime, a grace period for stream-table joins, and more!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.confluent.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/509</guid>
      <comments>https://voidmainvoid.tistory.com/509#entry509comment</comments>
      <pubDate>Fri, 20 Oct 2023 20:01:28 +0900</pubDate>
    </item>
    <item>
      <title>신뢰성 있는 카프카 애플리케이션을 만드는 3가지 방법</title>
      <link>https://voidmainvoid.tistory.com/508</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2023-09-22-18-25-07 004.png&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZCT2b/btsvlyMfeKN/YNV6qkdZDSgIVK9HyVNk3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZCT2b/btsvlyMfeKN/YNV6qkdZDSgIVK9HyVNk3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZCT2b/btsvlyMfeKN/YNV6qkdZDSgIVK9HyVNk3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZCT2b%2FbtsvlyMfeKN%2FYNV6qkdZDSgIVK9HyVNk3k%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;538&quot; height=&quot;360&quot; data-filename=&quot;KakaoTalk_Photo_2023-09-22-18-25-07 004.png&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;1078&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오 공개 기술 세미나인 kakao tech meet에서 &lt;b&gt;'신뢰성 있는 카프카 애플리케이션을 만드는 3가지 방법'&lt;/b&gt; 에 대해 발표하는 자리를 가졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/7_VdIFH6M6Q?si=6dIoY2X5d0q3ThdM&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=7_VdIFH6M6Q&quot;&gt;https://www.youtube.com/watch?v=7_VdIFH6M6Q&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이벤트&amp;nbsp;드리븐&amp;nbsp;아키텍처와&amp;nbsp;스트림&amp;nbsp;데이터&amp;nbsp;파이프라인을&amp;nbsp;만들때&amp;nbsp;고민해야&amp;nbsp;하는&amp;nbsp;부분을&amp;nbsp;다룹니다.&amp;nbsp;프로듀서/컨슈머와&amp;nbsp;같은&amp;nbsp;카프카&amp;nbsp;애플리케이션의&amp;nbsp;전달&amp;nbsp;신뢰도를&amp;nbsp;높이기&amp;nbsp;위해서&amp;nbsp;적용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기술들에&amp;nbsp;대해&amp;nbsp;설명하고&amp;nbsp;내부적으로&amp;nbsp;적용했던&amp;nbsp;경험을&amp;nbsp;공유합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카에서 다루는 신뢰도에 대해 다시 한 번 고민해보고, 내가 만든 애플리케이션이 고객에게 어떻게 가치를 줄 수 있는지 생각해볼만한 주제도 함께 알려드립니다.&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/508</guid>
      <comments>https://voidmainvoid.tistory.com/508#entry508comment</comments>
      <pubDate>Fri, 22 Sep 2023 18:25:43 +0900</pubDate>
    </item>
    <item>
      <title>카프카 프로듀서의 acks=all 옵션은 사실(?) 느리지 않다!</title>
      <link>https://voidmainvoid.tistory.com/507</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;카프카 프로듀서의 acks=all 옵션은 사실(?) 느리지 않다!.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CfhMe/btsqBp1z5te/CIYoNFLOTIjCbMOJyWkjFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CfhMe/btsqBp1z5te/CIYoNFLOTIjCbMOJyWkjFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CfhMe/btsqBp1z5te/CIYoNFLOTIjCbMOJyWkjFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCfhMe%2FbtsqBp1z5te%2FCIYoNFLOTIjCbMOJyWkjFk%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;140&quot; height=&quot;76&quot; data-filename=&quot;카프카 프로듀서의 acks=all 옵션은 사실(?) 느리지 않다!.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카 3.0 부터는 카프카 프로듀서의 acks 옵션이 all로 지정됩니다. &lt;b&gt;acks=all이 기본값으로 지정된 이유 중 하나는 프로듀서와 브로커 간 통신을 멱등성(idempotence)있게 만들기 위함&lt;/b&gt;입니다. 프로듀서와 브로커는 acks를 통해 레코드가 전송되었는지 확인합니다. 문제는 acks가 유실되었을 경우입니다. 네트워크 상태, 브로커 상태에 따라서 언제든 유실될 수 있는 acks를 정상적으로 전송하기 위해서는 acks를 위한 acks(!)를 만들어야만 합니다. 이는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Two_Generals%27_Problem&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;두 장군 문제 알고리즘&lt;/a&gt;과 동일하다고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 프로듀서의 중복 전달을 제거하기 위해 카프카 3.0부터는 enable.idempotence가 true로 변경되었고 이에 딸려오는 추가 옵션인 acks가 all로 설정되게 되었습니다. 프로듀서가 여러번 브로커로 전송하더라도 결과적으로 하나의 레코드만 적재하는 전략을 취했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로듀서의 옵션 중 acks는 all로 설정할 경우 min.insync.replicas 개수 만큼 리더/팔로워 파티션에 레코드가 분산 저장되었는지 확인하는 역할을 합니다. 당연하게도 acks=0(적재를 확인하지 않음), acks=1(리더에 적재 확인)보다도 더 느릴 수 밖에 없습니다. &lt;b&gt;그렇다면 이렇게 느릴 수 있는 acks=all 옵션을 왜 카프카 프로듀서에 기본 값으로 적용하게 되었던걸까요?&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;이유는 max.inflight.requests.per.connection과 관련 있습니다. &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/An+analysis+of+the+impact+of+max.in.flight.requests.per.connection+and+acks+on+Producer+performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An analysis of the impact of max.in.flight.requests.per.connection and acks on Producer performance&lt;/a&gt; 에 따르면 &lt;b&gt;acks=all로 설정하더라도 max.in.flight.requests.per.connection를 3으로 설정하고 비동기 프로듀서(Asynchronous producer)를 사용하면 acks=1과 동일한 성능을 낼 수 있음을 증명&lt;/b&gt;하였습니다. 비동기 프로듀서란 브로커로부터의 응답을 동기로 받지 않는 것을 뜻합니다. 즉, 프로듀서의 샌더가 max.in.flight.requests.per.connection 개수만큼 병렬로 레코드를 전송하면 되는 것이죠. 당연하게도 동기 프로듀서(Synchronous producer)를 사용하게 되면 속도는 매우느립니다.&lt;/p&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;Asynchronous producer&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691488898246&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;KafkaProducer&amp;lt;String, String&amp;gt; producer = new KafkaProducer&amp;lt;&amp;gt;(configs);
ProducerRecord&amp;lt;String, String&amp;gt; record = new ProducerRecord&amp;lt;&amp;gt;(TOPIC_NAME, messageValue);
producer.send(record); // 비동기 프로듀서 코드 #1
========
producer.send(record, new ProducerCallback()); // 비동기 프로듀서 코드 #2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Synchronous producer&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691488922912&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ProducerRecord&amp;lt;String, String&amp;gt; record = new ProducerRecord&amp;lt;&amp;gt;(TOPIC_NAME, messageValue);
try {
    RecordMetadata metadata = producer.send(record).get();
    logger.info(metadata.toString());
} catch (Exception e) {
    logger.error(e.getMessage(),e);
} finally {
    producer.flush();
    producer.close();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 특징으로 인해 &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-679%3A+Producer+will+enable+the+strongest+delivery+guarantee+by+default&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;KIP-679&lt;/a&gt;에서는 프로듀서와 브로커간 통신에서 레코드를 단 한번만 전송(Exactly-once)하기 위해 enable.idempotence를 true와 변경함과 동시에 acks를 all로 설정하게 되었습니다. 이를 통해 카프카 클라이언트 3.0 이후 버전에서 프로듀서는 브로커로 단 한번만 레코드를 전송할 수 있게 되었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카프카 클라이언트 프로듀서 3.0 이후에는 acks가 all로 기본값으로 설정됨&lt;/li&gt;
&lt;li&gt;acks=all로 성능이 유지되기 위해서는 비동기 프로듀서를 사용해야 함&lt;/li&gt;
&lt;li&gt;만약 카프카 클라이언트 3.0 미만 버전을 사용하고 있다가 3.0 이상으로 올려야 할 경우 acks 옵션의 기본값이 변경되므로 성능 및 동작에 차이에 대해 파악해야 함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/507</guid>
      <comments>https://voidmainvoid.tistory.com/507#entry507comment</comments>
      <pubDate>Tue, 8 Aug 2023 19:08:23 +0900</pubDate>
    </item>
    <item>
      <title>기존에 생성된 compact topic의 cleanup.policy를 변경하는 방법</title>
      <link>https://voidmainvoid.tistory.com/506</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;기존에 생성된 compact topic의 cleanup.policy를 변경하는 방법.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/maoxZ/btslS8wcXEL/v0bwLqj44PTs25ZbmIE0X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/maoxZ/btslS8wcXEL/v0bwLqj44PTs25ZbmIE0X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/maoxZ/btslS8wcXEL/v0bwLqj44PTs25ZbmIE0X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmaoxZ%2FbtslS8wcXEL%2Fv0bwLqj44PTs25ZbmIE0X1%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;166&quot; height=&quot;103&quot; data-filename=&quot;기존에 생성된 compact topic의 cleanup.policy를 변경하는 방법.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 cleanup.policy 확인&lt;/p&gt;
&lt;pre id=&quot;code_1688080104592&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-topics.sh --bootstrap-server localhost:9092 --topic compact-
test --describe
Topic: compact-test	PartitionCount: 1	ReplicationFactor: 1	Configs: cleanup.policy=compact,segment.bytes=1073741824
	Topic: compact-test	Partition: 0	Leader: 0	Replicas: 0Isr: 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kafka-configs.sh를 사용하여 토픽 수정&lt;/p&gt;
&lt;pre id=&quot;code_1688080038263&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-configs.sh --bootstrap-server localhost:9092 --alter --entit
y-type topics --entity-name compact-test --add-config cleanup.policy=delete
Completed updating config for topic compact-test.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토픽 변경된 내용 확인&lt;/p&gt;
&lt;pre id=&quot;code_1688080070011&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-topics.sh --bootstrap-server localhost:9092 --topic compact-
test --describe
Topic: compact-test	PartitionCount: 1	ReplicationFactor: 1	Configs: cleanup.policy=delete,segment.bytes=1073741824
	Topic: compact-test	Partition: 0	Leader: 0	Replicas: 0Isr: 0&lt;/code&gt;&lt;/pre&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/506</guid>
      <comments>https://voidmainvoid.tistory.com/506#entry506comment</comments>
      <pubDate>Fri, 30 Jun 2023 08:08:35 +0900</pubDate>
    </item>
    <item>
      <title>Compacted topic에 null key 레코드를 전송하면?</title>
      <link>https://voidmainvoid.tistory.com/505</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Compacted topic에 null key 레코드를 전송하면?.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUy2gW/btslOB7FEuK/azueqig24Ku0EHn3yUBUJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUy2gW/btslOB7FEuK/azueqig24Ku0EHn3yUBUJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUy2gW/btslOB7FEuK/azueqig24Ku0EHn3yUBUJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUy2gW%2FbtslOB7FEuK%2Fazueqig24Ku0EHn3yUBUJk%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;144&quot; height=&quot;89&quot; data-filename=&quot;Compacted topic에 null key 레코드를 전송하면?.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Compacted topic에 null key를 전송(produce)하면 어떻게 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Compacted 토픽 생성&lt;/h4&gt;
&lt;pre id=&quot;code_1688079471392&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./kafka-topics.sh --bootstrap-server localhost:9092 --topic compact-test --config &quot;cleanup.policy=compact&quot; --create
Created topic compact-test.

$ ./kafka-topics.sh --bootstrap-server localhost:9092 --topic compact-test --describe
Topic: compact-test	PartitionCount: 1	ReplicationFactor: 1	Configs: cleanup.policy=compact,segment.bytes=1073741824
	Topic: compact-test	Partition: 0	Leader: 0	Replicas: 0	Isr: 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) null key 레코드 전송&lt;/h4&gt;
&lt;pre id=&quot;code_1688079494429&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) throws Exception{
    Properties configs = new Properties();
    configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
    configs.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
    configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());

    KafkaProducer&amp;lt;String, String&amp;gt; producer = new KafkaProducer&amp;lt;&amp;gt;(configs);
    ProducerRecord&amp;lt;String, String&amp;gt; record = new ProducerRecord&amp;lt;&amp;gt;(TOPIC_NAME, &quot;test&quot;);
    RecordMetadata meta = producer.send(record).get();
    logger.info(meta.toString());
    producer.flush();
    producer.close();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) 결과 로그&lt;/h4&gt;
&lt;pre id=&quot;code_1688079532073&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Exception in thread &quot;main&quot; java.util.concurrent.ExecutionException: org.apache.kafka.common.InvalidRecordException: This record has failed the validation on broker and hence be rejected.
	at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.valueOrError(FutureRecordMetadata.java:98)
	at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:67)
	at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:30)
	at com.example.SimpleProducer.main(SimpleProducer.java:27)
Caused by: org.apache.kafka.common.InvalidRecordException: This record has failed the validation on broker and hence be rejected.

FAILURE: Build failed with an exception.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;InvalidRecordException&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/505</guid>
      <comments>https://voidmainvoid.tistory.com/505#entry505comment</comments>
      <pubDate>Fri, 30 Jun 2023 07:59:49 +0900</pubDate>
    </item>
    <item>
      <title>아파치 카프카 Exactly-once 처리의 진실과 거짓</title>
      <link>https://voidmainvoid.tistory.com/504</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_아파치 카프카 Exactly-once 처리의 진실과 거짓.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSSbWW/btskAHAD5rx/4lHM1YQKfnFNsSr9RKBc90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSSbWW/btskAHAD5rx/4lHM1YQKfnFNsSr9RKBc90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSSbWW/btskAHAD5rx/4lHM1YQKfnFNsSr9RKBc90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSSbWW%2FbtskAHAD5rx%2F4lHM1YQKfnFNsSr9RKBc90%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;218&quot; height=&quot;124&quot; data-filename=&quot;edited_아파치 카프카 Exactly-once 처리의 진실과 거짓.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아파치 카프카와 같은 분산 이벤트 스트리밍 플랫폼을 사용하거나 메시지 브로커를 활용하다 보면 항상 마주치는 문제는 마로&lt;b&gt; 메시지 전달 시멘틱(message delivery semantic)&lt;/b&gt;입니다. 메시지 전달 시멘틱은 A지점에서 B지점으로 데이터를 전송할 때 어느 만큼의 신뢰도로 데이터를 전송하는지에 대한 정의입니다. 즉, 특정한 장애 상황(또는 임계치를 벗어난 상황)에서도 보증하는 데이터 전달 신뢰도라고 볼 수 있습니다.&lt;/p&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;적어도 한번(at least once), 많아도 한번(at most once), 정확히 한번(exactly once).&lt;/b&gt; '적어도 한번'은 데이터가 전달될 때 유실이 발생하지는 않지만 중복이 발생할 가능성이 있음을 뜻합니다. 아파치 카프카는 기본 옵션으로 사용할 경우 '적어도 한번'을 보장합니다. '많아도 한번'은 최대 한번의 메시지를 보내고 일부 데이터는 유실될 수 있음을 뜻합니다. 마지막으로 '정확히 한번'은 A에서 B로 데이터를 보낼 때 &lt;b&gt;어떠한 경우&lt;/b&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;어떠한 경우&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;즉, 아파치 카프카를 사용하는 상황에서 '어떠한 경우'가 발생하지 않는다면 기본적으로는 '정확히 한번'을 수행합니다.&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;카프카에서 '어떠한 경우'가 생기는 것의 예는 네트워크상 이슈 또는 애플리케이션 이슈를 예로 들 수 있습니다. 프로듀서 입장에서 브로커에 레코드가 정상적으로 저장되더라도 ack가 유실되면 데이터가 적재되지 못했다고 생각해서 retry를 하게 되어 데이터의 중복 전달이 발생할 수 있습니다. 컨슈머 입장에서는 데이터를 안전하게 처리했음에도 불구하고 애플리케이션 장애로 인해서 commit을 못하게 되면 이전 레코드를 중복처리할 수 있는 경우가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 '어떠한 경우'가 발생하더라도 데이터 처리의 중복/유실을 방지 위해 아파치 카프카는 많은 노력을 기울여 왔습니다. 크게 두가지가 있는데요. 첫번째는 &lt;b&gt;멱등성 프로듀서(idempotence producer)&lt;/b&gt;이고 두번째는 &lt;b&gt;트랜잭션 프로듀서/컨슈머(transaction producer/consumer)&lt;/b&gt;입니다. 멱등성 프로듀서는 네트워크 장애가 발생하더라도 브로커에 단 하나의 레코드만 보낼 수 있도록 보장하여 '정확히 한번'을 달성하였습니다. 트랜잭션 프로듀서/컨슈머는 여러 레코드를 원자(atomic) 단위로 데이터를 처리할 수 있도록 설계되었는데, 여기에 추가적으로 컨슈머의 커밋을 트랜잭션에 포함시키는 기능(sendOffsetsToTransaction)을 가지고 있습니다. 이를 통해 &lt;b&gt;A토픽-&amp;gt;컨슈머-&amp;gt;데이터 처리-&amp;gt;프로듀서-&amp;gt;B토픽&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; 프로듀서-&amp;gt;토픽&lt;/b&gt; 또는 &lt;b&gt;토픽-&amp;gt;컨슈머-&amp;gt;프로듀서-&amp;gt;토픽&lt;/b&gt; 에 대해서 '정확히 한번'을 달성하였다는 사실이 있지만 우리가 흔히 사용하게 되는 &lt;b&gt;토픽-&amp;gt;컨슈머&lt;/b&gt; 는 '정확히 한번' 달성에 대한 이야기가 없습니다. 왜냐면 컨슈머가 레코드를 토픽에서 가져가서 처리한 뒤 중복처리를 막기 위해 오프셋 저장을 수행하는데, 오프셋 저장을 특정 처리와 함께 트랜잭션으로 묶는 것이 어렵기 때문입니다. 예를 들어 토픽의 레코드들을 데이터베이스에 데이터를 저장한다고 가정할 경우 데이터 insert와 commit offset을 하나의 트랜잭션으로 묶는 것은 불가능합니다. 서로 연동되는 서비스가 아니기 때문이죠. 그렇기 때문에 &lt;b&gt;토픽-&amp;gt;컨슈머&lt;/b&gt; 처리에서 '정확히 한번'을 달성하기 위해서는 멱등성(idempotence) 처리를 하도록 가이드합니다. 멱등성이라는 것은 동일한 명령이 여러번 가더라도 결과물은 동일한 것을 뜻합니다. 컨슈머가 멱등성 특징을 가지게 하기 위해서는 관련 데이터베이스에서 해당 기능을 지원해야 합니다. 예를 들어 동일한 레코드가 중복 적재될 때는 결과가 하나만 나올 수 있도록 유니크 키 같은 것을 지원한다면 이 문제가 쉽게 해소될 수 있습니다. 이를 통해 &lt;b&gt;토픽-&amp;gt;컨슈머&lt;/b&gt;까지 '정확히 한번' 달성을 수행할 수 있게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카프카 뿐만 아니라 플링크, 스파크 등 많은 스트리밍 플랫폼을 사용할 때 간과하는 것이 메시지 전달 시멘틱입니다. 또한 어떻게 동작하는지 모르는 상태에서 단순히 &lt;i&gt;exactly_once=true&lt;/i&gt; 옵션을 적용하고 사용하는 경우가 많습니다. 비즈니스 요구사항에 따라 어떤 동작을 할지 정의하고 우리가 사용하는 플랫폼이 어떤 동작을 할지 결정하고 내부적으로 어떻게 동작하는지 명확히 파악하고 사용하는 것이 중요합니다. 그렇기 때문에 관련 옵션이나 오픈소스 도큐먼트에 적혀있는 내용이 모든 것을 커버한다고 과장해서 생각하면 추후 운영시 이슈가 발생할 확률이 커질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 카프카를 사용할 때, '정확히 한번'을 달성하기 위한 방법을 알려드립니다. 크게 3단계에 대해 고려해야 하는데요. &lt;b&gt;프로듀서-&amp;gt;토픽, 토픽-&amp;gt;컨슈머-&amp;gt;프로듀서-&amp;gt;토픽, 토픽-&amp;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;- 프로듀서-&amp;gt;토픽 :&lt;b&gt; 멱등성 프로듀서&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 토픽-&amp;gt;컨슈머-&amp;gt;프로듀서-&amp;gt;토픽 : &lt;b&gt;트랜잭션 프로듀서/컨슈머&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 토픽-&amp;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;아무쪼록 카프카를 활용하면서 메시지 전달 처리를 고민하는데 많은 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;P.S.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://issues.apache.org/jira/browse/KAFKA-8587&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://issues.apache.org/jira/browse/KAFKA-8587&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1689764806564&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[KAFKA-8587] One producer per thread for Kafka Streams EOS - ASF JIRA&quot; data-og-description=&quot;Currently exactly-once producer is coupled with individual input partitions. This is not a well scaled solution for client application such as Kafka Streams, and the root cause is that EOS producer doesn't understand the topic partition move throughout con&quot; data-og-host=&quot;issues.apache.org&quot; data-og-source-url=&quot;https://issues.apache.org/jira/browse/KAFKA-8587&quot; data-og-url=&quot;https://issues.apache.org/jira/browse/KAFKA-8587&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://issues.apache.org/jira/browse/KAFKA-8587&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://issues.apache.org/jira/browse/KAFKA-8587&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[KAFKA-8587] One producer per thread for Kafka Streams EOS - ASF JIRA&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Currently exactly-once producer is coupled with individual input partitions. This is not a well scaled solution for client application such as Kafka Streams, and the root cause is that EOS producer doesn't understand the topic partition move throughout con&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;issues.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1689764810595&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apache Kafka&amp;rsquo;s Exactly-Once Semantics Are Now Easier &amp;amp; More Robust&quot; data-og-description=&quot;Kafka 2.5 brings important improvements to exactly-once semantics: enhanced producer error handling and simplified transactional APIs for more powerful, simplified production use cases.&quot; data-og-host=&quot;www.confluent.io&quot; data-og-source-url=&quot;https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/&quot; data-og-url=&quot;https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bDxuoa/hyTmzO2ayw/kEEO3m5Km5yh5TlapmrGZk/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/kzbQZ/hyTmyJntKv/btesjsa278vdVcKega8G6k/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/bwstzQ/hyTnHEGJTE/xv86d9ly1p97DvCnNWWvVK/img.png?width=2546&amp;amp;height=1428&amp;amp;face=0_0_2546_1428&quot;&gt;&lt;a href=&quot;https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bDxuoa/hyTmzO2ayw/kEEO3m5Km5yh5TlapmrGZk/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/kzbQZ/hyTmyJntKv/btesjsa278vdVcKega8G6k/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/bwstzQ/hyTnHEGJTE/xv86d9ly1p97DvCnNWWvVK/img.png?width=2546&amp;amp;height=1428&amp;amp;face=0_0_2546_1428');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka&amp;rsquo;s Exactly-Once Semantics Are Now Easier &amp;amp; More Robust&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kafka 2.5 brings important improvements to exactly-once semantics: enhanced producer error handling and simplified transactional APIs for more powerful, simplified production use cases.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.confluent.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/504</guid>
      <comments>https://voidmainvoid.tistory.com/504#entry504comment</comments>
      <pubDate>Tue, 20 Jun 2023 10:38:12 +0900</pubDate>
    </item>
    <item>
      <title>[개발자를 넘어 기술 리더로 가는 길]읽고 정리</title>
      <link>https://voidmainvoid.tistory.com/503</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;944&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xEtKz/btsknOGXucW/QZSqOF3lUEclkIM1kgpxkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xEtKz/btsknOGXucW/QZSqOF3lUEclkIM1kgpxkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xEtKz/btsknOGXucW/QZSqOF3lUEclkIM1kgpxkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxEtKz%2FbtsknOGXucW%2FQZSqOF3lUEclkIM1kgpxkk%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;138&quot; height=&quot;180&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;944&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/in/tanyareilly/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.linkedin.com/in/tanyareilly/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타냐 라일리는 중간급 엔지니어가 되었을 때 매니저가 되고 싶지 않았고 '스태프 엔지니어의 길'로 가고 싶었다.&amp;nbsp; 기술 전략 수립, 조직을 성공적으로 이끌기 위한 방법에 대해 고민했고 이에 대한 내용을 정리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;두 가지 진로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 크게 두가지 진로가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 위기 상황에서 침착함 유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동료들이 더 나은 일을 할 수 있도록 도움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 많은 사례들이 나와 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 스태프 엔지니어(기술 리더)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 불분명한 길&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타냐 라일리가 생각하는 스태프 엔지니어의 필요한 역할 3가지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 빅 픽처 관점의 사고력&lt;/b&gt; : 현재 상황에 대해 인지하고 기업에 필요한 것이 무엇인지 파악하여 n년 단위 프로젝트 진행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 성공적인 프로젝트 실행력&lt;/b&gt; : 정치적 자본, 영향력, 기업 문화 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 조직 차원의 레벨 업&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;위 3가지를 다루기 위해서는 반드시 &lt;b&gt;다양한 기술적 지식과 풍부한 경험&lt;/b&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;- 커뮤니케이션 및 리더십&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 복잡한 문제 탐색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 업무상 관점 제시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 멘토링, 후원, 위임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;빅 픽처 관점의 사고력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 엔지니어 조직은 다양한 배경지식 아래에 최고의 결정을 내리기 위해 노력한다. 이런 상황을 파악하기 위해서는 전체적인 맥락(context)를 파악해야만 한다. 그렇기 때문에 시니어 엔지니어는 항상 동일한 답을 하지 않는다. 오히려 때에 따라 다른 답을 내린다. 좋은 답을 내리기 위해서는 단순히 특정 기술의 장단점을 아는 것을 넘어서서 세부사항까지 완벽하게 알고 있어야만 한다.&lt;/p&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년 후, 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;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성공적인 프로젝트 실행력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째는 업무 선별을 하는 것이고 두번째는 시간 측면을 고려하는 것이다. 유한한 시간안에서 최고의 성과를 내기 위해서는 무엇을 어떻게 하는지가 가장 중요하다. 하지만 모든 사람에게 동일한 시간이 주어지는 것은 아니다. 근무시간은 동일하겠지만 각자의 삶, 휴가, 휴식, 질병 등으로 인해 수정이 필요할 수 있기 때문이다. 또한 업무에 집중하기 위해서는 포기해야하는 부분도 필연적으로 있다. 그러므로 이런 모든 부분에 대해서 관리가 필요하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;조직 차원의 레벨 업&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;훌륭한 스태프 엔지니어의 세번째 핵심 역량이다. 팀, 조직의 동료, 기업이나 업계 차원에서 엔지니어의 표준 및 스킬 역량을 향상시켜야할 책임이 있다. 스스로 롤모델이 되는 것 뿐만 아니라 무의식적으로 영향력을 바뤼하고 가르침과 멘토링을 통해 의도적으로 널리 영향을 발휘하는 것도 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이 책을 읽고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러모로 의외였던 내용으로 가득차 있었습니다. 사실 세상에 많은 개발자를 위한 교양서적이 많지만 와닿는 내용이 적힌 경우는 거의 없었습니다. 많은 교양 서적들은 문서화를 잘 하고 미래 가치를 보고 어떻게 개발을 진행할지 적혀있지만 실제로 어떻게 행해야할지 너무 구체적으로 적혀 있어서 작가의 색이 짙게 들어나는 경우도 있어서 공감이 가지 않을 때도 많았습니다. 하지만 이 책은 그런 선입견을 타파하는 아주 좋은 책입니다.&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;현재 내가 주니어 이더라도 혹은 지금 시니어더라도 현재 바로 집중해서 어떻게 개발자로 살아가야할지 보여주는 지침서라고 할 수 있습니다. X라고 하는 방향을 가지고 반드시 무엇을 해야한다고 강요하는 것이 아니라, '상황에 따라 변할 수 있다' 라는 가정하에 개발자가 나아가야할 방향을 설명하고 있습니다. 그렇기 때문에 글이 더 잘 읽히는 것 같습니다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발이야기</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/503</guid>
      <comments>https://voidmainvoid.tistory.com/503#entry503comment</comments>
      <pubDate>Mon, 19 Jun 2023 15:54:44 +0900</pubDate>
    </item>
    <item>
      <title>모던 데이터 플로우: 데이터 파이프라인을 잘 운영하는 방법</title>
      <link>https://voidmainvoid.tistory.com/502</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;모던 데이터 플로우 데이터 파이프라인을 잘 운영하는 방법.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKiFU1/btsjHGOFUmG/0Ijxk1sN0PngSwPf0WQqM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKiFU1/btsjHGOFUmG/0Ijxk1sN0PngSwPf0WQqM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKiFU1/btsjHGOFUmG/0Ijxk1sN0PngSwPf0WQqM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKiFU1%2FbtsjHGOFUmG%2F0Ijxk1sN0PngSwPf0WQqM0%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;390&quot; height=&quot;203&quot; data-filename=&quot;모던 데이터 플로우 데이터 파이프라인을 잘 운영하는 방법.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.confluent.io/events/kafka-summit-london-2022/modern-data-flow-data-pipelines-done-right/&quot;&gt;https://www.confluent.io/events/kafka-summit-london-2022/modern-data-flow-data-pipelines-done-right/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686554933004&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kafka Summit London 2022 Keynote | Jay Kreps, CEO, Confluent featuring Avi Perez, Wix.com&quot; data-og-description=&quot;Confluent is building the foundational platform for data in motion so any organization can innovate and win in a digital-first world.&quot; data-og-host=&quot;www.confluent.io&quot; data-og-source-url=&quot;https://www.confluent.io/events/kafka-summit-london-2022/modern-data-flow-data-pipelines-done-right/&quot; data-og-url=&quot;https://www.confluent.io/events/kafka-summit-london-2022/modern-data-flow-data-pipelines-done-right/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/HPDyi/hySYFgnIUc/pJzewZNksFO0tCNk77oFW1/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/mh5uW/hySW07wn3R/VWTS8FUelvvUwfvJsq5100/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748&quot;&gt;&lt;a href=&quot;https://www.confluent.io/events/kafka-summit-london-2022/modern-data-flow-data-pipelines-done-right/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.confluent.io/events/kafka-summit-london-2022/modern-data-flow-data-pipelines-done-right/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/HPDyi/hySYFgnIUc/pJzewZNksFO0tCNk77oFW1/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748,https://scrap.kakaocdn.net/dn/mh5uW/hySW07wn3R/VWTS8FUelvvUwfvJsq5100/img.png?width=748&amp;amp;height=748&amp;amp;face=0_0_748_748');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kafka Summit London 2022 Keynote | Jay Kreps, CEO, Confluent featuring Avi Perez, Wix.com&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Confluent is building the foundational platform for data in motion so any organization can innovate and win in a digital-first world.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.confluent.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpu32T/btsjGwTkbDM/KFEYzTSiKbZDQMTbLoP0O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpu32T/btsjGwTkbDM/KFEYzTSiKbZDQMTbLoP0O0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpu32T/btsjGwTkbDM/KFEYzTSiKbZDQMTbLoP0O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdpu32T%2FbtsjGwTkbDM%2FKFEYzTSiKbZDQMTbLoP0O0%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;2500&quot; height=&quot;1438&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메이븐에서 카프카 자바 라이브러리의 사용율이 급격하게 올라가는 것을 볼 수 있음. 그만큼 카프카의 사용량이 엄청나게 많아지고 있다는 것을 뜻함.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2508&quot; data-origin-height=&quot;1402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyNrg/btsjx4qnp6m/1G1IbEqla2hiHk3tProCR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyNrg/btsjx4qnp6m/1G1IbEqla2hiHk3tProCR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyNrg/btsjx4qnp6m/1G1IbEqla2hiHk3tProCR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyNrg%2Fbtsjx4qnp6m%2F1G1IbEqla2hiHk3tProCR1%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;2508&quot; height=&quot;1402&quot; data-origin-width=&quot;2508&quot; data-origin-height=&quot;1402&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2516&quot; data-origin-height=&quot;1412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKsnMa/btsjpDmq0t8/8mgnoa1DWzsopBkUQ5IS81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKsnMa/btsjpDmq0t8/8mgnoa1DWzsopBkUQ5IS81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKsnMa/btsjpDmq0t8/8mgnoa1DWzsopBkUQ5IS81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKsnMa%2FbtsjpDmq0t8%2F8mgnoa1DWzsopBkUQ5IS81%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;2516&quot; height=&quot;1412&quot; data-origin-width=&quot;2516&quot; data-origin-height=&quot;1412&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;. 그리고 이 2개가 속한 스트리밍 플랫폼. 물론. 이 2개의 타입을 나누는 것은 정확하지 않을 수 있고 때로는 파이프라인이 애플리케이션으로 전환될 때도 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 여기서 이 스트리밍 데이터가 옳은 시간에 올바른 포맷으로 올바른 팀에게 적절히 가고자 할 때는 어떻게 해야하는지 고민해야 한다는 점임.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2508&quot; data-origin-height=&quot;1414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJOyId/btsjGIszTye/7kk6aEvoRrMVjSgyXsW11k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJOyId/btsjGIszTye/7kk6aEvoRrMVjSgyXsW11k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJOyId/btsjGIszTye/7kk6aEvoRrMVjSgyXsW11k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJOyId%2FbtsjGIszTye%2F7kk6aEvoRrMVjSgyXsW11k%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;2508&quot; height=&quot;1414&quot; data-origin-width=&quot;2508&quot; data-origin-height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 해결하기 위해 다양한 솔루션들이 나왔었음. 그러나 각기 따로 운영되고 통합되지 못했음. 현재의 카프카는 필수조건이지만 카프카 자체로 모든 요구사항을 만족시키지 않다는 특징이 있음.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;KAFKA IS NECESSARY BUT NOT SUFFICIENT&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 대부분이 배치기반 데이터 처리에 집중되고 있음. 일부는 스트리밍을 지원하지만 2022년에 새로 만들어지는 플랫폼도 배치 위주로 개발되고 있음 이런 현상은 좀 회의적임. 이와 함께 제이 크랩스는 핸리 포드의 명언을 인용했음.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;핸리포드 - 만약 고객에게 무엇을 원하는지 물었다면 그들은 더 빠른 말(horse)라고 답했을 것이다&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만큼, 현재 나아가고 있는 미래는 스트림 데이터 처리임에도 불구하고 현재 배치 기반 플랫폼을 만들거나 관련 기술을 성장시키기 위해 노력하는 모습이 부정적으로 보이는 것으로 말함.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2502&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/COpN7/btsjFRjvUYr/3ekX5EvwxfLvJ1oD6uDFjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/COpN7/btsjFRjvUYr/3ekX5EvwxfLvJ1oD6uDFjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/COpN7/btsjFRjvUYr/3ekX5EvwxfLvJ1oD6uDFjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCOpN7%2FbtsjFRjvUYr%2F3ekX5EvwxfLvJ1oD6uDFjk%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;2502&quot; height=&quot;612&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2502&quot; data-origin-height=&quot;612&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;를 달성하기 위해서는 카프카라는 기술적인 개념에서 넘어서서 5가지의 핵심 개념을 항상 생각해야만함.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;1. 스트리밍&lt;/b&gt;&lt;br /&gt;&lt;b&gt;2. 탈중앙화&lt;/b&gt;&lt;br /&gt;&lt;b&gt;3. 선언적&lt;/b&gt;&lt;br /&gt;&lt;b&gt;4. 개발자 중심&lt;/b&gt;&lt;br /&gt;&lt;b&gt;5. 거버넌스 &amp;amp; 관측성&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조직에 데이터가 흐르고 있는 상태에서 잘 활용하기 위한 조건이라 보면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 스트리밍&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치로 많은 데이터가 사용되고 있지만 앞으로 스트림 데이터가 사용될 것임에 틀림없다고 생각함. '눈을 감고 횡단보도를 걷는다고 생각할 때 5분전 교통정보를 토대로 걸을 것인가?'라는 인용과 함께 실시간 데이터만이 실제 비즈니스를 운용하는데 중심이 됨을 설명. 스트림 데이터 처리가 완벽하게 정확하지 않을 수도 있고, 리소스가 더 많이 들 수도 있고, 운영상 회의적일 수 있음. 하지만 카프카는 이런 파이프라인을 운영하는데 적합하게 구성(확장성, 내구성 등)되어 있음.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2488&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tU4P0/btsjGm4swG8/5NKLGwpYE98EpkskeNWEJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tU4P0/btsjGm4swG8/5NKLGwpYE98EpkskeNWEJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tU4P0/btsjGm4swG8/5NKLGwpYE98EpkskeNWEJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtU4P0%2FbtsjGm4swG8%2F5NKLGwpYE98EpkskeNWEJ0%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;2488&quot; height=&quot;470&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2488&quot; data-origin-height=&quot;470&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; 실시간으로 들어오는 데이터를 한번에 잘 처리하는 것이 더 좋은 방법이라고 생각함.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 탈중앙화&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2462&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bToesR/btsjGlYLAlN/gTDNPtuUi8axb1MKN9Pctk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bToesR/btsjGlYLAlN/gTDNPtuUi8axb1MKN9Pctk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bToesR/btsjGlYLAlN/gTDNPtuUi8axb1MKN9Pctk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbToesR%2FbtsjGlYLAlN%2FgTDNPtuUi8axb1MKN9Pctk%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;2462&quot; height=&quot;630&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2462&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날 ETL은 상기 그림과 같이 단순하지만 복잡한 파이프라인을 운영하기 어려웠고 항상 중앙화된 데이터를 보아야만 했음. 실제로 우리가 비즈니스를 운영할 때는 매우 다양한 실시간/배치 데이터가 발생하고 있고 이를 상황에 따라 개별 추출하여 봐야할 경우도 있기 때문에 현대 비즈니스에는 부적합함.&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;2472&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v7UF0/btsjGmwAzdA/fUQ2nAZsLrReONJhFa7PW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v7UF0/btsjGmwAzdA/fUQ2nAZsLrReONJhFa7PW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v7UF0/btsjGmwAzdA/fUQ2nAZsLrReONJhFa7PW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv7UF0%2FbtsjGmwAzdA%2FfUQ2nAZsLrReONJhFa7PW0%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;2472&quot; height=&quot;596&quot; data-origin-width=&quot;2472&quot; data-origin-height=&quot;596&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2506&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tY6sl/btsjGxENxmV/WYDSK9kDALpJq6ArqsA8Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tY6sl/btsjGxENxmV/WYDSK9kDALpJq6ArqsA8Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tY6sl/btsjGxENxmV/WYDSK9kDALpJq6ArqsA8Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtY6sl%2FbtsjGxENxmV%2FWYDSK9kDALpJq6ArqsA8Z1%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;2506&quot; height=&quot;642&quot; data-origin-width=&quot;2506&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 이런 아키텍처에서는 REST+JSON 만큼이나 카프카를 스키마와 함께 사용하는 것이 중요하다고 설명함. 이 스키마를 토대로 데이터를 정확히, 잘 사용할 수 있기 때문. 다양한 요구사항을 가진 여러 고객들을 위해 토픽에 데이터를 넣고 활용할 수 있는 기회를 만들어주는 격.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2471&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AtTlu/btsjBuvEITX/5MZ3GkDAdW8i5sUdfAiuE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AtTlu/btsjBuvEITX/5MZ3GkDAdW8i5sUdfAiuE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AtTlu/btsjBuvEITX/5MZ3GkDAdW8i5sUdfAiuE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAtTlu%2FbtsjBuvEITX%2F5MZ3GkDAdW8i5sUdfAiuE0%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;2471&quot; height=&quot;632&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2471&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 일반적인 배치 프로세싱의 도구 사용 방법을 보여줌. A가 끝나면 B를 하고 C를 수행하는 이런 단계를 구성하는데 익숙함. 이런 순서 지향적 데이터 처리는 확장이 어렵기 때문에 데이터 처리 이슈를 찾기 어려움. 이를 스트림으로 구성하면 다음과 같음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p9vpU/btsjFRw1pqz/kOlCleRm8tgWVQ8s4KGVk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p9vpU/btsjFRw1pqz/kOlCleRm8tgWVQ8s4KGVk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p9vpU/btsjFRw1pqz/kOlCleRm8tgWVQ8s4KGVk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp9vpU%2FbtsjFRw1pqz%2FkOlCleRm8tgWVQ8s4KGVk0%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;2464&quot; height=&quot;608&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2524&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pamlZ/btsjH0sMtS9/M5f6LezUnULFsi2nBpybe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pamlZ/btsjH0sMtS9/M5f6LezUnULFsi2nBpybe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pamlZ/btsjH0sMtS9/M5f6LezUnULFsi2nBpybe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpamlZ%2FbtsjH0sMtS9%2FM5f6LezUnULFsi2nBpybe1%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;2524&quot; height=&quot;608&quot; data-origin-width=&quot;2524&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 DAG로 표현가능하기 때문에 구형의 순서지향 배치처리가 아니라 확장가능하고 여러 종류로 통합 가능한 처리를 지향.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 선언적&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 실제로 데이터를 처리할 때 어떤 것을 원하는지 정확히 적는것이 중요함. 이전에 배치성 데이터는 SQL을 잘 구성함으로서 데이터를 잘 뽑아낼 수 있었음.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2520&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8C9zH/btsjEl6gxxU/LXdJbdv8pTisVVnRwZ4vk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8C9zH/btsjEl6gxxU/LXdJbdv8pTisVVnRwZ4vk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8C9zH/btsjEl6gxxU/LXdJbdv8pTisVVnRwZ4vk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8C9zH%2FbtsjEl6gxxU%2FLXdJbdv8pTisVVnRwZ4vk1%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;2520&quot; height=&quot;616&quot; data-origin-width=&quot;2520&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림도 SQL로 구성하여 뽑아 낼 수 있음. ksqlDB 광고.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 개발자 중심&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 개발은 개발자 중심으로 되어야 하며 코드기반의 데이터 처리가 되어야 함. 또한 개발은 항상 발전이 되어야 하기 때문에 이를 지원하는 형태가 되어야함. 마지막으로 오픈 플랫폼을 통해 카프카 관련 파이프라인을 운영하기 위한 low level 코드와 같은 시스템이 관련 에코 시스템을 운영하기 좋아질 수 있다고 볼 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 새로운 커넥터가 여러 에코시스템에서 개발하고 지원하는 것을 예로 들 수 있음&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 거버넌스 &amp;amp; 관측성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이건 모든 데이터에서 중요함. 하지만 스트리밍에서는 이를 잘 다루어야함. 배치에서는 사실 다루기 쉬웠음. 되거나/안되거나 둘중 하나였고 실제로 안되었다면 다시 실행하면 되었기 때문임. 스트리밍은 배치와 다르게 투명하게 운영해야만 하며 이를 놓쳐서는 안됨. 또한 데이터를 사용할 때는 여러 법적인 측면도 잘 다루어야 하기 대문에 이 데이터가 어떻게 운영되고 있는지, 어떤 원천 데이터를 활용하고 있는지 파악이 되어야만함.&amp;nbsp;이를 위해 confluent에서는 Catalog, Schema, Lineage를 지원하고 있음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2502&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cgvdy/btsjFVTBtVM/x6abmmKEtEpzUMLKGVMuO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cgvdy/btsjFVTBtVM/x6abmmKEtEpzUMLKGVMuO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cgvdy/btsjFVTBtVM/x6abmmKEtEpzUMLKGVMuO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCgvdy%2FbtsjFVTBtVM%2Fx6abmmKEtEpzUMLKGVMuO1%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;2502&quot; height=&quot;612&quot; data-origin-width=&quot;2502&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2514&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2FOGz/btsjGH1zLgA/aCS1dKfnRmuOZJ3vFgY9q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2FOGz/btsjGH1zLgA/aCS1dKfnRmuOZJ3vFgY9q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2FOGz/btsjGH1zLgA/aCS1dKfnRmuOZJ3vFgY9q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2FOGz%2FbtsjGH1zLgA%2FaCS1dKfnRmuOZJ3vFgY9q0%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;2514&quot; height=&quot;616&quot; data-origin-width=&quot;2514&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkOAmm/btsjHdeQ0kX/KHQ46Wf1kkeO5k7aK81cKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkOAmm/btsjHdeQ0kX/KHQ46Wf1kkeO5k7aK81cKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkOAmm/btsjHdeQ0kX/KHQ46Wf1kkeO5k7aK81cKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkOAmm%2FbtsjHdeQ0kX%2FKHQ46Wf1kkeO5k7aK81cKK%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;2470&quot; height=&quot;524&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;524&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;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/502</guid>
      <comments>https://voidmainvoid.tistory.com/502#entry502comment</comments>
      <pubDate>Mon, 12 Jun 2023 17:04:42 +0900</pubDate>
    </item>
    <item>
      <title>golang struct type을 JSON으로 Print 하기</title>
      <link>https://voidmainvoid.tistory.com/501</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;golang struct type을 JSON으로 Print 하기.png&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mkMGk/btsjtAQC1mA/qT1C9IWEOhFBVzzHGdKeSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mkMGk/btsjtAQC1mA/qT1C9IWEOhFBVzzHGdKeSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mkMGk/btsjtAQC1mA/qT1C9IWEOhFBVzzHGdKeSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmkMGk%2FbtsjtAQC1mA%2FqT1C9IWEOhFBVzzHGdKeSK%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;126&quot; height=&quot;69&quot; data-filename=&quot;golang struct type을 JSON으로 Print 하기.png&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1680087117782&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
)

type Person struct {
	Name string
	Age  int
}

func main() {
	myStruct := Person{&quot;dvwy&quot;, 145}
	fmt.Println(&quot;=======&quot;)
	fmt.Println(myStruct)
	fmt.Println(prettyPrint(myStruct))
}

func prettyPrint(i interface{}) string {
	s, _ := json.MarshalIndent(i, &quot;&quot;, &quot;\t&quot;)
	return string(s)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680087148310&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{dvwy 145}
{
        &quot;Name&quot;: &quot;dvwy&quot;,
        &quot;Age&quot;: 145
}&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;a href=&quot;https://stackoverflow.com/a/51270134&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/a/51270134&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680087142446&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to print struct variables in console?&quot; data-og-description=&quot;How can I print (to the console) the Id, Title, Name, etc. of this struct in Golang? type Project struct { Id int64 &amp;#96;json:&amp;quot;project_id&amp;quot;&amp;#96; Title string &amp;#96;json:&amp;quot;title&amp;amp;qu...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/a/51270134&quot; data-og-url=&quot;https://stackoverflow.com/questions/24512112/how-to-print-struct-variables-in-console&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Q3uSq/hyR5oOnAYJ/iKtG5cAGdjMgCP5tNW6nI1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/a/51270134&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/a/51270134&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Q3uSq/hyR5oOnAYJ/iKtG5cAGdjMgCP5tNW6nI1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;How to print struct variables in console?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How can I print (to the console) the Id, Title, Name, etc. of this struct in Golang? type Project struct { Id int64 `json:&quot;project_id&quot;` Title string `json:&quot;title&amp;amp;qu...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/501</guid>
      <comments>https://voidmainvoid.tistory.com/501#entry501comment</comments>
      <pubDate>Wed, 29 Mar 2023 19:52:30 +0900</pubDate>
    </item>
    <item>
      <title>아파치 카프카 브로커 설정에서 listener와 advertised.isteners의 차이?</title>
      <link>https://voidmainvoid.tistory.com/500</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;아파치 카프카 브로커 설정에서 listener와 advertised.isteners의 차이?.png&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdBhJi/btsjG0UaPNA/nFbrdFWCVxVIGaH0tgo8KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdBhJi/btsjG0UaPNA/nFbrdFWCVxVIGaH0tgo8KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdBhJi/btsjG0UaPNA/nFbrdFWCVxVIGaH0tgo8KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdBhJi%2FbtsjG0UaPNA%2FnFbrdFWCVxVIGaH0tgo8KK%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;153&quot; height=&quot;105&quot; data-filename=&quot;아파치 카프카 브로커 설정에서 listener와 advertised.isteners의 차이?.png&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka 브로커의 설정에서 listener와 advertised.listeners 옵션은 다음과 같은 특징이 있다.&lt;/p&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;listener&lt;/b&gt;는 Kafka 브로커가 클라이언트로부터 듣고있는 네트워크 인터페이스와 포트를 나타낸다. 예를 들어, listener를 PLAINTEXT://localhost:9092로 설정하면 브로커는 localhost의 9092 포트에서 PLAINTEXT 프로토콜을 사용하여 들어오는 클라이언트 연결을 수신한다.&lt;/p&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;advertised.listeners&lt;/b&gt;는 Kafka 브로커가 클라이언트에게 알려주는 네트워크 인터페이스와 포트를 나타낸다. 클라이언트는 이 정보를 사용하여 브로커에 연결한다. 이 정보는 일반적으로 브로커가 외부에 노출되는 경우 사용된다. 예를 들어, advertised.listeners를 PLAINTEXT://example.com:9092로 설정하면 클라이언트는 example.com의 9092 포트에서 PLAINTEXT 프로토콜을 사용하여 브로커에 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결론&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;listener&lt;/b&gt;는 브로커가 실제로 수신 대기 중인 네트워크 인터페이스와 포트를 설정하고, &lt;b&gt;advertised.listeners&lt;/b&gt;는 브로커가 클라이언트에게 알려주는 네트워크 인터페이스와 포트를 설정한다.&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/500</guid>
      <comments>https://voidmainvoid.tistory.com/500#entry500comment</comments>
      <pubDate>Sun, 26 Mar 2023 21:08:35 +0900</pubDate>
    </item>
    <item>
      <title>spring boot HttpServletRequest 사용 쿠키 구현시 HttpSession.getAttribute(String) is null 에러 발생 대응</title>
      <link>https://voidmainvoid.tistory.com/499</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spring boot HttpServletRequest 사용 쿠키 구현시 HttpSession.getAttribute(String) is null 에러 발생 대응.png&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFxdn6/btsjGmQPQpq/N0TtwVNlVwS60OsokKSWt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFxdn6/btsjGmQPQpq/N0TtwVNlVwS60OsokKSWt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFxdn6/btsjGmQPQpq/N0TtwVNlVwS60OsokKSWt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFxdn6%2FbtsjGmQPQpq%2FN0TtwVNlVwS60OsokKSWt0%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;176&quot; height=&quot;119&quot; data-filename=&quot;spring boot HttpServletRequest 사용 쿠키 구현시 HttpSession.getAttribute(String) is null 에러 발생 대응.png&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring boot에서 쿠키/세션 로그인 기능 구현시 다음과 같은 에러를 만났습니다&lt;/p&gt;
&lt;pre id=&quot;code_1678801630147&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...HttpSession.getAttribute(String)&quot; is null&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분명히 다음과 같이 attribute를 제대로 설정했는데 왜그랬을까요?&lt;/p&gt;
&lt;pre id=&quot;code_1678801659073&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HttpSession session = request.getSession(true);
session.setAttribute(&quot;LOGIN_MEMBER&quot;, 123);&lt;/code&gt;&lt;/pre&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;- server : localhost:8080&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- client : localhost:3000&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- client는 server로 axios 요청을 함&lt;/p&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;1) CORS 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로스 도메인에 대응하여 spring boot에 다음과 같은 옵션을 줬습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678801779166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping(&quot;/**&quot;)
                .allowCredentials(true)
                .allowedHeaders(&quot;*&quot;)
                .allowedOrigins(&quot;http://localhost:3000&quot;);
    }
}&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;2) withCredential 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios 전역변수에 다음과 같이 설정하여 헤더에 session id가 넘어가도록 설정하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678801791019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from &quot;axios&quot;;
axios.defaults.withCredentials = true;&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Java &amp;amp; Scala</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/499</guid>
      <comments>https://voidmainvoid.tistory.com/499#entry499comment</comments>
      <pubDate>Tue, 14 Mar 2023 22:50:05 +0900</pubDate>
    </item>
    <item>
      <title>golang prviate repository에서 디펜던시 가져오는 방법</title>
      <link>https://voidmainvoid.tistory.com/498</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;golang prviate repository에서 디펜던시 가져오는 방법.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AvmDe/btr2tCh0O90/wWPeDphHHwv92vJvRLR2iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AvmDe/btr2tCh0O90/wWPeDphHHwv92vJvRLR2iK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AvmDe/btr2tCh0O90/wWPeDphHHwv92vJvRLR2iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAvmDe%2Fbtr2tCh0O90%2FwWPeDphHHwv92vJvRLR2iK%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;155&quot; height=&quot;157&quot; data-filename=&quot;golang prviate repository에서 디펜던시 가져오는 방법.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;golang private repository를 하위 모듈로 가져올 때 그냥 import를 실행하고 나면 다음과 같은 이슈가 종종 발생하곤합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678088857883&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ go get github.com/AndersonChoi/my-private-repo
go: downloading github.com/AndersonChoi/my-private-repo v0.0.0-20230306053459-dec1333da9d3
go: github.com/AndersonChoi/my-private-repo@v0.0.0-20230306053459-dec1333da9d3: verifying module: github.com/AndersonChoi/my-private-repo@v0.0.0-20230306053459-dec1333da9d3: reading https://sum.golang.org/lookup/github.com/AndersonChoi/my-private-repo@v0.0.0-20230306053459-dec1333da9d3: 404 Not Found
        server response: not found: github.com/AndersonChoi/my-private-repo@v0.0.0-20230306053459-dec1333da9d3: unrecognized import path &quot;github.com/AndersonChoi/my-private-repo&quot;: https fetch: Get &quot;https://github.com/AndersonChoi/my-private-repo?go-get=1&quot;: dial tcp 10.93.97.11:443: connect: connection refused&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에는 다음과 같이 명령어를 내리면 module로 디펜던시를 가져오게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678088928052&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ GOPRIVATE=&quot;github.com&quot; go get github.com/AndersonChoi/my-private-repo
go: downloading github.com/AndersonChoi/my-private-repo v0.0.0-20230306053459-dec1333da9d3
go: added github.com/AndersonChoi/my-private-repo v0.0.0-20230306053459-dec1333da9d3&lt;/code&gt;&lt;/pre&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;이를 해결하기 위해서는 vendor를 사용하면됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678089277588&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ go mod tidy                                                                                                     1 &amp;crarr;
$ go mod vendor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 vendor 디렉토리가 생긴 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678089298025&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ls
Dockerfile README.md  go.mod     go.sum     src        vendor&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/498</guid>
      <comments>https://voidmainvoid.tistory.com/498#entry498comment</comments>
      <pubDate>Mon, 6 Mar 2023 16:55:00 +0900</pubDate>
    </item>
    <item>
      <title>goroutine 함수 여러번 실행 결과값 기다리는 2가지 방법 - js callback 처럼</title>
      <link>https://voidmainvoid.tistory.com/497</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;goroutine 함수 여러번 실행 결과값 기다리는 방법 - js callback 처럼.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brExhi/btr1VePu54s/fBX2OGudRrRxkhhK2d3zn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brExhi/btr1VePu54s/fBX2OGudRrRxkhhK2d3zn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brExhi/btr1VePu54s/fBX2OGudRrRxkhhK2d3zn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrExhi%2Fbtr1VePu54s%2FfBX2OGudRrRxkhhK2d3zn0%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;137&quot; height=&quot;139&quot; data-filename=&quot;goroutine 함수 여러번 실행 결과값 기다리는 방법 - js callback 처럼.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;WaitGroup을 사용하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) sync.WaitGroup을 사용하여 대기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) go func 사용하여 goroutine 함수 호출&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;위 2가지 방법을 사용하면 여러번 실행된 결과값을 병렬 처리한 뒤 한개의 결과값으로 추출할 수 있습니다. 예제 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677828114025&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;strconv&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {

	result := 0
	count := 10
	var wg sync.WaitGroup // WaitGroup 선언
	wg.Add(count) // Wait 개수 지정

	for i := 1; i &amp;lt;= count; i++ {

		go func(goroutineNumber int) {
			defer wg.Done() // function이 종료될 때 Done() 호출로 1 감소
			time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
			result++
			fmt.Println(strconv.Itoa(goroutineNumber) + &quot; is done&quot;) // goroutine 번호
		}(i)
	}

	wg.Wait()
	fmt.Print(&quot;result:&quot; + strconv.Itoa(result)) // result는 1씩 증가 x 10번
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677828129362&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3 is done
5 is done
1 is done
4 is done
7 is done
8 is done
6 is done
2 is done
9 is done
10 is done
result:10&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;channel을 사용하는 방법&lt;/h2&gt;
&lt;pre id=&quot;code_1677829217843&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

func worker(id int, c chan int) {
    // 각 함수에서 실행할 작업
    time.Sleep(time.Second)
    result := id + 1
    // 결과값을 채널에 보내기
    c &amp;lt;- result
}

func main() {
    // 결과값을 저장할 채널 생성
    c := make(chan int)

    // 3번의 함수 실행
    for i := 0; i &amp;lt; 3; i++ {
        go worker(i, c)
    }

    // 채널을 통해 결과값 수집
    var results []int
    for i := 0; i &amp;lt; 3; i++ {
        result := &amp;lt;-c
        results = append(results, result)
    }

    // 결과값 출력
    fmt.Println(results)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;worker() 함수를 3번 실행시키고, 각 함수에서 반환된 값을 채널 c를 통해 수집. worker() 함수에서는 각각 다른 id 값을 받아와서 1을 더한 값을 결과값으로 반환. 이렇게 반환된 결과값은 c 채널에 보내지고, main() 함수에서는 채널을 통해 모든 결과값을 수집합니다. 마지막으로 수집된 결과값들을 출력합니다.&lt;/p&gt;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/497</guid>
      <comments>https://voidmainvoid.tistory.com/497#entry497comment</comments>
      <pubDate>Fri, 3 Mar 2023 16:22:11 +0900</pubDate>
    </item>
    <item>
      <title>go gin framework graceful shutdown 예제</title>
      <link>https://voidmainvoid.tistory.com/496</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gin-gonic.com/docs/examples/graceful-restart-or-stop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gin-gonic.com/docs/examples/graceful-restart-or-stop/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1677809833888&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Graceful restart or stop&quot; data-og-description=&quot;Do you want to graceful restart or stop your web server? There are some ways this can be done. We can use fvbock/endless to replace the default ListenAndServe. Refer issue #296 for more details. router := gin.Default() router.GET(&amp;quot;/&amp;quot;, handler) // [...] end&quot; data-og-host=&quot;gin-gonic.com&quot; data-og-source-url=&quot;https://gin-gonic.com/docs/examples/graceful-restart-or-stop/&quot; data-og-url=&quot;https://gin-gonic.com/docs/examples/graceful-restart-or-stop/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://gin-gonic.com/docs/examples/graceful-restart-or-stop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gin-gonic.com/docs/examples/graceful-restart-or-stop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Graceful restart or stop&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Do you want to graceful restart or stop your web server? There are some ways this can be done. We can use fvbock/endless to replace the default ListenAndServe. Refer issue #296 for more details. router := gin.Default() router.GET(&quot;/&quot;, handler) // [...] end&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gin-gonic.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;gin framework.png&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwq5Dl/btr1I9aogov/qV5iqb0kCToMuiObfFRDQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwq5Dl/btr1I9aogov/qV5iqb0kCToMuiObfFRDQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwq5Dl/btr1I9aogov/qV5iqb0kCToMuiObfFRDQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcwq5Dl%2Fbtr1I9aogov%2FqV5iqb0kCToMuiObfFRDQ1%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;281&quot; height=&quot;137&quot; data-filename=&quot;gin framework.png&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gin은 golang에서 많이 쓰이는 웹프레임워크입니다. graceful shutdown을 적용 유무에 따른 동작 방식을 알아보고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) graceful shutdown 적용한 경우&lt;/h3&gt;
&lt;pre id=&quot;code_1677809901269&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;os&quot;
	&quot;os/signal&quot;
	&quot;syscall&quot;
	&quot;time&quot;

	&quot;github.com/gin-gonic/gin&quot;
)

func main() {
	router := gin.Default()
	router.GET(&quot;/&quot;, func(c *gin.Context) {
		time.Sleep(5 * time.Second)
		c.String(http.StatusOK, &quot;Welcome Gin Server&quot;)
	})

	srv := &amp;amp;http.Server{
		Addr:    &quot;:8080&quot;,
		Handler: router,
	}

	go func() {
		// service connections
		if err := srv.ListenAndServe(); err != nil &amp;amp;&amp;amp; err != http.ErrServerClosed {
			log.Fatalf(&quot;listen: %s\n&quot;, err)
		}
	}()

	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 5 seconds.
	quit := make(chan os.Signal)
	// kill (no param) default send syscanll.SIGTERM
	// kill -2 is syscall.SIGINT
	// kill -9 is syscall. SIGKILL but can&quot;t be catch, so don't need add it
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	&amp;lt;-quit
	log.Println(&quot;Shutdown Server ...&quot;)

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal(&quot;Server Shutdown:&quot;, err)
	}
	// catching ctx.Done(). timeout of 5 seconds.
	select {
	case &amp;lt;-ctx.Done():
		log.Println(&quot;timeout of 5 seconds.&quot;)
	}
	log.Println(&quot;Server exiting&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 후 localhost:8080에 호출을 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677809947255&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl localhost:8080/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 해당 process를 찾아 kill -term 명령어를 내리면&lt;/p&gt;
&lt;pre id=&quot;code_1677809957261&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kill -term 80021&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 로그와 함께 안전하게 종료됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677809987127&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2021/03/03 22:16:23 Shutdown Server ...
[GIN] 2021/03/03 - 22:16:27 | 200 |  5.000389654s |       127.0.0.1 | GET      &quot;/&quot;
2021/03/03 22:16:28 timeout of 5 seconds.
2021/03/03 22:16:28 Server exiting&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 동시에 안전하게 종료되기 전 요청에 대해서 리턴을 수행합니다. 그렇기 때문에 요청이 끊키지 않습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677810230028&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Welcome Gin Server&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) graceful shutdown 적용하지 않은 경우&lt;/h3&gt;
&lt;pre id=&quot;code_1677810198266&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;net/http&quot;
	&quot;time&quot;

	&quot;github.com/gin-gonic/gin&quot;
)

func main() {
	router := gin.Default()
	router.GET(&quot;/&quot;, func(c *gin.Context) {
		time.Sleep(5 * time.Second)
		c.String(http.StatusOK, &quot;Welcome Gin Server&quot;)
	})

	err := router.Run(&quot;:8080&quot;)
	if err != nil {
		panic(err)
		return
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 후 localhost:8080에 호출을 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677810277123&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl localhost:8080&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 해당 process를 찾아 kill -term 명령어를 내리면&lt;/p&gt;
&lt;pre id=&quot;code_1677810284278&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kill -term 80529&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 에러가 발생하고 원치 않은 리턴값이 노출됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677810292619&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl localhost:8080/
curl: (52) Empty reply from server&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/496</guid>
      <comments>https://voidmainvoid.tistory.com/496#entry496comment</comments>
      <pubDate>Fri, 3 Mar 2023 11:25:59 +0900</pubDate>
    </item>
    <item>
      <title>windows의 WSL환경에서 아파치 카프카 설치, 실행하는 방법</title>
      <link>https://voidmainvoid.tistory.com/495</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) git 설치&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;253&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/63cME/btr0zSoCiaf/U15FHxTz6qpX646bLhNBGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/63cME/btr0zSoCiaf/U15FHxTz6qpX646bLhNBGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/63cME/btr0zSoCiaf/U15FHxTz6qpX646bLhNBGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F63cME%2Fbtr0zSoCiaf%2FU15FHxTz6qpX646bLhNBGk%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;409&quot; height=&quot;96&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;253&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://git-scm.com/download/win&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://git-scm.com/download/win&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1677232163025&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Git - Downloading Package&quot; data-og-description=&quot;Download for Windows Click here to download the latest (2.39.2) 32-bit version of Git for Windows. This is the most recent maintained build. It was released 10 days ago, on 2023-02-14. Other Git for Windows downloads Standalone Installer 32-bit Git for Win&quot; data-og-host=&quot;git-scm.com&quot; data-og-source-url=&quot;https://git-scm.com/download/win&quot; data-og-url=&quot;https://git-scm.com/download/win&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://git-scm.com/download/win&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://git-scm.com/download/win&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Git - Downloading Package&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Download for Windows Click here to download the latest (2.39.2) 32-bit version of Git for Windows. This is the most recent maintained build. It was released 10 days ago, on 2023-02-14. Other Git for Windows downloads Standalone Installer 32-bit Git for Win&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;git-scm.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상기 URL에서 windows용 git을 설치합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) WSL 환경 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows Subsystem for Linux는 리눅스 또는 맥환경처럼 bash쉘을 활용하는 것을 뜻합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/about&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://learn.microsoft.com/ko-kr/windows/wsl/about&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1677228431373&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Linux용 Windows 하위 시스템이란?&quot; data-og-description=&quot;다양한 버전 및 이를 사용하는 방법을 포함하여 Linux용 Windows 하위 시스템에 대해 알아봅니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/about&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/about&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QVsOb/hyRJKc6maV/HVO4hdjekhqYkalZCMOWtk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/about&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/about&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QVsOb/hyRJKc6maV/HVO4hdjekhqYkalZCMOWtk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Linux용 Windows 하위 시스템이란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;다양한 버전 및 이를 사용하는 방법을 포함하여 Linux용 Windows 하위 시스템에 대해 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로&lt;b&gt;Windows 기능 켜기/끄기 로 가서 다음 내역을 활성화 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;- Linux용 Windows 하위 시스템&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;- Windows 하이퍼바이저 플랫폼&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;- 가상 머신 플랫폼&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷(2).png&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czUQSD/btr0BA1ZnYv/jT1TweAc939dLopBKwSemk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czUQSD/btr0BA1ZnYv/jT1TweAc939dLopBKwSemk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czUQSD/btr0BA1ZnYv/jT1TweAc939dLopBKwSemk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczUQSD%2Fbtr0BA1ZnYv%2FjT1TweAc939dLopBKwSemk%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;217&quot; height=&quot;231&quot; data-filename=&quot;스크린샷(2).png&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직까지는 터미널에서 &lt;b&gt;bash&lt;/b&gt;를 쳐도 정상동작하지 않는점 참고.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1725&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbxHAI/btr0Gb8I6i1/6M2w1JdaUgtkrWDXTo9ez1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbxHAI/btr0Gb8I6i1/6M2w1JdaUgtkrWDXTo9ez1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbxHAI/btr0Gb8I6i1/6M2w1JdaUgtkrWDXTo9ez1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbxHAI%2Fbtr0Gb8I6i1%2F6M2w1JdaUgtkrWDXTo9ez1%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;637&quot; height=&quot;171&quot; data-origin-width=&quot;1725&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 &lt;b&gt;Ubuntu&lt;/b&gt;를 &lt;b&gt;마이크로소프트 스토어&lt;/b&gt;에서 설치합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1435&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzlNd/btr0HRIJzSj/feMp6N8GQmrSpdcWsOAFh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzlNd/btr0HRIJzSj/feMp6N8GQmrSpdcWsOAFh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzlNd/btr0HRIJzSj/feMp6N8GQmrSpdcWsOAFh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkzlNd%2Fbtr0HRIJzSj%2FfeMp6N8GQmrSpdcWsOAFh0%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;641&quot; height=&quot;278&quot; data-origin-width=&quot;1435&quot; data-origin-height=&quot;622&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package&quot;&gt;이전 버전 WSL의 수동 설치 단계 | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1677246918933&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;이전 버전 WSL의 수동 설치 단계&quot; data-og-description=&quot;wsl install 명령을 사용하지 않고 이전 버전의 Windows에 WSL을 수동으로 설치하는 방법에 대한 단계별 지침입니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install-manual&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Vm7QC/hyRJNOsRps/TGtILvBrSNV53JVBghsDN1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/e3jso/hyRJJkZKtK/AKuLly5J8ooK0JJcsltkmK/img.png?width=1802&amp;amp;height=1399&amp;amp;face=0_0_1802_1399,https://scrap.kakaocdn.net/dn/cIqexZ/hyRJVsb679/Ocm5YdYu7bTNLIgmjO1MG0/img.png?width=1593&amp;amp;height=1060&amp;amp;face=0_0_1593_1060&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Vm7QC/hyRJNOsRps/TGtILvBrSNV53JVBghsDN1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/e3jso/hyRJJkZKtK/AKuLly5J8ooK0JJcsltkmK/img.png?width=1802&amp;amp;height=1399&amp;amp;face=0_0_1802_1399,https://scrap.kakaocdn.net/dn/cIqexZ/hyRJVsb679/Ocm5YdYu7bTNLIgmjO1MG0/img.png?width=1593&amp;amp;height=1060&amp;amp;face=0_0_1593_1060');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;이전 버전 WSL의 수동 설치 단계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;wsl install 명령을 사용하지 않고 이전 버전의 Windows에 WSL을 수동으로 설치하는 방법에 대한 단계별 지침입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cedmiF/btr0BWxCioR/CCstyfY7N4epen6zQ89bkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cedmiF/btr0BWxCioR/CCstyfY7N4epen6zQ89bkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cedmiF/btr0BWxCioR/CCstyfY7N4epen6zQ89bkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcedmiF%2Fbtr0BWxCioR%2FCCstyfY7N4epen6zQ89bkK%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;396&quot; height=&quot;158&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 터미널을 실행시키고 명령어를 실행할 때는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bash&lt;/b&gt; &lt;/span&gt;명령을 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNG8DD/btr0Gb1PNdK/AmSd86EVK5NXaSNiuhbUjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNG8DD/btr0Gb1PNdK/AmSd86EVK5NXaSNiuhbUjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNG8DD/btr0Gb1PNdK/AmSd86EVK5NXaSNiuhbUjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNG8DD%2Fbtr0Gb1PNdK%2FAmSd86EVK5NXaSNiuhbUjk%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;522&quot; height=&quot;224&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) JDK 1.8 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널을 실행하고 &lt;b&gt;bash&lt;/b&gt;를 입력하여 쉘을 변경합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677248005041&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 아래 명령어를 실행하여 &lt;b&gt;openjdk-8-jdk를 설치&lt;/b&gt;합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677248037218&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt update
$ sudo apt install openjdk-8-jdk&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;설치가 완료되면 아래 명령어를 쳐서 openjdk-8-jdk가 잘 설치되었는지 확인합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677228672643&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ java -version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mLkxD/btr0BXpr1dH/7K0xIoe4PbsbM17ikaYc9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mLkxD/btr0BXpr1dH/7K0xIoe4PbsbM17ikaYc9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mLkxD/btr0BXpr1dH/7K0xIoe4PbsbM17ikaYc9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmLkxD%2Fbtr0BXpr1dH%2F7K0xIoe4PbsbM17ikaYc9K%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;450&quot; height=&quot;112&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 스크린샷과 같이 현재 자바 버전이 나오게 된다면 설치가 잘 된 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) 카프카 바이너리 파일 다운로드 및 압축 풀기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kafka.apache.org/downloads&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1677228724054&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apache Kafka&quot; data-og-description=&quot;Apache Kafka: A Distributed Streaming Platform.&quot; data-og-host=&quot;kafka.apache.org&quot; data-og-source-url=&quot;https://kafka.apache.org/downloads&quot; data-og-url=&quot;https://kafka.apache.org/downloads&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://kafka.apache.org/downloads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kafka.apache.org/downloads&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Apache Kafka: A Distributed Streaming Platform.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kafka.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상기 url에서 카프카 바이너리파일을 다운로드할 수 있습니다. 여기서는&lt;b&gt; kafka 2.7.0을 다운로드하여 테스트&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck89Xx/btr0zTOwsBF/7A6oonXQ5GuKdnQC00N920/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck89Xx/btr0zTOwsBF/7A6oonXQ5GuKdnQC00N920/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck89Xx/btr0zTOwsBF/7A6oonXQ5GuKdnQC00N920/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck89Xx%2Fbtr0zTOwsBF%2F7A6oonXQ5GuKdnQC00N920%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;675&quot; height=&quot;212&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kafka_2.12-2.7.0.tgz를 다운로드, 압축을 풀고 적절한 디렉토리로 옮깁니다. 압축을 풀 때는 알집과 같은 도구를 사용해도 되고 아니면 터미널 환경에서 다음 명령어로 압축을 풀 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677229029991&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cd Downloads
$ tar -xvf kafka_2.12-2.7.0.tgz
$ ls
kafka_2.12-2.7.0
kafka_2.12-2.7.0.tgz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 tgz와 디렉토리가 보인다면 정상적으로 압축이 풀렸다고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) 주키퍼, 카프카 브로커 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주키퍼는 다음 명령어로 실행&lt;/b&gt; 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677232358277&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/zookeeper-server-start.sh config/zookeeper.properties
[2023-02-24 18:52:26,944] INFO Reading configuration from: config/zookeeper.properties (org.apache.zookeeper.server.quorum.QuorumPeerConfig)
[2023-02-24 18:52:26,946] WARN config/zookeeper.properties is relative. Prepend ./ to indicate that you're sure! (org.apache.zookeeper.server.quorum.QuorumPeerConfig)
[2023-02-24 18:52:26,951] WARN UserschocoDownloadskafka_2.12-2.7.0/zookeeper is relative. Prepend ./ to indicate that you're sure! (org.apache.zookeeper.server.quorum.QuorumPeerConfig)
[2023-02-24 18:52:26,957] INFO clientPortAddress is 0.0.0.0:2181 (org.apa
...&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_1677232408251&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/kafka-server-start.sh config/server.properties
[2023-02-24 18:53:13,530] INFO Registered kafka:type=kafka.Log4jController MBean (kafka.utils.Log4jControllerRegistration$)
[2023-02-24 18:53:14,078] INFO Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation (org.apache.zookeeper.common.X509Util)
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5) 카프카 명령어 테스트하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 터미널 탭을 열고 카프카 바이너리 위치로 이동하여 다음 코드를 실행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677232518192&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ bin/kafka-topics.sh --bootstrap-server localhost:9092 --topic test --create&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행이 잘 되었다면 다음과 같이 토픽 이름이 노출됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;303&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wENAa/btr0IF8P72O/iihGta37LrvwKTG5ktM5E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wENAa/btr0IF8P72O/iihGta37LrvwKTG5ktM5E0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wENAa/btr0IF8P72O/iihGta37LrvwKTG5ktM5E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwENAa%2Fbtr0IF8P72O%2FiihGta37LrvwKTG5ktM5E0%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;634&quot; height=&quot;118&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;303&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/495</guid>
      <comments>https://voidmainvoid.tistory.com/495#entry495comment</comments>
      <pubDate>Fri, 24 Feb 2023 18:00:41 +0900</pubDate>
    </item>
    <item>
      <title>intellij에서 golang 프로젝트 인식이 잘 안될때</title>
      <link>https://voidmainvoid.tistory.com/494</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;intellij에서 golang을 최초로 실행 시키고 난뒤에&lt;/p&gt;
&lt;pre id=&quot;code_1677043717694&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ go mod init myapplication&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;프로젝트가 정상적으로 라이브러리들을 Import시키지 못할 때가 있습니다. 그럴 경우에는 cmd + , 를 눌러서 &lt;b&gt;Preferences&lt;/b&gt;로 간 뒤 &lt;b&gt;Go Modules&lt;/b&gt;의 &lt;b&gt;Enable Go modules integration&lt;/b&gt;을 체크하면 싱크됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2690&quot; data-origin-height=&quot;2030&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xECpu/btr0fJS6U1F/uyktBUChtKbxbg2oz5CDA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xECpu/btr0fJS6U1F/uyktBUChtKbxbg2oz5CDA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xECpu/btr0fJS6U1F/uyktBUChtKbxbg2oz5CDA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxECpu%2Fbtr0fJS6U1F%2FuyktBUChtKbxbg2oz5CDA0%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;2690&quot; height=&quot;2030&quot; data-origin-width=&quot;2690&quot; data-origin-height=&quot;2030&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱크가 완료된 go.mod 파일 모습&lt;/p&gt;
&lt;pre id=&quot;code_1677043780196&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module myapplication

go 1.19

require (
	github.com/gin-gonic/gin v1.9.0
	github.com/prometheus/client_golang v1.14.0
)

require (
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/bytedance/sonic v1.8.0 // indirect
	github.com/cespare/xxhash/v2 v2.1.2 // indirect
	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/go-playground/locales v0.14.1 // indirect
...&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;</description>
      <category>Programming Language/golang</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/494</guid>
      <comments>https://voidmainvoid.tistory.com/494#entry494comment</comments>
      <pubDate>Wed, 22 Feb 2023 14:31:07 +0900</pubDate>
    </item>
    <item>
      <title>맥 벤투라 디스플레이 해상도 조정하기</title>
      <link>https://voidmainvoid.tistory.com/492</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7upyX/btrUbqSjMLY/WWC6cFKrrkaaLIq5vHLb01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7upyX/btrUbqSjMLY/WWC6cFKrrkaaLIq5vHLb01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7upyX/btrUbqSjMLY/WWC6cFKrrkaaLIq5vHLb01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7upyX%2FbtrUbqSjMLY%2FWWC6cFKrrkaaLIq5vHLb01%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;479&quot; height=&quot;369&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥 벤투라에서 디스플레이 옵션에서 확장된 해상도를 확인하기 위해서는 &lt;b&gt;5개 디스플레이 옵션 위에서 마우스 우클릭을 하여 '목록 보기'&lt;/b&gt;를 클릭하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;757&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz1jC9/btrUa2xrCQI/xJEg9jdaFUOX7gzDvfKCdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz1jC9/btrUa2xrCQI/xJEg9jdaFUOX7gzDvfKCdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz1jC9/btrUa2xrCQI/xJEg9jdaFUOX7gzDvfKCdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz1jC9%2FbtrUa2xrCQI%2FxJEg9jdaFUOX7gzDvfKCdK%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;783&quot; height=&quot;757&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;757&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 모든 해상도 보기 버튼을 누르면 hidpi가 적용되지 않은 해상도도 함께 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;827&quot; data-origin-height=&quot;801&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HzRHt/btrUfKu0rUT/Uxj91wWeZLLyUTC8NAF511/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HzRHt/btrUfKu0rUT/Uxj91wWeZLLyUTC8NAF511/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HzRHt/btrUfKu0rUT/Uxj91wWeZLLyUTC8NAF511/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHzRHt%2FbtrUfKu0rUT%2FUxj91wWeZLLyUTC8NAF511%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;827&quot; height=&quot;801&quot; data-origin-width=&quot;827&quot; data-origin-height=&quot;801&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발이야기</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/492</guid>
      <comments>https://voidmainvoid.tistory.com/492#entry492comment</comments>
      <pubDate>Wed, 21 Dec 2022 15:02:11 +0900</pubDate>
    </item>
    <item>
      <title>RestHighLevelClient로 구현한 idempotence 데이터 적재</title>
      <link>https://voidmainvoid.tistory.com/491</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0tLFL/btrSkFcSd1T/yLpk7vqxkUj815wpF3DY9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0tLFL/btrSkFcSd1T/yLpk7vqxkUj815wpF3DY9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0tLFL/btrSkFcSd1T/yLpk7vqxkUj815wpF3DY9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0tLFL%2FbtrSkFcSd1T%2FyLpk7vqxkUj815wpF3DY9K%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;128&quot; height=&quot;59&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SHA-256이란?&lt;/b&gt; &lt;a href=&quot;http://wiki.hash.kr/index.php/SHA256&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://wiki.hash.kr/index.php/SHA256&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1669688408193&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SHA256 - 해시넷&quot; data-og-description=&quot;SHA-256은 SHA(Secure Hash Algorithm) 알고리즘의 한 종류로서 256비트로 구성되며 64자리 문자열을 반환한다. SHA-256은 미국의 국립표준기술연구소(NIST; National Institute of Standards and Technology)에 의해 공표된 &quot; data-og-host=&quot;wiki.hash.kr&quot; data-og-source-url=&quot;http://wiki.hash.kr/index.php/SHA256&quot; data-og-url=&quot;http://wiki.hash.kr/index.php/SHA256&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dbWI3C/hyQJFjjP66/NDkx5Jemk1XpEygsMWcJuK/img.png?width=450&amp;amp;height=210&amp;amp;face=0_0_450_210&quot;&gt;&lt;a href=&quot;http://wiki.hash.kr/index.php/SHA256&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://wiki.hash.kr/index.php/SHA256&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dbWI3C/hyQJFjjP66/NDkx5Jemk1XpEygsMWcJuK/img.png?width=450&amp;amp;height=210&amp;amp;face=0_0_450_210');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SHA256 - 해시넷&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SHA-256은 SHA(Secure Hash Algorithm) 알고리즘의 한 종류로서 256비트로 구성되며 64자리 문자열을 반환한다. SHA-256은 미국의 국립표준기술연구소(NIST; National Institute of Standards and Technology)에 의해 공표된&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wiki.hash.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;SHA-256 해시 함수는 어떤 길이의 값을 입력하더라도 256비트의 고정된 결과값을 출력한다. 일반적으로 입력값이 조금만 변동하여도 출력값이 완전히 달라지기 때문에 출력값을 토대로 입력값을 유추하는 것은 거의 불가능하다. 아주 작은 확률로 입력값이 다름에도 불구하고 출력값이 같은 경우가 발생하는데 이것을 충돌이라고 한다. 이러한 충돌의 발생 확률이 낮을수록 좋은 함수라고 평가된다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 ES의 Document의 id를 적재하고자 하는 데이터의 HASH로 사용하면 멱등성 적재가 되지 않을까?&lt;/p&gt;
&lt;pre id=&quot;code_1669688513730&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost(&quot;localhost&quot;, 9200)));
BulkRequest request = new BulkRequest();

String data = &quot;{\&quot;data\&quot;:{\&quot;type\&quot;:\&quot;company\&quot;,\&quot;name\&quot;:\&quot;es\&quot;,\&quot;time\&quot;:\&quot;2022-01-29T01:59:00.275Z\&quot;}}&quot;;
String index = &quot;test-log&quot;;
request.add(new IndexRequest(index)
        .source(data, XContentType.JSON)
        .id(encrypt(data)));

client.bulk(request, RequestOptions.DEFAULT);
client.close();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;encrypt 메서드&lt;/p&gt;
&lt;pre id=&quot;code_1669688531704&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static String encrypt(String text) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance(&quot;SHA-256&quot;);
    md.update(text.getBytes());
    return bytesToHex(md.digest());
}
private static String bytesToHex(byte[] bytes) {
    StringBuilder builder = new StringBuilder();
    for (byte b : bytes) {
        builder.append(String.format(&quot;%02x&quot;, b));
    }
    return builder.toString();
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Elasticsearch</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/491</guid>
      <comments>https://voidmainvoid.tistory.com/491#entry491comment</comments>
      <pubDate>Tue, 29 Nov 2022 11:22:32 +0900</pubDate>
    </item>
    <item>
      <title>ElasticsearchClient 7.17.7 기준 java client example code</title>
      <link>https://voidmainvoid.tistory.com/490</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;118&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEvm5X/btrSlXXn8H2/aq382QXcU7LtcZkit4hSe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEvm5X/btrSlXXn8H2/aq382QXcU7LtcZkit4hSe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEvm5X/btrSlXXn8H2/aq382QXcU7LtcZkit4hSe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEvm5X%2FbtrSlXXn8H2%2Faq382QXcU7LtcZkit4hSe0%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;118&quot; height=&quot;60&quot; data-origin-width=&quot;118&quot; data-origin-height=&quot;60&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;1) host, port&amp;nbsp; 주입&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1669622233355&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RestClient restClient = RestClient.builder(
    new HttpHost(&quot;localhost&quot;, 9200, &quot;http&quot;),
    new HttpHost(&quot;localhost&quot;, 9201, &quot;http&quot;)).build();
    
    

BulkRequest.Builder br = new BulkRequest.Builder();
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
ElasticsearchClient  esClient = new ElasticsearchClient(transport);&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;2) String으로 된 JSON 데이터 정의&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1669622321227&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String json = &quot;{\&quot;test\&quot;:1}&quot;
Reader input = new StringReader(json);
IndexRequest&amp;lt;JsonData&amp;gt; request = IndexRequest.of(i -&amp;gt; i
        .index(&quot;test-log&quot;)  //set index
        .withJson(input)
);&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;3) 전송&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1669622327363&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IndexResponse response = esClient.index(request);
log.info(&quot;Indexed with version &quot; + response.version());&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-rest-low-usage-initialization.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-rest-low-usage-initialization.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1669622223480&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Initialization | Elasticsearch Java API Client [7.17] | Elastic&quot; data-og-description=&quot;A RestClient instance can be built through the corresponding RestClientBuilder class, created via RestClient#builder(HttpHost...) static method. The only required argument is one or more hosts that the client will communicate with, provided as instances of&quot; data-og-host=&quot;www.elastic.co&quot; data-og-source-url=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-rest-low-usage-initialization.html&quot; data-og-url=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-rest-low-usage-initialization.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-rest-low-usage-initialization.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-rest-low-usage-initialization.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Initialization | Elasticsearch Java API Client [7.17] | Elastic&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A RestClient instance can be built through the corresponding RestClientBuilder class, created via RestClient#builder(HttpHost...) static method. The only required argument is one or more hosts that the client will communicate with, provided as instances of&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.elastic.co&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1669622423797&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Indexing single documents | Elasticsearch Java API Client [7.17] | Elastic&quot; data-og-description=&quot;Indexing single documentsedit The Java API Client offers several ways to index data: you can provide application objects that will be automatically mapped to JSON, or you can provide raw JSON data. Using application objects is more suited to applications w&quot; data-og-host=&quot;www.elastic.co&quot; data-og-source-url=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html&quot; data-og-url=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Indexing single documents | Elasticsearch Java API Client [7.17] | Elastic&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Indexing single documentsedit The Java API Client offers several ways to index data: you can provide application objects that will be automatically mapped to JSON, or you can provide raw JSON data. Using application objects is more suited to applications w&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.elastic.co&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Elasticsearch</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/490</guid>
      <comments>https://voidmainvoid.tistory.com/490#entry490comment</comments>
      <pubDate>Mon, 28 Nov 2022 16:59:04 +0900</pubDate>
    </item>
    <item>
      <title>커넥트 REST API 확장 플러그인 : Connect Rest Extension Plugin</title>
      <link>https://voidmainvoid.tistory.com/489</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KIP-285 Connect Rest Extension Plugin.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR2Gfi/btrNMbf3dbg/5VUNj2gyULlIk05KT4uEV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR2Gfi/btrNMbf3dbg/5VUNj2gyULlIk05KT4uEV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR2Gfi/btrNMbf3dbg/5VUNj2gyULlIk05KT4uEV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR2Gfi%2FbtrNMbf3dbg%2F5VUNj2gyULlIk05KT4uEV0%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;285&quot; height=&quot;98&quot; data-filename=&quot;KIP-285 Connect Rest Extension Plugin.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Connect Framework offers REST API that is used to mange the lifecycle of the connector. Its imperative in most enterprises to secure the API and also add authorization to the end points. We could add the ability for authentication and authorization in the framework. But the security requirements are so broad that it's not practical to support all of them in the framework. Hence we must provide ability for users to plug resources that help achieve the required capabilities.&lt;br /&gt;&lt;br /&gt;While security is prime use cases for this extension. Its not limited to that. Some of the common use cases are &lt;br /&gt;&lt;br /&gt;- Build a custom Authentication filter &lt;br /&gt;- Build a custom Authorization filter &lt;br /&gt;- &lt;b&gt;Complex extensions can even provide filters that rewrite/validate the connector requests to enforce additional constraints on the connector configurations&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-285%3A+Connect+Rest+Extension+Plugin&quot;&gt;https://cwiki.apache.org/confluence/display/KAFKA/KIP-285%3A+Connect+Rest+Extension+Plugin&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1664884554387&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;KIP-285: Connect Rest Extension Plugin - Apache Kafka - Apache Software Foundation&quot; data-og-description=&quot;Status Current state:&amp;nbsp;Accepted Discussion thread: here&amp;nbsp; JIRA: KAFKA-6776 - 이슈 세부사항 가져오는 중... 상태 PR :&amp;nbsp;https://github.com/apache/kafka/pull/4931 Released: 2.0.0 Motivation Connect Framework offers REST API that is used to mange t&quot; data-og-host=&quot;cwiki.apache.org&quot; data-og-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-285%3A+Connect+Rest+Extension+Plugin&quot; data-og-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-285%3A+Connect+Rest+Extension+Plugin&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-285%3A+Connect+Rest+Extension+Plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cwiki.apache.org/confluence/display/KAFKA/KIP-285%3A+Connect+Rest+Extension+Plugin&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;KIP-285: Connect Rest Extension Plugin - Apache Kafka - Apache Software Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Status Current state:&amp;nbsp;Accepted Discussion thread: here&amp;nbsp; JIRA: KAFKA-6776 - 이슈 세부사항 가져오는 중... 상태 PR :&amp;nbsp;https://github.com/apache/kafka/pull/4931 Released: 2.0.0 Motivation Connect Framework offers REST API that is used to mange t&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cwiki.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Debezium 사용 예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/debezium/debezium-ui/blob/main/backend/src/main/java/io/debezium/configserver/rest/client/KafkaConnectClient.java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/debezium/debezium-ui/blob/main/backend/src/main/java/io/debezium/configserver/rest/client/KafkaConnectClient.java&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1664884620922&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - debezium/debezium-ui: A web UI for Debezium; Please log issues at https://issues.redhat.com/browse/DBZ.&quot; data-og-description=&quot;A web UI for Debezium; Please log issues at https://issues.redhat.com/browse/DBZ. - GitHub - debezium/debezium-ui: A web UI for Debezium; Please log issues at https://issues.redhat.com/browse/DBZ.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/debezium/debezium-ui/blob/main/backend/src/main/java/io/debezium/configserver/rest/client/KafkaConnectClient.java&quot; data-og-url=&quot;https://github.com/debezium/debezium-ui&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PtbGv/hyP19dtHtX/cldgS1KUPKk5D7HjOKYUb1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/debezium/debezium-ui/blob/main/backend/src/main/java/io/debezium/configserver/rest/client/KafkaConnectClient.java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/debezium/debezium-ui/blob/main/backend/src/main/java/io/debezium/configserver/rest/client/KafkaConnectClient.java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PtbGv/hyP19dtHtX/cldgS1KUPKk5D7HjOKYUb1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - debezium/debezium-ui: A web UI for Debezium; Please log issues at https://issues.redhat.com/browse/DBZ.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A web UI for Debezium; Please log issues at https://issues.redhat.com/browse/DBZ. - GitHub - debezium/debezium-ui: A web UI for Debezium; Please log issues at https://issues.redhat.com/browse/DBZ.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1664884630738&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@POST
@Path(&quot;/connectors/{connector-name}/restart&quot;)
@Consumes(&quot;application/json&quot;)
@Produces(&quot;application/json&quot;)
Response restartConnector(@PathParam(&quot;connector-name&quot;) String connectorName) throws ProcessingException, IOException;

@POST
@Path(&quot;/connectors/{connector-name}/tasks/{task-number}/restart&quot;)
@Consumes(&quot;application/json&quot;)
@Produces(&quot;application/json&quot;)
Response restartConnectorTask(@PathParam(&quot;connector-name&quot;) String connectorName, @PathParam(&quot;task-number&quot;) int taskNumber) throws ProcessingException, IOException;

 // 새로운 endpoint 
@GET
@Path(&quot;/debezium/transforms&quot;)
@Produces(&quot;application/json&quot;)
List&amp;lt;TransformsInfo&amp;gt; listTransforms() throws ProcessingException, IOException;

@GET
@Path(&quot;/debezium/topic-creation&quot;)
@Produces(&quot;application/json&quot;)
Boolean isTopicCreationEnabled() throws ProcessingException, IOException;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적인 rest endpoint를 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/debezium/debezium/blob/aa1982adc50cad10cf1c7e4123335a7900e3d16e/debezium-connect-rest-extension/src/main/java/io/debezium/kcrestextension/DebeziumResource.java#L114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/debezium/debezium/blob/aa1982adc50cad10cf1c7e4123335a7900e3d16e/debezium-connect-rest-extension/src/main/java/io/debezium/kcrestextension/DebeziumResource.java#L114&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1664884770424&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - debezium/debezium: Change data capture for a variety of databases. Please log issues at https://issues.redhat.com/brows&quot; data-og-description=&quot;Change data capture for a variety of databases. Please log issues at https://issues.redhat.com/browse/DBZ. - GitHub - debezium/debezium: Change data capture for a variety of databases. Please log i...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/debezium/debezium/blob/aa1982adc50cad10cf1c7e4123335a7900e3d16e/debezium-connect-rest-extension/src/main/java/io/debezium/kcrestextension/DebeziumResource.java#L114&quot; data-og-url=&quot;https://github.com/debezium/debezium&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cjEejb/hyP2bPUwth/BHrfjinN7cYVDKTGbuo0R0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/debezium/debezium/blob/aa1982adc50cad10cf1c7e4123335a7900e3d16e/debezium-connect-rest-extension/src/main/java/io/debezium/kcrestextension/DebeziumResource.java#L114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/debezium/debezium/blob/aa1982adc50cad10cf1c7e4123335a7900e3d16e/debezium-connect-rest-extension/src/main/java/io/debezium/kcrestextension/DebeziumResource.java#L114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cjEejb/hyP2bPUwth/BHrfjinN7cYVDKTGbuo0R0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - debezium/debezium: Change data capture for a variety of databases. Please log issues at https://issues.redhat.com/brows&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Change data capture for a variety of databases. Please log issues at https://issues.redhat.com/browse/DBZ. - GitHub - debezium/debezium: Change data capture for a variety of databases. Please log i...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1664884783190&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GET
@Path(&quot;/transforms&quot;)
public List&amp;lt;TransformsInfo&amp;gt; listTransforms() {
    return this.getTransforms();
}

private synchronized List&amp;lt;TransformsInfo&amp;gt; getTransforms() {
    if (this.transforms.isEmpty()) {
        for (PluginDesc&amp;lt;Transformation&amp;lt;?&amp;gt;&amp;gt; plugin : herder.plugins().transformations()) {
            if (&quot;org.apache.kafka.connect.runtime.PredicatedTransformation&quot;.equals(plugin.className())) {
                this.transforms.add(new TransformsInfo(HasHeaderKey.class.getName(), (new HasHeaderKey&amp;lt;&amp;gt;().config())));
                this.transforms.add(new TransformsInfo(RecordIsTombstone.class.getName(), (new RecordIsTombstone&amp;lt;&amp;gt;().config())));
                this.transforms.add(new TransformsInfo(TopicNameMatches.class.getName(), (new TopicNameMatches&amp;lt;&amp;gt;().config())));
            }
            else {
                this.transforms.add(new TransformsInfo(plugin));
            }
        }
    }

    return Collections.unmodifiableList(this.transforms);
}

@GET
@Path(&quot;/topic-creation&quot;)
public boolean getTopicCreationEnabled() {
    return this.isTopicCreationEnabled;
}

private synchronized Boolean isTopicCreationEnabled() {
    Version kafkaConnectVersion = parseVersion(AppInfoParser.getVersion());
    String topicCreationProperty = (String) config.get(&quot;topic.creation.enable&quot;);
    if (null == topicCreationProperty) { // when config is not set, default to true
        topicCreationProperty = &quot;true&quot;;
    }
    return TOPIC_CREATION_KAFKA_VERSION.compareTo(kafkaConnectVersion) &amp;lt;= 0
            &amp;amp;&amp;amp; Boolean.parseBoolean(topicCreationProperty);
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>빅데이터/Kafka</category>
      <author>AndersonChoi</author>
      <guid isPermaLink="true">https://voidmainvoid.tistory.com/489</guid>
      <comments>https://voidmainvoid.tistory.com/489#entry489comment</comments>
      <pubDate>Tue, 4 Oct 2022 20:59:47 +0900</pubDate>
    </item>
  </channel>
</rss>