<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>파이의 꿈</title>
    <link>https://developer-pi.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 24 Jun 2026 12:48:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>PI.314</managingEditor>
    <item>
      <title>TimescaleDB는 무엇인가?</title>
      <link>https://developer-pi.tistory.com/394</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 PostgreSQL 기반의 오픈 소스 시계열 데이터베이스인 TimescaleDB와 그 핵심 기능인 하이퍼테이블에 대해 알아보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;TimescaleDB&lt;/h2&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;TimescaleDB는 관계형 데이터베이스의 강력한 기능과 시계열 데이터를 효율적으로 처리하는 능력을 결합한 데이터베이스입니다. PostgreSQL의 확장으로, 기존 SQL 지식을 활용하여 시계열 데이터를 쉽게 처리할 수 있습니다. 높은 쓰기 성능, 효율적인 데이터 압축, 강력한 쿼리 기능이 특징입니다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;하이퍼테이블&lt;/h2&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하이퍼테이블은 TimescaleDB의 핵심 개념으로, 일반적인 PostgreSQL 테이블처럼 보이지만 내부적으로 여러 개의 데이터 파티션(청크라고 함)으로 나뉩니다. 이 구조는 시계열 데이터의 대량 삽입과 복잡한 쿼리를 효율적으로 처리할 수 있도록 해줍니다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;하이퍼테이블 생성 및 관리&lt;/h2&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;하이퍼테이블은 대규모 시계열 데이터를 효율적으로 관리하기 위해 파티셔닝과 인덱싱을 사용합니다. 이 글에서는 하이퍼테이블의 파티셔닝 방법, 설정 및 관련 쿼리에 대해 설명하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;하이퍼테이블 파티셔닝의 이해&lt;/h2&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하이퍼테이블은 시계열 데이터를 '청크(chunk)'라는 파티션으로 분할하여 관리합니다. 이 청크는 시간 또는 다른 치수(예: 장치 ID)에 따라 생성될 수 있으며, 데이터의 삽입과 쿼리 성능을 향상시킵니다.&lt;/p&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;/li&gt;
&lt;li&gt;청크의 크기와 수명 주기는 사용자가 설정할 수 있으며, 이는 데이터의 볼륨과 쿼리 패턴에 따라 다릅니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TimescaleDB에서 하이퍼테이블 설정과 관련된 다양한 쿼리들과 그들의 용도에 대해 설명해드리겠습니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 하이퍼테이블 생성&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하이퍼테이블을 생성하는 기본 쿼리입니다. 일반 PostgreSQL 테이블을 생성한 후, 이를 하이퍼테이블로 변환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859112973&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE temperature_data (
    time TIMESTAMPTZ NOT NULL,
    sensor_id INT,
    temperature DOUBLE PRECISION
);

SELECT create_hypertable('temperature_data', 'time');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 청크 시간 간격 설정&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하이퍼테이블의 청크 크기를 시간 간격으로 설정합니다. 예를 들어, 아래 쿼리는 각 청크가 1주일의 데이터를 보유하도록 설정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859126515&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT set_chunk_time_interval('temperature_data', INTERVAL '1 week');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 청크 사이즈 제한 설정&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;청크의 최대 크기를 설정할 수 있습니다. 이는 디스크 공간을 관리하고 쿼리 성능을 최적화하는 데 유용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859149599&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT set_chunk_size_constraint('temperature_data', 524288000); -- 예: 500MB&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. 데이터 보존 정책 설정&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터 보존 정책을 설정하여 오래된 데이터를 자동으로 삭제할 수 있습니다. 예를 들어, 아래 쿼리는 12개월 이상 된 데이터를 삭제합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859163384&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT add_retention_policy('temperature_data', INTERVAL '12 months');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;5. 데이터 압축 정책 설정&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터 압축 정책을 설정하여 공간을 절약하고 쿼리 성능을 향상시킬 수 있습니다. 아래 쿼리는 7일보다 오래된 데이터를 압축합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859176349&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT add_compression_policy('temperature_data', INTERVAL '7 days');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;6. 연속 집계(Continuous Aggregation) 생성&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;연속 집계를 설정하여 자주 실행되는 집계 쿼리의 성능을 향상시킬 수 있습니다. 아래는 시간별 평균 온도를 계산하는 연속 집계의 예시입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859192766&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE VIEW hourly_temperature_stats
WITH (timescaledb.continuous)
AS
SELECT time_bucket('1 hour', time) as bucket,
       sensor_id,
       AVG(temperature) as avg_temp
FROM temperature_data
GROUP BY bucket, sensor_id;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;7. 청크 조회&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현재 생성된 청크를 조회하는 쿼리입니다. 데이터 관리 및 트러블슈팅에 유용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1703859210233&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT show_chunks('temperature_data');&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 쿼리들은 하이퍼테이블의 성능 최적화, 공간 관리, 데이터 보존 등 다양한 측면에서 중요한 역할을 합니다. 하이퍼테이블 설정을 적절히 관리함으로써, 대규모 시계열 데이터를 효과적으로 처리하고 분석할 수 있습니다.&lt;/p&gt;</description>
      <category>Database.</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/394</guid>
      <comments>https://developer-pi.tistory.com/394#entry394comment</comments>
      <pubDate>Fri, 29 Dec 2023 23:14:31 +0900</pubDate>
    </item>
    <item>
      <title>TimescaleDB vs InfluxDB 비교하기</title>
      <link>https://developer-pi.tistory.com/393</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;시계열 데이터베이스는 시간에 따라 변하는 데이터를 저장하기 위해 설계되었습니다. 이것은 시간이 지남에 따라 수집된 모든 종류의 데이터일 수 있습니다. 예를 들어, 어떤 시스템에서 수집한 메트릭들이 이에 해당합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우리는 다양한 종류의 시계열 데이터베이스를 가지고 있는데, 어떤 것을 사용해야 할까요? 이 글에서는 TimescaleDB와 InfluxDB, 두 주요 옵션 사이의 주요 차이점을 살펴볼 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;InfluxDB&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;InfluxDB는 InfluxData에 의해 만들어졌습니다. 이것은 Go 언어로 작성된 맞춤형, 오픈 소스, NoSQL 시계열 데이터베이스입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 데이터 저장소는 InfluxQL이라고 하는 SQL과 유사한 언어를 제공하여 개발자들이 자신들의 애플리케이션에 쉽게 통합할 수 있습니다. 또한 Flux라는 새로운 맞춤형 쿼리 언어도 있습니다. 이 언어는 일부 작업을 더 쉽게 만들 수 있지만, 맞춤형 쿼리 언어를 채택할 때 항상 학습 곡선이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Flux Query Example&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703856689890&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from(db:&quot;testing&quot;)
|&amp;gt; range(start:-1h)
|&amp;gt; filter(fn: (r) =&amp;gt; r._measurement == &quot;cpu&quot;)
|&amp;gt; exponentialMovingAverage()&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;이 데이터베이스에서는 각 측정값이 타임스탬프와 연관된 태그 세트와 필드 세트를 가집니다. 필드는 실제 측정 읽기 값들을 나타내며, 태그는 측정값들을 설명하는 메타데이터를 나타냅니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;필드 데이터 유형은 float, int, string, boolean으로 제한되며, 데이터를 다시 쓰지 않고는 변경할 수 없습니다. 태그 값은 인덱싱됩니다. 이들은 문자열로 표현되며 업데이트할 수 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;InfluxDB는 스키마나 인덱스를 만드는 것에 대해 걱정할 필요 없이 시작하기 쉽습니다. 그러나, 추가 인덱스를 만들거나, 연속 필드에 인덱스를 만들거나, 사후에 메타데이터를 업데이트하거나, 데이터 유효성을 강제하는 등의 능력이 없어 꽤 제한적이고 경직되어 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;InfluxDB는 스키마가 없는 것이 아닙니다. 입력 데이터로부터 자동으로 생성되는 기본 스키마가 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;InfluxDB는 장애 허용, 고가용성, 백업/복원과 같은 여러 도구를 처음부터 구현해야 했으며, 디스크 신뢰성에 대해 책임을 져야 합니다. 이러한 도구들과 많은 기능들, 예를 들어 HA는 엔터프라이즈 버전에서만 사용할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;InfluxDB 백업 도구는 전체 또는 증분 백업을 수행할 수 있으며, 특정 시점 복구에 사용할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;InfluxDB는 PostgreSQL 및 TimescaleDB보다 디스크 압축이 뛰어납니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;TimescaleDB&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TimescaleDB는 빠른 삽입과 복잡한 쿼리에 최적화된 오픈 소스 시계열 데이터베이스로, 전체 SQL을 지원합니다. PostgreSQL을 기반으로 하며, 시계열 데이터를 위한 NoSQL과 관계형 세계의 최고를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것은 TimescaleDB 쿼리 예제입니다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703856716684&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT time,
exponential_moving_average(value, 0.5) OVER (ORDER BY time)
FROM testing
WHERE measurement = cpu and time &amp;gt; now() - '1 hour';&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; 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;span style=&quot;color: #000000;&quot;&gt;TimescaleDB는 PostgreSQL 확장으로서 관계형 데이터베이스입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것은 새로운 사용자들에게 짧은 학습 곡선을 제공하고, pg_dump 또는 pg_backup과 같은 백업 도구와 고가용성 도구를 상속한다는 것을 의미합니다. 이것은 다른 시계열 데이터베이스에 비해 장점입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한 주된 복제 방법으로 스트리밍 복제를 지원하며, 고가용성 설정에서 사용할 수 있습니다. 장애 복구 및 백업과 관련하여, ClusterControl과 같은 외부 시스템을 사용하여 이 과정을 자동화할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TimescaleDB에서는 각 시계열 측정값이 자신만의 행에 시간 필드와 그 뒤를 이어 여러 필드로 기록됩니다. 이 필드들은 float, int, string, boolean, 배열, JSON 블롭, 지리공간 차원, 날짜/시간/타임스탬프, 화폐, 바이너리 데이터 등이 될 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필드(표준 인덱스), 여러 필드(복합 인덱스), 함수와 같은 표현식 또는 행의 부분 집합(부분 인덱스)에 대한 인덱스를 만들 수 있습니다. 이러한 필드 중 어느 하나를 부차적인 테이블로의 외래 키로 사용할 수 있으며, 이 테이블은 추가 메타데이터를 저장할 수 있습니다. 이와 같은 방식으로, 시스템에 필요한 스키마와 인덱스를 선택해야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Performance&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;성능에 대해 이야기하자면, &lt;a style=&quot;color: #000000; text-align: start;&quot; href=&quot;https://blog.timescale.com/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&quot;&gt;TimescaleDB comparison&lt;/a&gt; 블로그를 확인할 수 있습니다. 거기에서는 차트와 메트릭을 포함하여 두 데이터베이스 간의 상세한 성능 비교가 있습니다. 이 블로그에서 가장 중요한 정보 몇 가지를 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Insert&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;1360&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ikq42/btsCKTqxpQ0/EejhKMTatNEKaXi62XGBw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ikq42/btsCKTqxpQ0/EejhKMTatNEKaXi62XGBw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ikq42/btsCKTqxpQ0/EejhKMTatNEKaXi62XGBw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIkq42%2FbtsCKTqxpQ0%2FEejhKMTatNEKaXi62XGBw1%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;1360&quot; height=&quot;602&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;span style=&quot;color: #000000;&quot;&gt;매우 낮은 카디널리티(예: 100개 장치)를 가진 워크로드의 경우 InfluxDB가 TimescaleDB보다 성능이 좋습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;카디널리티가 증가함에 따라 InfluxDB의 삽입 성능이 TimescaleDB보다 빠르게 떨어집니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;중간에서 높은 카디널리티(예: 100개 장치에서 10개 메트릭 전송)를 가진 워크로드의 경우 TimescaleDB가 InfluxDB보다 성능이 좋습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;948&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PfkDI/btsCN1g8O8Q/D4HOjvkhEzzmJxolgRAS6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PfkDI/btsCN1g8O8Q/D4HOjvkhEzzmJxolgRAS6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PfkDI/btsCN1g8O8Q/D4HOjvkhEzzmJxolgRAS6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPfkDI%2FbtsCN1g8O8Q%2FD4HOjvkhEzzmJxolgRAS6k%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;1122&quot; height=&quot;948&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;948&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Read latency&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;1310&quot; data-origin-height=&quot;1492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxPzfc/btsCTCNPmTk/U11DMwdoGFVrT3zKEofKO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxPzfc/btsCTCNPmTk/U11DMwdoGFVrT3zKEofKO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxPzfc/btsCTCNPmTk/U11DMwdoGFVrT3zKEofKO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxPzfc%2FbtsCTCNPmTk%2FU11DMwdoGFVrT3zKEofKO0%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;1310&quot; height=&quot;1492&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;1492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;span style=&quot;color: #000000; text-align: start;&quot;&gt;간단한 쿼리의 경우 결과가 상당히 다양합니다. 어떤 경우에는 한 데이터베이스가 다른 것보다 확실히 우수한 반면, 다른 경우에는 데이터셋의 카디널리티에 따라 달라집니다. 이 차이는 종종 한 자리수에서 두 자리수 밀리초 범위에 있습니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;복잡한 쿼리의 경우 TimescaleDB는 InfluxDB보다 훨씬 뛰어난 성능을 보이며, 더 다양한 쿼리 유형을 지원합니다. (여기서의 차이는 종종 몇 초에서 수십 초 범위에 있습니다.)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;참고 : &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&lt;a href=&quot;https://www.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703857816414&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;TimescaleDB vs. InfluxDB: Purpose-built for time-series data&quot; data-og-description=&quot;An in-depth look into how TimescaleDB and InfluxDB stack up in terms of data model, query language, reliability, performance, ecosystem, operational management, and company/community support.&quot; data-og-host=&quot;www.timescale.com&quot; data-og-source-url=&quot;https://www.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&quot; data-og-url=&quot;https://www.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9D02n/hyUTDI8D8P/FLhBXrZ1rqqabIR04E2881/img.png?width=2400&amp;amp;height=1350&amp;amp;face=0_0_2400_1350,https://scrap.kakaocdn.net/dn/tbIFd/hyUXLFwl1n/nVkkwwxCqyEQpm6JK3Re51/img.png?width=2400&amp;amp;height=1350&amp;amp;face=0_0_2400_1350,https://scrap.kakaocdn.net/dn/Gm2JD/hyUTJig8rV/t3Zkdpfnp3WcHls1k7QdHk/img.png?width=1710&amp;amp;height=1734&amp;amp;face=0_0_1710_1734&quot;&gt;&lt;a href=&quot;https://www.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9D02n/hyUTDI8D8P/FLhBXrZ1rqqabIR04E2881/img.png?width=2400&amp;amp;height=1350&amp;amp;face=0_0_2400_1350,https://scrap.kakaocdn.net/dn/tbIFd/hyUXLFwl1n/nVkkwwxCqyEQpm6JK3Re51/img.png?width=2400&amp;amp;height=1350&amp;amp;face=0_0_2400_1350,https://scrap.kakaocdn.net/dn/Gm2JD/hyUTJig8rV/t3Zkdpfnp3WcHls1k7QdHk/img.png?width=1710&amp;amp;height=1734&amp;amp;face=0_0_1710_1734');&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;TimescaleDB vs. InfluxDB: Purpose-built for time-series data&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An in-depth look into how TimescaleDB and InfluxDB stack up in terms of data model, query language, reliability, performance, ecosystem, operational management, and company/community support.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.timescale.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>Database.</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/393</guid>
      <comments>https://developer-pi.tistory.com/393#entry393comment</comments>
      <pubDate>Fri, 29 Dec 2023 22:46:32 +0900</pubDate>
    </item>
    <item>
      <title>Kafka Consumer DLT(Dead Letter Topic) 전략</title>
      <link>https://developer-pi.tistory.com/390</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;분산 시스템과 메시지 큐를 다루는 과정에서 메시지 처리 실패는 흔한 일입니다. 이러한 실패를 효과적으로 관리하기 위해 Dead Letter Topic(DLT)과 재시도 전략이 필수적입니다. 해당 포스팅에서는&amp;nbsp;DLT의 개념을 설명하고, Kafka를 사용하는 구체적인 예시를 통해 재시도 전략을 설계 및 구현하는 방법을 알아보겠습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Dead Letter Topic(DLT)이란?&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DLT는 메시지 처리에 실패했을 때 해당 메시지를 저장하는 Kafka 토픽입니다. 재시도 과정에서 여전히 실패하는 메시지를 위한 '마지막 피난처'로 사용됩니다. DLT의 주요 목적은 다음과 같습니다.&lt;/p&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;/li&gt;
