Kafka 프로듀서에서 Callback과 함께 Sticky Partitioner를 사용하는 이유는 파티션 사용의 효율성과 성능 최적화를 위해서입니다. 이를 좀 더 구체적으로 살펴보겠습니다.
Sticky Partitioner는 Kafka 2.4.0부터 도입된 파티셔닝 전략으로, 특정 파티션에 메시지를 "묶어서(sticky)" 전송하도록 설계되었습니다.
- 기존 파티셔너 (Round-Robin 파티셔너 또는 Key-Based 파티셔너)는 메시지가 각각 다른 파티션으로 분산되는 경우가 많아 파티션 변경 시 오버헤드가 발생할 수 있습니다.
- Sticky Partitioner는 연속적인 메시지 배치를 하나의 파티션으로 묶어 전송합니다.
- 기본적으로 배치 크기가 꽉 차거나, 전송 타임아웃이 발생하면 다른 파티션으로 전환됩니다.
Kafka 프로듀서에서 Callback은 메시지 전송이 성공적으로 완료되었는지, 혹은 오류가 발생했는지를 확인하는 메커니즘입니다. Sticky Partitioner와 Callback을 함께 사용하는 이유는 다음과 같습니다:
- Sticky Partitioner는 동일한 파티션에 메시지를 묶어서 전송하므로 배치 처리 효율이 높아집니다.
- 이로 인해, 네트워크 호출 수를 줄이고, 브로커가 메시지를 처리하는 데 드는 리소스를 절약할 수 있습니다.
- Callback은 이러한 전송이 정상적으로 완료되었는지 확인할 수 있습니다.
- 파티션이 자주 변경되면 브로커와의 연결 설정과 전송 오버헤드가 증가합니다.
- Sticky Partitioner는 파티션 변경을 최소화하여 네트워크 트래픽과 오버헤드를 줄입니다.
- Callback을 사용하면 네트워크 오류가 발생했는지 확인할 수 있어, 장애 복구 로직을 추가할 수 있습니다.
- 특정 파티션에 메시지를 묶어서 전송하므로, 파티션 단위로 메시지 순서를 보장할 수 있습니다.
- Callback을 사용하면 메시지가 제대로 전송되었는지 확인하고, 실패한 메시지를 재시도하는 로직을 구현할 수 있습니다.
- Sticky Partitioner는 동일한 파티션에 메시지를 묶어 전송하지만, 전송 중 문제가 발생하면 다른 파티션으로 전환할 수 있습니다.
- Callback은 이러한 실패를 감지하고, 메시지를 재전송하거나 로그를 남기는 데 활용됩니다.
다음은 Sticky Partitioner와 Callback을 함께 사용하는 예제입니다:
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class StickyPartitionerExample {
public static void main(String[] args) {
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "org.apache.kafka.clients.producer.internals.DefaultPartitioner"); // Sticky Partitioner가 기본값
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 100; i++) {
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key-" + i, "message-" + i);
// Callback 사용
producer.send(record, (metadata, exception) -> {
if (exception == null) {
System.out.println("Message sent to partition " + metadata.partition() + " with offset " + metadata.offset());
} else {
System.err.println("Error while producing message: " + exception.getMessage());
}
});
}
producer.close();
}
}
- 특정 파티션을 "고정"하여 메시지를 전송합니다.
- 배치가 완료되거나, 특정 시간 간격(
linger.ms
)이 지나면 새로운 파티션으로 전환합니다. - 이를 통해 브로커와의 연결 빈도 및 파티션 변경으로 인한 오버헤드를 최소화합니다.
- 배치 크기 조정: Sticky Partitioner는 배치 크기(
batch.size
)와 전송 지연(linger.ms
) 설정에 따라 성능에 큰 영향을 미칩니다. - 균등 분산 문제: 특정 파티션으로 데이터가 몰릴 수 있으므로, 데이터 분산이 중요한 경우 Key-Based 파티셔너를 사용해야 합니다.
Kafka에서 Sticky Partitioner를 Callback과 함께 사용하는 이유는:
- 배치 효율성: 메시지를 묶어 전송하여 네트워크 오버헤드를 줄임.
- 순서 보장: 동일 파티션 내 메시지 순서를 보장.
- 오류 처리: Callback을 통해 메시지 전송 성공/실패를 확인하고 재시도 로직 구현 가능.
Sticky Partitioner는 특히 배치 전송과 고성능 처리를 요구하는 애플리케이션에서 매우 유용합니다! 😊
네, 맞습니다! Sticky 파티셔닝을 사용하면 오버헤드를 줄일 수 있습니다. Sticky 파티셔닝은 특정 배치(batch) 내의 메시지가 같은 물리적 파티션에 이어지도록 보장하기 때문에, 여러 가지 성능상의 이점을 제공합니다.
Sticky 파티셔닝이 오버헤드를 줄이는 이유
1. 물리적 파티션 연속성
• 배치 내의 메시지들이 같은 파티션에 지속적으로 쌓이면, Kafka 브로커는 파티션 간에 데이터를 이동하거나 분산할 필요가 없습니다.
• 따라서 디스크 쓰기나 네트워크 I/O 오버헤드가 줄어듭니다.
2. I/O 효율성
• 배치 처리(batch processing)는 한 번의 네트워크 호출로 여러 메시지를 전송할 수 있도록 최적화됩니다.
• Sticky 파티셔닝은 배치를 구성하는 동안 동일한 파티션을 유지하므로, 여러 파티션으로 분산될 경우 발생할 수 있는 추가 I/O 오버헤드(메타데이터 갱신, 리더 전환 등)를 피할 수 있습니다.
3. 네트워크 비용 감소
• 동일한 파티션으로 계속 쓰는 경우, Kafka 브로커와 클라이언트 간의 파티셔닝 메타데이터 업데이트가 줄어들어 네트워크 요청 비용이 감소합니다.
4. 페이지 캐시 활용
• Kafka의 설계 특성상, 물리적 파티션은 주로 디스크에 데이터를 기록하지만, OS 페이지 캐시를 활용하여 디스크 접근을 줄입니다.
• Sticky 파티셔닝은 특정 파티션에 지속적으로 데이터를 기록하므로, 페이지 캐시가 효율적으로 활용되어 디스크 접근을 최소화할 수 있습니다.
Sticky 파티셔닝의 동작 방식
1. Batch 단위로 유지
• Sticky 파티셔닝은 프로듀서의 배치가 완료될 때까지 동일한 파티션을 유지합니다.
• 배치가 끝나면 다음 배치에서 새로운 파티션을 선택합니다.
• 이를 통해 균등한 분산과 쓰기 효율성을 동시에 달성합니다.
2. Fallback
• 특정 파티션이 과부하 상태라면(예: 리더 파티션 실패), Sticky 파티셔닝은 다른 파티션으로 자동으로 전환됩니다.
Sticky 파티셔닝이 유리한 경우
1. 메시지 키가 없는 경우
• 메시지 키를 설정하지 않을 때, Sticky 파티셔닝은 기본 Round Robin 전략보다 효율적입니다. Round Robin은 파티션을 계속 전환하며 메타데이터 갱신과 네트워크 비용이 발생하지만, Sticky는 이를 줄입니다.
2. 높은 쓰기 속도
• 프로듀서가 많은 메시지를 빠르게 전송해야 하는 경우 Sticky 파티셔닝은 배치를 유지하며 효율적으로 데이터를 처리합니다.
3. 순서가 중요하지 않은 경우
• Sticky 파티셔닝은 메시지 키를 사용하지 않기 때문에, 메시지가 특정 파티션에 라우팅되더라도 순서 보장은 하지 않습니다. 따라서 순서 보장이 필요 없는 경우 적합합니다.
예제: Sticky Partitioning vs Round Robin
네, 이어서 설명드리겠습니다!
Round Robin 예시
Round Robin은 메시지를 순차적으로 다른 파티션에 분배합니다.
예를 들어, 메시지 10개를 my-topic에 보내고 파티션이 3개일 때:
1. 메시지 분배 결과:
파티션 1: 메시지 1, 메시지 4, 메시지 7, 메시지 10
파티션 2: 메시지 2, 메시지 5, 메시지 8
파티션 3: 메시지 3, 메시지 6, 메시지 9
2. 문제점:
• 각 메시지가 다른 파티션으로 전송되므로 파티션 전환 비용이 발생합니다.
• 디스크 I/O와 네트워크 레이턴시가 높아질 수 있습니다.
• 배치 효율성이 떨어질 수 있습니다(한 번의 배치 요청이 여러 파티션에 걸칠 수 있기 때문).
Sticky Partitioning 예시
Sticky Partitioning은 **하나의 배치(batch)**가 완료될 때까지 동일한 파티션으로 메시지를 보냅니다.
예를 들어, 동일한 10개의 메시지를 배치 크기 5로 전송한다고 가정하면:
1. 메시지 분배 결과:
파티션 1: 메시지 1, 메시지 2, 메시지 3, 메시지 4, 메시지 5
파티션 2: 메시지 6, 메시지 7, 메시지 8, 메시지 9, 메시지 10
2. 장점:
• 각 배치가 하나의 파티션에 기록되므로 파티션 전환 비용이 줄어듭니다.
• 배치 처리 효율성이 높아지고, 네트워크 및 디스크 I/O의 오버헤드가 감소합니다.
• 페이지 캐시 활용이 극대화되어 디스크 쓰기 성능이 향상됩니다.
Sticky Partitioning의 한계
1. 파티션 간 부하 불균형:
• 특정 배치가 너무 큰 경우, 일부 파티션에만 데이터가 몰릴 수 있습니다.
• 이를 방지하려면 적절한 배치 크기와 브로커 설정이 필요합니다.
2. 순서 보장 어려움:
• Sticky Partitioning은 순서 보장을 지원하지 않으므로, 메시지가 순차적으로 처리되어야 하는 경우에는 적합하지 않습니다.
Kafka 프로듀서 설정 예시
Sticky Partitioning은 Kafka의 기본 동작(2.4 이상)이지만, 필요에 따라 설정을 확인하거나 조정할 수 있습니다.
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 프로듀서 설정
props.put("linger.ms", 5); // 배치를 위해 대기하는 시간
props.put("batch.size", 16384); // 배치 크기
props.put("partitioner.class", "org.apache.kafka.clients.producer.internals.DefaultPartitioner"); // 기본 Sticky 파티셔닝 사용
• linger.ms: 메시지가 바로 전송되지 않고, 지정된 시간 동안 배치를 기다리도록 설정합니다.
• batch.size: 한 번에 전송할 메시지 배치 크기(바이트 단위)입니다.
• partitioner.class: Sticky Partitioning은 DefaultPartitioner에서 기본 동작으로 처리됩니다.
결론
Sticky Partitioning은 다음과 같은 이점을 제공합니다:
• 오버헤드 감소: 배치 내 메시지를 동일한 파티션으로 라우팅하여 디스크와 네트워크 I/O 효율성 극대화.
• 효율적인 데이터 쓰기: 페이지 캐시 활용과 배치 전송 최적화를 통해 성능 향상.
하지만, 데이터의 순서가 중요하거나 키 기반 파티셔닝이 필요한 경우에는 메시지 키를 사용하는 것이 더 적합합니다. 사용 사례에 따라 Sticky Partitioning과 메시지 키 기반 파티셔닝을 적절히 조합하는 것이 중요합니다!
'GPT Archiving' 카테고리의 다른 글
Java - CompletableFuture & addCallBack (0) | 2025.01.06 |
---|---|
kafka - ProducerRecord (0) | 2025.01.06 |
dockerfile - 의존성 캐싱 (1) | 2025.01.06 |
dockerfile - booJar, plain Jar (1) | 2025.01.06 |