kafka实战:
一.安装kafka集群:
1.下载kafka已经编译好的源码,可在官方网站下载:http://kafka.apache.org/downloads,我们选择2.0.0版本进行安装。
2.将下载好的源码解压到文件夹。
3.进入解压后的文件夹的config目录,修改server.properties文件,主要修改几个点:
------3.1. broker.id=0(集群模式下修改为不一样的id)。
------3.2. listeners=PLAINTEXT://192.168.174.128:9092 打开监听一般写为本机的ip:9092(记得关闭防火墙,云服务器设置为外网ip
------------的时候不能能分配地址,所以我们使用本地虚拟机部署)。
------3.3.zookeeper.connect=117.50.90.226:2181 修改zookeeper地址,可集群(多个地址逗号隔开),可单机(我们使用单机
-------zk)。
4.进入bin目录,此目录下主要是一些shell脚本,找到kafka-server-start.sh(启动此broker)脚本,进行编辑,主要编辑的点是
export KAFKA_HEAP_OPTS="-Xmx256M -Xms128M" 分配内存,我们虚拟机内存有限,所以最大分配256M,最小128M。
5.启动broker服务,在bin 目录下使用命令sh kafka-server-start.sh …/config/server.properties &。
6.其他节点也这样配置好,然后启动就好。
二.测试安装的集群:
1.创建一个topic :使用bin目录下的kafka-topics.sh 脚本创建topic,命令如:sh kafka-topics.sh --create --zookeeper 117.50.90.226:2181 --replication-factor 3 --partitions 3 --topic topic1,命令解释:–replication-factor 3 表示指定此topic的分区副本数为3个,–partitions 3 表示分区数为3个,–topic topic1 表示topic 名称为topic1,关于分区、副本后面会详细说明。
2.发送消息,使用kafka-console-producer.sh脚本,命令如:sh kafka-console-producer.sh --broker-list 192.168.174.128:9092,192.168.174.129:9092,192.168.174.130:9092 --topic topic1 ,命令解释:–broker-list 指定brokers多个逗号可开,
–topic topic 指定发送到的topic名称,结果如下图:
3.消费消息,使用kafka-console-consumer.sh脚本,命令如:sh kafka-console-consumer.sh --bootstrap-server 192.168.174.128:9092,192.168.174.129:9092,192.168.174.130:9092 --topic topic1 --from-beginning,命令解释:–from-beginning表示从最开始的消息消费,效果如下:
三.使用kafka-clients 测试集群:
1.由于kafka版本为2.0.0,因此kafka-clients版本使用2.0.1,pom文件中添加如下依赖:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.0.1</version>
</dependency>
2.发送端代码:
public class DemoKafkaProducer extends Thread{
//producer api
KafkaProducer<Integer,String> producer;
String topic; //主题
public DemoKafkaProducer(String topic) {
Properties properties=new Properties();
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.174.128:9092,192.168.174.129:9092,192.168.174.130:9092");
properties.put(ProducerConfig.CLIENT_ID_CONFIG,"producer1");
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.wzy.sourceclient.MyPartition");//此处的分区策略后面会详细说明。
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
//连接的字符串
//通过工厂
//new
producer=new KafkaProducer<Integer, String>(properties);
this.topic = topic;
}
@Override
public void run() {
int num=0;
while(num<20) {
try {
String msg="msg:"+num;
//get 会拿到发送的结果
//同步 get() -> Future()
//回调通知
producer.send(new ProducerRecord<>(topic, msg), (metadata, exception) -> {
System.out.println(metadata.offset()+"->"+metadata.partition()+"->"+metadata.topic());
});
TimeUnit.SECONDS.sleep(2);
++num;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new DemoKafkaProducer("topic1").start();
}
}
ProducerConfig详解:
先说一下kafka的MetData:就是一句话,元数据就是整个集群的信息。
1、bootstrap.servers:brokers ip:端口信息,多个使用逗号隔开。
metadata.max.age.ms : 元数据最大生存时间,每隔metadata.max.age.ms时间,producer客户端会强制刷新一遍元数据metadata,单位毫秒,默认30000。
2、batch.size:producer 发送数据的时候,是批量写入数据到分区,此参数就是指定批量数据的大小batch.size就是用来设置一个batch的最大字节数byte。当设置为0时,表示完全禁用batch的功能。如果batch.size设置过大,那么可能造成内存浪费,因为每个发送到不同partition的record都需要预先分配一块batch.size大小的内存。单位字节,默认16384字节,即16K。
3、acks :消息确认机制,应答数设置。producer只有接收到来自server的acks指定数量的应答,才会认为发送给server的消息记录已送达。该配置项用于控制已发送消息记录的持久性,有以下几种设置值:默认为1
acks = 0:表示producer无需等待server端的应答消息,producer将record扔到发送缓冲区,就认为该record已经发送,然后转身走人。这种情况无法保证server端真的成功接收到该消息记录,且此时即使retries配置项也无法生效,因为producer无法知道是否失败。另外,每个record返回的offset都被设为-1。acks = 1:表示接收该消息记录的分区leader将消息记录写入到本地log文件,就返回Acknowledgement,告知producer本次发送已完成,而无需等待其他follower分区的确认。这种情况下,可能出现消息记录没有备份的情况(follower宕机等)。
acks = all:表示消息记录只有得到分区leader以及其他分区副本同步结点队列(ISR)中的分区follower的确认之后,才能回复acknowlegement,告知producer本次发送已完成。这种情况下,只要分区副本同步结点队列(ISR)中某一个follower存活,那么消息记录就不会被丢失。这种方式最安全,但效率也最低。
acks = -1:等同于acks = all。
4、linger.ms:表示延迟发送消息到分区的时间,默认为0表示无延迟,立即发送。
延迟发送消息记录的时间,上面及前面文章中也已经提到过,producer在发送消息记录record的时候,会将发送到同一个partition的records压缩在batch中。但通常这只发生在records到达速度快于records发送速度的情况下,很容易理解:如果发送速度大于record到达速度,则每来一个record都会被立即发送出去,根本不存在将多个records压缩为一个的可能。
但很多时候,即便是发送速度大于到达速度,我们也不希望每个record就发送一次,还是希望分批次发送,以减少发送次数,提升producer客户端和服务器端的性能。为此,我们需要人为地加一个发送延迟限制,即每次发送之间,存在一定的时间间隔linger.ms,在这段时间内,可能有多个records到达,此时就可以对他们分组压缩,成批次发送。这类似于TCP的拥塞控制方法。
注意:linger.ms设置了发送延迟的最高时间上限,另一个配置项batch.size也同时控制着发送的时机。如果为某个partition压缩的batch字节数已经达到了batch.size设置的字节数,那么该batch将被立即发送到指定的partition,即使此时延迟时间还没达到linger.ms的设置。
同样的,如果延迟的时间已经达到了linger.ms的设置,那么即使压缩累积的batch没有达到batch.size设置的字节数,也会被发送到指定的partition。linger.ms是针对每一个发送到partition的request。即不同partition的request并不是同时发送的。
延迟以为这性能降低,需要在延迟和性能之间进行平衡,找到一个合适的linger.ms值。
5、client.id:producer 客户端ID,在创建request时,会传送到kafka服务。其目的是为了跟踪记录请求的来源,虽然服务端可以通过ip/port来追踪请求的来源,但ip/port无法表达业务语义,所以,可以通过client.id来设置一个富有业务逻辑语义的名字(如PDK游戏),有助于后续的分析和记录。
6、send.buffer.bytes:TCP发送缓冲区(SO_SNDBUF)的大小,若send.buffer.bytes设为-1,则使用操作系统的默认值,默认值131072字节,即128K。
7、receive.buffer.bytes:TCP接收缓冲区(SO_RCVBUF)大小,当receive.buffer.bytes设置为-1,则使用操作系统默认的大小,默认值为32768字节,即32K。
8、max.request.size:一个请求request中最大字节数,用于限制producer发送的单个请求request中,record batches的最大数量,以避免单个请求数据过于巨大,默认值1048576字节,即1M,注意点
一个请求request中,可能包含多个record batch。
max.request.size可能影响record batch的大小上限,即当batch.size 大于 max.request.size时,batch的上限就变成了max.request.size设置的大小。
9、reconnect.backoff.ms:重连间隔时间,避免producer客户端过于紧密循环地重连kafka服务broker。该值针对的是所有client到broker的连接,默认为50毫秒。
10、reconnect.backoff.max.ms:producer客户端连接一个kafka服务(broker)失败重连的总时间,每次连接失败,重连时间都会指数级增加,每次增加的时间会存在20%的随机抖动,以避免连接风暴,默认值为1000毫秒。
11、max.block.ms:该配置值控制着KafkaProducer.send()函数以及KafkaProducer.partitionsFor()函数将阻塞的最大时间。另外当发送缓冲区满或者metadata不可用时,这两个方法也会被阻塞。如果阻塞发生在用户提供的自定义序列化类serializers或者是自定义的分区类partitioner,那么这些阻塞的时间不会被计算在该配置值之类,默认为1000毫秒。
12、buffer.memory:producer可以用于缓存等待发送到服务端的消息记录的缓冲区大小,当消息记录发送到缓冲区的速度大于传输到server的速度,那么等待发送的消息记录将会放在缓冲区,缓冲区如果满了,那么producer会阻塞max.block.ms指定的毫秒数,超过该毫秒数时,将抛出异常,默认值为33554432字节,即32M。
注意:该缓冲区的大小设置与整个producer需要使用到的producer大体一致,但是要注意并不是所有的缓冲区都是用来存放待发送的records的,比如还有一部分用于压缩数据(当压缩数据的选项开启),还有一部分用于维护in-flight(正在发送)的请求列表。
13、retry.backoff.ms:当一个producer到指定的partition的请求request失败时,在重连之前,需要等待的毫秒数。这是为了避免在某些失败的场景下,过于密集地重复发送请求,默认值100毫秒。
14、compression.type:
producer对数据使用的压缩类型,包括:
none:无压缩类型
gzip
snappy
lz4,producer在压缩数据时,是对所有batches的数据一起进行压缩,而不是一个batch一个batch压缩,所以,一次压缩的batches越多,压缩率越高,压缩效果越好,默认为none。
15、retries:当该值被设置成大于0时,客户端会重新发送消息,并且记录发送失败的错误。注意,该重试配置项和客户端因收到错误而重发是一样的。当retries配置项大于0,且max.in.flight.requests.per.connection配置项的值大于1时,存在将重试记录重新排序的风险,也就是说,消息记录的顺序可能会被打乱。原因是:当两个batch被发送到同一个partition时,如果第一个失败,而第二个成功,那么第一个会被重试,此时第二个batch就排在前面了,默认值为0,表示不重试。
16、key.serializer:消息记录key的序列化类。
17、value.serializer:消息记录中value的序列化类。
18、connections.max.idle.ms:如果一个连接空闲时间超过该配置值,那么该连接将会被关闭,默认540000毫秒,即9分钟。
19、partitioner.class:计算消息记录要分配到哪个partitioner的类,默认无,可重写后制定。
20、enable.idempotence:是否使用幂等性。如果设置为true,表示producer将确保每一条消息都恰好有一份备份;如果设置为false,则表示producer因发送数据到broker失败重试使,可能往数据流中写入多分重试的消息。
注意:如果使用idempotence,即enable.idempotence为true,那么要求配置项max.in.flight.requests.per.connection的值必须小于或等于5;配置项retries的值必须大于0;acks配置项必须设置为all。如果这些值没有被用户明确地设置,那么系统将自动选择合适的值。如果设置的值不合适,那么会抛出ConfigException异常,默认为false不使用幂等性。
transaction.timeout.ms:在主动中止(aborting)一个事务transaction之前,事务协调员(transaction coordinator)最多等待的最长时间——为了让producer更新事务状态。如果该值大于kafka broker中设置的transaction.max.timeout.ms配置项的值,那么producer 的请求将因为InvalidTransactionTimeout错误而失败,默认值为60000毫秒即60秒。
transactional.id:配置TransactionalId,用于事务的递交(delivery)。该配置项可以为跨多个producer的session提供可靠性语义,因为它可以保证在开始一个新的事务之前,使用相同事务ID(TransactionalId)的事务一定会完成。
注意:如果配置了transactional.id的值,那么必须配置enable.idempotence为true。在发布环境中,事务要求一个kafka集群必须有最少3个brokers(推荐设置)。在开发环境中,可以通过调整broker的配置项transaction.state.log.replication.factor来进行调整,以方便开发,默认值为null,表示transactions不能被使用。
3.消费端代码:
public class DemoKafkaConsumer extends Thread{
KafkaConsumer<Integer,String> consumer;
String topic;
public DemoKafkaConsumer(String topic) {
Properties properties=new Properties();
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.174.128:9092,192.168.174.129:9092,192.168.174.130:9092");
properties.put(ConsumerConfig.CLIENT_ID_CONFIG,"consumer1");
properties.put(ConsumerConfig.GROUP_ID_CONFIG,"group1");
properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,"30000");
properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG,"5000"); //自动提交(批量确认)
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class.getName());
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
//一个新的group的消费者去消费一个topic
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest"); //这个属性. 它能够消费最早的消息。
consumer=new KafkaConsumer<Integer, String>(properties);
this.topic = topic;
}
@Override
public void run() {
consumer.subscribe(Collections.singleton(this.topic));
while(true){
ConsumerRecords<Integer,String> consumerRecords=consumer.poll(Duration.ofSeconds(1));
consumerRecords.forEach(record->{
//null->gp kafka practice msg:0->63
System.out.println(record.key()+"->"+record.value()+"->"+record.offset());
});
}
}
public static void main(String[] args) {
new DemoKafkaConsumer("topic1").start();
}
}
ConsumerConfig详解:
1、bootstrap.servers:borkers ip:端口。
2、group.id:分组id,同一个分组里的消费者只会有一个消费者会消费消息。
3、max.poll.records: 消费者在一次调用抓取消息中返回的最大记录数,默认为500条。
max.poll.interval.ms:在使用消费者组管理时,调用poll()之间的最大延迟。这提出了消费者在获取更多记录之前可以闲置的时间量的上界。如果在此超时到期之前未调用poll(),则认为使用者失败,并且组将重新平衡以将分区重新分配给其他成员,默认为300000毫秒。
4、session.timeout.ms:使用Kafka的组管理设施时,用于检测消费者失败的超时。消费者定期发送心跳来向经纪人表明其活跃度。如果代理在该会话超时到期之前没有收到心跳,那么代理将从该组中删除该消费者并启动重新平衡。请注意,该值必须在允许的范围内Consumer session 过期时间。这个值必须设置在broker configuration中的group.min.session.timeout.ms 与 group.max.session.timeout.ms之间,默认值为10000毫秒。
5、heartbeat.interval.ms:心跳间隔。心跳是在consumer与coordinator之间进行的。心跳是确定consumer存活,加入或者退出group的有效手段。这个值必须设置的小于session.timeout.ms,因为:当Consumer由于某种原因不能发Heartbeat到coordinator时,并且时间超过session.timeout.ms时,就会认为该consumer已退出,它所订阅的partition会分配到同一group 内的其它的consumer上。通常设置的值要低于session.timeout.ms的1/3,默认为3000毫秒。
enable.auto.commit:Consumer 在commit offset时有两种模式:自动提交,手动提交。手动提交在前面已经说过。自动提交:是Kafka Consumer会在后台周期性的去commit。默认值是true。
auto.commit.interval.ms:动提交间隔。范围:[0,Integer.MAX],默认值是 5000 (5 s)消费者偏移的频率以毫秒为单位自动提交给Kafka,如果enable.auto.commit设置为true,默认为5000毫秒。
partition.assignment.strategy:分区分配策略类名。
auto.offset.reset:这个配置项,是告诉Kafka Broker在发现kafka在没有初始offset,或者当前的offset是一个不存在的值(如果一个record被删除,就肯定不存在了)时,该如何处理。它有4种处理方式:
● earliest: 自动将偏移量重置为最早的偏移量
● latest:自动将偏移量重置为最新的偏移量
● none: 如果边更早的offset也没有的话,就抛出异常给consumer,告诉consumer在整个consumer group中都没有发现有这样的offset。
● anything else: 如果不是上述3种,只抛出异常给consumer。
默认为:latest。
6、fetch.min.bytes:服务器为获取请求返回的最小数据量。如果没有足够的数据可用,请求将等待那么多的数据在应答请求之前积累。1字节的默认设置意味着只要有一个字节的数据可用,或者提取请求超时等待数据到达,就会立即应答提取请求。将其设置为大于1的值将导致服务器等待大量的数据累积,这可以稍稍提高服务器吞吐量,但需要花费一些额外的延迟时间。
当consumer向一个broker发起fetch请求时,broker返回的records的大小最小值。如果broker中数据量不够的话会wait,直到数据大小满足这个条件。取值范围是:[0, Integer.Max],默认值是1。默认值设置为1的目的是:使得consumer的请求能够尽快的返回。
7、fetch.max.wait.ms:一次fetch请求,从一个broker中取得的records最大大小。如果在从topic中第一个非空的partition取消息时,如果取到的第一个record的大小就超过这个配置时,仍然会读取这个record,也就是说在这片情况下,只会返回这一条record。 broker、topic都会对producer发给它的message size做限制。所以在配置这值时,可以参考broker的message.max.bytes 和 topic的max.message.bytes的配置,默认为52428800字节。
8、metadata.max.age.ms:元数据最大生存时间,每隔metadata.max.age.ms时间,producer客户端会强制刷新一遍元数据metadata,单位毫秒,默认300000。
9、max.partition.fetch.bytes:一次fetch请求,从一个partition中取得的records最大大小。如果在从topic中第一个非空的partition取消息时,如果取到的第一个record的大小就超过这个配置时,仍然会读取这个record,也就是说在这片情况下,只会返回这一条record。 broker、topic都会对producer发给它的message size做限制。所以在配置这值时,可以参考broker的message.max.bytes 和 topic的max.message.bytes的配置,默认为1048576字节。
10、send.buffer.bytes:发送数据时要使用的TCP发送缓冲区(SO_SNDBUF)的大小。默认为131072字节,如果值为-1,则将使用操作系统默认值。
11、receive.buffer.bytes:读取数据时使用的TCP接收缓冲区(SO_RCVBUF)的大小。默认为65536字节,如果值为-1,则将使用操作系统默认值。
12、client.id:发出请求时传递给服务器的id字符串。这样做的目的是通过允许在服务器端请求日志中包含一个逻辑应用程序的名字来跟踪请求的来源,而不仅仅是ip / port。
13、reconnect.backoff.ms:尝试重新连接到给定主机之前等待的基本时间。这避免了在一个紧密的循环中重复连接到主机。该退避适用于客户端向经纪人的所有连接尝试,默认为50毫秒。
14、reconnect.backoff.max.ms:重新连接到重复连接失败的代理程序时要等待的最长时间(以毫秒为单位)。如果提供的话,每个主机的退避将以指数方式增加,对于每个连续的连接失败,达到这个最大值。计算后退增加后,增加20%随机抖动以避免连接风暴,默认为1000毫秒。
15、retry.backoff.ms:尝试重试对给定主题分区的失败请求之前等待的时间量。这样可以避免在某些故障情况下重复发送请求,默认为100毫秒。
16、check.crcs:自动检查消耗的记录的CRC32。这可以确保没有在线或磁盘损坏的消息发生。这个检查会增加一些开销,所以在寻求极高性能的情况下可能会被禁用,默认为true。
17、key.deserializer:实现org.apache.kafka.common.serialization.Deserializer接口的密钥的反序列化器类。
18、value.deserializer:用于实现org.apache.kafka.common.serialization.Deserializer接口的值的反序列化器类。
19、connections.max.idle.ms:连接空闲超时时间。因为consumer只与broker有连接(coordinator也是一个broker),所以这个配置的是consumer到broker之间的,默认为540000毫秒。
20、request.timeout.ms:配置控制客户端等待请求响应的最长时间。如果在超时过去之前未收到响应,则客户端将在必要时重新发送请求,或者如果重试耗尽,则请求失败,默认为305000毫秒。
21、interceptor.classes:用作拦截器的类的列表。实现org.apache.kafka.clients.consumer.ConsumerInterceptor接口允许你拦截(也可能是变异)消费者收到的记录。默认情况下,没有拦截器。
22、exclude.internal.topics:内部主题(如偏移)的记录是否应该暴露给消费者。如果设置为true从内部主题接收记录的唯一方法是订阅它,如__consumer_offsets 内部主题。
四、kafka集成springboot。
1.添加maven依赖如下:
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
2.发送端代码:
@Component
public class DemoKafkaProducer {
@Resource
private KafkaTemplate<String,String> kafkaTemplate;
public void send(String topic, String key,String message){
kafkaTemplate.send(topic, key, message);
}
}
3.消费端代码:
@Component
public class DemoKafkaConsumer {
@KafkaListener(topics = "topic1")
public void consumer(ConsumerRecord record){
Optional msg = Optional.ofNullable(record.value());
if (msg.isPresent()){
System.out.println(msg.get());
}
}
}
4.配置内容:生产者、消费者的调优参数上面已经列举过了,可以尝试配置适合自己业务的客户端。
spring.kafka.bootstrap-servers=192.168.174.128:9092,192.168.174.129:9092,192.168.174.130:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.IntegerSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.linger.ms=10
spring.kafka.consumer.group-id=group1
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.enable-auto-commit=true
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.IntegerDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer