消息系统:Kafka

一、Kafka基础

1、什么是消息系统?常见的消息系统

复习:
(1)消息:字符串、对象(序列化)
(2)消息类型:

  • queue:队列,点对点
  • topic:主题,群发----Kafka只支持

(3)同步消息系统:等待对方的回答,例如:ATM机
异步消息系统:不需要等待对方的回答,例如:微信
Kafka都支持

2、Kafka的体系架构、术语(概念)

producer生产者、consumer消费者、consumer group 消费者组。在这里插入图片描述
Topic主题:分区Partition、冗余replicas、段Segment。Topic有分区组成、分区化为多个段。
在这里插入图片描述

3、部署Kafka的环境

tar -zxvf kafka_2.11-2.4.0.tgz -C ~/training/
核心配置文件:config/server.properties
注意:一个server.properties文件,对应一个broker
注意:在启动kafka的时候,默认启动内存为1G,修改kafka-server-start.sh脚本,修改启动内存为256M。

详细配置文件的说明请看最后。
(1)单机单broker

broker.id=0
表示broker0日志的路径
log.dirs=/root/training/kafka_2.11-2.4.0/logs/broker0		
zookeeper.connect=bigdata111:2181

启动

zkServer.sh start
bin/kafka-server-start.sh config/server.properties &

(2)单机多broker
复制上面的单机单broker的配置文件

cp config/server.properties config/server1.properties

进行一下修改

broker.id=1
port=9093
log.dirs=/root/training/kafka_2.11-2.4.0/logs/broker1

zookeeper地址是一样的,所以不用修改
启动

bin/kafka-server-start.sh config/server1.properties &

(3)多机多broker,和单机多broker一样,只不过改一下broker.id,必须保证每个broker.id都不一样。

4、使用Kafka的命令行工具

(1)创建一个topic

 bin/kafka-topics.sh --create \
 --zookeeper bigdata111:2181 \
 --replication-factor 2 \
 --partitions 3 \
 --topic mydemotopic1

分区的冗余度:一般跟broker一致,不超过3

bin/kafka-topics.sh --zookeeper bigdata111:2181 --list 列出所有的topic
bin/kafka-topics.sh --zookeeper bigdata111:2181 --describe --topic mydemotopic1

在这里插入图片描述

启动producer

bin/kafka-console-producer.sh --broker-list bigdata111:9092 --topic mydemotopic1

启动consumer消息消费

bin/kafka-console-consumer.sh --bootstrap-server bigdata111:9092 --topic mydemotopic1

从开始位置消费

bin/kafka-console-consumer.sh --bootstrap-server bigdata111:9092 --from-beginning --topic mydemotopic1

当消费者已经消费过信息,消费者就会把offset上交到zookeeper,记录到日志,下次消费时,接着这个位置进行消费。

显示key消费

bin/kafka-console-consumer.sh --bootstrap-server bigdata111:9092 --property print.key=true --topic mydemotopic1	

(2)彻底删除topic

1、bin/kafka-topics.sh --delete
2、删除ZooKeeper中的topic对应的信息
3、删除broker中对应的日志

二、Kafka的应用程序开发:Java、Scala

在这里只简要说明Java如何开发。
添加依赖:

<dependency>
	<groupId>org.apache.kafka</groupId>
	<artifactId>kafka-clients</artifactId>
	<version>2.4.0</version>
</dependency>	

1、使用Java开发消息生产者Producer、消息消费者Consumer:消息----String

创建ProducerDemo 类

public class ProducerDemo {
    public static void main(String[] args) {

        // 生成配置文件
        Properties pro = new Properties();
        // broker地址
        pro.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.92.111:9092,192.168.92.111:9093");

        /* 生产者需要server端在接收到消息后,进行反馈确认的尺度,主要用于消息的可靠性传输;
         * acks=0表示生产者不需要来自server的确认;
         * acks=1表示server端将消息保存后即可发送ack,而不必等到其他follower角色的都收到了该消息;
         * acks=all(or acks=-1)意味着server端将等待所有的副本都被接收后才发送确认。
        pro.put("acks", "all");

        pro.put("retries", 0); //生产者发送失败后,重试的次数
        //当多条消息发送到同一个partition时,该值控制生产者批量发送消息的大小
        //批量发送可以减少生产者到服务端的请求数,有助于提高客户端和服务端的性能。
        pro.put("batch.size", 16384);

        //默认情况下缓冲区的消息会被立即发送到服务端,即使缓冲区的空间并没有被用完。
        //可以将该值设置为大于0的值,这样发送者将等待一段时间后,再向服务端发送请求,以实现每次请求可以尽可能多的发送批量消息。
        pro.put("linger.ms", 1);

        //生产者缓冲区的大小,保存的是还未来得及发送到server端的消息,如果生产者的发送速度大于消息被提交到server端的速度,该缓冲区将被耗尽。
        pro.put("buffer.memory", 33554432);
        */



        // 指定消息的序列化 ----字符串
        pro.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
        pro.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
        // 创建producer对象
        Producer<String,String> producer = new KafkaProducer<String, String>(pro);

        for (int i = 0; i < 10; i++) {
            producer.send(new ProducerRecord<String, String>("mydemotopic1","key"+i ,"value:"+i));
        }

        producer.close();
    }
}

创建ConsumerDemo类

public class ConsumerDemo {
    public static void main(String[] args) {
        // 生成配置文件
        Properties pro = new Properties();
        // broker 地址
        pro.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.92.111:9092,192.168.92.111:9093");
        //指定消费者组
        pro.put(ConsumerConfig.GROUP_ID_CONFIG, "mygroup1");

        /*
         * kafka使用消费者分组的概念来允许多个消费者共同消费和处理同一个topic中的消息。
         * 分组中消费者成员是动态维护的,如果一个消费者处理失败了,那么之前分配给它的partition将被重新分配给分组中其他消费者;
         * 同样,如果分组中加入了新的消费者,也将触发整个partition的重新分配,每个消费者将尽可能的分配到相同数目的partition,以达到新的均衡状态;

        pro.put("group.id", "mygroup");
        //用于配置是否自动的提交消费进度;
        pro.put("enable.auto.commit", "true");
        //用于配置自动提交消费进度的时间
        pro.put("auto.commit.interval.ms", "1000");
        */


        //指定反序列化的方式
        pro.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
        pro.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");

        // 创建对象
        Consumer<String,String> consumer = new KafkaConsumer<String, String>(pro);
        // 监听topic主题
        consumer.subscribe(Arrays.asList("mydemotopic1"));

        while (true)
        {
            // 拉取信息
            ConsumerRecords<String, String> polls = consumer.poll(Duration.ofSeconds(1));
            for (ConsumerRecord<String, String> poll : polls) {
                System.out.println("key:"+poll.key()+"\t"+"valus"+poll.value());
            }
        }
    }
}

2、发送一个自定义的消息:对象(序列化)

添加依赖:

    	<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

在这里用student进行举例

创建student类

public class Student {
    private int stuID;
    private String stuName;

    public Student() {

    }

    public int getStuID() {
        return stuID;
    }

    public void setStuID(int stuID) {
        this.stuID = stuID;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    @Override
    public String toString() {
        return "Student [stuID=" + stuID + ", stuName=" + stuName + "]";
    }
}


对于生产者,要对提交的数据进行序列化,故创建StudentJSONSerializer类

public class StudentJSONSerializer implements Serializer<Student> {
    @Override
    public byte[] serialize(String s, Student student) {
        return JSON.toJSONBytes(student);
    }
}

创建生产者ProducerDemo 类

public class ProducerDemo {
    public static void main(String[] args) {

        // 生成配置文件
        Properties pro = new Properties();
        // broker地址
        pro.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.92.111:9092,192.168.92.111:9093");

        // 指定消息的序列化 ----字符串
        pro.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
        pro.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"StudentJSONSerializer");
        // 创建producer对象
        Producer<String,Student> producer = new KafkaProducer<String, Student>(pro);

