Kafka单机安装部署
下载kafka
https://archive.apache.org/dist/kafka/2.0.0/kafka_2.11-2.0.0.tgz
安装过程
安装过程非常简单,只需要解压就行,因为这个是编译好之后的可执行程序解压
tar -zxvf kafka_2.11-2.0.0.tgz
配置zookeeper
因为kafka依赖于zookeeper来做master选举一起其他数据的维护,所以需要先启动zookeeper节点 kafka内置了zookeeper的服务,所以在bin目录下提供了这些脚本
zookeeper-server-start.sh
zookeeper-server-stop.sh
在config目录下,存在一些配置文件
zookeeper.properties
server.properties
所以我们可以通过下面的脚本来启动zk服务,当然,也可以自己搭建zk的集群来实现
启动zookeeper
sh zookeeper-server-start.sh -daemon ../config/zookeeper.properties
停止zookeeper
首先,修改zookeeper-server-stop.sh
脚本,原脚本可能执行停止zookeeper失败,修改脚本的PIDS
vim zookeeper-server-stop.sh
PIDS=$(jps -lm | grep -i QuorumPeerMain | grep -v grep | awk ‘{print $1}’)
再执行脚本
sh zookeeper-server-stop.sh -daemon ../config/zookeeper.properties
启动和停止kafka
-
修改server.properties, 增加zookeeper的配置,localhost替换为具体的ip
zookeeper.connect=localhost:2181
-
启动kafka
sh kafka-server-start.sh -daemon ../config/server.properties
-
停止kafka
首先,修改
kafka-server-stop.sh
脚本,原脚本可能执行停止kafka失败,修改脚本的PIDSvim kafka-server-stop.sh
PIDS=$(jps -lm | grep -i ‘kafka.Kafka’ | awk ‘{print $1}’)
再执行脚本
sh kafka-server-stop.sh -daemon ../config/server.properties
kafka的基本操作
创建topic
sh kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 -partitions 2 --topic case-keyPerson
replication-factor 表示该topic需要在不同的broker中保存几份,这里设置成1,表示在两个broker中 保存两份
partitions 分区数
topic 消息主题
查看topic
sh kafka-topics.sh --list --zookeeper localhost:2181
查看topic属性
sh kafka-topics.sh --describe --zookeeper localhost:2181 --topic case-keyPerson
消费消息
sh kafka-console-consumer.sh --bootstrap-server 当前服务ip:9092 --topic case-keyPerson --from-beginning
发送消息
sh kafka-console-producer.sh --broker-list 当前服务ip:9092 --topic case-keyPerson
日志清除策略
修改server.properties, 设置日志清除策略
#消息保留达到12小时,就会执行删除
log.retention.hours=12
Java客户端
依赖引用
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
...
</dependencies>
kafka配置
#============== kafka ===================
# 指定kafka server的地址,集群配多个,中间,逗号隔开
spring.kafka.bootstrap-servers=kafka服务ip:9092
#=============== producer 生产者=======================
# 写入失败时,重试次数。当leader节点失效,一个repli节点会替代成为leader节点,此时可能出现写入失败,
# 当retris为0时,produce不会重复。retirs重发,此时repli节点完全成为leader节点,不会产生消息丢失。
spring.kafka.producer.retries=0
# 每次批量发送消息的数量,produce积累到一定数据,一次发送
spring.kafka.producer.batch-size=16384
# produce积累数据一次发送,缓存大小达到buffer.memory就发送数据
#spring.kafka.producer.buffer-memory=33554432
# 提交延时
spring.kafka.producer.properties.linger.ms=0
#procedure要求leader在考虑完成请求之前收到的确认数,用于控制发送记录在服务端的持久化,其值可以为如下:
#acks = 0 如果设置为零,则生产者将不会等待来自服务器的任何确认,该记录将立即添加到套接字缓冲区并视为已发送。在这种情况下,无法保证服务器已收到记录,并且重试配置将不会生效(因为客户端通常不会知道任何故障),为每条记录返回的偏移量始终设置为-1。
#acks = 1 这意味着leader会将记录写入其本地日志,但无需等待所有副本服务器的完全确认即可做出回应,在这种情况下,如果leader在确认记录后立即失败,但在将数据复制到所有的副本服务器之前,则记录将会丢失。
#acks = all 这意味着leader将等待完整的同步副本集以确认记录,这保证了只要至少一个同步副本服务器仍然存活,记录就不会丢失,这是最强有力的保证,这相当于acks = -1的设置。
#可以设置的值为:all, -1, 0, 1
spring.kafka.producer.acks=1
# 指定消息key和消息体的编解码方式
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
#=============== consumer 消费者 =======================
# 指定默认消费者group id --> 由于在kafka中,同一组中的consumer不会读取到同一个消息,依靠groud.id设置组名
spring.kafka.consumer.group-id=group.dev
# earliest:从最早的offset开始消费,就是partition的起始位置开始消费
# latest:从最近的offset开始消费,就是新加入partition的消息才会被消费
spring.kafka.consumer.auto-offset-reset=earliest
# enable.auto.commit:true --> 设置自动提交offset
spring.kafka.consumer.enable-auto-commit=true
#如果'enable.auto.commit'为true,则消费者偏移自动提交给Kafka的频率(以毫秒为单位),默认值为5000。
spring.kafka.consumer.auto-commit-interval=100
# 消费端监听的topic不存在时,项目启动会报错(关掉)
spring.kafka.listener.missing-topics-fatal=false
# 设置批量消费
# spring.kafka.listener.type=batch
# 批量消费每次最多消费多少条消息
# spring.kafka.consumer.max-poll-records=50
# 指定消息key和消息体的编解码方式
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
java代码创建 topic
@Bean()
public NewTopic newTopic() {
// 参数1:name 消息主题
// 参数2:partitions 分区数量
// 参数3:replication factor 数量
return new NewTopic("topic", 2, (short) 1);
}
加载流程:
1.
KafkaAutoConfiguration
自动化装配,会加载KafkaAdmin
类,KafkaAdmin
类使用KafkaProperties
.admin
构建。
@Bean
@ConditionalOnMissingBean
public KafkaAdmin kafkaAdmin() {
KafkaAdmin kafkaAdmin = new KafkaAdmin(this.properties.buildAdminProperties());
kafkaAdmin.setFatalIfBrokerNotAvailable(this.properties.getAdmin().isFailFast());
return kafkaAdmin;
}
2.
KafkaAdmin
继承ApplicationContextAware
,SmartInitializingSingleton
接口
ApplicationContextAware
: 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware
接口中的setApplicationContext
方法。
SmartInitializingSingleton
: 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization
之后。
@Override
public void afterSingletonsInstantiated() {
this.initializingContext = true;
// 默认true,可通过KafkaProperties.admin设值
if (this.autoCreate) {
initialize();
}
}
/**
* Call this method to check/add topics; this might be needed if the broker was not
* available when the application context was initialized, and
* {@link #setFatalIfBrokerNotAvailable(boolean) fatalIfBrokerNotAvailable} is false,
* or {@link #setAutoCreate(boolean) autoCreate} was set to false.
* @return true if successful.
* @see #setFatalIfBrokerNotAvailable(boolean)
* @see #setAutoCreate(boolean)
*/
public final boolean initialize() {
// 这里从spring上下文获取NewTopic.class类型的bean,也就是我们上文使用java代码定义的NewTopic
Collection<NewTopic> newTopics = this.applicationContext.getBeansOfType(NewTopic.class, false, false).values();
if (newTopics.size() > 0) {
AdminClient adminClient = null;
try {
// 创建admin客户端
adminClient = AdminClient.create(this.config);
}
catch (Exception e) {
if (!this.initializingContext || this.fatalIfBrokerNotAvailable) {
throw new IllegalStateException("Could not create admin", e);
}
else {
LOGGER.error(e, "Could not create admin");
}
}
if (adminClient != null) {
try {
// 如果topic不存在,创建topic
addTopicsIfNeeded(adminClient, newTopics);
return true;
}
catch (Exception e) {
if (!this.initializingContext || this.fatalIfBrokerNotAvailable) {
throw new IllegalStateException("Could not configure topics", e);
}
else {
LOGGER.error(e, "Could not configure topics");
}
}
finally {
this.initializingContext = false;
adminClient.close(this.closeTimeout);
}
}
}
this.initializingContext = false;
return false;
}
kafka生产者
@Component
public class CaseKafkaProducer {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void send(String topic, String data) {
kafkaTemplate.send(topic, String.valueOf(System.currentTimeMillis()), data);
}
/**
* <p>
* <code>send</code> 分发机制,默认情况下kafka采用的是hash取模的分区算法。如果key为null,则会随机分配一个分区。
* 这个随机实在参数"metadata.max.age.ms"的事件范围内随机训责一个,对于这个时间段内,如果可疑为null,则只会发送到唯一的分区。
* spring.kafka.producer.properties.metadata.max.age.ms=50000
* 这个值默认情况下是10分钟更新一次
* </p>
*
* @param topic
* @param key
* @param data
* @return
*/
public void send(String topic, String key, String data) {
kafkaTemplate.send(topic, key, data);
}
}
kafka生产者自定义分区策略
实现org.apache.kafka.clients.producer.Partitioner接口
kafka消费者
@Component
public class CaseKafkaConsumer {
// 监听topic主题
@KafkaListener(topics = {"topicName"})
public void listener(ConsumerRecord record) {
Optional msg = Optional.ofNullable(record.value());
if (msg.isPresent()) {
System.out.println("consumer get:" + msg.get());
}
}
}
kafka消费者自定义分区策略
@KafkaListener(topicPartitions={@TopicPartition(topic = “”, partitions = {“0”})})