1. カフカプロデューサー
1.1 プロデューサーメッセージ送信処理
1.1.1 送信原理
メッセージ生成のプロセスでは、メイン スレッドと送信者スレッドの 2 つのスレッドが設計されます。両端キュー RecordAccumulator がメイン スレッドで作成されます。メイン スレッドは RecordAccumulator にメッセージを送信し、Sender スレッドは継続的に RecordAccumulator からメッセージを取得して Kafka Broker に送信します。
- batch.size: 送信者は、データがbatch.sizeに蓄積された後にのみデータを送信します。デフォルト 16k
- linger.ms: データがbatch.sizeに達していない場合、送信者はlinger.msで設定された時間が経過するのを待ってからデータを送信します。単位はミリ秒で、デフォルト値は 0 ミリ秒で、遅延がないことを意味します。
ACK に返信:
- 0: プロデューサによって生成されたデータは、応答のためにデータがディスクに配置されるのを待つ必要はありません。
- 1: データはプロデューサーによって生成され、リーダーはデータを受信した後に応答します
- -1 (すべて): プロデューサによって送信されたデータの場合、リーダーと ISR キュー内のすべてのノードはデータを受信した後に応答します。-1 はすべてに相当します。
1.1.2 プロデューサの重要なパラメータのリスト
パラメータ名 | 説明 |
---|---|
ブートストラップ.サーバー | プロデューサーがクラスターに接続するために必要なブローカー アドレスのリスト。たとえば、hadoop102:9092、hadoop103:9092、hadoop104:9092 のように、カンマで区切って 1 つ以上を設定できます。プロデューサは特定のブローカーから他のブローカー情報を見つけることができるため、ここではすべてのブローカー アドレスが必要なわけではないことに注意してください。 |
key.serializer と value.serializer | 生成される情報のキーと値のシリアル化タイプを指定します。必ず完全なクラス名を書いてください |
バッファ.メモリ | RecordAccumulator バッファの合計サイズ。デフォルトは 32MB です。 |
バッチサイズ | バッファ内のデータのバッチの最大値。デフォルトは 16K です。値を適切に増やすとスループットが向上しますが、値が大きすぎるとデータ送信の遅延が増加します。 |
linger.ms | データがbatch.sizeに達していない場合、送信者はlinger.timeを待ってからデータを送信します。単位はミリ秒で、デフォルト値は 0 ミリ秒で、遅延がないことを意味します。運用環境では、値を 5 ~ 100 ミリ秒にすることを推奨します。 |
ありがとう | 0: プロデューサによって生成されたデータは、応答のためにデータがディスクに配置されるのを待つ必要はありません。1: プロデューサーが送信したデータに対して、リーダーはデータを受信してから応答します。-1 (すべて): プロデューサーによって送信されたデータの場合、リーダー キューと ISR キュー内のすべてのノードがデータの受信後に応答します。デフォルト値は -1、-1 であり、すべて同等です。 |
接続ごとのフライト中の最大リクエスト数 | ACK が返されない最大回数は許可されており、デフォルトは 5 であり、値が 1 ~ 5 の数値になるように冪等性パッケージが有効になっています。 |
再試行 | メッセージの送信中にエラーが発生した場合、システムはメッセージを再送信します。retries は再試行回数を示します。デフォルトは int の最大値 2147483647 です。再試行が設定されており、メッセージの順序を維持したい場合は、MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION=1 を設定する必要があります。そうしないと、この失敗したメッセージを再試行すると、他のメッセージが正常に送信される可能性があります。 |
retry.backoff.ms | 2 回の再試行間の時間間隔。デフォルトは 100 ミリ秒です。 |
冪等性を有効にする | 冪等性を有効にするかどうか。デフォルトは true で、冪等性が有効になります。 |
圧縮の種類 | プロデューサーから送信されたすべてのデータを圧縮する方法。デフォルトは none で、圧縮しないことを意味します。サポートされている圧縮タイプ: none、gzip、snappy、lz4、および zstd。 |
1.2 非同期送信API
1.2.1 通常の非同期送信
1. 要件: Kafka プロデューサーを作成し、非同期で Kafka Broker に送信します。
2. コードの記述
(1) プロジェクト (KafkaDemo) を作成します
(2) 依存関係をインポートします
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
(3) パッケージ名 org.zhm.Producer を作成
(4) コールバック関数を使用しない API コードを記述する
package org.zhm.producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
/**
* @ClassName CustomProducer
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 18:35
* @Version 1.0
*/
public class CustomProducer {
public static void main(String[] args) {
//1、创建kafka生产者的配置对象
Properties properties=new Properties();
//2、给kafka配置对象添加配置信息:bootstrap.servers
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop102:9092");
//key,value序列化(必须):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
//3、创建kafka生产者对象
KafkaProducer<String,String> kafkaProducer=new KafkaProducer<String, String>(properties);
//4、调用send()方法,发生消息
for (int i = 0; i < 5; i++) {
kafkaProducer.send(new ProducerRecord<>("first","zhm"+i));
}
//5、关闭资源
kafkaProducer.close();
}
}
(5) テスト
① hadoop102 上で Kafka コンシューマを起動します。
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
② IDEA でコードを実行し、hadoop102 コンソールでメッセージが受信されるかどうかを確認します。
1.2.2 コールバック関数による非同期送信
コールバック関数は、プロデューサーが ack を受信したときに呼び出されます。これは非同期呼び出しです。このメソッドには、メタデータ情報 (RecordMetadata) と例外情報 (Exception) の 2 つのパラメーターがあります。Exception が null の場合、メッセージが発生したことを意味しますIf Exception null でない場合は、メッセージの送信が失敗したことを意味します。
注: メッセージの送信に失敗した場合は、自動的に再試行されるため、コールバック関数で手動で再試行する必要はありません。
package org.zhm.producer;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
/**
* @ClassName CustoProducerCallback
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 18:44
* @Version 1.0
*/
public class CustoProducerCallback {
public static void main(String[] args) throws InterruptedException {
//1、创建kafka生产者的配置对象
Properties properties=new Properties();
//2、给kafka配置对象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop102:9092");
//key、value序列化(必须)
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
//3、创建kafka生产者对象
KafkaProducer<String,String> producer=new KafkaProducer<>(properties);
//4、调用send()方法 发送信息
for (int i = 0; i < 6; i++) {
//添加回调
producer.send(new ProducerRecord<>("first", "zhm" + i), new Callback() {
//该方法在Producer收到ack时调用,为异步调用
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
//没有异常,输出信息到控制台
System.out.println("主题:"+recordMetadata.topic()+"->"+"分区:"
+recordMetadata.partition());
}
else {
//出现异常打印
e.printStackTrace();
}
}
});
//延迟一会会看到数据发往不同分区
Thread.sleep(20);
}
//5、关闭资源
producer.close();
}
}
1. テスト
① hadoop102 で Kafka コンシューマを有効にします。
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
② IDEA でコードを実行し、hadoop102 コンソールでメッセージが受信されるかどうかを確認します。
1.3 同期送信API
非同期送信に基づいて get() メソッドを呼び出すだけです。
package org.zhm.producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
/**
* @ClassName CustomProducerSync
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 18:58
* @Version 1.0
*/
public class CustomProducerSync {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1、创建kafka生产者的配置对象
Properties properties=new Properties();
//2、给kafka配置对象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop102:9092");
//key、value序列化
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
//3、创建kafka生产者对象
KafkaProducer<String,String> producer=new KafkaProducer<>(properties);
//4、调用send方法,发送信息
for (int i = 0; i < 10; i++) {
//异步发送 默认
// producer.send(new ProducerRecord<>("first","zhm"+i));
//同步发送
producer.send(new ProducerRecord<>("first","zhmzhm"+i)).get();
}
//5、关闭资源
producer.close();
}
}
1. テスト
① hadoop102 で Kafka コンシューマを有効にします。
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
② IDEA でコードを実行し、hadoop102 コンソールでメッセージが受信されるかどうかを確認します。
1.4 プロデューサーパーティション
1.4.1 パーティショニングの利点
1. ストレージリソースの合理的な利用に便利 各パーティションを Broker 上に格納し、大量のデータをパーティションごとに分割して複数の Broker に格納できます。パーティション タスクを合理的に制御すると、負荷分散の効果が得られます。
2. 並列度を向上させるために、プロデューサーはパーティション単位でデータを送信し、コンシューマーはパーティション単位でデータを消費できます。
1.4.2 プロデューサがメッセージを生成するパーティション
1. デフォルト パーティショナ DefaultPartitioner
(1) パーティションが指定されている場合、指定された値がパーティション値として直接使用されます (たとえば、partition=0 の場合、すべてのデータがパーティション 0 に書き込まれます)。
(2) パーティション値が指定されていないがキーがある場合は、キーのハッシュ値の余りとトピックのパーティション番号を取得してパーティション値を取得します (例: key1=5 のハッシュ値)。 key2のハッシュ値=6、トピック番号=2のパーティションの場合、key1に対応するvalue1がパーティション1に書き込まれ、key2に対応するvalue2がパーティション0に書き込まれます。
(3) パーティション値もキー値も存在しない場合、Kafka は Sticky Partition (スティッキー パーティショナー) を使用します。これはランダムにパーティションを選択し、パーティションのバッチがいっぱいになるか完了するまで可能な限りそのパーティションを使用します。Kafka は別のパーティションを使用します
。ランダムなパーティション (前のパーティションとは異なります)。
例: パーティション 0 が初めてランダムに選択され、パーティション 0 の現在のバッチがいっぱいになるか (デフォルトは 16k)、linger.ms で設定された時間が経過すると、Kafka は別のパーティションをランダムに使用します (まだ 0 の場合) 、引き続きランダムになります)
。
2. ケース1:
指定したパーティションにデータを送信する場合
package org.zhm.producer;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
/**
* @ClassName CustomProducerCallbackPartitions
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 19:10
* @Version 1.0
*/
public class CustomProducerCallbackPartitions {
public static void main(String[] args) {
//1、创建kafka生产者的配置对象
Properties properties=new Properties();
//2、给kafka配置对象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop102:9092");
//键值序列化
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
//3、创建生产者对象
KafkaProducer<String ,String> producer=new KafkaProducer<String, String>(properties);
//4、调用send方法,发送信息
for (int i = 0; i < 5; i++) {
//指定数据发送到1号分区,key1为空
producer.send(new ProducerRecord<>("first", 1, "", "zhm" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
System.out.println("主题:"+recordMetadata.topic()+"->"+"分区:"+recordMetadata.partition());
}else {
e.printStackTrace();
}
}
});
}
//5、关闭资源
producer.close();
}
}
(1) テスト
① hadoop102 上で Kafka コンシューマーを有効にします。
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
② IDEA でコードを実行し、hadoop102 コンソールでメッセージが受信されるかどうかを確認します。
3. ケース 2
パーティション値が指定されていないが、キーがある場合、パーティション値は、キーのハッシュ値とトピックのパーティション番号の余りを取得することによって取得されます。
package org.zhm.producer;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
/**
* @ClassName CustomProducerCallback1
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 19:21
* @Version 1.0
*/
public class CustomProducerCallback1 {
public static void main(String[] args) {
Properties properties=new Properties();
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop102:9092");
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
KafkaProducer<String,String> kafkaProducer=new KafkaProducer(properties);
for (int i = 0; i < 5; i++) {
//依次指定key值为a、b、f,数据key的hash值与3分别发往1、2、0
kafkaProducer.send(new ProducerRecord<>("first", "a", "zhm" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
System.out.println("当key为a时:"+"主题:"+recordMetadata.topic()+"分区:"+recordMetadata.partition());
}else {
e.printStackTrace();
}
}
});
}
for (int i = 0; i < 5; i++) {
//依次指定key值为a、b、f,数据key的hash值与3分别发往1、2、0
kafkaProducer.send(new ProducerRecord<>("first", "b", "zhm" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
System.out.println("当key为b时:"+"主题:"+recordMetadata.topic()+"分区:"+recordMetadata.partition());
}else {
e.printStackTrace();
}
}
});
}
for (int i = 0; i < 5; i++) {
//依次指定key值为a、b、f,数据key的hash值与3分别发往1、2、0
kafkaProducer.send(new ProducerRecord<>("first", "f", "zhm" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
System.out.println("当key为f时:"+"主题:"+recordMetadata.topic()+"分区:"+recordMetadata.partition());
}else {
e.printStackTrace();
}
}
});
}
kafkaProducer.close();
}
}
(1) テスト
① hadoop102 上で Kafka コンシューマーを有効にします。
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
② IDEA でコードを実行し、hadoop102 コンソールでメッセージが受信されるかどうかを確認します。
1.4.3 カスタムパーティショナー
研究開発担当者が
企業のニーズに応じてパーティショナー 1 を再実装できる場合、たとえばパーティショナーを実装すると、送信されたデータに atguigu が含まれている場合はパーティション 0 に送信され、atguigu が含まれていない場合はパーティション 0 に送信されます。パーティション 1 に送信されます。
2. ケースの実装
(1) Partitionerインタフェースを実装するクラスを定義します。
(2)partition()メソッドを書き換えます。
package org.zhm.producer;
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
import java.util.Map;
/**
* @ClassName Mypartitioner
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 19:28
* @Version 1.0
*/
/**
1、实现接口Partitioner
2、实现三个方法:Partition、close、configure
3、编写Partition方法,返回分区号
*/
public class MyPartitioner implements Partitioner {
/*
*
* @description:返回信息对应的分区
* @author: zouhuiming
* @date: 2023/6/12 19:30
* @param: [s, o, bytes, o1, bytes1, cluster]
* [主题、消息的key、消息的key序列化后的字节数组、消息的value、消息的value序列哈后字节数组、集群元数据可以查看的分区信息]
* @return: int
**/
@Override
public int partition(String s, Object o, byte[] bytes, Object o1, byte[] bytes1, Cluster cluster) {
//获取信息
String msyValue = o1.toString();
//创建partition
int partition;
//判断信息是否包含zhm
if (msyValue.contains("zhm")){
partition=0;
}
else {
partition=1;
}
//返回分区号
return partition;
}
@Override
public void close() {
}
@Override
public void configure(Map<String, ?> map) {
}
}
(3) パーティショナー メソッドを使用して、プロデューサー設定にパーティショナー パラメーターを追加します。
package org.zhm.producer;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
/**
* @ClassName CustomProducerCallbackPartitionsMine
* @Description TODO
* @Author Zouhuiming
* @Date 2023/6/12 19:35
* @Version 1.0
*/
public class CustomProducerCallbackPartitionsMine {
public static void main(String[] args) {
Properties properties=new Properties();
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop102:9092");
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
//添加自定义分区器
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"org.zhm.producer.MyPartitioner");
KafkaProducer<String,String> kafkaProducer=new KafkaProducer<String, String>(properties);
for (int i = 0; i < 5; i++) {
kafkaProducer.send(new ProducerRecord<>("first", "zhm" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
System.out.println("主题:"+recordMetadata.topic()+"分区:"+recordMetadata.partition());
}else {
e.printStackTrace();
}
}
});
}
for (int i = 0; i < 5; i++) {
kafkaProducer.send(new ProducerRecord<>("first", "hello" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e==null){
System.out.println("主题:"+recordMetadata.topic()+"分区:"+recordMetadata.partition());
}else {
e.printStackTrace();
}
}
});
}
kafkaProducer.close();
}
}
(4) テスト
① hadoop102 上で Kafka コンシューマを起動します。
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
② IDEA コンソールでコールバック情報を確認します。
1.5 プロダクション エクスペリエンス - プロデューサーがスループットを向上させる方法
- バッチ.サイズ: バッチ サイズ、デフォルトは 16k
- linger.ms: 待機時間、5 ~ 100 ミリ秒に変更
- Compression.type: 圧縮スナッピー
- RecordAccumulator: バッファ サイズ、1 から 64MB に変更します
1.6 実稼働環境 - データの信頼性
1. ACK 応答の
原理 信頼性の概要:
- acks=0、プロデューサーによって送信されたデータは無視され、信頼性は低く、効率は高くなります。
- acks=1、プロデューサーによって送信されたデータ リーダー応答、信頼性は中程度、効率は中程度です。
- acks=-1 (all)、プロデューサーはデータを送信 ISR キュー内のリーダーとすべてのフォロワー応答、高信頼性、低効率、
運用環境では、acks=0 はほとんど使用されません、acks=1、通常は送信に使用されます 通常のログ個々のデータが失われることを許容します。acks=-1 は一般に金銭に関連するデータの送信に使用され、高い信頼性が必要です。
データ繰り返し分析
1.7 本番環境の経験 - データの重複排除
1.7.1 データ転送のセマンティクス
- 少なくとも 1 回 (At Least Once) = ACK レベルは -1 に設定 + パーティションのコピー数は 2 以上 + ISR 内の応答の最小コピー数は 2 以上
- 最大 1 回 = ACK レベルが 0 に設定される
- 要約する
- 「At Least Once」では、データが失われないことを保証できますが、データが繰り返されないことは保証できません。
- At Most Once では、データが繰り返されないことを保証できますが、データが失われないことは保証できません。
- 必ず 1 回: お金に関連するデータなど、一部の非常に重要な情報については、データを繰り返したり、紛失したりしないことが必要です。Kafka バージョン 0.11 以降、冪等性とトランザクションという主要な機能が導入されました。
1.7.2 べき等性
冪等性とは、プロデューサーが反復データをブローカーに何度送信しても、反復がないことを保証するために、ブローカーは 1 つのデータのみを保持することを意味します。
厳密に 1 回 = 冪等性 + 少なくとも 1 回 (ack=-1 + パーティション コピー数 >=2 + ISR の最小コピー数 >=2)。
重複データの判断基準: <PID, Partition, SeqNumber> と同じ主キーを持つメッセージが送信された場合、Broker は 1 つのメッセージのみを保持します。このうち、PIDはKafkaが再起動するたびに新しいものが割り当てられ、Partitionはパーティション番号を表し、Sequence Numberは単調増加します。
したがって、冪等性は、単一のパーティションおよび単一のセッション内で重複がないことのみを保証できます。
冪等性を有効にする方法
パラメータenable.idempotenceをオンにします。デフォルトはtrue、falseはオフです。
1.7.3 プロデューサーのトランザクション
1. Kafka のトランザクション原理
注: トランザクションを開始するには、冪等性を有効にする必要があります
2. Kafka のトランザクションには次の 5 つの API があります
// 1 初始化事务
void initTransactions();
// 2 开启事务
void beginTransaction() throws ProducerFencedException;
// 3 在事务内提交已经消费的偏移量(主要用于消费者)
void sendOffsetsToTransaction(Map<TopicPartition, OffsetAndMetadata> offsets,
String consumerGroupId) throws
ProducerFencedException;
// 4 提交事务
void commitTransaction() throws ProducerFencedException;
// 5 放弃事务(类似于回滚事务的操作)
void abortTransaction() throws ProducerFencedException;
1.8 本番環境の経験 - 秩序あるデータ
1.8 製造検査 - データ障害
1. バージョン 1.x より前では、kafka はデータ パーティションが適切であることを保証し、その条件は次のとおりです:
max.in.flight.requests.per.connection=1 (冪等性を有効にするかどうかを考慮する必要はありません) 。
2. Kafka 1.x 以降のバージョンでは、データの単一パーティションが適切であることが保証されており、条件は次のとおりです: (1) 以下
の場合
、Max.in.flight.requests.per.connection を 1 に設定する必要があります。冪等性が有効になっていません。
(2) 冪等性を有効にするには、
max.in.flight.requests.per.connection を 5 以下に設定する必要があります。
理由の説明: Kafka1.x 以降、冪等性が有効になった後、Kafka サーバーはプロデューサーによって送信された最後の 5 つのリクエストのメタデータをキャッシュするため、何があっても最後の 5 つのリクエストのデータが確実に保存されるようになります。ご注文を承ります。