Kafka가 스토리지 구현에 대한 동시 액세스 문제를 처리하는 방법

1. 소개

Kafka는 주로 파일 시스템을 사용하여 메시지 데이터를 저장하고 게시-구독 모드를 지원하며 스트리밍 데이터를 처리하는 분산 메시지 대기열입니다. 여러 Topic 및 Partition 저장 작업을 수행하면 동시 액세스 및 데이터 충돌과 같은 문제가 발생합니다.

2. Kafka 저장 방식의 설계

Kafka 스토리지 솔루션의 설계는 여러 주제 및 파티션 스토리지 작업의 동시성 및 잠금 문제를 해결하기 위해 관련 기술의 선택과 해당 메커니즘의 구현이 필요하며 동시에 생산자의 읽기 및 쓰기를 최적화해야 합니다. 그리고 소비자 데이터.

2.1 관련 기술의 선정

2.1.1 파일 시스템 선택

Kafka는 ext3, ext4, XFS 등과 같은 디스크 기반 파일 시스템을 사용합니다. 이러한 파일 시스템은 빅 데이터 시나리오에서 널리 사용됩니다. 현재 대부분의 Kafka 메시지 저장소는 영구 저장소 및 빠른 데이터 복구를 지원하는 Linux 호환 파일 시스템을 기반으로 합니다.

2.1.2 잠금 메커니즘 선택

Kafka의 주제와 파티션은 모두 여러 생산자가 작성하고 동시에 여러 소비자가 읽을 수 있습니다. 주제와 파티션의 동시 쓰기 문제를 해결하기 위해 Kafka는 파일 잠금 기반 메커니즘을 채택합니다. 즉, 각 파일은 잠금 파일에 해당하고 잠금 파일은 데이터 파일과 동일한 이름을 가지며 접미사는 .잠금. 잠금 메커니즘을 사용하면 여러 생성자가 파티션에 동시에 쓸 때 각 생성자가 고유한 잠금을 획득하여 순차적 쓰기 및 데이터 일관성을 보장할 수 있음을 인식할 수 있습니다.

2.2 구현 메커니즘

2.2.1 순차적 쓰기 및 버퍼링 구현

Kafka는 디자인에서 순차적 쓰기 기반 메커니즘을 사용하여 디스크 처리량을 최대화하고 데이터 쓰기 효율성을 향상시킬 수 있습니다. 동시에 Kafka는 메모리 버퍼링 기술을 사용하여 쓸 데이터를 캐시하여 디스크에 쓰는 빈도를 줄입니다. 특정 조건이 충족되면 캐시된 데이터가 일괄적으로 디스크에 기록되어 Kafka의 성능을 크게 향상시킬 수 있습니다.

2.2.2 압축 및 인덱싱 구현

Kafka는 메시지 압축과 인덱싱을 동시에 지원하며 압축과 인덱싱을 통해 Kafka의 전체 데이터 볼륨을 줄이고 소비 중에 필요한 데이터를 빠르게 찾을 수 있으므로 읽기 효율성이 향상됩니다.

2.3 생산자/소비자 데이터 읽기 및 쓰기 최적화

생산자와 소비자의 데이터 읽기 및 쓰기 효율성을 최적화하기 위해 Kafka는 메시지 캐시, 제로 복사 기술 및 최적화를 위한 디스크 파티션과 같은 기술 솔루션을 채택합니다. 또한 Kafka는 일괄 처리를 사용하여 여러 데이터 조각을 하나의 큰 메시지로 결합하여 전송하므로 서버와의 통신 수를 줄이고 데이터 전송 효율성을 향상시킵니다.

// kafka 生产者生产消息示例
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");

Producer<String, String> producer = new KafkaProducer<>(props);
for(int i = 0; i < 100; i++)
    producer.send(new ProducerRecord<>("test-topic", Integer.toString(i), Integer.toString(i)));
producer.close();

// kafka 消费者消费消息示例
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "test-group");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList("test-topic"));
while (true) {
    
    
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records)
        System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
}

3. Kafka 저장 방식 실습

3.1 구현 세부 사항 및 고려 사항

Kafka를 사용하여 데이터를 저장할 때 주의해야 할 몇 가지 사항이 있습니다.

  • 메시지 키 및 값 크기 제한 : 기본적으로 Kafka 메시지의 키 및 값 크기는 최대 1MB입니다. 더 큰 메시지를 보내야 하는 경우 브로커 구성에서 message.max.bytes및 매개변수를 수정하고 브로커를 다시 시작해야 합니다 .replica.fetch.max.bytes
  • 메시지 영구 저장 : Kafka의 메시지는 추가 방식으로 디스크에 기록되며 일단 기록되면 수정할 수 없습니다. Kafka의 기본 메시지 보존 정책은 시간 보존이므로 메시지는 자동으로 삭제됩니다. 메시지를 지속적으로 저장해야 하는 경우 메시지 크기 또는 메시지 수에 따라 보존하도록 메시지 보존 정책을 변경할 수 있습니다.
  • 메시지 신뢰성 보장 : 메시지의 신뢰성을 보장하기 위해 다음과 같이 구성할 수 있습니다.
    • acks매개변수: 메시지가 성공적으로 전송된 것으로 간주되기 위해 승인을 수신해야 하는 복제본을 지정하는 데 사용됩니다. 세 가지 값이 있습니다: 0확인이 필요하지 않음을 의미하고, 1최소 하나의 복제본에서 확인을 받아야 함을 의미하고, all사용 가능한 모든 복제본에서 확인을 기다려야 함을 의미합니다.
    • retries매개변수: 네트워크 오류 또는 파티션 오류가 발생할 때 메시지를 재시도할 수 있는 횟수입니다. 기본값은 0이며 재시도하지 않음을 의미합니다. retry.backoff.ms이 매개변수는 재시도 사이의 지연을 제어하는 ​​매개변수와 함께 사용해야 합니다 .
    • max.in.flight.requests.per.connection매개변수: 클라이언트가 서버로부터 응답을 받기 전에 서버에 보낼 수 있는 최대 요청 수를 지정하는 데 사용됩니다. 기본값은 5이며, 이는 Kafka가 처음 5개의 요청에 대한 응답을 받기 전에 다른 5개의 요청을 보낼 수 있음을 의미합니다.

3.2 시스템 성능 테스트 및 최적화 계획

실제 사용 시 Kafka 스토리지 솔루션의 성능을 테스트하고 최적화해야 합니다. 다음은 몇 가지 일반적인 성능 테스트 및 최적화 솔루션입니다.

  • 동시 읽기 및 쓰기 성능 테스트 : Kafka에 많은 수의 동시 메시지를 전송하여 읽기 및 쓰기 성능을 테스트합니다. 성능 병목 현상이 있는 경우 파티션 수를 늘리고 브로커 구성에서 num.io.threads및 매개 변수를 늘리고 num.network.threadsKafka 클러스터의 크기를 늘려 성능을 최적화할 수 있습니다.
  • 데이터 보존 정책 성능 테스트 : 다양한 메시지 보존 정책(시간, 크기 또는 수량 기준)을 설정하여 Kafka의 성능을 테스트합니다. 데이터 스토리지 병목 현상이 있는 경우 cleanup.policy 매개변수를 조정하거나 소비자를 추가하여 메시지 스토리지 부담을 줄여야 합니다.
  • 메시지 크기와 수 및 처리량 간의 관계 테스트 : 다양한 수와 크기의 메시지를 전송하여 Kafka의 성능을 테스트합니다. 테스트 결과에 따르면 메시지 크기와 수를 최적화하여 더 나은 처리량을 달성할 수 있습니다.

3.3 스토리지 솔루션 업데이트 및 업그레이드