&lt;li&gt;실패 원인 분석 및 디버깅 용이성 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;재시도 전략의 필요성&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;메시지 처리 중 잠깐의 네트워크 지연이나 일시적인 오류로 인해 실패할 수 있습니다. 이러한 경우, 메시지를 바로 DLT로 보내기보다는 몇 차례 재시도를 하는 것이 바람직합니다. 재시도 전략은 다음과 같은 이점을 제공합니다&lt;/p&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;/li&gt;
&lt;li&gt;데이터 손실 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 DLT 구현 샘플 예제를 한번 살펴보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Retry 전략 설계 및 구현 샘플 예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;19&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;20&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;21&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;22&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;23&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;24&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;25&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;26&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RetryableTopic(&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;attempts&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;5&quot;&lt;/span&gt;,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;backoff&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;@Backoff(delay&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;5000&lt;/span&gt;,&amp;nbsp;multiplier&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color:#2CE1BC&quot;&gt;0&lt;/span&gt;),&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dltStrategy&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;DltStrategy.FAIL_ON_ERROR,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dltTopicSuffix&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;.dlt&quot;&lt;/span&gt;,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retryTopicSuffix&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;.retry&quot;&lt;/span&gt;,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exclude&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;NonRetryableException.&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@KafkaListener(&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;topics&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;sample.topic&quot;&lt;/span&gt;,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groupId&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;sample.topic.v1&quot;&lt;/span&gt;,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containerFactory&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;concurrentFactory&quot;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;consume(ConsumerRecord&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;record)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;try&lt;/span&gt;&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;log.info(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Received&amp;nbsp;message:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;record.value());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;catch&lt;/span&gt;&amp;nbsp;(RetryableException&amp;nbsp;e)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;log.error(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Retryable&amp;nbsp;error&amp;nbsp;processing&amp;nbsp;message:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;e.getMessage());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;throw&lt;/span&gt;&amp;nbsp;e;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;catch&lt;/span&gt;&amp;nbsp;(NonRetryableException&amp;nbsp;e)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;log.error(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Non-retryable&amp;nbsp;error&amp;nbsp;processing&amp;nbsp;message:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;e.getMessage());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;throw&lt;/span&gt;&amp;nbsp;e;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;@RetryableTopic을 통해 재시도 전략을 구성합니다. 이 설정에는 최대 시도 횟수(attempts), 지연 시간(delay), 지연 시간 증가율(multiplier), DLT 전략(dltStrategy), DLT 및 재시도 토픽 접미사(dltTopicSuffix, retryTopicSuffix)가 포함됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;consume 메서드는 Kafka로부터 메시지를 수신하여 처리합니다. 이 과정에서 재시도 가능한 예외(RetryableException)와 재시도 불가능한 예외(NonRetryableException)를 구분하여 처리합니다.&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DLT 구현 &lt;b&gt;샘플 예제&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@KafkaListener(&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;topics&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;sample.topic.dlt&quot;&lt;/span&gt;,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;groupId&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;sample.topic.dlt.v1&quot;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;processDltMessages(&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConsumerRecord&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;record,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Header(KafkaHeaders.RECEIVED_TOPIC)&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;topic,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Header(KafkaHeaders.RECEIVED_PARTITION_ID)&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;int&lt;/span&gt;&amp;nbsp;partitionId,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Header(KafkaHeaders.OFFSET)&amp;nbsp;Long&amp;nbsp;offset,&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Header(KafkaHeaders.EXCEPTION_MESSAGE)&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;errorMessage&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;log.info(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;key:&amp;nbsp;{},&amp;nbsp;value:&amp;nbsp;{},&amp;nbsp;topic&amp;nbsp;:&amp;nbsp;{},&amp;nbsp;partition&amp;nbsp;:&amp;nbsp;{},&amp;nbsp;offset&amp;nbsp;:&amp;nbsp;{},&amp;nbsp;errorMessage&amp;nbsp;:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;record.key(),&amp;nbsp;record.value(),&amp;nbsp;topic,&amp;nbsp;partitionId,&amp;nbsp;offset,&amp;nbsp;errorMessage);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;샘플코드를 보면, processDltMessages 메서드는 DLT로 전송된 메시지를 처리하게 됩니다.&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;Kafka의 DLT는 메시지 처리 과정에서 발생하는 오류를 효과적으로 관리하기 위한 메커니즘으로 작용합니다. 처리 과정에서 재시도 전략에도 불구하고 실패한 메시지들은 DLT로 이동되어, 시스템의 주요 메시지 흐름에서 분리됩니다. 이는 전체 시스템의 안정성을 유지하고, 메인 데이터 스트림의 방해를 최소화하는 데 중요합니다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DLT로 이동된 메시지들은 오류의 원인을 분석하고, 필요한 코드 수정 및 문제를 해결하는 데 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;저는 이 과정에서 개발자가 Kafka 리스너를 동적으로 제어할 수 있도록 구현했고, 개발자나 운영자는 DLT에 적재된 메시지를 분석한 후, 문제를 해결하고 Kafka 리스너의 Start/Stop을 제어함으로써, 수정 사항이 시스템에 올바르게 반영되었는지 확인할 수 있습니다.&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 부분에 대해서 예제를 한번 살펴보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Kafka Listener (DLT) 동적 제어&lt;/b&gt;&amp;nbsp;&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;1. Kafka Listener 제어 관련 API 구현&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;span style=&quot;color: #374151; text-align: left;&quot;&gt;먼저 외부에서 HTTP 요청을 통해 Kafka 리스너를 제어하도록 하는 API 구현이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;다음은 Kafka 토픽에 메시지를 보내는 요청을 처리하여 리스너의 상태(시작/중지)를 변경하는 명령을 Kafka Topic에 전달하는 과정입니다. (&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;분산 시스템 환경에서는 여러 서버 또는 인스턴스가 동시에 운영되기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Kafka 토픽을 통해 리스너를 제어하는 방식으로 구현)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;19&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Slf4j&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RestController&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RequestMapping(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;/v1/kafka&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RequiredArgsConstructor&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;&amp;nbsp;KafkaControlController&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;private&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;final&lt;/span&gt;&amp;nbsp;KafkaControlService&amp;nbsp;kafkaControlService;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostMapping(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;/control&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;ResponseEntity&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;control(@RequestBody&amp;nbsp;Map&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;Object&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;request)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;try&lt;/span&gt;&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;kafkaControlService.control(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;kafka.control&quot;&lt;/span&gt;,&amp;nbsp;request);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;ResponseEntity.ok().body(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Message&amp;nbsp;sent&amp;nbsp;successfully&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;catch&lt;/span&gt;&amp;nbsp;(Exception&amp;nbsp;e)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;log.error(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Error&amp;nbsp;sending&amp;nbsp;Kafka&amp;nbsp;message:&amp;nbsp;&quot;&lt;/span&gt;,&amp;nbsp;e);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Error&amp;nbsp;sending&amp;nbsp;message&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;19&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;20&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;21&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;22&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;23&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Slf4j&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Service&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RequiredArgsConstructor&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;&amp;nbsp;KafkaControlService&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;private&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;final&lt;/span&gt;&amp;nbsp;KafkaProducerService&amp;nbsp;kafkaProducerService;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;private&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;final&lt;/span&gt;&amp;nbsp;ObjectMapper&amp;nbsp;objectMapper;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;control(&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;topic,&amp;nbsp;Map&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;Object&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;event)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;PartitionInfo&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;partitions&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;kafkaProducerService.partitions(topic);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;for&lt;/span&gt;&amp;nbsp;(PartitionInfo&amp;nbsp;partitionInfo&amp;nbsp;:&amp;nbsp;partitions)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#F1A5A5&quot;&gt;try&lt;/span&gt;&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;eventString&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;objectMapper.writeValueAsString(event);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;kafkaProducerService.send(&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ProducerRecord&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;(topic,&amp;nbsp;partitionInfo.partition(),&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;null&lt;/span&gt;,&amp;nbsp;eventString));&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;log.info(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Message&amp;nbsp;sent&amp;nbsp;to&amp;nbsp;partition&amp;nbsp;{}:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;partitionInfo.partition(),&amp;nbsp;eventString);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#F1A5A5&quot;&gt;catch&lt;/span&gt;&amp;nbsp;(JsonProcessingException&amp;nbsp;e)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;log.error(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Error&amp;nbsp;processing&amp;nbsp;JSON:&amp;nbsp;&quot;&lt;/span&gt;,&amp;nbsp;e);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#F1A5A5&quot;&gt;throw&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;RuntimeException(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Error&amp;nbsp;processing&amp;nbsp;JSON&quot;&lt;/span&gt;,&amp;nbsp;e);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;19&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;20&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;21&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;22&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;23&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;24&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;25&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;26&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Slf4j&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Service&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RequiredArgsConstructor&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;&amp;nbsp;KafkaProducerService&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;private&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;final&lt;/span&gt;&amp;nbsp;KafkaTemplate&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;kafkaTemplate;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;sendMessage(&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;topic,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;message)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;kafkaTemplate.send(topic,&amp;nbsp;message).addCallback(&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;result&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;log.info(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Message&amp;nbsp;sent&amp;nbsp;to&amp;nbsp;topic&amp;nbsp;{}:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;topic,&amp;nbsp;message),&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;ex&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;log.error(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Error&amp;nbsp;sending&amp;nbsp;message&amp;nbsp;to&amp;nbsp;topic&amp;nbsp;{}:&amp;nbsp;{}&quot;&lt;/span&gt;,&amp;nbsp;topic,&amp;nbsp;ex.getMessage())&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;send(ProducerRecord&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;record)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;kafkaTemplate.send(record).addCallback(&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;result&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;log.info(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Message&amp;nbsp;sent&amp;nbsp;to&amp;nbsp;topic-partition&amp;nbsp;{}:{}&quot;&lt;/span&gt;,&amp;nbsp;record.topic(),&amp;nbsp;record.partition()),&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;ex&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;log.error(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Error&amp;nbsp;sending&amp;nbsp;message&amp;nbsp;to&amp;nbsp;topic-partition&amp;nbsp;{}:{}&quot;&lt;/span&gt;,&amp;nbsp;record.topic(),&amp;nbsp;ex.getMessage())&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;List&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;PartitionInfo&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;partitions(&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;topic)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;kafkaTemplate.partitionsFor(topic);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. KafkaListenerEndpointRegistry를 활용한 Kafka Listener 제어 기능 구현&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 kafka.control&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt; 토픽로부터 소비한 메시지를 통해 특정 리스너의 상태(시작 또는 중지)를 변경하는 예제를 구현하겠습니다. (분산 환경에서 Kafka 리스너를 동적으로 제어하기 위함)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;참고로 &lt;b&gt;KafkaListenerEndpointRegistry&lt;/b&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;는 Spring Kafka에서 Kafka 리스너 컨테이너들을 관리하는 역할을 하는 클래스입니다. 이 클래스를 사용함으로써, 개발자는 프로그래밍 방식으로 Kafka 메시지 리스너의 등록, 조회, 그리고 실행 상태를 제어할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@KafkaListener(topics&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;kafka.control&quot;&lt;/span&gt;,&amp;nbsp;groupId&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;control-group&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;listen(ConsumerRecord&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;record)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;listenerId&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;record.key();&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;boolean&lt;/span&gt;&amp;nbsp;active&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;Boolean.parseBoolean(record.value());&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;kafkaListenerEndpoint.startOrStopListener(listenerId,&amp;nbsp;active);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Component&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@RequiredArgsConstructor&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Slf4j&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;&amp;nbsp;KafkaListenerEndpoint&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;private&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;final&lt;/span&gt;&amp;nbsp;KafkaListenerEndpointRegistry&amp;nbsp;registry;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;startOrStopListener(&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&amp;nbsp;listenerId,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;boolean&lt;/span&gt;&amp;nbsp;active)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageListenerContainer&amp;nbsp;listenerContainer&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;registry.getListenerContainer(listenerId);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;if&lt;/span&gt;&amp;nbsp;(active)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;listenerContainer.start();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&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;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;listenerContainer.stop();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;이렇게 DLT &amp;amp; 동적 제어 메카니즘을 구축하게 되면 시스템의 전반적인 관리와 유지보수를 용이하게 하며, 복잡한 분산 환경에서의 운영상의 편의성을 제공합니다. 오류 발생 시 적절한 대응과 빠른 문제 해결을 통해, 시스템의 안정성과 신뢰성을 보장하는 데 필수적인 기능입니다.&lt;/span&gt;&lt;/p&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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;DLT와 재시도 전략은 Kafka를 사용하는 분산 시스템에서 메시지 처리의 안정성을 보장하는 중요한 요소입니다. &lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;예시를 통해 이러한 전략을 어떻게 구현할 수 있는지 알아보았습니다. 이러한 접근 방식은 메시지 처리 실패를 효과적으로 관리하고 시스템의 전반적인 신뢰성을 높이는 데 도움이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kafka</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/390</guid>
      <comments>https://developer-pi.tistory.com/390#entry390comment</comments>
      <pubDate>Mon, 11 Dec 2023 19:18:21 +0900</pubDate>
    </item>
    <item>
      <title>하루 n억 건 모니터링 데이터를 적재하는 Telemetry 서비스 만들기</title>
      <link>https://developer-pi.tistory.com/389</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 인식&lt;/b&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;회사에서 운영하고 있는 Telemetry 서비스는 &lt;b&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;1분 마다 &lt;/span&gt;각 장비의 모니터링 메시지를 받아서 파싱 및 저장하는 역할&lt;/b&gt;을 수행하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;해당&lt;/span&gt;&amp;nbsp;서비스는 원래 각 메시지를 개별적으로 처리하고, &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;이를 데이터베이스에 건별로 삽입하는 방식을&lt;/span&gt; 사용했습니다. &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;이 접근법은 단순하고 직관적이지만, 데이터 양이 급격하게 증가하면서 서비스 구조 변경이 필요했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1746&quot; data-origin-height=&quot;1420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mpwJ3/btsCzGdf0Pv/i7IrRUJ1vM3XdJJEgi39yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mpwJ3/btsCzGdf0Pv/i7IrRUJ1vM3XdJJEgi39yk/img.png&quot; data-alt=&quot;Telemetry 서비스 구조 개선 전 (AS-IS)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mpwJ3/btsCzGdf0Pv/i7IrRUJ1vM3XdJJEgi39yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmpwJ3%2FbtsCzGdf0Pv%2Fi7IrRUJ1vM3XdJJEgi39yk%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;1746&quot; height=&quot;1420&quot; data-origin-width=&quot;1746&quot; data-origin-height=&quot;1420&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Telemetry 서비스 구조 개선 전 (AS-IS)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;그래서 대용량 데이터를 처리하기 위해 다음과 같이 3가지 개선 전략을 적용했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개선 전략 1: Kafka Batch Listener 도입&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처리 효율성을 높이기 위해 Kafka Batch Listener를 도입했습니다. 전통적인 Kafka Listener가 메시지를 개별적으로 처리하는 것과 달리, Batch Listener는 여러 메시지를 한 번에 처리할 수 있어 네트워크 오버헤드와 처리 지연을 줄일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Batch Listener 설정&lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Bean&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;ConcurrentKafkaListenerContainerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;kafkaListenerContainerFactory()&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConcurrentKafkaListenerContainerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;factory&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ConcurrentKafkaListenerContainerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;factory.setConsumerFactory(consumerFactory());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;factory.setBatchListener(&lt;span style=&quot;color:#2CE1BC&quot;&gt;true&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;containerProperties&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;factory.getContainerProperties();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containerProperties.setAckMode(ContainerProperties.AckMode.TIME);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containerProperties.setAckTime(&lt;span style=&quot;color:#2CE1BC&quot;&gt;10000&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;factory;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@KafkaListener(topics&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;topicName&quot;&lt;/span&gt;,&amp;nbsp;containerFactory&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;kafkaListenerContainerFactory&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;listen(List&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;ConsumerRecord&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;records)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;TODO&amp;nbsp;:&amp;nbsp;로직&amp;nbsp;구현&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Kafka Consumer Config 설정&lt;/b&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 외에도 Kafka Batch Listener를 도입할 때 고려해야 할 주요 Kafka Consumer Config 옵션들은 다음과 같습니다. 이러한 설정들은 Kafka 메시지의 효율적인 배치 처리를 위해 조정될 수 있으며, 시스템의 성능과 처리량에 중요한 영향을 미칩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;19&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;20&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;21&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;22&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;ConsumerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;consumerFactory()&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Map&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;Object&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;props&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;HashMap&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;localhost:9092&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.GROUP_ID_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;example-group&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;earliest&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;false&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,&amp;nbsp;StringDeserializer.&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,&amp;nbsp;StringDeserializer.&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;해당&amp;nbsp;설정&amp;nbsp;값들은,&amp;nbsp;성능&amp;nbsp;최적화를&amp;nbsp;위해&amp;nbsp;서비스&amp;nbsp;특성을&amp;nbsp;고려하여&amp;nbsp;변경하시면&amp;nbsp;됩니다.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.FETCH_MIN_BYTES_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;500000&lt;/span&gt;);&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;fetch.min.bytes&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;3000&lt;/span&gt;);&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;fetch.max.wait.ms&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;500&lt;/span&gt;);&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;max.poll.records&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;1048576&lt;/span&gt;);&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;max.partition.fetch.bytes&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;10485760&lt;/span&gt;);&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;fetch.max.bytes&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;15000&lt;/span&gt;);&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;session.timeout.ms&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;props.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG,&amp;nbsp;&lt;span style=&quot;color:#2CE1BC&quot;&gt;5000&lt;/span&gt;);&amp;nbsp;&lt;span style=&quot;color:#6BC46B&quot;&gt;//&amp;nbsp;heartbeat.interval.ms&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;DefaultKafkaConsumerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;(props);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 602px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 117px;&quot;&gt;
&lt;td style=&quot;width: 27.3256%; height: 117px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.6744%; height: 117px;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Kafka 브로커가 컨슈머에게 데이터를 반환하기 전에 최소한으로 모아야 하는 데이터의 양&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 큰 배치 크기를 위해 컨슈머가 더 많은 데이터를 기다리게 하고, 네트워크 사용량을 최적화하고 브로커의 부하를 줄일 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 92px;&quot;&gt;
&lt;td style=&quot;width: 27.3256%; height: 92px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;fetch.max.bytes&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.6744%; height: 92px;&quot;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단일 fetch 요청으로 브로커에서 가져올 수 있는 데이터의 최대 크기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨슈머가 한 번에 가져올 수 있는 데이터의 양을 제한하여 메모리 사용을 관리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 116px;&quot;&gt;
&lt;td style=&quot;width: 27.3256%; height: 116px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;max.poll.records&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.6744%; height: 116px;&quot;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한 번의 poll() 호출에서 컨슈머가 가져올 수 있는 최대 레코드 수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 값을 조정함으로써 컨슈머가 처리할 수 있는 데이터의 양을 제어할 수 있음. 배치 처리에 적합한 크기로 설정 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 92px;&quot;&gt;
&lt;td style=&quot;width: 27.3256%; height: 92px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;fetch.max.wait.ms&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.6744%; height: 92px;&quot;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브로커가 fetch.min.bytes에 지정된 데이터 크기에 도달하기 위해 기다리는 최대 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;응답 지연을 통제하여 더 큰 배치를 만들지만, 지연 시간이 너무 길면 전체 처리 속도가 느려질 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 92px;&quot;&gt;
&lt;td style=&quot;width: 27.3256%; height: 92px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;session.timeout.ms &lt;br /&gt;/ heartbeat.interval.ms&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.6744%; height: 92px;&quot;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨슈머 그룹 내에서 세션 타임아웃과 하트비트 간격을 설정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배치 처리 시간이 길어질 경우, 컨슈머가 그룹에서 타임아웃되지 않도록 설정 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 93px;&quot;&gt;
&lt;td style=&quot;width: 27.3256%; height: 93px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;max.partition.fetch.bytes&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 72.6744%; height: 93px;&quot;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;파티션 당 한 번의 fetch 요청으로 가져올 수 있는 최대 데이터 크기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;파티션별 데이터 크기를 제어하여 컨슈머의 메모리 사용을 관리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&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;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러한 설정들은 Kafka의 성능과 리소스 사용에 직접적인 영향을 미칩니다. 따라서, 배치 리스너를 사용할 때 이러한 설정을 적절히 조정하는 것이 중요합니다. 설정값은 사용 사례, 메시지 크기, 처리량 요구사항, 시스템 리소스 등에 따라 달라질 수 있기 때문에 모니터링을 통해 최적의 값을 찾는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개선 전략 2: Bulk Insert 전략 사용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데이터베이스 작업 성능을 개선하기 위해, 각 메시지를 개별적으로 삽입하는 대신 Bulk Insert 전략을 적용했습니다. Spring JDBC의 Bulk Insert 기능을 사용하여 여러 레코드를 단일 쿼리로 데이터베이스에 삽입함으로써, 데이터베이스 쓰기 작업의 횟수를 줄이고 전반적인 성능을 향상시켰습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;int&lt;/span&gt;[]&amp;nbsp;save(List&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;Data&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;bulkData)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SqlParameterSource[]&amp;nbsp;batch&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;SqlParameterSourceUtils.createBatch(bulkData.toArray());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;namedParameterJdbcTemplate.batchUpdate(SQL_INSERT_TELEMETRY_INFO),&amp;nbsp;batch);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개선 전략 3: 파티션 수 증가 대신 Concurrency &amp;amp; @Async 사용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Kafka에서 파티션 수를 늘리는 것은 다음과 같은 이슈들을 야기할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. 브로커의 메모리 사용 증가&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Kafka 브로커는 각 파티션에 대한 메타데이터를 메모리에 저장합니다. 파티션 수가 증가하면 이 메타데이터의 크기도 증가하여 브로커의 메모리 사용량이 늘어납니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. 리더 선출과 리밸런싱 오버헤드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Kafka는 각 파티션에 대해 리더를 선출하고, 컨슈머 그룹 내에서 파티션을 리밸런싱합니다. 파티션 수가 많으면 이러한 작업이 더 자주 발생할 수 있으며, 이는 추가적인 오버헤드를 유발합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;3. 복제 지연&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 파티션은 여러 브로커에 복제됩니다. 파티션 수가 많을수록 복제할 데이터도 많아지기 때문에, 복제 지연을 증가시킬 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;4. 장애 복구 시간 증가&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;파티션이 많아지면 장애 발생 시 복구해야 할 데이터 양도 늘어나기 때문에, 전체 복구 시간을 길어지게 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위와 같은 이슈들 때문에, Telemetry 서비스의 경우 시스템의 확장성과 관리 효율성을 고려하여 단순히 파티션 수를 증가시키는 대신에 동시성(Concurrency)과 @Async 어노테이션을 사용했습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Concurrency 설정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Bean&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;ConcurrentKafkaListenerContainerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;kafkaListenerContainerFactory()&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConcurrentKafkaListenerContainerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;color:#8AC7FD&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;factory&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ConcurrentKafkaListenerContainerFactory&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;factory.setConsumerFactory(consumerFactory());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;factory.setBatchListener(&lt;span style=&quot;color:#2CE1BC&quot;&gt;true&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;factory.setConcurrency(&lt;span style=&quot;color:#2CE1BC&quot;&gt;2&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;containerProperties&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;factory.getContainerProperties();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containerProperties.setAckMode(ContainerProperties.AckMode.TIME);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containerProperties.setAckTime(&lt;span style=&quot;color:#2CE1BC&quot;&gt;10000&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;factory;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Async 설정 및 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;6&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;7&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;8&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;9&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;10&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;11&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;12&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;13&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;14&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;15&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;16&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;17&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;18&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;19&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;20&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;21&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;22&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;23&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;24&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;25&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;26&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;27&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;28&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;29&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;30&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Configuration&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@EnableAsync&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;class&lt;/span&gt;&amp;nbsp;AsyncConfig&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Bean(name&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;taskExecutorBatch&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;Executor&amp;nbsp;taskExecutorBatch()&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ThreadPoolTaskExecutor&amp;nbsp;executor&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ThreadPoolTaskExecutor();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setCorePoolSize(&lt;span style=&quot;color:#2CE1BC&quot;&gt;3&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setMaxPoolSize(&lt;span style=&quot;color:#2CE1BC&quot;&gt;8&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setQueueCapacity(&lt;span style=&quot;color:#2CE1BC&quot;&gt;20&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setKeepAliveSeconds(&lt;span style=&quot;color:#2CE1BC&quot;&gt;120&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setRejectedExecutionHandler(&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ThreadPoolExecutor.CallerRunsPolicy());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setThreadNamePrefix(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Async-Executor-Batch&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.initialize();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;executor;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Bean(name&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;taskExecutorParser&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;Executor&amp;nbsp;taskExecutorParser()&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ThreadPoolTaskExecutor&amp;nbsp;executor&amp;nbsp;&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ThreadPoolTaskExecutor();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setCorePoolSize(&lt;span style=&quot;color:#2CE1BC&quot;&gt;3&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setMaxPoolSize(&lt;span style=&quot;color:#2CE1BC&quot;&gt;8&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setQueueCapacity(&lt;span style=&quot;color:#2CE1BC&quot;&gt;20&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setKeepAliveSeconds(&lt;span style=&quot;color:#2CE1BC&quot;&gt;120&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setRejectedExecutionHandler(&lt;span style=&quot;color:#F1A5A5&quot;&gt;new&lt;/span&gt;&amp;nbsp;ThreadPoolExecutor.CallerRunsPolicy());&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.setThreadNamePrefix(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;Async-Executor-Parser&quot;&lt;/span&gt;);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.initialize();&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;return&lt;/span&gt;&amp;nbsp;executor;&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class=&quot;colorscripter-code&quot; style=&quot;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto&quot;&gt;&lt;table class=&quot;colorscripter-code-table&quot; style=&quot;margin:0;padding:0;border:none;background-color:#1C1818;border-radius:4px;&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td style=&quot;padding:6px;border-right:2px solid #4f4f4f&quot;&gt;&lt;div style=&quot;margin:0;padding:0;word-break:normal;text-align:right;color:#aaa;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;line-height:130%&quot;&gt;1&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;2&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;3&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;4&lt;/div&gt;&lt;div style=&quot;line-height:130%&quot;&gt;5&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;padding:6px 0;text-align:left&quot;&gt;&lt;div style=&quot;margin:0;padding:0;color:#FFFFFF;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%&quot;&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Async(&lt;span style=&quot;color:#DBB84A&quot;&gt;&quot;taskExecutorBatch&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;@Transactional&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color:#F1A5A5&quot;&gt;void&lt;/span&gt;&amp;nbsp;saveAll(List&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;lt;&lt;/span&gt;Data&lt;span style=&quot;color:#BB86F9&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F1A5A5&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;bulkdata)&amp;nbsp;{&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dao.saveAll(bulkdata);&lt;/div&gt;&lt;div style=&quot;padding:0 6px; white-space:pre; line-height:130%&quot;&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;color:#4f4f4ftext-decoration:none&quot;&gt;Colored by Color Scripter&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;vertical-align:bottom;padding:0 2px 4px 0&quot;&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot; target=&quot;_blank&quot; style=&quot;text-decoration:none;color:white&quot;&gt;&lt;span style=&quot;font-size:9px;word-break:normal;background-color:#4f4f4f;color:white;border-radius:10px;padding:1px&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;이렇게 Concurrency &amp;amp; Async 설정을 통해 파티션 수를 증가시키지 않고 애플리케이션 레벨에서의 스케일링하는 방법을 알아보았습니다. &lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;애플리케이션 레벨에서의 스케일링은 Kafka 시스템의 구조적 변경 없이도 가능하기 때문에&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Kafka를 효율적으로 관리할 수 있었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러한 전략들의 도입으로 Telemetry 서비스는 하루에 수억 건의 데이터를 처리할 수 있는 서비스 아키텍처로 바뀌었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Kafka Batch Listener의 사용은 데이터 처리량이 많은 상황에서도 효율적인 메시지 처리를 가능하게 했으며, Bulk Insert 전략은 데이터베이스 쓰기 작업의 성능을 크게 향상시켰습니다. 또한, 파티션 수를 무작정 늘리는 대신 Concurrency와 @Async 어노테이션을 활용함으로써 시스템의 복잡성을 최소화하면서 처리 능력을 극대화했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmoUT/btsBGu4pStb/ryfklQVK4gtTQbzNIfC3N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmoUT/btsBGu4pStb/ryfklQVK4gtTQbzNIfC3N1/img.png&quot; data-alt=&quot;Telemetry 서비스 구조 개선 전 (TO-BE)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmoUT/btsBGu4pStb/ryfklQVK4gtTQbzNIfC3N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvmoUT%2FbtsBGu4pStb%2FryfklQVK4gtTQbzNIfC3N1%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;1174&quot; height=&quot;892&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Telemetry 서비스 구조 개선 전 (TO-BE)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러한 개선을 통해, Telemetry 서비스는 높은 처리량과 확장성을 요구하는 환경에서도 원활하게 작동할 수 있는 견고한 아키텍처를 갖추게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;미션 목표&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1분마다 50만개 메시지 처리 (하루 누적 7억 2천개)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1개 Message&amp;nbsp;크기 : 5 KB&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #374151; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;부하테스트 환경&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7209%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Kafka Broker&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.2791%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Instance Type&lt;/b&gt;: kafka.m5.2xlarge&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Zone 당 Broker 개수&lt;/b&gt;: 1개&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;총 Broker 개수&lt;/b&gt;: 2개&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7209%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;K8S Deployment&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.2791%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Pod 개수&lt;/b&gt;: 4개&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;리소스 사양&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Limits&lt;/b&gt;: CPU - 6 cores, 메모리 - 6000Mi&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Requests&lt;/b&gt;: CPU - 1 core, 메모리 - 1000Mi&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7209%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Timescale DB (EC2)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.2791%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Access Node&lt;/b&gt;: m5.4xlarge&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Data Node 1&lt;/b&gt;: m5.4xlarge&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Data Node 2&lt;/b&gt;: m5.4xlarge&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&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;</description>
      <category>이슈 해결과정 기록</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/389</guid>
      <comments>https://developer-pi.tistory.com/389#entry389comment</comments>
      <pubDate>Fri, 8 Dec 2023 16:23:02 +0900</pubDate>
    </item>
    <item>
      <title>Kafka Batch Listener를 활용하여 성능 개선하기</title>
      <link>https://developer-pi.tistory.com/388</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka Consumer를 운영하는 서비스에서 메시지를 개별적으로 처리하면, 각 메시지를 가져오고 처리하는데 필요한 네트워크 오버헤드와 CPU 사용량이 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;특히, 각 메시지에 대해 별도의 트랜잭션을 시작하고 커밋하는 것은 비용이 많이 든다. &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;DB와의 네트워크 통신, 트랜잭션 로그의 쓰기, 디스크 I/O 등에 의한 오버헤드가 각 메시지마다 발생하므로 메시지 처리 성능이 저하될 수 있다. 뿐 만 아니라 각 메시지 처리에 대해 별도 DB Connection Pool이 고갈되어, 새로운 트랜잭션을 생성할 수 없게된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f7f7f8; color: #374151; text-align: left;&quot;&gt;이러한 경우 배치 처리를 사용하면 여러 메시지를 하나의 트랜잭션으로 쉽게 묶어 처리할 수 있다.&lt;/span&gt;&lt;span style=&quot;background-color: #f7f7f8; color: #374151; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Batch Listener를 구현하는 방법에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &amp;nbsp;Kafka Listener 구현&lt;/p&gt;
&lt;pre id=&quot;code_1687087243182&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @KafkaListener(topics = {&quot;topic&quot;}, containerFactory = &quot;batchKafkaListenerContainerFactory&quot;)
    public void consume(List&amp;lt;ConsumerRecord&amp;lt;String, String&amp;gt;&amp;gt; records, Acknowledgment ack) {	
        
        // 로직 수행
        handler.process();
        
        // Commit
        ack.acknowledge();
    }&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;2. Container Factory 설정&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1687087458821&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Bean
    public ConcurrentKafkaListenerContainerFactory&amp;lt;String, String&amp;gt; batchKafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory&amp;lt;String, String&amp;gt; factory = new ConcurrentKafkaListenerContainerFactory&amp;lt;&amp;gt;();
        var containerProperties = factory.getContainerProperties();
        containerProperties.setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
        // Auto Commit일 경우
        // containerProperties.setAckMode(ContainerProperties.AckMode.BATCH);
        factory.getContainerProperties().setIdleBetweenPolls(60000);
        factory.setConsumerFactory(batchConsumerFactory());
        factory.setBatchListener(true);
        return factory;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;setIdleBetweenPolls:&amp;nbsp;두&amp;nbsp;poll&amp;nbsp;사이의&amp;nbsp;최대&amp;nbsp;대기&amp;nbsp;시간을&amp;nbsp;설정&lt;/li&gt;
&lt;li&gt;setBatchListener: Listener가&amp;nbsp;배치&amp;nbsp;모드로&amp;nbsp;동작 (여러&amp;nbsp;메시지를&amp;nbsp;한&amp;nbsp;번에&amp;nbsp;가져와&amp;nbsp;처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setIdleBetweenPolls를 설정하지 않으면, Consumer가 바로 poll을 수행하기 때문에 상황에 따라 batch가 의미가 없어질 수 도 있다. setIdleBetweenPolls를 설정하면, poll을 수행하기 전에 idle time 동안 메시지를 쌓고 난후에 batch 처리할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1687087072061&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Bean
    public ConsumerFactory&amp;lt;String, String&amp;gt; batchConsumerFactory() {
        Map&amp;lt;String, Object&amp;gt; props = new HashMap&amp;lt;&amp;gt;();
        props.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, &quot;earliest&quot;);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, keyDeserializer);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, valueDeserializer);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
        props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);
        props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 300000);
        props.put(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, 60000);
        // Auto Commit일 경우
        // props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
        // props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 10000);

        return new DefaultKafkaConsumerFactory&amp;lt;&amp;gt;(props);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MAX_POLL_RECORDS_CONFIG: 한 번의 poll에 의해 반환될 수 있는 최대 레코드 수를 지정&lt;/li&gt;
&lt;li&gt;MAX_POLL_INTERVAL_MS_CONFIG: Consumer가 Broker에게 정상적으로 응답하기 위한 최대 시간을 지정&lt;/li&gt;
&lt;li&gt;FETCH_MAX_WAIT_MS_CONFIG: Broker가 요청에 응답하기 전에 대기하는 최대 시간을 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;batch 처리의 효과를 높이기 위해서는 MAX_POLL_RECORDS_CONFIG를 통해 반환될 수 있는 최대 레코드 수를 적절하게 지정해야 한다. 각 비즈니스 환경에 따라 다르기 때문에 상황을 고려해서 적절하게 설정하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FETCH_MAX_WAIT_MS_CONFIG는 메세지가 없을 때 대기하는 최대시간을 설정할 수 있다. 이 때 주의해야할 것은 FETCH_MAX_WAIT_MS_CONFIG&amp;nbsp;값은 MAX_POLL_INTERVAL_MS_CONFIG 값보다 작아야 된다. MAX_POLL_INTERVAL_MS_CONFIG은 Consumer가 Brokerd에게 정상적으로 응답하기 위한 최대 시간을 설정하는 값이기 때문에 FETCH_MAX_WAIT_MS_CONFIG값이 더 크면 Timeout이 발생하여 Broker가 비정상으로 인지하여 Rebalancing이 일어날 수 있다.&lt;/p&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2646&quot; data-origin-height=&quot;42&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CbG9U/btskrnA1yZG/RS1mtdk4xuKK3MSdW8UWB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CbG9U/btskrnA1yZG/RS1mtdk4xuKK3MSdW8UWB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CbG9U/btskrnA1yZG/RS1mtdk4xuKK3MSdW8UWB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCbG9U%2FbtskrnA1yZG%2FRS1mtdk4xuKK3MSdW8UWB0%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;3809&quot; height=&quot;60&quot; data-origin-width=&quot;2646&quot; data-origin-height=&quot;42&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka Batch Listener를 통해 한 번에 여러 메시지를 batch 처리하고, &amp;nbsp;bulk Insert까지 잘 수행 된 것을 볼 수 있다.&lt;/p&gt;</description>
      <category>Kafka</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/388</guid>
      <comments>https://developer-pi.tistory.com/388#entry388comment</comments>
      <pubDate>Sun, 18 Jun 2023 20:58:14 +0900</pubDate>
    </item>
    <item>
      <title>[우아한테크캠프 Pro] 8주차 미션 후기 (안정적인 서비스 만들기)</title>
      <link>https://developer-pi.tistory.com/375</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우아한테크캠프 Pro 8주차 안정적인 서비스 만들기 미션을 진행한 내용과 후기를 정리해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;미션 저장소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/infra-subway-performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Gyeom/infra-subway-performance&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672667068825&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 - Gyeom/infra-subway-performance&quot; data-og-description=&quot;Contribute to Gyeom/infra-subway-performance development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Gyeom/infra-subway-performance&quot; data-og-url=&quot;https://github.com/Gyeom/infra-subway-performance&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EM3W6/hyQ6ZbHB9T/jxRkOkfx95SA6xeGMfwPP0/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/infra-subway-performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Gyeom/infra-subway-performance&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EM3W6/hyQ6ZbHB9T/jxRkOkfx95SA6xeGMfwPP0/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211');&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 - Gyeom/infra-subway-performance&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to Gyeom/infra-subway-performance 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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;학습 내용&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;HTTP 개선에 따른 차이를 이해하고 Reverse Proxy 성능 개선을 해봅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;HTTP Cache 전략을 이해하여 적절한 정책을 설정해봅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;쿼리를 최적화하여 조회 성능을 개선해봅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;인덱스를 설정하여 조회 성능을 개선해봅니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;단계별 요구사항 및 PR 리뷰&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;1단계&amp;nbsp;-&amp;nbsp;화면&amp;nbsp;응답&amp;nbsp;개선하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Reverse Proxy 개선하기&lt;/li&gt;