        for (int i = 0; i < 10; i++) {
            Student s = new Student();
            s.setStuID(i);
            s.setStuName("wu"+i);

            producer.send(new ProducerRecord<String, Student>("mydemotopic1","key"+i ,s));
        }

        producer.close();
    }
}

对于消费者,要对接收的数据进行反序列化,故创建StudentJSONDeSerializer

public class StudentJSONDeSerializer implements Deserializer<Student> {
    @Override
    public Student deserialize(String s, byte[] bytes) {
        return JSON.parseObject(bytes,Student.class);
    }
}

创建消费者ConsumerDemo

public class ConsumerDemo {
    public static void main(String[] args) {
        // 生成配置文件
        Properties pro = new Properties();
        // broker 地址
        pro.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.92.111:9092,192.168.92.111:9093");
        //指定消费者组
        pro.put(ConsumerConfig.GROUP_ID_CONFIG, "mygroup1");
      
        //指定反序列化的方式,指定key-value类型,都是Kafka封装好的序列化。
        pro.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
        pro.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"StudentJSONDeSerializer");

        // 创建对象
        Consumer<String,Student> consumer = new KafkaConsumer<String, Student>(pro);
        // 监听topic主题
        consumer.subscribe(Arrays.asList("mydemotopic1"));

        while (true)
        {
            // 拉取信息
            ConsumerRecords<String, Student> polls = consumer.poll(Duration.ofSeconds(1));
            for (ConsumerRecord<String, Student> poll : polls) {
                System.out.println("key:"+poll.key()+"\t"+"valus:"+poll.value().getStuName()+"|"+poll.value().getStuID());

            }

        }
    }
}

三、Kafka的原理解析和监控

1、Kafka的原理解析

(1)持久化:日志log

  • 指Kafka数据(消息)的持久化,将消息持久化到日志文件
  • 顺序写入,新的消息被写到log文件的最后
  • 记录offset的偏移量,当消费者进行消费消息的时候,会把自己的消费进度offset提交给kafka,然后kafka记录下来,下次消费时,就知道消费者消费到哪里。
  • 为了加快查找消息对应的log文件,维护索引文件,索引文件和log文件在同个目录下。

查看log中的数据

bin/kafka-run-class.sh kafka.tools.DumpLogSegments --help
bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files logs/broker0/mydemotopic1-0/00000000000000000000.log --print-data-log 
  • 写入数据:顺序写入日志,新消息写在后面
  • 读取数据:根据offset偏移量。

(2)Producer生产者:三种消息发送的模式

  • 发完即忘:发了就不管、性能最好
  • acks=1 : leader收到就可以
  • acks=all leader和follower都收到

另一角度:Java api提供的有。
同步:Future 对象
异步:回调函数

(3)Consumer消费者:采用消费者进行消息

(4)Leader的选举

副本机制 ----> 针对分区

(5)日志的清理

最后的配置文件说明也都提到过

log.retention.hours=168
日志默认保存7天
				
log.retention.bytes=1073741824
当磁盘空间小于1G,开始删除日志

log.retention.check.interval.ms=300000
每隔多长时间检查一下日志的过期

(6)消息的可靠传输----> 记录到log中,同时记录offset的偏移量

高水位线
支持:Kafka、Oracle----- 高水位线

  • Kafka:消费者Consumer只能消费高水位线以下的数据
    在这里插入图片描述

  • Oracle:插入insert数据的时候,只能插入到高水位线的位置
    在这里插入图片描述
    容易造成存储碎片。

  • Flink ----水位线Watermark,作用:处理乱序数据