Kafka 스토리지 솔루션을 업데이트하거나 업그레이드해야 하는 경우 다음 사항에 주의해야 합니다.

  • 데이터 백업 : 업데이트 또는 업그레이드 전에 모든 데이터를 백업해야 합니다. 데이터 손실을 방지하기 위해 데이터를 독립적인 저장 매체에 백업하는 것이 가장 좋습니다.
  • 서비스 중지 : KafKa를 업그레이드할 때 모든 서비스를 중지하고 업그레이드가 완료될 때까지 서비스가 시작되지 않도록 해야 합니다.
  • 업그레이드 순서 : 예를 들어 먼저 Zookeeper를 업그레이드한 다음 브로커를 업그레이드하고 마지막으로 Kafka-client를 업그레이드하는 순서대로 각 구성 요소를 업그레이드해야 합니다.
  • 테스트 및 검증 : 업그레이드가 완료된 후 시스템이 제대로 작동하고 데이터가 손실되지 않았는지 확인하기 위해 테스트 및 검증이 필요합니다.

4. Kafka 동시 접속 문제의 적용 시나리오

Kafka는 실시간 데이터 스트림 처리, 로그, 이벤트 및 메트릭과 같은 시나리오에서 널리 사용되는 분산 메시지 대기열 시스템입니다. Kafka 스토리지 구현에서 동시 액세스 문제를 해결하기 위해 몇 가지 우수한 설계를 채택하므로 다음 시나리오에도 적용할 수 있습니다.

4.1 Kafka 기반 분산 트랜잭션

Kafka는 동시에 동일한 주제에 메시지를 보내고 메시지 순서를 보장하기 위해 여러 생산자를 지원할 수 있습니다. 분산 트랜잭션을 구현할 때 Kafka는 모든 비즈니스 관련 작업을 기록하는 트랜잭션 로그로 사용할 수 있습니다. 분산 트랜잭션의 정확성과 신뢰성은 Kafka 트랜잭션 로그 메커니즘의 멱등성 및 원자성 기능을 사용하여 보장할 수 있습니다.

다음은 샘플 Java 코드입니다.

// 创建 Kafka 生产者
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
// 初始化事务
producer.initTransactions();
try {
    
    
    // 开启事务
    producer.beginTransaction();
    // 发送消息
    producer.send(new ProducerRecord<String, String>(topic, message));
    // 提交事务
    producer.commitTransaction();
} catch (ProducerFencedException | OutOfOrderSequenceException | AuthorizationException e) {
    
    
    // 异常处理
    producer.abortTransaction();
} catch (KafkaException e) {
    
    
    // 异常处理
    producer.abortTransaction();
}

4.2 Kafka 기반의 대규모 로그 수집 시스템

대규모 로그 수집 시스템에서는 방대한 양의 로그 데이터를 실시간으로 처리하여 스토리지 시스템으로 전송해야 하므로 효율적인 데이터 스트림 처리와 안정적인 메시지 전송이 필요합니다. Kafka는 메시지 신뢰성, 시퀀스 및 재시도 메커니즘을 보장하면서 로그 수집을 위한 미들웨어로 사용되어 로그 정보를 수락하고 다운스트림 스토리지 계층에 배포할 수 있습니다.

// 创建 Kafka 生产者
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
// 发送消息
producer.send(new ProducerRecord<String, String>(topic, message));

4.3 Kafka 기반 스트림 처리 시스템

Kafka는 주로 데이터 입력, 출력 및 전송과 같은 기능을 위해 스트림 처리 시스템의 인프라로 사용할 수도 있습니다. 스트림 처리 시스템은 방대한 양의 실시간 데이터를 수집하고 계산, 필터링, 집계 등의 작업을 수행하고 최종적으로 그 결과를 다운스트림 스토리지 시스템으로 출력합니다. Kafka는 스트림 처리 시스템에서 캐시 계층으로 사용되어 데이터의 적시성과 신뢰성을 보장할 수 있습니다.

// 创建 Kafka 流处理器
StreamsBuilder builder = new StreamsBuilder();
// 输入源头 topic1
KStream<String, String> inputStream = builder.stream("topic1");
// 数据处理
KStream<String, String> outputStream = inputStream.filter((k, v) -> v.length() > 10);
// 输出目标 topic2
outputStream.to("topic2");
// 构建拓扑并启动应用
KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();

위의 샘플 코드는 Kafka를 사용하여 데이터 스트림을 필터링 및 출력하고, topic1에서 길이가 10보다 큰 데이터를 필터링하여 topic2로 출력하는 방법을 보여줍니다.

추천

출처blog.csdn.net/u010349629/article/details/130935186