&lt;li&gt;WAS 성능 개선하기&lt;/li&gt;
&lt;li&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;확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/410&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-performance/pull/410&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672667514372&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #410 &amp;middot; next-step/infra-subway-performance&quot; data-og-description=&quot;안녕하세요 리뷰어님, Step1 화면 응답 개선하기 미션 리뷰 요청드립니다~! revers proxy 및 redis 캐싱적용을 했지만 개선 효과를 비교하기 좀 어려운 상황인데, 자문을 구해도 될까요~? 감사합니다.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/410&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-performance/pull/410&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cx29Ro/hyQ84bmjLp/wlTOvJ90ss6kYklvScJK2k/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/410&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/410&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cx29Ro/hyQ84bmjLp/wlTOvJ90ss6kYklvScJK2k/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #410 &amp;middot; next-step/infra-subway-performance&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, Step1 화면 응답 개선하기 미션 리뷰 요청드립니다~! revers proxy 및 redis 캐싱적용을 했지만 개선 효과를 비교하기 좀 어려운 상황인데, 자문을 구해도 될까요~? 감사합니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;994&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQkP7E/btrU8GfzvtH/fa1XB5OFytAhikwLRQ12JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQkP7E/btrU8GfzvtH/fa1XB5OFytAhikwLRQ12JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQkP7E/btrU8GfzvtH/fa1XB5OFytAhikwLRQ12JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQkP7E%2FbtrU8GfzvtH%2Ffa1XB5OFytAhikwLRQ12JK%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;994&quot; height=&quot;228&quot; data-origin-width=&quot;994&quot; data-origin-height=&quot;228&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;993&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2cWs9/btrVecSj4ui/EauhHZKW3FZNVSliLs20J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2cWs9/btrVecSj4ui/EauhHZKW3FZNVSliLs20J0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2cWs9/btrVecSj4ui/EauhHZKW3FZNVSliLs20J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2cWs9%2FbtrVecSj4ui%2FEauhHZKW3FZNVSliLs20J0%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;993&quot; height=&quot;591&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;591&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;995&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nQaqA/btrU44aaQZj/375IhitxG7ieKg1TfUbC2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nQaqA/btrU44aaQZj/375IhitxG7ieKg1TfUbC2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nQaqA/btrU44aaQZj/375IhitxG7ieKg1TfUbC2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnQaqA%2FbtrU44aaQZj%2F375IhitxG7ieKg1TfUbC2k%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;995&quot; height=&quot;316&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;316&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;993&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsXhIM/btrU9ddkDg6/SncMl5SsYAtCz6xQCbmUS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsXhIM/btrU9ddkDg6/SncMl5SsYAtCz6xQCbmUS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsXhIM/btrU9ddkDg6/SncMl5SsYAtCz6xQCbmUS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsXhIM%2FbtrU9ddkDg6%2FSncMl5SsYAtCz6xQCbmUS0%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;993&quot; height=&quot;449&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Reverse Proxy와 WAS에 캐싱을 적용했는데 생각보다 개선효과과 미미했다.&lt;/li&gt;
&lt;li&gt;부하테스트를 진행할 때는 일정 간격을 두고 점진적으로 VUser가 증가 되도록 시나리오를 구성해보자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  2단계 - 스케일 아웃 (with ASG)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;springboot에 HTTP Cache, gzip 설정하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;Launch Template 작성하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;Auto Scaling Group 생성하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;Smoke, Load, Stress 테스트 후 결과를 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/459&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-performance/pull/459&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672668314950&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #459 &amp;middot; next-step/infra-subway-performance&quot; data-og-description=&quot;안녕하세요 리뷰어님, 2단계 - 스케일 아웃 (with ASG) 리뷰 요청 드립니다. 일단 저번에 healthy 힌트를 주셔서, 가장 먼저 helathy 포트를 8080으로 변경하여 정상 상태로 만들었습니다. 그래도 똑같은 &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/459&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-performance/pull/459&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b2o2wC/hyQ8WxDm4H/nSDgsTSL78UODAcxtGfKzK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/459&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/459&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b2o2wC/hyQ8WxDm4H/nSDgsTSL78UODAcxtGfKzK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #459 &amp;middot; next-step/infra-subway-performance&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 2단계 - 스케일 아웃 (with ASG) 리뷰 요청 드립니다. 일단 저번에 healthy 힌트를 주셔서, 가장 먼저 helathy 포트를 8080으로 변경하여 정상 상태로 만들었습니다. 그래도 똑같은&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;994&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TLOAE/btrVecxXI9J/NANaoaIKvBV8TZ6iB3g5hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TLOAE/btrVecxXI9J/NANaoaIKvBV8TZ6iB3g5hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TLOAE/btrVecxXI9J/NANaoaIKvBV8TZ6iB3g5hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTLOAE%2FbtrVecxXI9J%2FNANaoaIKvBV8TZ6iB3g5hk%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;994&quot; height=&quot;503&quot; data-origin-width=&quot;994&quot; data-origin-height=&quot;503&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;882&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EKadU/btrVexPBrqW/4WBNBkAHMekQwsOT4KQxXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EKadU/btrVexPBrqW/4WBNBkAHMekQwsOT4KQxXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EKadU/btrVexPBrqW/4WBNBkAHMekQwsOT4KQxXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEKadU%2FbtrVexPBrqW%2F4WBNBkAHMekQwsOT4KQxXK%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;882&quot; height=&quot;448&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Auto Scaling은 warm up이 있어서 구간을 보다 길게 갖고 가자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;389&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3zXGR/btrVcl9JOrb/mqfAKTOQexxZoqyzBj6KeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3zXGR/btrVcl9JOrb/mqfAKTOQexxZoqyzBj6KeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3zXGR/btrVcl9JOrb/mqfAKTOQexxZoqyzBj6KeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3zXGR%2FbtrVcl9JOrb%2FmqfAKTOQexxZoqyzBj6KeK%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;882&quot; height=&quot;389&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;389&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작템플릿에 redis를 띄우는 스크립트까지 포함 했다. 이렇게 되면 매 인스턴스마다 불필요하게 redis가 새로 만들어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HLU4T/btrValhUlXj/dul7AquoUlGjLeOiPF1lD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HLU4T/btrValhUlXj/dul7AquoUlGjLeOiPF1lD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HLU4T/btrValhUlXj/dul7AquoUlGjLeOiPF1lD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHLU4T%2FbtrValhUlXj%2Fdul7AquoUlGjLeOiPF1lD1%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;267&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Controller에서 HttpServletResponse 를 받은 후 직접 `Cache-Controle`을 할당하여 설정할 수도 있고, WebContentInterceptor를 활용할 수 도 있다.&lt;/li&gt;
&lt;li&gt;로그인용 사용자 이름, 비밀번호 및 기타 민감한 정보들을 보호하기 위해 SSL 을 로그인 페이지나 회원 정보 페이지등은 SSL로 암호화하는 경우가 많다. SSL 을 사용해서 민감한 정보들을 보호한다고 해도 브라우저에 이 정보가 캐싱되면 문제가 발생할 수 있기 때문에 `Cache-Control: no-cache, no-store, must-revalidate` 와 같이 사용하면 브라우저 캐싱을 방지할 수 있다. 단 캐싱을 하지 않으면 성능 저하가 발생할 수 있으므로 로그인 페이지등에 제한적으로 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;3단계&amp;nbsp;-&amp;nbsp;쿼리&amp;nbsp;최적화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;활동중인(Active) 부서의 현재 부서관리자(manager) 중 연봉 상위 5위안에 드는 사람들이 최근에 각 지역별로 언제 퇴실(O)했는지 조회해보세요.&lt;br /&gt;(사원번호, 이름, 연봉, 직급명, 지역, 입출입구분, 입출입시간)&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;인덱스 설정을 추가하지 않고 200ms 이하로 반환합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;M1의 경우엔 시간 제약사항을 달성하기 어렵습니다. 2s를 기준으로 해보시고 어렵다면, 일단 리뷰요청 부탁드려요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;급여 테이블의 사용여부 필드는 사용하지 않습니다. 현재 근무중인지 여부는 종료일자 필드로 판단해주세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/485&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-performance/pull/485&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672670677511&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #485 &amp;middot; next-step/infra-subway-performance&quot; data-og-description=&quot;안녕하세요 리뷰어님 :) 3단계 쿼리최적화 리뷰 요청드립니다. 이번 미션은 성능 효율이 중요했기 때문에, query condition부분에 신경을 써서 작성했습니다. 감사합니다.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/485&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-performance/pull/485&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/l60EY/hyQ6YRpoKK/GDKK0rWSn4Tcxz8tLQ1zM0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/485&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/485&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/l60EY/hyQ6YRpoKK/GDKK0rWSn4Tcxz8tLQ1zM0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #485 &amp;middot; next-step/infra-subway-performance&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님 :) 3단계 쿼리최적화 리뷰 요청드립니다. 이번 미션은 성능 효율이 중요했기 때문에, query condition부분에 신경을 써서 작성했습니다. 감사합니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9DL0q/btrU45tmPRE/NjCD3MjKIIgnmyrb0YHfwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9DL0q/btrU45tmPRE/NjCD3MjKIIgnmyrb0YHfwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9DL0q/btrU45tmPRE/NjCD3MjKIIgnmyrb0YHfwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9DL0q%2FbtrU45tmPRE%2FNjCD3MjKIIgnmyrb0YHfwK%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;993&quot; height=&quot;233&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;233&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;994&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfcFre/btrU7HMvJAD/lWi8wQAi5QAimbGGietoAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfcFre/btrU7HMvJAD/lWi8wQAi5QAimbGGietoAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfcFre/btrU7HMvJAD/lWi8wQAi5QAimbGGietoAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfcFre%2FbtrU7HMvJAD%2FlWi8wQAi5QAimbGGietoAk%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;994&quot; height=&quot;727&quot; data-origin-width=&quot;994&quot; data-origin-height=&quot;727&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;4단계&amp;nbsp;-&amp;nbsp;인덱스&amp;nbsp;설계&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;주어진 데이터셋을 활용하여 아래 조회 결과를 100ms 이하로 반환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;M1의 경우엔 시간 제약사항을 달성하기 어렵습니다. 2배를 기준으로 해보시고 어렵다면, 일단 리뷰요청 부탁드려요&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;&lt;a href=&quot;https://insights.stackoverflow.com/survey/2018#developer-profile-_-coding-as-a-hobby&quot;&gt;Coding as a Hobby&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;와 같은 결과를 반환하세요.&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;프로그래머별로 해당하는 병원 이름을 반환하세요. (covid.id, hospital.name)&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;프로그래밍이 취미인 학생 혹은 주니어(0-2년)들이 다닌 병원 이름을 반환하고 user.id 기준으로 정렬하세요. (covid.id, hospital.name, user.Hobby, user.DevType, user.YearsCoding)&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;서울대병원에 다닌 20대 India 환자들을 병원에 머문 기간별로 집계하세요. (covid.Stay)&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;서울대병원에 다닌 30대 환자들을 운동 횟수별로 집계하세요. (user.Exercise)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/513&quot;&gt;https://github.com/next-step/infra-subway-performance/pull/513&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672670792689&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;[김대겸] Step4 PR by Gyeom &amp;middot; Pull Request #513 &amp;middot; next-step/infra-subway-performance&quot; data-og-description=&quot;안녕하세요 리뷰어님 4단계 - 인덱스 설계 리뷰 요청드립니다. 이번 리뷰도 잘 부탁드립니다 ~!&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/513&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-performance/pull/513&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b41Q8W/hyQ8VZPa9c/XsKgnrYXdnKMyj3PjVatY0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/513&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/513&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b41Q8W/hyQ8VZPa9c/XsKgnrYXdnKMyj3PjVatY0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step4 PR by Gyeom &amp;middot; Pull Request #513 &amp;middot; next-step/infra-subway-performance&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님 4단계 - 인덱스 설계 리뷰 요청드립니다. 이번 리뷰도 잘 부탁드립니다 ~!&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1cJiA/btrU56Z4JaU/SSsB08EW0RU90KxClkAuiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1cJiA/btrU56Z4JaU/SSsB08EW0RU90KxClkAuiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1cJiA/btrU56Z4JaU/SSsB08EW0RU90KxClkAuiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1cJiA%2FbtrU56Z4JaU%2FSSsB08EW0RU90KxClkAuiK%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;998&quot; height=&quot;197&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;197&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;1002&quot; data-origin-height=&quot;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4ZGEx/btrVgjXsvZN/JNEd7HrIKnm8muy6yHGQlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4ZGEx/btrVgjXsvZN/JNEd7HrIKnm8muy6yHGQlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4ZGEx/btrVgjXsvZN/JNEd7HrIKnm8muy6yHGQlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4ZGEx%2FbtrVgjXsvZN%2FJNEd7HrIKnm8muy6yHGQlK%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;1002&quot; height=&quot;661&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;661&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;[추가]&amp;nbsp;페이징,&amp;nbsp;Replication&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이징 쿼리 작성&lt;/li&gt;
&lt;li&gt;MySQL&amp;nbsp;Replication&amp;nbsp;with&amp;nbsp;JPA&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/542&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-performance/pull/542&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672671018381&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;[김대겸] Step5 PR by Gyeom &amp;middot; Pull Request #542 &amp;middot; next-step/infra-subway-performance&quot; data-og-description=&quot;안녕하세요 리뷰어님, [추가] 페이징, Replication 단계 리뷰 요청드립니다. 처음에 제가 설정을 잘못했는지 위와 같이 Slave_IO_Running이 NO로 나오더라구요.. 현재는 정상적으로 나오도록 조치했습니&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/542&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-performance/pull/542&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dwsn9X/hyQ8XJ6o1N/Kd9RJTEvb9ojKwNKhaN9U1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-performance/pull/542&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-performance/pull/542&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dwsn9X/hyQ8XJ6o1N/Kd9RJTEvb9ojKwNKhaN9U1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step5 PR by Gyeom &amp;middot; Pull Request #542 &amp;middot; next-step/infra-subway-performance&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, [추가] 페이징, Replication 단계 리뷰 요청드립니다. 처음에 제가 설정을 잘못했는지 위와 같이 Slave_IO_Running이 NO로 나오더라구요.. 현재는 정상적으로 나오도록 조치했습니&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rq1Jy/btrVcMlYKi2/Ct49OzMtKj4RgNeBiBs0b0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rq1Jy/btrVcMlYKi2/Ct49OzMtKj4RgNeBiBs0b0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rq1Jy/btrVcMlYKi2/Ct49OzMtKj4RgNeBiBs0b0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frq1Jy%2FbtrVcMlYKi2%2FCt49OzMtKj4RgNeBiBs0b0%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;995&quot; height=&quot;356&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;356&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;1003&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CTxFS/btrU542fReg/5X51OKnjGtn4JxBLFfYiA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CTxFS/btrU542fReg/5X51OKnjGtn4JxBLFfYiA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CTxFS/btrU542fReg/5X51OKnjGtn4JxBLFfYiA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCTxFS%2FbtrU542fReg%2F5X51OKnjGtn4JxBLFfYiA1%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;1003&quot; height=&quot;668&quot; data-origin-width=&quot;1003&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;미션 회고&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&amp;nbsp;이번 미션에서 Auto Scaling Group을 구성하는 실습을 진행하면서 삽질을 좀 많이했다. 502 Bad Gateway가 발생해서 보니 서버가 아예 구동되지 않았고 시작템플릿의 문제임을 짐작할 수 있었다. 원인은 mac에서 업로드한 배포스크립트의 행간 문제였던것으로 파악되었다. 그 외에도 인증 관련 이슈 때문에 시간을 많이 날려먹었는데 알고보니 chain.pem을 잘못 복사해서 alb에 적용해서 발생한 이슈였다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;8주차까지 우아한테크캠프 PRO 미션을 모두 완료했다. 8주 전 보다 많은 양의 학습 지식을 습득 한 것은 분명하다. 밑 빠진 독이 되지 않기 위해서 지금까지 배운 내용들을 복습하자. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;늘 초심의 마음으로.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>우아한테크캠프 PRO/우아한테크캠프 회고록</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/375</guid>
      <comments>https://developer-pi.tistory.com/375#entry375comment</comments>
      <pubDate>Tue, 3 Jan 2023 00:15:48 +0900</pubDate>
    </item>
    <item>
      <title>[우아한테크캠프 Pro] 7주차 미션 후기 (레거시 코드 리팩터링)</title>
      <link>https://developer-pi.tistory.com/374</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우아한테크캠프 Pro 7주차 레거시&amp;nbsp;코드&amp;nbsp;리팩터링을 진행한 내용과 후기를 정리해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;미션 저장소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/jwp-refactoring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Gyeom/jwp-refactoring&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672658677556&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 - Gyeom/jwp-refactoring&quot; data-og-description=&quot;Contribute to Gyeom/jwp-refactoring development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Gyeom/jwp-refactoring&quot; data-og-url=&quot;https://github.com/Gyeom/jwp-refactoring&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bw4okq/hyQ6Rq6nT8/SJAiWLgpv12we3oo7udKyK/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/jwp-refactoring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Gyeom/jwp-refactoring&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bw4okq/hyQ6Rq6nT8/SJAiWLgpv12we3oo7udKyK/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211');&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 - Gyeom/jwp-refactoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to Gyeom/jwp-refactoring 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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;학습 내용&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;많은 기업들이 &quot;서비스를 안정적으로 운영하면서 레거시 코드를 리팩터링할 수 있는 역량을 갖춘 개발자&quot;를 요구한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레거시 프로젝트를 리팩터링하는 경험을 통해 서비스를 안정적으로 운영하면서 레거시 코드를 리팩터링할 수 있는 역량을 키운다.&lt;/li&gt;