一个topic有3个分区,消费者只能消费follow的最少哪个数据位置开始消费,这是从安全的角度进行考虑的,保持数据的一致性,假如leader死掉了,不至于丢失数据。

(7)Kafka的配额:quota

HDFS的配额:名称配额、空间配额
Oracle的配额:举例:张三最多只能使用200M表空间
alter user 张三 quota 200M on users;
alter user 张三 quota unlimited on users; 没有限制

Kafka的配额:针对生产者、消费者
(1)producer:生产者单位时间(每秒)能发布到单台broker的字节数(producer_byte_rate)
(2)consumer:消费者单位时间(每秒)从单台broker上拉取的字节数(consumer_byte_rate)

针对三种不同级别

  • user用户级别
    使用Kafka的用户认证的机制
    借助JAAS(Java Authentication Authorization Service:Java认证授权服务)来实现

  • client ID客户端
    ProducerConfig.CLIENT_ID
    ConsumerConfig.CLIENT_ID

  • user+Client ID
    配置client-id。例如,client-id为”clientA”

bin/kafka-configs.sh  --zookeeper bigdata111:2181 --alter --add-config \
'producer_byte_rate=1024,consumer_byte_rate=2048' \
-entity-type clients --entity-name clientA

配置user。例如,user为”user1”

bin/kafka-configs.sh  --zookeeper bigdata111:2181 --alter --add-config \
'producer_byte_rate=1024,consumer_byte_rate=2048' \
--entity-type users --entity-name user1

配置user+clientid。例如,user为”user1”,clientid为”clientA”。

bin/kafka-configs.sh  --zookeeper bigdata111:2181 --alter --add-config \
			'producer_byte_rate=1024,consumer_byte_rate=2048'  \
			--entity-type users --entity-name user1 --entity-type clients \
			--entity-name clientA

2、监控:KafkaOffsetMonitor

KafkaOffsetMonitor是Kafka的一款客户端消费监控工具,用来实时监控Kafka服务的Consumer以及它们所在的Partition中的Offset,我们可以浏览当前的消费者组,并且每个Topic的所有Partition的消费情况都可以一目了然。

2.1 启动KafkaOffsetMonitor

将下载下来的KafkaOffsetMonitor jar包上传到linux上,可以新建一个目录KafkaMonitor,用于存放KafkaOffsetMonitor-assembly-0.2.0.jar进入到KafkaMonitor目录下,通过java编译命令来运行这个jar包:

 java -cp KafkaOffsetMonitor-assembly-0.2.0.jar com.quantifind.kafka.offsetapp.OffsetGetterWeb --zk 10.0.0.50:12181,10.0.0.60:12181,10.0.0.70:12181 --port 8088  --refresh 5.seconds --retain 1.days
参数说明:

zk :zookeeper主机地址,如果有多个,用逗号隔开
port :应用程序端口
refresh :应用程序在数据库中刷新和存储点的频率
retain :在db中保留多长时间
dbName :保存的数据库文件名,默认为offsetapp

四、集成Kafka

1、flume集成kafka

flume集成kafka只需要修改配置文件就可以了,在sink层有对应kafka的配置。
flume官方配置样例

flume配置文件如下

#bin/flume-ng agent -n a4 -f myagent/a4.conf -c conf -Dflume.root.logger=INFO,console
#定义agent名, source、channel、sink的名称
a4.sources = r1
a4.channels = c1
a4.sinks = k1

#具体定义source
a4.sources.r1.type = spooldir
a4.sources.r1.spoolDir = /tmp/logs

#定义拦截器,为消息添加时间戳
a4.sources.r1.interceptors = i1
a4.sources.r1.interceptors.i1.type = org.apache.flume.interceptor.TimestampInterceptor$Builder

#具体定义channel
a4.channels.c1.type = memory
a4.channels.c1.capacity = 10000
a4.channels.c1.transactionCapacity = 100

