カフカ(9)を学ぶためにあなたに同行してください-変位リプレイ

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して5日目です。クリックしてイベントの詳細をご覧ください。

意味

Kafkaオフセット再生は、消費者のオフセットをリセットすることです

シーン

  • 履歴メッセージは再利用する必要があります
  • kafkaデータ移行

ストラテジー

変位寸法

最古

変位を現在の最も早い変位に調整します

最も早い戦略とは、変位を被験者の現在の最も早い変位に調整することを意味します。実稼働環境では、遠くにあるメッセージはKafkaによって自動的に削除されるため、この最も早い変位は必ずしも0ではありません。したがって、現在の最も早い変位は0より大きい値になる可能性があります。トピックのすべてのメッセージを再利用する場合は、最も早い戦略を使用できます。

最新

変位を現在の最新の変位に調整します

最新の戦略とは、変位を最新の最終変位にリセットすることを意味します。トピックに合計15個のメッセージを送信する場合、最新のエンドシフトは15です。すべての履歴メッセージをスキップして最新のメッセージから消費を開始したい場合は、最新の戦略を使用できます

現在

ディスプレイスメントを現在の最新のコミットディスプレイスメントに調整します

現在の戦略とは、消費者が現在提出している最新の変位に変位を調整することを意味します。このようなシナリオが発生する場合があります。コンシューマープログラムコードを変更してコンシューマーを再起動すると、コードに問題があることが判明し、以前のコード変更をロールバックして、コンシューマーへの変位をリセットする必要があります。再起動時の場所、つまり、現在の戦略は、この機能を実現するのに役立ちます。

指定-オフセット

指定された変位に変位を調整します

Specified-Offset戦略は、より一般的な戦略です。つまり、コンシューマーは、オフセット値を指定したオフセットに調整します。この戦略の一般的な使用例は、コンシューマープログラムがエラーメッセージを処理するときに、このメッセージの処理を手動で「スキップ」できることです。実際の使用では、破損したメッセージを消費できない場合があります。このとき、コンシューマープログラムは例外をスローし、動作を継続できません。この問題が発生したら、Specified-Offset戦略を使用して回避することができます。

Shift-By-N

変位を現在の変位+Nに調整します(Nは負の場合もあります)

Specified-Offset戦略で変位の絶対値を指定する必要がある場合、Shift-By-N戦略では変位の相対値を指定します。つまり、スキップするメッセージの距離を指定できます。ここでの「ジャンプ」は双方向であり、前方または後方に「ジャンプ」できます。たとえば、変位を現在の変位の最初の100変位にリセットする場合は、Nを-100として指定する必要があります。

時間ディメンション

日付時刻

変位を所定の時間よりも大きい最小変位に調整します

DateTimeを使用すると、時間を指定して、その時間の後の最も早い変位に変位をリセットできます。一般的な使用シナリオは、昨日のデータを再利用したい場合です。その後、この戦略を使用して、オフセットを昨日の0時にリセットできます。

間隔

変位を現在時刻から指定した間隔の変位に調整します

期間戦略は、指定された相対時間間隔を参照し、現在の指定された時間間隔からの変位に合わせて変位を調整します。特定の形式はPnDTnHnMnSです。Java 8で導入されたDurationクラスに精通している場合は、この形式に精通していないはずです。これは、ISO-8601仕様に準拠した期間形式であり、文字Pで始まり、その後にそれぞれ日、時間、分、秒を表すD、H、M、Sの4つの部分が続きます。たとえば、オフセットを15分前に戻す場合は、PT0H15M0Sを指定できます。

操作する

Api

KafkaConsumerのseekメソッド、またはそのバリアントメソッドseekToBeginningおよびseekToEnd。

package org.apache.kafka.clients.consumer; 
..... 
public class KafkaConsumer implements Consumer { 
    ..... 
    @Override public void seek(TopicPartition partition, long offset) {
        .... 
    } 
    public void seekToBeginning(Collection partitions) { 
        .... 
    } 
    public void seekToEnd(Collection partitions) {
        .... 
    } 
        .... 
}
复制代码

実装例

初期の実装

Properties consumerProperties = new Properties(); 
...... 
String topic = "test"; // 要重设位移的 Kafka 主题 
try (final KafkaConsumer consumer = 
    new KafkaConsumer<>(consumerProperties)) { 
        consumer.subscribe(Collections.singleton(topic)); 
        consumer.poll(0); 
        consumer.seekToBeginning( consumer.partitionsFor(topic).stream().map(partitionInfo -> 
        new TopicPartition(topic, partitionInfo.partition())) 
        .collect(Collectors.toList()));
}
复制代码

最新の実装

consumer.seekToEnd( 
    consumer.partitionsFor(topic).stream().map(partitionInfo -> 
    new TopicPartition(topic, partitionInfo.partition())) 
    .collect(Collectors.toList()));

复制代码

現在の実装

consumer.partitionsFor(topic).stream().map(info -> 
    new TopicPartition(topic, info.partition())) .forEach(tp -> { 
    long committedOffset = consumer.committed(tp).offset(); 
    consumer.seek(tp, committedOffset); });
复制代码

指定オフセットの実装

long targetOffset = 1234L; 
for (PartitionInfo info : consumer.partitionsFor(topic)) { 
    TopicPartition tp = new TopicPartition(topic, info.partition()); 
    consumer.seek(tp, targetOffset); 
}
复制代码

Shift-By-Nの実装

for (PartitionInfo info : consumer.partitionsFor(topic)) { 
    // 假设向前跳 123 条消息 
    TopicPartition tp = new TopicPartition(topic, info.partition()); 
    long targetOffset = consumer.committed(tp).offset() + 123L; 
    consumer.seek(tp, targetOffset); 
}
复制代码

データ時間の実装

long ts = LocalDateTime.of( 
2020, 7, 20, 20, 0).toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); 
Map timeToSearch = consumer.partitionsFor(topic).stream().map(info -> 
new TopicPartition(topic, info.partition())) 
.collect(Collectors.toMap(Function.identity(), tp -> ts)); 
for (Map.Entry entry : consumer.offsetsForTimes(timeToSearch).entrySet()) {   
    consumer.seek(entry.getKey(), entry.getValue().offset()); 
}
复制代码

期間の実装

Map timeToSearch = 
consumer.partitionsFor(topic).stream() 
.map(info -> new TopicPartition(topic, info.partition())) .collect(Collectors.toMap(Function.identity(), tp -> 
System.currentTimeMillis() - 30 * 1000 * 60)); 
for (Map.Entry entry : 
    consumer.offsetsForTimes(timeToSearch).entrySet()) { 
    consumer.seek(entry.getKey(), entry.getValue().offset()); 
}
复制代码

終了

コミュニケーションと学習が必要な場合は、パブリックアカウント[古いJavaの確認と新しいJavaの理解]に注意を払い、お互いから学び、一緒に進歩することができます。

おすすめ

転載: juejin.im/post/7085225980905652255