&lt;li&gt;프로젝트를 만드는 단계에서 끝나는 것이 아니라 프로젝트를 완료한 후 일정 기간 유지보수를 함으로써 레거시 코드를 리팩터링하는 경험을 쌓는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;단계별 요구사항 및 PR 리뷰&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;1단계&amp;nbsp;-&amp;nbsp;테스트를&amp;nbsp;통한&amp;nbsp;코드&amp;nbsp;보호&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;kitchenpos&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&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;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;README.md에 작성한다. 미션을 진행함에 있어 아래 문서를 적극 활용한다.&lt;/span&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://dooray.com/htmls/guides/markdown_ko_KR.html&quot;&gt;마크다운(Markdown) - Dooray!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정리한 키친포스의 요구 사항을 토대로 테스트 코드를 작성한다. 모든 Business Object에 대한 테스트 코드를 작성한다.&amp;nbsp;@SpringBootTest를 이용한 통합 테스트 코드 또는 @ExtendWith(MockitoExtension.class)를 이용한 단위 테스트 코드를 작성한다.&lt;/li&gt;
&lt;li&gt;인수 테스트 코드 작성은 권장하지만 필수는 아니다. 미션을 진행함에 있어 아래 문서를 적극 활용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-boot-testing&quot;&gt;Testing in Spring Boot - Baeldung&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-boot-testresttemplate&quot;&gt;Exploring the Spring Boot TestRestTemplate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/jwp-refactoring/pull/651&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/jwp-refactoring/pull/651&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672659999133&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #651 &amp;middot; next-step/jwp-refactoring&quot; data-og-description=&quot;안녕하세요 리뷰어님, 1단계 - 테스트를 통한 코드 보호 리뷰 요청 드립니다. 잘 부탁드립니다 :)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/jwp-refactoring/pull/651&quot; data-og-url=&quot;https://github.com/next-step/jwp-refactoring/pull/651&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VeJgA/hyQ87FRXOd/1dzVKTd9KkkGAG4vhuQwYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/jwp-refactoring/pull/651&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/jwp-refactoring/pull/651&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VeJgA/hyQ87FRXOd/1dzVKTd9KkkGAG4vhuQwYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #651 &amp;middot; next-step/jwp-refactoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 1단계 - 테스트를 통한 코드 보호 리뷰 요청 드립니다. 잘 부탁드립니다 :)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1047&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZ49k/btrVeWIlcZe/g4IPhDJM545Ttg4lQG3mO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZ49k/btrVeWIlcZe/g4IPhDJM545Ttg4lQG3mO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZ49k/btrVeWIlcZe/g4IPhDJM545Ttg4lQG3mO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZ49k%2FbtrVeWIlcZe%2Fg4IPhDJM545Ttg4lQG3mO0%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;1047&quot; height=&quot;317&quot; data-origin-width=&quot;1047&quot; data-origin-height=&quot;317&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;880&quot; data-origin-height=&quot;847&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBwwre/btrVeyHHnli/qkYv29XxgkqV3tc4p2kwZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBwwre/btrVeyHHnli/qkYv29XxgkqV3tc4p2kwZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBwwre/btrVeyHHnli/qkYv29XxgkqV3tc4p2kwZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBwwre%2FbtrVeyHHnli%2FqkYv29XxgkqV3tc4p2kwZ1%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;880&quot; height=&quot;847&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;847&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재사용이 빈번한 객체는 fixture 올려놓자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;2단계&amp;nbsp;-&amp;nbsp;서비스&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;&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-te-task=&quot;&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;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/jwp-refactoring/pull/681&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/jwp-refactoring/pull/681&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672660280111&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #681 &amp;middot; next-step/jwp-refactoring&quot; data-og-description=&quot;안녕하세요 리뷰어님, 정말 힘들었던 미션이었습니다 ㅠㅠㅠㅠ 도메인 생성 관련 테스트 코드 작성 서비스 레이어에 있던 비즈니스 로직을 각 도메인에 책임 부여 dao 정상 동작을 위해, dao호출 &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/jwp-refactoring/pull/681&quot; data-og-url=&quot;https://github.com/next-step/jwp-refactoring/pull/681&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/M7ct1/hyQ6WFX25d/AnI2fd9k9FKKaak3qtWZF1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1006_138_1051_186&quot;&gt;&lt;a href=&quot;https://github.com/next-step/jwp-refactoring/pull/681&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/jwp-refactoring/pull/681&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/M7ct1/hyQ6WFX25d/AnI2fd9k9FKKaak3qtWZF1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1006_138_1051_186');&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #681 &amp;middot; next-step/jwp-refactoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 정말 힘들었던 미션이었습니다 ㅠㅠㅠㅠ 도메인 생성 관련 테스트 코드 작성 서비스 레이어에 있던 비즈니스 로직을 각 도메인에 책임 부여 dao 정상 동작을 위해, dao호출&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;991&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nlHUN/btrU6XIzJQN/Ja6kdwHGkwEkWo38uhpLZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nlHUN/btrU6XIzJQN/Ja6kdwHGkwEkWo38uhpLZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nlHUN/btrU6XIzJQN/Ja6kdwHGkwEkWo38uhpLZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnlHUN%2FbtrU6XIzJQN%2FJa6kdwHGkwEkWo38uhpLZK%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;991&quot; height=&quot;495&quot; data-origin-width=&quot;991&quot; data-origin-height=&quot;495&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;929&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r7ZzX/btrVe5kW979/w0f6CcqCXqq6VIOz2CtPv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r7ZzX/btrVe5kW979/w0f6CcqCXqq6VIOz2CtPv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r7ZzX/btrVe5kW979/w0f6CcqCXqq6VIOz2CtPv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr7ZzX%2FbtrVe5kW979%2Fw0f6CcqCXqq6VIOz2CtPv1%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;929&quot; height=&quot;239&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;239&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;884&quot; data-origin-height=&quot;811&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MS772/btrVebMwlNS/pxW5Suf47TgldJl2pb1SaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MS772/btrVebMwlNS/pxW5Suf47TgldJl2pb1SaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MS772/btrVebMwlNS/pxW5Suf47TgldJl2pb1SaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMS772%2FbtrVebMwlNS%2FpxW5Suf47TgldJl2pb1SaK%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;884&quot; height=&quot;811&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;811&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떻게하면 inquery로 개선할 수 있을 지 고민하다가 복잡도가 N이 초과하지 않는 방법으로 map을 활용했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1672660930868&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    private List&amp;lt;MenuProduct&amp;gt; findAllMenuProductsByProductId(List&amp;lt;MenuProductRequest&amp;gt; menuProductRequests) {
        List&amp;lt;Product&amp;gt; products = toProduct(menuProductRequests);
        validateProducts(products, menuProductRequests);
        Map&amp;lt;Long, Product&amp;gt; productIdToProduct = new HashMap&amp;lt;&amp;gt;();
        
        for (Product product : products) {
            productIdToProduct.put(product.getId(), product);
        }
        
        return menuProductRequests.stream()
        		.map(menuProductRequest -&amp;gt; menuProductRequest.toMenuProduct(productIdToProduct.get(menuProductRequest.getProductId())))
  		        .collect(Collectors.toList());
}&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;880&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXL2Io/btrVam8U27S/B86IA1txOUBGMuVUpsDKU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXL2Io/btrVam8U27S/B86IA1txOUBGMuVUpsDKU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXL2Io/btrVam8U27S/B86IA1txOUBGMuVUpsDKU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXL2Io%2FbtrVam8U27S%2FB86IA1txOUBGMuVUpsDKU1%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;880&quot; height=&quot;477&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;477&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;884&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKBNkB/btrU3bN6SEh/wYcpgxwI9xoCYhkFTW7mlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKBNkB/btrU3bN6SEh/wYcpgxwI9xoCYhkFTW7mlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKBNkB/btrU3bN6SEh/wYcpgxwI9xoCYhkFTW7mlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKBNkB%2FbtrU3bN6SEh%2FwYcpgxwI9xoCYhkFTW7mlK%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;884&quot; height=&quot;370&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순히 change보다 해당 명령을 표현할 수 있는 네이밍을 고려하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0T9aJ/btrVgiYpRRv/R1l4WKVkwjXKUInBYcjGKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0T9aJ/btrVgiYpRRv/R1l4WKVkwjXKUInBYcjGKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0T9aJ/btrVgiYpRRv/R1l4WKVkwjXKUInBYcjGKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0T9aJ%2FbtrVgiYpRRv%2FR1l4WKVkwjXKUInBYcjGKK%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;884&quot; height=&quot;387&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt; enum 사용 시, 역할을 보다 쉽고 명확하게 알아볼 수 있도록 description을 만들어 관리하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JF95i/btrVcmngyJo/1S0L9efN7t645axIwtjtKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JF95i/btrVcmngyJo/1S0L9efN7t645axIwtjtKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JF95i/btrVcmngyJo/1S0L9efN7t645axIwtjtKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJF95i%2FbtrVcmngyJo%2F1S0L9efN7t645axIwtjtKk%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;879&quot; height=&quot;403&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OneToMany Lazy에서는 Hibernate Batch Size 옵션의 사용을 고려하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIt95l/btrU29JtJKH/2lVTPy9lvMhcAV9kkRPkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIt95l/btrU29JtJKH/2lVTPy9lvMhcAV9kkRPkK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIt95l/btrU29JtJKH/2lVTPy9lvMhcAV9kkRPkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIt95l%2FbtrU29JtJKH%2F2lVTPy9lvMhcAV9kkRPkK1%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;886&quot; height=&quot;372&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;repository를 통해 조회하는 것은 findXXX 규칙을 사용하자. (다른 CRUD 도 마찬가지)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;3단계&amp;nbsp;-&amp;nbsp;의존성&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;이전 단계에서 객체 지향 설계를 의식하였다면 아래의 문제가 존재한다. 의존성 관점에서 설계를 검토해 본다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메뉴의 이름과 가격이 변경되면 주문 항목도 함께 변경된다. 메뉴 정보가 변경되더라도 주문 항목이 변경되지 않게 구현한다.&lt;/li&gt;
&lt;li&gt;클래스 간의 방향도 중요하고 패키지 간의 방향도 중요하다. 클래스 사이, 패키지 사이의 의존 관계는 단방향이 되도록 해야 한다.&lt;/li&gt;
&lt;li&gt;데이터베이스 스키마 변경 및 마이그레이션이 필요하다면 아래 문서를 적극 활용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://meetup.toast.com/posts/173&quot;&gt;DB도 형상관리를 해보자!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/jwp-refactoring/pull/735&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/jwp-refactoring/pull/735&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672661404042&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #735 &amp;middot; next-step/jwp-refactoring&quot; data-og-description=&quot;안녕하세요 리뷰어님, 3단계 의존성 리팩터링 리뷰요청드립니다. 패키지 분리 (Lifecycle이 같은 도메인들은 같은 Aggregate) 서로 다른 Aggregate의 엔티티간의 단방향 참조를 할 수 있도록 간접참조 활&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/jwp-refactoring/pull/735&quot; data-og-url=&quot;https://github.com/next-step/jwp-refactoring/pull/735&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cATzej/hyQ8Tt5MB9/lZAeAHqptVLjSWzQfkA8nK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/jwp-refactoring/pull/735&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/jwp-refactoring/pull/735&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cATzej/hyQ8Tt5MB9/lZAeAHqptVLjSWzQfkA8nK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #735 &amp;middot; next-step/jwp-refactoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 3단계 의존성 리팩터링 리뷰요청드립니다. 패키지 분리 (Lifecycle이 같은 도메인들은 같은 Aggregate) 서로 다른 Aggregate의 엔티티간의 단방향 참조를 할 수 있도록 간접참조 활&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y0wAB/btrU8FAWQ5G/l5jELkkVJ5DRzVG2tOPMy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y0wAB/btrU8FAWQ5G/l5jELkkVJ5DRzVG2tOPMy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y0wAB/btrU8FAWQ5G/l5jELkkVJ5DRzVG2tOPMy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY0wAB%2FbtrU8FAWQ5G%2Fl5jELkkVJ5DRzVG2tOPMy1%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;922&quot; height=&quot;347&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;347&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;884&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p9qRp/btrU433kH9H/Xh7sLC5t4loXGjESwyZ6kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p9qRp/btrU433kH9H/Xh7sLC5t4loXGjESwyZ6kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p9qRp/btrU433kH9H/Xh7sLC5t4loXGjESwyZ6kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp9qRp%2FbtrU433kH9H%2FXh7sLC5t4loXGjESwyZ6kk%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;884&quot; height=&quot;848&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조영호님의 우아한 객체지향 강의를 듣고, 꼭 절차지향이 안 좋은게 아니다라는 것을 깨달았다.&lt;/li&gt;
&lt;li&gt;비즈니스 로직을 보다 명확하고 쉽게 관리할 수 있도록 Validator를 활용해 절차지향을 적용했다.&lt;/li&gt;
&lt;li&gt;SRP, OCP를 준수해 validator들을 분리하고, validator들을 관리하는 별도의 객체를 생성해서 관리하면 보다 확장에 용이할 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BJkSq/btrVf7o6p0U/7KHREsKnjeKBDyNYUNbXLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BJkSq/btrVf7o6p0U/7KHREsKnjeKBDyNYUNbXLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BJkSq/btrVf7o6p0U/7KHREsKnjeKBDyNYUNbXLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBJkSq%2FbtrVf7o6p0U%2F7KHREsKnjeKBDyNYUNbXLK%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;879&quot; height=&quot;854&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;854&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;양방향 의존관계를 끊기 위해서, 인터페이스 및 구현체를 활용하여 DIP 원칙을 적용했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;미션 회고&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이번 미션은 생각보다 정말 손이 많이갔다. 우선 처음에는 서비스 레이어에 있는 비즈니스 로직을 도메인에 책임을 부여하도록 리팩토링을 진행했는데,&lt;span style=&quot;color: #555555;&quot;&gt; DTO를 개선하면서 구조가 바뀌다보니 테스트 코드에서 &lt;span style=&quot;color: #555555;&quot;&gt;계속&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에러가 발생했다. 그래서 한번에 모든 것을 변경하려고 하기보다 하나씩 점진적으로 리팩토링을 해나갔다. 어느 정도 코드 리팩토링이 된 후에는, 서비스&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;의존성 관점에서 설계를 검토하여 리팩토링을 진행했다. 미션을 진행하면서 평소에 어렵게만 느껴졌던 DDD 개념들이 하나씩 이해가 되기 시작했고, 프로젝트의 완성도가 점점 갖춰지는 것이 눈에 띄게 보여 성취감을 크게 느꼈다. 특히, 조영호님의 우아한 객체지향 강의를 통해 배운 'Validator를 활용한 절차지향 적용'과 '양방향 의존관계를 끊기 위한 DIP원칙 적용'은 평소에 내가 생각하던 고정관념을 완전히 깨뜨려 버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우아한 테크 캠프 PRO 과정에 도전하길 참 잘했다는 생각이 든다.&lt;/p&gt;</description>
      <category>우아한테크캠프 PRO/우아한테크캠프 회고록</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/374</guid>
      <comments>https://developer-pi.tistory.com/374#entry374comment</comments>
      <pubDate>Mon, 2 Jan 2023 22:19:41 +0900</pubDate>
    </item>
    <item>
      <title>[우아한테크캠프 Pro] 6주차 미션 후기 (서비스 진단하기)</title>
      <link>https://developer-pi.tistory.com/373</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우아한테크캠프 Pro 6주차 서비스 진단하기 미션을 진행한 내용과 후기를 정리해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;미션 저장소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/infra-subway-monitoring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Gyeom/infra-subway-monitoring&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672585459756&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 - Gyeom/infra-subway-monitoring&quot; data-og-description=&quot;Contribute to Gyeom/infra-subway-monitoring development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Gyeom/infra-subway-monitoring&quot; data-og-url=&quot;https://github.com/Gyeom/infra-subway-monitoring&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/j3LcI/hyQ6N2MMFe/R6mM1lK9ySHZ1PCm3c55C0/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/infra-subway-monitoring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Gyeom/infra-subway-monitoring&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/j3LcI/hyQ6N2MMFe/R6mM1lK9ySHZ1PCm3c55C0/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211');&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 - Gyeom/infra-subway-monitoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to Gyeom/infra-subway-monitoring 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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;학습 내용&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;USE 방법론을 활용하여 서버를 진단할 수 있고 쓰레드 덤프를 확인해봅니다.&lt;/li&gt;