#具体定义sink
a4.sinks.k1.channel = c1
a4.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a4.sinks.k1.kafka.topic = mytopic1
a4.sinks.k1.kafka.bootstrap.servers = bigdata111:9092
a4.sinks.k1.kafka.flumeBatchSize = 20
a4.sinks.k1.kafka.producer.acks = 1
a4.sinks.k1.kafka.producer.linger.ms = 1
a4.sinks.k1.kafka.producer.compression.type = snappy

#组装source、channel、sink
a4.sources.r1.channels = c1
a4.sinks.k1.channel = c1

注意事项:
1、首先kafka的主题实现存在,可以通过kafka命令进行创建主题

 bin/kafka-topics.sh --create \
 --zookeeper bigdata111:2181 \
 --replication-factor 2 \
 --partitions 3 \
 --topic mydemotopic1

2、启动flume

bin/flume-ng agent -n a4 -f myagent/a4.conf -c conf -Dflume.root.logger=INFO,console

3、启动kafka命令监听

bin/kafka-console-consumer.sh --bootstrap-server bigdata111:9092 --topic mydemotopic1

然后就可以尝试在监听的文件尝试放文件。

2、storm集成kafka

storm 集成kafka说白了就是通过kafka提供的接口订阅主题,在上面我们也通过Java代码也进行了实现,但是,这些代码可以进一步的封装,进行代码复用,而这些封装工作不用我们去完成,storm api已经完成这项工作,我们只管去用就可以。

遗留问题:在用maven方式搭建stormwithkafka的时候,导入storm-core版本1.0.3,发现其中api的方法与之前不一样,最后采用原生的方式,添加storm-core的jar包到项目中,不知是不是storm的api发生改变。

展示主函数代码:

import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.kafka.*;
import org.apache.storm.spout.SchemeAsMultiScheme;
import org.apache.storm.topology.IRichSpout;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.tuple.Fields;

//主函数
public class WordCountToplogy {

    public static void main(String[] args) throws Exception {

        // 创建任务
        TopologyBuilder builder = new TopologyBuilder();

        //指定第一级组件:Spout任务
        builder.setSpout("myspout", createKafkaSpout());
        
        

        //指定第二级组件:拆分单词bolt
        builder.setBolt("mysplit", new WordCountSplitBolt()).shuffleGrouping("myspout");

        //指定第三级组件:单词计数bolt
        builder.setBolt("mytotal", new WordCountTotalBolt()).fieldsGrouping("mysplit", new Fields("word"));


        //创建任务,并运行
        StormTopology job = builder.createTopology();

        //有两种运行模式
        // 1、本地模式
        LocalCluster cluster = new LocalCluster();
        cluster.submitTopology("MyDemo", new Config(), job);

        // 2、集群模式
//        StormSubmitter.submitTopology(args[0], new Config(), job);



    }

    private static IRichSpout createKafkaSpout() {


        //指定ZooKeeper的地址,通过ZooKeeper获取broker的信息
        BrokerHosts hosts = new  ZkHosts("192.168.92.111:2181");
        SpoutConfig conf = new SpoutConfig(hosts,"mydemotopic1","/mytopic1","mygroup");

        // 下面这两个是kafka的配置 , 上面是storm连接kafka配置

        //数据类型:String
        conf.scheme = new SchemeAsMultiScheme(new StringScheme());

        //注意:从最新的数据开始接收
        conf.startOffsetTime = kafka.api.OffsetRequest.LatestTime();

        return new KafkaSpout(conf);
    }


}

注意:在第二级组件 中应将WordCountSplitBolt类中,tuple.getStringByField改成tuple.getstring(0),因为在集成kafka,对数据并没有指定字段。

3、spark streaming集成kafka

java代码展示

import kafka.serializer.StringDecoder;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.spark.SparkConf;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaPairInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka.KafkaUtils;

import java.util.*;


