hi all
kafka学习简单分享
1、kafka内名词简介
什么是主题?什么是分区?
Kafka的消息通过 主题 (Topic)进行分类,一个主题被分为多个分区(Partitions)。消息以追加的方式写入分区,然后按照先进先出的方式进行读取。
主题的分区可以分布在不同服务器上,也就意味着主题是可以横跨多个服务器的。
生产者和消费者
生产者:创建消息的,消息的发布者和写入者,生产者将消息发布在特定的主题上,但是并不在乎消息被分配到那个分区上。
消费者:读取消息的。
消费者群组:可能或有一个或者多个消费者共同读取一个主题,群组保证每一个分区只能被一个消费者使用。
什么是broker
一个独立的Kafka服务器被称为一个broker(接收生产者信息,设置消息偏移量,提供消费者读取信息)
2、Kafka配置
Broker配置(Config文件夹下server.properties)
1)broker.id
每一个 broker 都有一个标识符,使用 broker.id 来标记,默认值为0,可以被设置成任意整数,但是这个值在整个Kafka集群中必须是唯一。
2)port(在配置文件中没有这个配置,但可以直接加入port=7777,重启生效)
broker服务启动端口,也是负责监听消息的端口。
3)zookeeper.connect
用于保存broker元数据的zookeeper地址,
默认设置 localhost:2181
hostname是zookeeper服务器的IP地址
2181是Zookeeper的客户端端口
4)log.dirs
kafka数据的存放地址,多个地址的话用逗号分割,多个目录分布在不同磁盘上可以提高读写性能。
关于主题配置(Config文件夹下server.properties)
1)num.partitions
每个topic的分区个数,若是在topic创建时候没有指定的话会被topic创建时的指定参数覆盖。(分区数要大于消费者数)
2)log.retention.ms
决定数据保存多久
3)log.retention.bytes
通过判断消息大小来,来决定消息是否过期,例如一个主题报刊8个分区,log.retention.bytes设置为1GB,则该主题最多可以保存8GB数据。
4)log.segment.bytes
topic的分区是以一堆segment文件存储的,这个控制每个segment的大小,会被topic创建时的指定参数覆盖
5)message.max.bytes
限制单个消息大小,默认1MB。
简单的案例
生产者
生产者配置
1、acks
acks参数指定了必须要多少个副本收到消息,生产者才会认为消息写入是成功的,这个参数对消息丢失的可能性有重要影响。
如果acks=0,生产者在写入消息之前不会等待任何来自服务器的响应。
如果acks=1,只要集群首领节点收到消息,生产者就会收到一个来自服务器的成功响应。
如过acks=all,只有当所有参与复制的节点全部收到消息时,生产者才会收到来自服务器的成功响应
2、buffer.memory
该参数用来设置生产者内存缓存区的大小,生产者内存缓存区
3、compression.type
该参数指定消息被发送给broker之前使用那一种压缩算法进行压缩。三种压缩方法:snappy、gzip 或 lz4。
snappy:占用比较少的CPU,却能提供较好的性能和相当可观的压缩比。
gzip:占用较多的CPU,但会提供更高的压缩比,所以如果带宽比较有限,可以采用这种算法。
4、retries
生产者重发消息的次数,
5、batch.size
该参数指定了一个批次可以使用的内存大小(一个批次最大使用内存大小)。
6、linger.ms
该参数指定了生产者在发送批次之前等待更多消息加入批次时间。(把批次填满或者达到linger.ms达到上限时把批次发送出去)。
生产者发送消息流程
消费者代码案例
public class ProducerDemo {
public static void main(String[] arg){
Properties properties = new Properties();
properties.put("bootstrap.servers", "127.0.0.1:7777"); //指定broker地址,最好指定一个集群中两个broker,一个冗机也可以连接到集群上。
properties.put("acks", "all");
properties.put("retries", 0);
properties.put("batch.size", 163);
properties.put("linger.ms", 1);
properties.put("buffer.memory", 33554432);
properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = null;
try {
producer = new KafkaProducer<String, String>(properties);
for (int i = 0; i < 1000; i++) {
String msg = "Message " + i;
producer.send(new ProducerRecord<String, String>("HelloWorld", msg)); //指定主题(Topic),和发送的消息。
System.out.println("Sent:" + msg);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
producer.close();
}
}
}
控制台输出:
消费者
消费者消费消息机制
1)Topic有多个分区一个消费者
描述:消费者会接受到这个Topic下所有分区的消息。
2)Topic协议有多个分区,多个消费者,消费者数小于分区数
描述:每个分区只能被一个消费者读取,但是broker群组协调器,会指定消费者和分区的所有权信息。将分区均衡的分配给可用的消费者。
3)Topic协议有多个分区,多个消费者,消费者数大于分区数
描述:会有消费者被闲置,不会接到任何消息
4)Topic有多个分区,有多个消费者群组,每个消费者群组有多个消费者
描述::每个分区可以被多个消费者读取(但多个消费者必须在不同的消费者群组),但是broker群组协调器,
会指定消费者群组内消费者和分区的所有权信息。将分区均衡的分配给消费者群组内可用的消费者。
生产者代码案例:
public class ConsumerDemo {
public static void main(String[] args){
Properties properties = new Properties();
properties.put("bootstrap.servers", "127.0.0.1:9092");
properties.put("group.id", "group-1");
properties.put("enable.auto.commit", "true");
properties.put("auto.commit.interval.ms", "1000");
properties.put("auto.offset.reset", "earliest");
properties.put("session.timeout.ms", "30000");
properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);
kafkaConsumer.subscribe(Arrays.asList("HelloWorld"));
while (true) {
ConsumerRecords<String, String> records = kafkaConsumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, value = %s", record.offset(), record.value());
System.out.println();
}
}
}
}
控制台输出:
Thanks
Mark