&lt;li&gt;webpageteat, pagespeed를 활용하여 웹 성능 예산을 고민해봅니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;목표치를 정하고 부하테스트를 직접 수행해봅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;단계별 요구사항 및 PR 리뷰&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;1단계&amp;nbsp;-&amp;nbsp;웹&amp;nbsp;성능&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;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;웹 성능 예산 작성 후 서버 목표 응답시간 도출&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-monitoring/pull/525&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-monitoring/pull/525&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672585631445&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #525 &amp;middot; next-step/infra-subway-monitoring&quot; data-og-description=&quot;안녕하세요 리뷰어님, 1단계 - 웹 성능 테스트 리뷰요청 드립니다. 감사합니다!&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/525&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/525&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Cd6yi/hyQ6Lw6Gnj/b4Nl6zSqMwoqkcTvHBbAuK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-monitoring/pull/525&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/525&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Cd6yi/hyQ6Lw6Gnj/b4Nl6zSqMwoqkcTvHBbAuK/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #525 &amp;middot; next-step/infra-subway-monitoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 1단계 - 웹 성능 테스트 리뷰요청 드립니다. 감사합니다!&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2106&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btF3cY/btrU6Y7uzce/dv09f8rzYfXQi1I2JKDaRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btF3cY/btrU6Y7uzce/dv09f8rzYfXQi1I2JKDaRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btF3cY/btrU6Y7uzce/dv09f8rzYfXQi1I2JKDaRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtF3cY%2FbtrU6Y7uzce%2Fdv09f8rzYfXQi1I2JKDaRk%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;2106&quot; height=&quot;472&quot; data-origin-width=&quot;2106&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.webpagetest.org/&quot;&gt;WebPageTest&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/&quot;&gt;PageSpeed&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등에서 테스트를 진행한 후, 웹 성능 예산을 작성했다.&lt;/li&gt;
&lt;li&gt;크롬 브라우저 도구를 활용하여 퍼포먼스 탭에서 각 api별 요청 응답시간을 확인했고, 웹 성능 예산에 영향을 주는 api 를 확인해보고 가설을 세웠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;2단계&amp;nbsp;-&amp;nbsp;부하테스트&lt;/b&gt;&lt;/p&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-te-task=&quot;&quot;&gt;테스트 전제조건 정리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;대상 시스템 범위&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;목푯값 설정 (latency, throughput, 부하 유지기간)&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;부하 테스트 시 저장될 데이터 건수 및 크기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;Smoke, Load, Stress 테스트 후 결과를 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-monitoring/pull/569&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-monitoring/pull/569&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672585923621&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #569 &amp;middot; next-step/infra-subway-monitoring&quot; data-og-description=&quot;안녕하세요 리뷰어님, 2단계 부하테스트하기 PR 입니다. 이번 미션도 리뷰 잘 부탁드립니다      &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/569&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/569&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lJ3k3/hyQ6Y4hAWy/RkbMOln52IRKsxvFOgQmE0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-monitoring/pull/569&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/569&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lJ3k3/hyQ6Y4hAWy/RkbMOln52IRKsxvFOgQmE0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #569 &amp;middot; next-step/infra-subway-monitoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 2단계 부하테스트하기 PR 입니다. 이번 미션도 리뷰 잘 부탁드립니다      &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2090&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cimGSi/btrU1NFRkAM/UtYGQsoGrMPMKmfQmSFDd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cimGSi/btrU1NFRkAM/UtYGQsoGrMPMKmfQmSFDd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cimGSi/btrU1NFRkAM/UtYGQsoGrMPMKmfQmSFDd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcimGSi%2FbtrU1NFRkAM%2FUtYGQsoGrMPMKmfQmSFDd1%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;2090&quot; height=&quot;414&quot; data-origin-width=&quot;2090&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부하테스트 실습을 진행하면서 진행과정을 정리해 보았다.
&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://developer-pi.tistory.com/357&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Grafana k6 사용하여 부하테스트 하는 방법 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer-pi.tistory.com/357&quot;&gt;Grafana k6 사용하여 부하테스트 하는 방법 2&lt;/a&gt;&amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer-pi.tistory.com/357&quot;&gt;Grafana k6 사용하여 부하테스트 하는 방법 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;3단계&amp;nbsp;-&amp;nbsp;로깅,&amp;nbsp;모니터링&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;애플리케이션 진단하기 실습을 진행해보고 문제가 되는 코드를 수정&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;로그 설정하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;Cloudwatch로 모니터링&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-monitoring/pull/601&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/infra-subway-monitoring/pull/601&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672586977096&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #601 &amp;middot; next-step/infra-subway-monitoring&quot; data-og-description=&quot;안녕하세요 리뷰어님~ 3단계 - 로깅, 모니터링 리뷰 요청 드립니다. 이번에도 리뷰 잘 부탁드립니다      &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/601&quot; data-og-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/601&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yvgXZ/hyQ6W6tEwN/wkz7q66w1RokRVKJSs1pN0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/infra-subway-monitoring/pull/601&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/infra-subway-monitoring/pull/601&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yvgXZ/hyQ6W6tEwN/wkz7q66w1RokRVKJSs1pN0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #601 &amp;middot; next-step/infra-subway-monitoring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님~ 3단계 - 로깅, 모니터링 리뷰 요청 드립니다. 이번에도 리뷰 잘 부탁드립니다      &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2102&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxMsXG/btrVcmme394/4a8k1KhK0NNSmAIZOgKd2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxMsXG/btrVcmme394/4a8k1KhK0NNSmAIZOgKd2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxMsXG/btrVcmme394/4a8k1KhK0NNSmAIZOgKd2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxMsXG%2FbtrVcmme394%2F4a8k1KhK0NNSmAIZOgKd2k%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;2102&quot; height=&quot;462&quot; data-origin-width=&quot;2102&quot; data-origin-height=&quot;462&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;2002&quot; data-origin-height=&quot;958&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceiION/btrU02cbKB1/VJIpYJ7BUg3QZMHmKqXW50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceiION/btrU02cbKB1/VJIpYJ7BUg3QZMHmKqXW50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceiION/btrU02cbKB1/VJIpYJ7BUg3QZMHmKqXW50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceiION%2FbtrU02cbKB1%2FVJIpYJ7BUg3QZMHmKqXW50%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;2002&quot; height=&quot;958&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;958&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그는 오래된 순서대로 지워지도록 maxHistory를 설정해주자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;미션 회고&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이번 미션을 통해 웹 성능 예산 작성, 부하테스트, 로깅 설정 등 &lt;span style=&quot;color: #555555;&quot;&gt;서비스 진단에 필요한 실습들을 순차적으로 진행해 볼 수 있었다. 특히, 테스트 설정 값을 직접 구해보고 시나리오를 구성해보는 과정을 경험할 수 있어 흥미로웠고, 부하테스트 결과 값이 기대했던 값으로 잘 나오지 않아서 몇차례 다시 시도하느라 시간이 오래 걸렸지만 꽤 유익한 시간이었다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>우아한테크캠프 PRO/우아한테크캠프 회고록</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/373</guid>
      <comments>https://developer-pi.tistory.com/373#entry373comment</comments>
      <pubDate>Mon, 2 Jan 2023 00:46:48 +0900</pubDate>
    </item>
    <item>
      <title>[우아한테크캠프 Pro] 5주차 미션 후기 (Subway - ATDD &amp;amp; 단위테스트)</title>
      <link>https://developer-pi.tistory.com/372</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우아한테크캠프 Pro 5주차 ATDD &amp;amp; 단위테스트 미션을 진행한 내용과 후기를 정리해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;미션 저장소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/atdd-subway-service&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Gyeom/atdd-subway-service&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672582474809&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 - Gyeom/atdd-subway-service: 우아한테크캠프 pro ATDD 과정 저장소&quot; data-og-description=&quot;우아한테크캠프 pro ATDD 과정 저장소. Contribute to Gyeom/atdd-subway-service development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Gyeom/atdd-subway-service&quot; data-og-url=&quot;https://github.com/Gyeom/atdd-subway-service&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jEkOA/hyQ6RjK9Ob/VmH5MnNGndKp3N78ohFmQk/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/atdd-subway-service&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Gyeom/atdd-subway-service&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jEkOA/hyQ6RjK9Ob/VmH5MnNGndKp3N78ohFmQk/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211');&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 - Gyeom/atdd-subway-service: 우아한테크캠프 pro ATDD 과정 저장소&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;우아한테크캠프 pro ATDD 과정 저장소. Contribute to Gyeom/atdd-subway-service 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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;학습 내용&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ATDD를 기반으로 지하철 노선도 서비스를 단계별 구현한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;단계별 요구사항 및 PR 리뷰&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;1단계&amp;nbsp;-&amp;nbsp;인수&amp;nbsp;테스트&amp;nbsp;기반&amp;nbsp;리팩터링&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LineService의 비즈니스 로직을 도메인으로 옮기기&lt;/li&gt;