/**
 * @author 
 * @date 2020/11/10-${TIEM}
 */
public class SparkKafka {
    public static void main(String[] args) throws Exception {

        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        final SparkConf conf = new SparkConf().setAppName("MyNetworkWordCount")
                // local[2] 表示:相当于有两个CPU的核数
                .setMaster("local[2]");

        JavaStreamingContext js = new JavaStreamingContext(conf, Durations.seconds(3));


        // 首先要创建一份kafka参数map
        Map<String, String> kafkaParams = new HashMap<String, String>();
        // 这里是不需要zookeeper节点,所以这里放broker.list
        kafkaParams.put("metadata.broker.list",
                "192.168.92.111:9092,192.168.92.111:9092");

        // kafkaParams.put("auto.offset.reset", "smallest");

        // 然后创建一个set,里面放入你要读取的Topic,可以并行读取多个topic
        Set<String> topics = new HashSet<String>();
        topics.add("mydemotopic1");


        // 获取kafka数据
        JavaPairInputDStream<String, String> line = KafkaUtils.createDirectStream(js,
                String.class, // key类型
                String.class, // value类型
                StringDecoder.class, // 解码器
                StringDecoder.class,
                kafkaParams,
                topics);

        line.print();

        js.start();
        js.awaitTermination();


    }
}

结果:
在这里插入图片描述
然后就可以做后续操作!

4、flink集成kafka

在讲flink的时候进行讲说。

配置文件的详细说明

大家可以用英语翻译软件把配置文件的英文翻译一下,配置文件的英文解释的很清楚。


############################# Server Basics #############################


broker.id=0     #是broker ID号,在集群中必须唯一

############################# Socket Server Settings #############################

#listeners=PLAINTEXT://:9092
使用的协议、broker端口(使用参数port)

num.network.threads=3   #接收请求的线程数
num.io.threads=8  #执行请求的线程数
socket.send.buffer.bytes=102400   #发送缓存区
socket.receive.buffer.bytes=102400  #接收缓冲区
socket.request.max.bytes=104857600  #接收请求的最大长度


############################# Log Basics #############################


log.dirs=/root/training/kafka_2.11-2.4.0/logs/broker0  #用于保存broker的日志(Kafka的数据文件)

num.partitions=1  # 是Topic默认分区数


num.recovery.threads.per.data.dir=1 #使用log执行恢复的线程数

############################# Internal Topic Settings  #############################
# The replication factor for the group metadata internal topics "__consumer_offsets" and "__transaction_state"
# For anything other than development testing, a value greater than 1 is recommended to ensure availability such as 3.
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1

############################# Log Flush Policy #############################


#log.flush.interval.messages=10000  #每隔多少条消息进行刷新

#log.flush.interval.ms=1000 #刷新的时间间隔

                              决定日志如何删除
############################# Log Retention Policy #############################

log.retention.hours=168  #日志默认保存7天

#log.retention.bytes=1073741824  #当磁盘空间小于1G,开始删除日志

log.segment.bytes=1073741824  #日志的段的大小

log.retention.check.interval.ms=300000  #每隔多长时间检查一下日志的过期

############################# Zookeeper #############################

# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002".
zookeeper.connect=bigdata111:2181

# Timeout in ms for connecting to zookeeper
zookeeper.connection.timeout.ms=6000


############################# Group Coordinator Settings #############################

# The following configuration specifies the time, in milliseconds, that the GroupCoordinator will delay the initial consumer rebalance.
# The rebalance will be further delayed by the value of group.initial.rebalance.delay.ms as new members join the group, up to a maximum of max.poll.interval.ms.
# The default value for this is 3 seconds.
# We override this to 0 here as it makes for a better out-of-the-box experience for development and testing.
# However, in production environments the default value of 3 seconds is more suitable as this will help to avoid unnecessary, and potentially expensive, rebalances during application startup.
group.initial.rebalance.delay.ms=0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值