学んだことカフカ(https://www.cnblogs.com/tree1123/p/11226880.html)の後
その別の研究のどのバージョンを見つけるようにしてください、混乱に特に脆弱いくつかの変更、後にコアAPIの消費者、カフカの消費者向けバージョンをご覧ください。
消費者の最初に、古いバージョン
唯一の古いバージョン(0.9の前)は、高レベルの消費者と低レベルの消費者のポイントを持って、多くの記事は、これら二つのことを述べた:低レベルとハイエンドの消費者の顧客が、より柔軟なローエンドの消費者を必要と自分の事の多くを維持し、上位ビットの剛性が、それはあまりにも多くのメンテナンスを必要としません。
高レベルの消費者は、消費者のグループです。
単一の低レベルの消費者は、消費者、単一コンシューマ・グループ、互いにおよび他の消費者との間に相関を持たない消費者です。
図1に示すように、低レベルのコンシューマ
低レベルの消費者の基礎となる実装です
彼は自分の消費者に管理することができますSimpleConsumer
嵐の嵐・カフカカフカプラグインはSimpleConsumerの使用であります
利点は、柔軟であり、任意の場所からメッセージを取ることができます。
あなたが必要な場合:データの読み出しを繰り返し、部分的にしか消費し、正確な消費データパーティションは、これを使用しなければなりません、
しかし、私たちは自分の変位は、パーティションのリーダーブローカーの取引のリーダーの変化をみると提出に対処しなければなりません。
接口中的方法:
fetch
send 发送请求
getOffsetBefore
commitOffsets
fetchOffsets
earliestOrlatestOffset
close
これらの手順を実行します。
公式サイトを参照して、より複雑なメッセージを引っ張って、いくつかの手順を実行します。
アクティブなブローカーを見つけ、ブローカーがあなたのトピックとパーティションのリーダーであるかを調べます
ブローカーはあなたのトピックとリーダーのパーティションを見つけることであるアクティブなブローカーを探します
レプリカブローカーは、あなたのトピックとパーティションのために誰であるかを判別
のブローカーのレプリカを見つけます
興味のあるものを定義するデータ要求を構築
確立要求
データをフェッチ
データを取ります
特定し、リーダーの変更からの回復
回復時間のリーダーの変更
いくつかは、次のようにもこのようなメタデータ、特定のコードなどの情報を確認することができますオフセット。
//根据指定的分区从主题元数据中找到主副本
SimpleConsumer consumer = new SimpleConsumer(seed, a_port, 100000, 64 * 1024,
"leaderLookup");
List<String> topics = Collections.singletonList(a_topic);
TopicMetadataRequest req = new TopicMetadataRequest(topics); kafka.javaapi.TopicMetadataResponse resp = consumer.send(req);
List<TopicMetadata> metaData = resp.topicsMetadata();
String leader = metaData.leader().host();
//获取分区的offset等信息
//比如获取lastoffset
TopicAndPartition topicAndPartition = new TopicAndPartition(topic, partition);
Map<TopicAndPartition, PartitionOffsetRequestInfo> requestInfo = new HashMap<TopicAndPartition, PartitionOffsetRequestInfo>();
requestInfo.put(topicAndPartition, new PartitionOffsetRequestInfo(whichTime, 1));
kafka.javaapi.OffsetRequest request = new kafka.javaapi.OffsetRequest(requestInfo, kafka.api.OffsetRequest.CurrentVersion(), clientName);
OffsetResponse response = consumer.getOffsetsBefore(request);
long[] offsets = response.offsets(topic, partition);
long lastoffset = offsets[0];
さて、ずっとこのAPIを適用するあなたは、自分のモニターを記述するなど、特別なニーズを持っていない限り、あなたはより多くのメタデータ情報が必要な場合があります。
図2に示すように、高レベルのコンシューマ
主な用途カテゴリー:ConsumerConnector
各トピックの投与のためのオフセット、各シールドを分割する(自動的に最終オフセットコンシューマ・グループの飼育係に読み込むため)
ブローカーのフェイルオーバー、ロードパーティションの消費者の減少で均衡(増減Partiotionと消費者、カフカ自動負荷分散)
これらの機能は、低レベルの消費者は、独自の実装を必要とします。
主要方法如下:
createMessageStreams
createMessageStreamsByFilter
commitOffsets
setconsumerReblanceListener
shutdown
グループは、飼育係を通じてコア機能を完了します
飼育係のディレクトリ構造は次のとおりです。
/consumers/groupId/ids/consumre.id
消費者のレコード契約情報、また、消費者に実行可能な状態を監視するために使用されます。これは、セッションは自動的に削除されます一時的なノード障害です。
/消費者/ groupIdを/所有者/トピック/パーティション
実行リバランスを保存し、各スレッドのid消費者の消費量を保存します。
/消費者/ groupIdを/オフセット/トピック/パーティション
変位情報パーティションを指定したコンシューマ・グループを保存します。
消費者のサポートマルチスレッド設計では、唯一の消費者のインスタンスを作成しますが、それは複数のパーティションがある場合、それは自動的に複数のスレッドの消費量を作成します。
これらの手順を実行します。
Properties properties = new Properties();
properties.put("zookeeper.connect", "ip1:2181,ip2:2181,ip3:2181");//声明zk
properties.put("group.id", "group03");
ConsumerConnector consumer = Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, 1); // 一次从主题中获取一个数据
Map<String, List<KafkaStream<byte[], byte[]>>> messageStreams = consumer.createMessageStreams(topicCountMap);
KafkaStream<byte[], byte[]> stream = messageStreams.get(topic).get(0);// 获取每次接收到的这个数据 如果是多线程在这里处理多分区的情况
ConsumerIterator<byte[], byte[]> iterator = stream.iterator();
while(iterator.hasNext()){
String message = new String(iterator.next().message());
System.out.println("接收到: " + message);
}
//auto.offset.reset 默认值为largest
//从头消费 properties.put("auto.offset.reset", "smallest");
簡単に言えば、我々は0.9より前のバージョンの多くを使用するには、ように、彼の、春の統合的なアプローチとしています。しかし、新しい消費者向けバージョン0.9の後に登場しました。
第二に、消費者の新バージョン
私は、問題のバージョンについてお話しましょう:
0.10.0.0はとても増加した後、カフカカフカはKafka1.0ストリームストリームは、安定し始めます。
カフカのセキュリティ、安定性0.9.0.0後0.10.0.1後
新バージョン0.10.1.0安定した消費者の後
でも、カフカの嵐2つのパッケージがあります。
消費者の古いバージョンを使用して、嵐、カフカ
嵐・カフカ - クライアントは、消費者の新しいバージョンを使用しています
カフカの0.9.0.0は、Java開発の新バージョン生産者と消費者のレガシーレガシーのScalaのバージョンを放棄しました
版 | 推奨プロデューサー | 推奨消費者 | 理由 |
---|---|---|---|
0.8.2.2 | 旧バージョン | 旧バージョン | 新しいプロデューサーはまだ安定していません |
0.9.0.x | 新しいです | 旧バージョン | 新しい生産安定 |
0.10.0.x | 新しいです | 旧バージョン | 新しい消費者の不安定 |
0.10.1.0 | 新しいです | 新しいです | 新しい消費者の安定しました |
0.10.2.x | 新しいです | 新しいです | 我々は安定しています |
古いバージョンでは、新しいバージョンが飼育係に頼らない、飼育係を頼っ管理を相殺しました。
言語 | パッケージ名 | 主な用途カテゴリー | |
---|---|---|---|
古いバージョン | スカラ | kafka.consumer。* | ZookeeperConsumerConnector SimpleConsumer |
新バージョン | ジャワ | org.apache.kafka.clients.consumer。* | カフカの消費者 |
コアコンセプトの新バージョン:
コンシューマ・グループ
消費者は、各メッセージのトピックは唯一の彼のコンシューマ・グループに加入する各消費者のインスタンスに送信されます、自分自身をマークするために、コンシューマ・グループ名(group.id)を使用します。
1、コンシューマ・グループは、消費者の数を持っています。
図2に示すように、グループに関して、各メッセージのトピックは、例えば、グループ内の消費者に送信することができます。
3、トピックメッセージは、グループの複数に送信してもよいです。
消費者側は、オフセット
位置レコードごとに消費者の消費パーティション
カフカ、サーバー側でこれを置くコンシューマ・グループに保存され、定期的に永続化ではありません。
古いバージョンで定期的プレゼンスのZooKeeperでこれを相殺します:パス/消費者/グループID /オフセット/トピック/ partitionid
新バージョンでは、内部トピックに置かオフセットします:50個の区画に分割されている__ consumer_offsets(フロント2つのアンダースコア)
だから、消費者の新しいバージョンでも飼育係を必要としません。
古いバージョンでは使用しません、この変位に提出するように設定=カフカoffsets.storageに設定されています。
構造__consumer_offsets:キー= group.id +トピック+パーティション値=オフセット
コンシューマ・グループreblance
個々の消費者がリバランスされていません。
彼はすべてのパーティションを割り当てる方法をコンシューマ・グループの下にあるすべての消費者を提供します。
シングルスレッドのサンプルコード:
Properties props = new Properties();
props.put("bootstrap.servers", "kafka01:9092,kafka02:9092");
props.put("group.id", "test");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("auto.offset.reset","earliest");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("foo", "bar"));
try{
while (true) {
ConsumerRecords<String, String> records = consumer.poll(1000);
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
}
}
}finally{
consumer.close();
}
非常に単純な、1だけでサーバーを設定する必要があるグループID自動コミット(bootstrap.server group.id key.deserializer value.deserializerが指定されなければならない)カフカ直列化autooffsetreset。
図2に示すように、これらの特性を有する構築消費者オブジェクト(KafkaConsumerその他の構成は、シリアライゼーション内に通過することができます)。
3、(あなたが定期購読Pattern.compile(使用できる「カフカを。*」)トピックのリストを購読
あなたは、通常のリスナーが(パターン・パターン、ConsumerRebalanceListenerリスナー))をサブスクライブ使用して指定する必要があります。このインターフェースの論理パーティショニングの変更を実装するために書き換えることができます。あなたが設定されている場合enable.auto.commitは、このロジックを無視する場合はtrue =。
4、その後(1000等タイムアウト、そうでない場合は、データの多くは、1秒である場合)、メッセージループをポーリングします。
図5に示すように、メッセージ処理(ここではオフセットキー値を印刷する処理ロジックを記述)。
図6は、クローズKafkaConsumer(デフォルトタイムアウト値は30秒待つことで通過することができます)。
詳細なプロパティ:
bootstrap.server(それはIPホスト名で構成されていない限り、最高のIPホスト名は、内部での使用をカフカません)
デシリアライザは、ブローカ最終消費者は、バイト配列から得られたオブジェクト・タイプに戻すされるデシリアライズ。
StringDeserializer LongDeserializer DoubleDeserializer:デフォルトではダースがあります。。
また、カスタマイズすることができる:作成したカスタムデシリアライザデシリアライザクラスは、論理フォーマット定義されたシリアライザを書き換えるためのインターフェースを実装
4に加えてbootstrap.server group.id key.deserializer value.deserializerを渡します
「コーディネーター障害検出時間」がありsession.timeout.ms
時間はタイムリーデフォルトをリバランスするために、検出されたハング消費者は、10秒の遅延メッセージを避けるために、より小さな値に設定することが可能です。
max.poll.interval.ms「消費者の処理ロジックの最大時間」
より複雑なロジックを扱う場合は繰り返されます、世論調査は二回長く、このパラメータよりも、カフカは消費者が追いついていないと思うので、あなたがグループから追い出される、不要なリバランスを避けるために、この値を設定することができ、およびオフセットに提出することができません消費。デフォルトは5分です。
auto.offset.reset「カフカには、変位または変位クロスボーダー対処戦略ません」
したがって、このパラメータの消費に続いてグループの後に最初から消費者が起動または再起動した場合に正常に送信さ変位は無効です。
だから、説明三つの値は以下のとおりです。
earliset提出開始オフセットの支出から、地区の下に提出されたオフセットすると、何の消費から提出され、早いシフトを相殺しません
各パーティションに提出がオフセットされている場合、提出されたオフセットからの支出を開始していない、最新の、オフセットが何のパーティションが存在しているパーティションのトピックで何を生産していない、新たな消費者データを提出開始オフセットから、コミットされたオフセット消費;限り存在しない提出オフセットのパーティションがあると、例外がスローされます
(カフカ-0.10.1.X以前のバージョンに注意:. Auto.offset.reset値が最小で、且つ、ZKに格納されている最大(offest)
私たちは新しいバージョンについて話している:カフカ-0.10.1.Xバージョン後:最古の、最新の、そしてなし(カフカと題したトピック特別に保存されているoffest:値auto.offset.resetを変更して内部__ consumer_offsets ))
enable.auto.commitは自動的に変位を提出したかどうか
自動的にfalseを提出する場合はtrueを手動で一つだけの治療が最近falseに設定され、独自のを制御するために必要とされている提出するユーザーを必要としています。
バイトの単一の最大数を取得するfetch.max.bytesコンシューマ
最大のメッセージは、単一の投票数を返すmax.poll.records
消費は、消費の増加は、この値の非常に光量が適切に増加させることができる量であれば500デフォルト。
時間rabalanceの他のチームメンバーhearbeat.interval.ms消費者の知覚
それはrabalanceを知覚することはできません単に消費者を検出した場合、この値はsession.timeout.msがハングアップしますよりも小さくなければなりません
connections.max.idle.msは、定期的に接続時間を閉じます
デフォルトでは、近くに決して9分-1
詳細な投票方法:
(旧バージョン:マルチスレッドの新しいバージョンマルチパーティション:複数のソケット接続を管理するためのスレッド)
等の取得メッセージ、リバランス、コーディネーター、変位を提出し、新しいバージョンがKafkaConsumerダブルスレッドである。しかし、メインスレッドは責任があります
もう一つは、バックグラウンドスレッドのハートビートです。
上側の様々な構成、方法をポーリングは、十分なデータが利用可能である場合、取得した、オフセット、または待機時間が指定されたタイムアウトを超え、戻り見つけます。
Javaの消費者はKafkaConsumerが複数のスレッドで使用すると、マルチスレッドの異常を評価するためにカフカの消費者は安全ではありません報告します、スレッドセーフではありません。あなたは、保護のための同期ロックを追加することができます。
ポーリングタイムアウトパラメータ1000は、このような5秒、タイムアウトパラメータはに、5000に設定することができ、メッセージを書き込むためのタイミングとして、リターン時に、それはなど、タイムアウト、そうでない場合はデータの多くは、また1秒であると言われてきました効率を最大化します。
あなたが定期的にタスクを実行していない場合は、無期限に待つの十分なデータが得られないはLong.MAX_VALUEに設定されています。ここではそれをWakeupExceptionキャプチャしたいです。
詳細な消費者は、オフセット:
消費者は、定期的にオフセットカフカに自分の情報を提出する必要があります。私たちは、新しいバージョンが__consumer_offsetsで彼に話題を提出される学びました。
より大きな役割をオフセットすることセマンティクスを達成することです。
最も一度に高々度繰り返さない失われることがあります
少なくとも一度は失われていない少なくとも一回繰り返してもよいです
一度だけ一度だけ失われていない正確な時刻が繰り返されていません
消費者の前に消費者が変位を提出する場合は最大で1回で達成
消費した後に提出された場合、少なくとも一度、このデフォルト実現されています。
消費者の複数の位置情報:
最新の変位の現在位置の最後のコミットログレベルの位置
0 1 ... 5 ... 10 ... 15
最終位置提出:消費者オフセット値、最後の提出を。
現在の場所:この位置への消費者の最後の世論調査が、提出されていません。
水のレベル:これは、消費者のパーティション管理は、メッセージの水位以上のログを読み取ることができないです。
最新の変位:管理とログパーティションの最大変位値は水位よりも小さくすることはありません。
消費者の新しいバージョンでは、グループのメンバーの管理、消費者の配布計画、提出された変位を実装するためのコーディネータconsumergroupとしてブローカーでブローカーを選ぶだろう。消費者がクラッシュした場合、彼はパーティションを担当していましたが、他の消費者に割り当てられている、行われていない場合は変位を繰り返し消費を提出することができます。
複数応募の場合は、カフカだけで最新のものを提出しました。
消費者は、自動的に間隔を置いて配置auto.commit.interval.msによって提供されてもよい5秒に提出され、デフォルトの変位を提出します。
自動提出が開発を減らすことができますが、消費繰り返すことができる、我々はまだ手動で正確な消費を提出する必要があります。偽のマニュアル提出enable.auto.commit =を設定し、それから)consumer.commitSync()またはconsumer.commitAyncを(呼び出し同期はブロックせずに、非同期モードにAyncを遮断する、同期システムです。これらの2つの方法は、より合理的である、提出されたパーティションを指定するパラメータを渡すことができます。
(自動送信の古いバージョンがあるauto.commit.enableデフォルト設定は60秒です)
詳細なリバランス:
リバランスのコンシューマ・グループは、すべてのパーティションのトピックを割り当てる方法です。
通常、このような隔壁10として、消費者グループが2つのパーティション各消費者に割り当てられる5平均的な消費者。
各パーティションは、消費者のインスタンスに与えられます。そこの消費者問題は、あるこのプロセスを再実行されますが、このプロセスはリバランスです。
(飼育係の管理リバランスによって旧バージョン、新バージョンでは、管理するために、グループコーディネーターのためのブローカーを選択します)
トリガ条件をリバランスします:
1、新しい消費者を追加し、消費者や残したり、ハングアップすることがあります。
2、グループ加入のトピックは、このような定期的なサブスクリプションとして、変更しました。
3、パーティション・グループのサブスクリプションの変更の数。
多くの場合、最初、必ずしもそれがrequest.timeout.msのmax.poll.recordsとma.poll.intervalを調整するために、頻繁にリバランスを避けるために、あまりにも遅いプロセスであってもよい、ハングアップしません。
パーティション化戦略をリバランスします:
partition.assignment.strategyセットカスタムパーティション化戦略 - パーティションデバイス譲渡を作成します
範囲戦略(デフォルト)、パーティションは、各消費者に割り当てられ、サブセクションに分けます。
ラウンドロビンポリシーのポーリングの割り当て。
複数のトピックをサブスクライブスティッキー戦略(0.11.0.0が良く見える)、レンジ政策が不均一になります。
粘着性の2つの原則、2回の衝突、第二のターゲット優先順位に最初のターゲット。
- できるだけ均一なパーティションに割り当てられています。
- 割り当てられたパーティションは、可能な限り最後の時間配分と同じまま。
重複提出の問題はときrabalance、旧世代オフセット情報の提出を遅らせることを保証するために、世代世代のメカニズムをリバランス異常ILLEGAL_GENERATIONを報告します
プロセスのリバランス:
ソケット接続を確立し、ブローカー・コーディネーター決定する1、。
決意アルゴリズム:Math.abs(groupID.hashCode)%offsets.topic.num.partitionパラメータ値(デフォルト50)
ブローカーは、ブローカーがこのグループのコーディネーターである50のコピー__consumer_offsetパーティションのリーダーを探し
2、グループに参加
すべての消費者がコーディネータに、サブスクリプション情報のJoinGroupコーディネーター、すべての要求を受け、コーディネーターとメンバーへのリクエストを送信した後、リーダーを行うには、消費者の選任(リーダーは、消費者のコーディネーターがブローカーです)。
図3に示すように、同期分配スキーム
コーディネーターにSyncGroup要求により配布計画を開発するリーダーは、各消費者が要求したプログラムに戻ります。
カフカはまた、リスナーConsumerRebalanceListener、再処理リバランスのロジックを実装する必要性に、あなたがカスタマイズすることができ、__consumer_offsetするために、この時間をオフセット提出していないサポートしています。
マルチスレッドのサンプルコード:
这里要根据自身需求开发,我这里只举一个简单的例子,就是几个分区就启动几个consumer,一一对应。
三个类:
Main:
public static void main(String[] args) {
String bootstrapServers = "kafka01:9092,kafka02:9092";
String groupId = "test";
String topic = "testtopic";
int consumerNum = 3;
ConsumerGroup cg = new ConsumerGroup(consumerNum,bootstrapServers,groupId,topic);
cg.execute();
}
import java.util.ArrayList;
import java.util.List;
public class ConsumerGroup {
private List<ConsumerRunnable> consumers;
public ConsumerGroup(int consumerNum,String bootstrapServers,String groupId,String topic){
consumers = new ArrayList<>(consumerNum);
for(int i=0;i < consumerNum;i++){
ConsumerRunnable ConsumerRunnable = new ConsumerRunnable(bootstrapServers,groupId,topic);
consumers.add(ConsumerRunnable);
}
}
public void execute(){
for(ConsumerRunnable consumerRunnable:consumers){
new Thread(consumerRunnable).start();
}
}
}
import java.util.Arrays;
import java.util.Properties;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
public class ConsumerRunnable implements Runnable{
private final KafkaConsumer<String,String> consumer;
public ConsumerRunnable(String bootstrapServers,String groupId,String topic){
Properties props = new Properties();
props.put("bootstrap.servers", bootstrapServers);
props.put("group.id", groupId);
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("auto.offset.reset","earliest");
this.consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList(topic));
}
@Override
public void run() {
while (true) {
ConsumerRecords<String, String> records = consumer.poll(10);
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
}
}
}
}
スタンドアロンの消費者
いくつかの要件は、個人消費のパーティションを指定する必要があります。互いに干渉しない、スタンドアロン消費者のクラッシュは、他には影響しません。
ローエンドの消費者の旧バージョンと同様。
次のサンプルコード:consumer.assignパーティションのサブスクリプション方式
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "kafka01:9092,kafka02:9092");
props.put("group.id", "test");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("auto.offset.reset","earliest");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
List<TopicPartition> partitions = new ArrayList<>();
List<PartitionInfo> allpartitions = consumer.partitionsFor("testtopic");
if(allpartitions!=null && !allpartitions.isEmpty()){
for(PartitionInfo partitionInfo:allpartitions){
partitions.add(new TopicPartition(partitionInfo.topic(),partitionInfo.partition()));
}
consumer.assign(partitions);
}
while (true) {
ConsumerRecords<String, String> records = consumer.poll(10);
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
}
}
}
上記は、消費者はまだ別の具体的な詳細を学ぶ慎重公式ウェブサイトを通じて文書を勉強する必要がカフカです。