&lt;li&gt;한번에 많은 부분을 고치려 하지 말고 나눠서 부분부분 리팩터링하기&lt;/li&gt;
&lt;li&gt;전체 기능은 인수 테스트로 보호한 뒤 세부 기능을 TDD로 리팩터링하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-service/pull/756&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/atdd-subway-service/pull/756&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672582699169&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #756 &amp;middot; next-step/atdd-subway-service&quot; data-og-description=&quot;안녕하세요 리뷰어님   Step1 인수 테스트 기반 리팩터링 PR 리뷰 요청 드립니다. 잘 부탁드립니다 :)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/atdd-subway-service/pull/756&quot; data-og-url=&quot;https://github.com/next-step/atdd-subway-service/pull/756&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/OnyEs/hyQ6O8npIn/ktv3gS599JZLCdLG64O5I0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-service/pull/756&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/atdd-subway-service/pull/756&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/OnyEs/hyQ6O8npIn/ktv3gS599JZLCdLG64O5I0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #756 &amp;middot; next-step/atdd-subway-service&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님   Step1 인수 테스트 기반 리팩터링 PR 리뷰 요청 드립니다. 잘 부탁드립니다 :)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2100&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHs7xe/btrU3atRTVm/UOj2ugkHyuDKolXkfGjNm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHs7xe/btrU3atRTVm/UOj2ugkHyuDKolXkfGjNm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHs7xe/btrU3atRTVm/UOj2ugkHyuDKolXkfGjNm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHs7xe%2FbtrU3atRTVm%2FUOj2ugkHyuDKolXkfGjNm1%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;2100&quot; height=&quot;522&quot; data-origin-width=&quot;2100&quot; data-origin-height=&quot;522&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;2002&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y65Dw/btrU9e90uiK/PYIAjV0UDryoZ39KA19L40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y65Dw/btrU9e90uiK/PYIAjV0UDryoZ39KA19L40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y65Dw/btrU9e90uiK/PYIAjV0UDryoZ39KA19L40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy65Dw%2FbtrU9e90uiK%2FPYIAjV0UDryoZ39KA19L40%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;2002&quot; height=&quot;912&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@BeforeEach에서 테스트 픽스쳐를 사용하게 되면 테스트 간 결합도가 높아진다.&lt;/li&gt;
&lt;li&gt;클래스 외부에 static 팩토리 메소드를 만들어서 사용하자.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jojoldu.tistory.com/611&quot;&gt;테스트 픽스처 올바르게 사용하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LSXnu/btrUYQ4dDju/khkKtOB0OScDdBTJiDsnZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LSXnu/btrUYQ4dDju/khkKtOB0OScDdBTJiDsnZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LSXnu/btrUYQ4dDju/khkKtOB0OScDdBTJiDsnZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLSXnu%2FbtrUYQ4dDju%2FkhkKtOB0OScDdBTJiDsnZ1%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;2000&quot; height=&quot;1000&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Optional은&amp;nbsp;비싸다.&amp;nbsp;그리고&amp;nbsp;컬렉션은&amp;nbsp;null이&amp;nbsp;아니라&amp;nbsp;비어있는&amp;nbsp;컬렉션을&amp;nbsp;반환하는&amp;nbsp;것이&amp;nbsp;좋을&amp;nbsp;때가&amp;nbsp;많다.&amp;nbsp;따라서&amp;nbsp;컬렉션은&amp;nbsp;Optional로&amp;nbsp;감싸서&amp;nbsp;반환하지&amp;nbsp;말고&amp;nbsp;비어있는&amp;nbsp;컬렉션을&amp;nbsp;반환하자.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://homoefficio.github.io/2019/10/03/Java-Optional-%EB%B0%94%EB%A5%B4%EA%B2%8C-%EC%93%B0%EA%B8%B0/&quot;&gt;Java Optional 바르게 쓰기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beesVs/btrU3aAEV0s/zgpBSuHujfvqE4ydMTRbA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beesVs/btrU3aAEV0s/zgpBSuHujfvqE4ydMTRbA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beesVs/btrU3aAEV0s/zgpBSuHujfvqE4ydMTRbA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeesVs%2FbtrU3aAEV0s%2FzgpBSuHujfvqE4ydMTRbA1%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;1998&quot; height=&quot;926&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주생성자는 하나 뿐이고, 나머지는 secondary constructor다. secondary constructor는 this(..)를 통해서 주생성자를 호출하는 것이 역할이다. 잘 구성된 클래스는 반드시 하나의 주생성자만 가지고 있어야하고, 모든 secondary constructor 이후에 선언되어야 한다. 그 이유는 코드의 중복을 줄여주기 때문이다.&lt;/li&gt;
&lt;li&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;/span&gt;&lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; href=&quot;https://velog.io/@injoon2019/%EC%A3%BC-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%B6%80-%EC%83%9D%EC%84%B1%EC%9E%90&quot;&gt;주생성자, 부생성자&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;2단계&amp;nbsp;-&amp;nbsp;경로&amp;nbsp;조회&amp;nbsp;기능&lt;/b&gt;&lt;/p&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-te-task=&quot;&quot;&gt;최단 경로 조회 인수 테스트 만들기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;최단 경로 조회 기능 구현하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-service/pull/765&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/atdd-subway-service/pull/765&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672583412284&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #765 &amp;middot; next-step/atdd-subway-service&quot; data-og-description=&quot;안녕하세요 리뷰어님, 2단계 - 경로 조회 기능 PR 입니다. 이번 리뷰도 잘 부탁드립니다      &quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/atdd-subway-service/pull/765&quot; data-og-url=&quot;https://github.com/next-step/atdd-subway-service/pull/765&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/elx7gw/hyQ6TWbscC/kL1T2Zi382ll2nfOM9SCd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-service/pull/765&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/atdd-subway-service/pull/765&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/elx7gw/hyQ6TWbscC/kL1T2Zi382ll2nfOM9SCd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #765 &amp;middot; next-step/atdd-subway-service&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 2단계 - 경로 조회 기능 PR 입니다. 이번 리뷰도 잘 부탁드립니다      &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2098&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5LZRL/btrU141IN3b/TM2EnhlBPZMPqxVNQMHdK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5LZRL/btrU141IN3b/TM2EnhlBPZMPqxVNQMHdK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5LZRL/btrU141IN3b/TM2EnhlBPZMPqxVNQMHdK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5LZRL%2FbtrU141IN3b%2FTM2EnhlBPZMPqxVNQMHdK0%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;2098&quot; height=&quot;472&quot; data-origin-width=&quot;2098&quot; data-origin-height=&quot;472&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;2002&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMoQ2H/btrU2K9UzkT/yGJxFnpbRgYgpKPSqEcAu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMoQ2H/btrU2K9UzkT/yGJxFnpbRgYgpKPSqEcAu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMoQ2H/btrU2K9UzkT/yGJxFnpbRgYgpKPSqEcAu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMoQ2H%2FbtrU2K9UzkT%2FyGJxFnpbRgYgpKPSqEcAu1%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;2002&quot; height=&quot;902&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매직넘버 상수화를 생활화 하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;3단계&amp;nbsp;-&amp;nbsp;인증을&amp;nbsp;통한&amp;nbsp;기능&amp;nbsp;구현&lt;/b&gt;&lt;/p&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-te-task=&quot;&quot;&gt;토큰 발급 기능 (로그인) 인수 테스트 만들기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;인증 - 내 정보 조회 기능 완성하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;인증 - 즐겨 찾기 기능 완성하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-service/pull/803&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/atdd-subway-service/pull/803&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672583710901&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #803 &amp;middot; next-step/atdd-subway-service&quot; data-og-description=&quot;안녕하세요 리뷰어님, 3단계 - 인증을 통한 기능 구현 PR 입니다. 이번 리뷰도 잘 부탁드립니다 :)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/atdd-subway-service/pull/803&quot; data-og-url=&quot;https://github.com/next-step/atdd-subway-service/pull/803&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCULeb/hyQ6L4VJi7/pm9tWor8ukaqcr3dgAt3t0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-service/pull/803&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/atdd-subway-service/pull/803&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCULeb/hyQ6L4VJi7/pm9tWor8ukaqcr3dgAt3t0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #803 &amp;middot; next-step/atdd-subway-service&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 3단계 - 인증을 통한 기능 구현 PR 입니다. 이번 리뷰도 잘 부탁드립니다 :)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2106&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUWwcH/btrU8EucH9R/5qxao2UaFIcIvIzkSXvq5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUWwcH/btrU8EucH9R/5qxao2UaFIcIvIzkSXvq5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUWwcH/btrU8EucH9R/5qxao2UaFIcIvIzkSXvq5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUWwcH%2FbtrU8EucH9R%2F5qxao2UaFIcIvIzkSXvq5k%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;2106&quot; height=&quot;466&quot; data-origin-width=&quot;2106&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;4단계&amp;nbsp;-&amp;nbsp;요금&amp;nbsp;조회&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;경로 조회 시 거리 기준 요금 정보 포함하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;노선별 추가 요금 정책 추가&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;연령별 할인 정책 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2104&quot; data-origin-height=&quot;558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/47Y7r/btrVclHCWGz/isLH4QSDTbCLpz7ltpB5Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/47Y7r/btrVclHCWGz/isLH4QSDTbCLpz7ltpB5Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/47Y7r/btrVclHCWGz/isLH4QSDTbCLpz7ltpB5Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F47Y7r%2FbtrVclHCWGz%2FisLH4QSDTbCLpz7ltpB5Kk%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;2104&quot; height=&quot;558&quot; data-origin-width=&quot;2104&quot; data-origin-height=&quot;558&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;2006&quot; data-origin-height=&quot;1272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TSGLD/btrU7HxOG9L/ltcY6eilTD0VXrmfV2WjtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TSGLD/btrU7HxOG9L/ltcY6eilTD0VXrmfV2WjtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TSGLD/btrU7HxOG9L/ltcY6eilTD0VXrmfV2WjtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTSGLD%2FbtrU7HxOG9L%2FltcY6eilTD0VXrmfV2WjtK%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;2006&quot; height=&quot;1272&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;1272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;age를 0으로 관리하다보면 나중에 side effect가 존재할 것 같아서 null은 null로 관리하는게 맞다고 판단했다. 물론 정답은 없겠지만, Enum을 통해 default 값을 관리하면 보다 명확하고 이해하기 쉬워서 유지보수에 용이할 것 같다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;리뷰어님이 말씀해주신 것처럼 null 체크를 계속해야 하는 이슈도 해결된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcVnkZ/btrU9dpKjBR/kbBmN9eNCafOaKSrjK2gv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcVnkZ/btrU9dpKjBR/kbBmN9eNCafOaKSrjK2gv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcVnkZ/btrU9dpKjBR/kbBmN9eNCafOaKSrjK2gv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcVnkZ%2FbtrU9dpKjBR%2FkbBmN9eNCafOaKSrjK2gv1%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;2002&quot; height=&quot;1570&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LoginMember를 상속받아서 GuestMember 클래스를 따로 관리하면 보다 명확해진다.&lt;/li&gt;
&lt;li&gt;뿐 만 아니라, GUEST는 어차피 동일한 값을 유지하기 때문에 static final로 관리하는 것은 좋은 인사이트다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;미션 회고&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 미션의 주제는 'ATDD &amp;amp; 단위테스트' 였지만 테스트 픽스처, Optional, 주생성자&amp;amp;부생성자, Enum Default값 활용 등 코드를 관리하는데 용이한 TIP들을 많이 공유받을 수 있었다. ATDD는 3주차 때도 진행해서 그런지 이번 미션에서는 보다 수월하게 진행할 수 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>우아한테크캠프 PRO/우아한테크캠프 회고록</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/372</guid>
      <comments>https://developer-pi.tistory.com/372#entry372comment</comments>
      <pubDate>Sun, 1 Jan 2023 23:54:54 +0900</pubDate>
    </item>
    <item>
      <title>[우아한테크캠프 Pro] 3주차 미션 후기 (Subway - ATDD)</title>
      <link>https://developer-pi.tistory.com/371</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우아한테크캠프 Pro 3주차 ATDD 미션을 진행한 내용과 후기를 정리해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;미션 저장소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/atdd-subway-admin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Gyeom/atdd-subway-admin&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672578237877&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 - Gyeom/atdd-subway-admin: 우아한테크캠프 pro ATDD 과정 저장소&quot; data-og-description=&quot;우아한테크캠프 pro ATDD 과정 저장소. Contribute to Gyeom/atdd-subway-admin development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Gyeom/atdd-subway-admin&quot; data-og-url=&quot;https://github.com/Gyeom/atdd-subway-admin&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bryyQh/hyQ6Wec6tB/bFFUNL29r1R1kG2lNqbs7K/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211&quot;&gt;&lt;a href=&quot;https://github.com/Gyeom/atdd-subway-admin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Gyeom/atdd-subway-admin&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bryyQh/hyQ6Wec6tB/bFFUNL29r1R1kG2lNqbs7K/img.png?width=1200&amp;amp;height=600&amp;amp;face=999_150_1055_211');&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 - Gyeom/atdd-subway-admin: 우아한테크캠프 pro ATDD 과정 저장소&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;우아한테크캠프 pro ATDD 과정 저장소. Contribute to Gyeom/atdd-subway-admin 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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;학습 내용&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/next-step/nextstep-docs/blob/master/codereview/review-step1.md&quot;&gt;미션 수행 방법&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;문서를 참고하여 실습 환경을 구축한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지하철 노선도를 관리&lt;/b&gt;할 수 있는 어드민 서비스를 단계별로 구현하세요.&lt;/li&gt;
&lt;li&gt; 인수 테스트 주도 개발 프로세스를 단계별로 경험하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;단계별 요구사항 및 PR 리뷰&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1단계&amp;nbsp;-&amp;nbsp;지하철역&amp;nbsp;인수&amp;nbsp;테스트&amp;nbsp;작성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철역 관련 인수 테스트를 완성하세요.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철역 목록 조회 인수 테스트 작성하기&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철역 삭제 인수 테스트 작성하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-admin/pull/837&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/atdd-subway-admin/pull/837&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672578337084&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;[김대겸]  Step1 PR by Gyeom &amp;middot; Pull Request #837 &amp;middot; next-step/atdd-subway-admin&quot; data-og-description=&quot;안녕하세요 리뷰어님, 1단계 지하철역의 인수 테스트 작성 PR입니다. 잘 부탁드립니다 :)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/837&quot; data-og-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/837&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7nJFh/hyQ6WrKzx1/UkYsKCkOijOhfoQOr3WG2K/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-admin/pull/837&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/837&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7nJFh/hyQ6WrKzx1/UkYsKCkOijOhfoQOr3WG2K/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step1 PR by Gyeom &amp;middot; Pull Request #837 &amp;middot; next-step/atdd-subway-admin&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 1단계 지하철역의 인수 테스트 작성 PR입니다. 잘 부탁드립니다 :)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2104&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMtZfY/btrU56EBdik/4LpX0xweuo5yznjxQXc2a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMtZfY/btrU56EBdik/4LpX0xweuo5yznjxQXc2a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMtZfY/btrU56EBdik/4LpX0xweuo5yznjxQXc2a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMtZfY%2FbtrU56EBdik%2F4LpX0xweuo5yznjxQXc2a1%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;2104&quot; height=&quot;674&quot; data-origin-width=&quot;2104&quot; data-origin-height=&quot;674&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;2260&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqtZbc/btrU299ySN6/PKEQmCTnX1U2EkKKpIktWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqtZbc/btrU299ySN6/PKEQmCTnX1U2EkKKpIktWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqtZbc/btrU299ySN6/PKEQmCTnX1U2EkKKpIktWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqtZbc%2FbtrU299ySN6%2FPKEQmCTnX1U2EkKKpIktWk%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;2260&quot; height=&quot;1150&quot; data-origin-width=&quot;2260&quot; data-origin-height=&quot;1150&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;2246&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GSFZq/btrU01jZIQu/oHa1r6ti9KCJkI6LBlf1z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GSFZq/btrU01jZIQu/oHa1r6ti9KCJkI6LBlf1z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GSFZq/btrU01jZIQu/oHa1r6ti9KCJkI6LBlf1z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGSFZq%2FbtrU01jZIQu%2FoHa1r6ti9KCJkI6LBlf1z0%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;2246&quot; height=&quot;596&quot; data-origin-width=&quot;2246&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리뷰어님께서 인수테스트의 동작들을 분리해보는 것을 제안해주셨고 샘플 예제까지 링크를 공유해주셨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1672579048138&quot; class=&quot;reasonml&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @DisplayName(&quot;지하철 노선 생성하면 응답상태 201을 반환한다.&quot;)
    @Test
    void createLine() {
        // given
        StationResponse 종각역 = 등록된_지하철역(&quot;종각역&quot;).as(StationResponse.class);
        StationResponse 역삼역 = 등록된_지하철역(&quot;역삼역&quot;).as(StationResponse.class);

        // when
        ExtractableResponse&amp;lt;Response&amp;gt; response =
                지하철노선_생성_요청(&quot;1호선&quot;, &quot;indigo darken-2&quot;, 종각역.getId(), 역삼역.getId(), 10);

        // then
        지하철노선_생성_응답상태_201_검증(response);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;피드백을 수용하여 위 코드와 같이 Given - When - Then 의 각 구문을 함수로 리팩토링했더니 코드가 깔끔해졌고, 테스트코드로 API 문서를 대체할 수 있다는게 어떤 느낌인지 알 수 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2단계&amp;nbsp;-&amp;nbsp;지하철&amp;nbsp;노선&amp;nbsp;기능&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 구현 전에 인수 조건을 만족하는지 검증하는 인수 테스트를 먼저 만들고 기능구현을 해보세요.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철 노선 생성&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철 노선 목록 조회&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철 노선 조회&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철 노선 수정&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;지하철 노선 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-admin/pull/854&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/atdd-subway-admin/pull/854&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672579553691&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #854 &amp;middot; next-step/atdd-subway-admin&quot; data-og-description=&quot;안녕하세요 리뷰어님, 2단계 - 지하철 노선 기능 PR 입니다. 이번에도 잘 부탁드립니다 :)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/854&quot; data-og-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/854&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/JvlJE/hyQ6Xxrkoc/J7dAyhKX3FbC2LsfGr6SB0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-admin/pull/854&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/854&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/JvlJE/hyQ6Xxrkoc/J7dAyhKX3FbC2LsfGr6SB0/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step2 PR by Gyeom &amp;middot; Pull Request #854 &amp;middot; next-step/atdd-subway-admin&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 2단계 - 지하철 노선 기능 PR 입니다. 이번에도 잘 부탁드립니다 :)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2088&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wSqQP/btrU2K9SLEB/9oWJkhXmuSw6WfQyuWbViK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wSqQP/btrU2K9SLEB/9oWJkhXmuSw6WfQyuWbViK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wSqQP/btrU2K9SLEB/9oWJkhXmuSw6WfQyuWbViK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwSqQP%2FbtrU2K9SLEB%2F9oWJkhXmuSw6WfQyuWbViK%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;2088&quot; height=&quot;630&quot; data-origin-width=&quot;2088&quot; data-origin-height=&quot;630&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;2006&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKOsH8/btrU9dQJ9us/6R3BOwn0DVvi3SKzSs9uY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKOsH8/btrU9dQJ9us/6R3BOwn0DVvi3SKzSs9uY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKOsH8/btrU9dQJ9us/6R3BOwn0DVvi3SKzSs9uY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKOsH8%2FbtrU9dQJ9us%2F6R3BOwn0DVvi3SKzSs9uY0%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;2006&quot; height=&quot;570&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 테스트 간에 격리를 위해 DatabaseCleanup 클래스를 활용했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;1358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejxZqf/btrUZXvmF1X/tGgDj6DvPzJsUeuzjLGYc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejxZqf/btrUZXvmF1X/tGgDj6DvPzJsUeuzjLGYc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejxZqf/btrUZXvmF1X/tGgDj6DvPzJsUeuzjLGYc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FejxZqf%2FbtrUZXvmF1X%2FtGgDj6DvPzJsUeuzjLGYc1%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;1998&quot; height=&quot;1358&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;1358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;평소에도 많이 고민을 했던 부분이지만 의존성 방향에 대해서는 생각하지 못했던 것 같다. 이 부분에 대해 짚어주셔서 관련 Case에 대한 컨벤션을 어떻게 잡아갈 지 방향성이 확고해졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6etIW/btrU7IpWe2e/c5p8EDfkdcnD6U520O5VqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6etIW/btrU7IpWe2e/c5p8EDfkdcnD6U520O5VqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6etIW/btrU7IpWe2e/c5p8EDfkdcnD6U520O5VqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6etIW%2FbtrU7IpWe2e%2Fc5p8EDfkdcnD6U520O5VqK%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;2000&quot; height=&quot;1016&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1016&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더티 체킹이 일어나면서 데이트 업데이트가 이뤄지지만 save 코드를 작성함으로써 명확하고 읽기 쉬운코드를 작성할 수 있다고 생각했는데, 불필요한 로직이 수행 될 수 있는 지에 대해 파악이 필요할 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3단계&amp;nbsp;-&amp;nbsp;구간&amp;nbsp;추가&amp;nbsp;기능&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;기능 구현 전에 인수 조건을 만족하는지 검증하는 인수 테스트를 먼저 만들고 기능구현을 해보세요.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-te-task=&quot;&quot;&gt;역 사이에 새로운 역을 등록할 경우&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;새로운 역을 상행 종점으로 등록할 경우&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;새로운 역을 하행 종점으로 등록할 경우&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;역 사이에 새로운 역을 등록할 경우 기존 역 사이 길이보다 크거나 같으면 등록을 할 수 없음&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;상행역과 하행역이 이미 노선에 모두 등록되어 있다면 추가할 수 없음&lt;/li&gt;
&lt;li data-te-task=&quot;&quot;&gt;상행역과 하행역 둘 중 하나도 포함되어있지 않으면 추가할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-admin/pull/881&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/next-step/atdd-subway-admin/pull/881&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672580400546&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #881 &amp;middot; next-step/atdd-subway-admin&quot; data-og-description=&quot;안녕하세요 리뷰어님, 3단계 구간 추가 기능 PR 입니다. 이번에도 잘 부탁드립니다 :)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/881&quot; data-og-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/881&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bFqm01/hyQ6Ogc78s/6ZK3A6A6oi3i63dheIxT8K/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184&quot;&gt;&lt;a href=&quot;https://github.com/next-step/atdd-subway-admin/pull/881&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/next-step/atdd-subway-admin/pull/881&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bFqm01/hyQ6Ogc78s/6ZK3A6A6oi3i63dheIxT8K/img.png?width=1200&amp;amp;height=600&amp;amp;face=1008_138_1051_184');&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;[김대겸] Step3 PR by Gyeom &amp;middot; Pull Request #881 &amp;middot; next-step/atdd-subway-admin&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 리뷰어님, 3단계 구간 추가 기능 PR 입니다. 이번에도 잘 부탁드립니다 :)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2096&quot; data-origin-height=&quot;816&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F5FzI/btrU292Kxs7/uvEFJbRT7Q1immIwGzKkF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F5FzI/btrU292Kxs7/uvEFJbRT7Q1immIwGzKkF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F5FzI/btrU292Kxs7/uvEFJbRT7Q1immIwGzKkF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF5FzI%2FbtrU292Kxs7%2FuvEFJbRT7Q1immIwGzKkF1%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;2096&quot; height=&quot;816&quot; data-origin-width=&quot;2096&quot; data-origin-height=&quot;816&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;1998&quot; data-origin-height=&quot;1220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnKz6g/btrU1NZ590w/oGO8UxexbAiLJ3oFTZdre0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnKz6g/btrU1NZ590w/oGO8UxexbAiLJ3oFTZdre0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnKz6g/btrU1NZ590w/oGO8UxexbAiLJ3oFTZdre0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnKz6g%2FbtrU1NZ590w%2FoGO8UxexbAiLJ3oFTZdre0%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;1998&quot; height=&quot;1220&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;1220&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성이 양방향이라면 결국 하나의 서비스라는 것을 의미하기도 한다. 하지만, Line과 Section은 같은 서비스가 아니기 때문에 단방향을 향하도록 변경이 필요하다. 처음에는 의존성 개념에 대해 이해하기 어려웠지만, 미션을 수행하면서 리뷰어님이 지속적으로 피드백을 제공해주고 코드를 작성하면서 비슷한 상황을 반복해서 접하다보니 자연스럽게 이해할 수 있었다.&lt;/li&gt;
&lt;li&gt;의존성 방향은 단방향을 향해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;974&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uZsCZ/btrU9eIT3bH/4nXkcsJk6gIpQ4fuJZ6bZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uZsCZ/btrU9eIT3bH/4nXkcsJk6gIpQ4fuJZ6bZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uZsCZ/btrU9eIT3bH/4nXkcsJk6gIpQ4fuJZ6bZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuZsCZ%2FbtrU9eIT3bH%2F4nXkcsJk6gIpQ4fuJZ6bZK%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;2002&quot; height=&quot;974&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;974&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getter 사용을 지양하자. getter를 사용하기 전에 다른 클래스를 통해 책임을 위임할 수는 없을 지에 대해 고민하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;미션 회고&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 미션을 진행하면서  인수 테스트 주도 개발 프로세스를 단계별로 경험할 수 있었고, 인수테스트의 동작들을 분리에 대한 좋은 인사이트를 얻을 수 있었다. 특히, 이번 미션을 진행하면서 의존성 개념에 대해 명확하게 이해할 수 있었다. 처음에는 의존성 개념이 어렵게 느껴졌는데, 리뷰어님의 피드백을 시작으로 조영호님의 우아한 객체지향 강의를 통해 의존성의 필요성에 대해 명확하게 이해할 수 있었다.&lt;/p&gt;</description>
      <category>우아한테크캠프 PRO/우아한테크캠프 회고록</category>
      <author>PI.314</author>
      <guid isPermaLink="true">https://developer-pi.tistory.com/371</guid>
      <comments>https://developer-pi.tistory.com/371#entry371comment</comments>
      <pubDate>Sun, 1 Jan 2023 23:05:13 +0900</pubDate>
    </item>
  </channel>
</rss>