kafka是目前使用的比较多的消息中间件,这里将kafka的安装及使用,做一个大致的介绍。
一、kafka基本知识
消息队列通信的模式
点对点模式通常是基于拉取或者轮询的消息传送模型,这个模型的特点是发送到队列的消息被一个且只有一个消费者进行处理。生产者将消息放入消息队列后,由消费者主动的去拉取消息进行消费。点对点模型的的优点是消费者拉取消息的频率可以由自己控制。但是消息队列是否有消息需要消费,在消费者端无法感知,所以在消费者端需要额外的线程去监控。这也是目前kafka使用的模式。另外一种模式是发布订阅模式,这种模式改模型可以有多种不同的订阅者。消费者被动接收推送,所以无需感知消息队列是否有待消费的消息,会造成比较大的浪费。
基础架构及术语
Producer:Producer即生产者,消息的产生者,是消息的入口。
Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……
Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。
Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!
Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。
Message:每一条发送的消息主体。
Consumer:消费者,即消息的消费方,是消息的出口。
Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量。
Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。
目前这些术语基本足够去理解下面使用的参数了。
二、kafka的下载与安装
环境准备:
1、kafka依赖zookeeper,需要先安装zookeeper。
2、kafka 根据版本的不同依赖java,一般高于kafka2版本,需要java8的版本,此次测试我环境使用jdk1.8.0_11, kafka_2.11-1.1.1.tgz。(由于下载文件太慢,目前就使用比较低的版本)
kafka文件的下载地址
http://kafka.apache.org/downloads
将文件上传,并解压
tar -zxvf kafka_2.11-1.1.1.tgz
进入到对应的目录
cd /usr/local/taotao-servers/kafka_2.11-1.1.1/config
编辑对应server.properties 文件,此时kafka 的server配置文件里面已经写入
#唯一标识(如果单机部署直接已经配置了)
broker.id=0
# 指定服务的端口(需要增加)
listeners = PLAINTEXT://192.168.25.133:9092
#zookeeper的连接地址(如果单机部署直接已经配置了)
zookeeper.connect=localhost:2181
#日志目录(已经配置了)
log.dirs=/tmp/kafka-logs
kafka的启动,进入到kafka的bin目录,以守护式方式启动kafka
./kafka-server-start.sh -daemon ../config/server.properties
验证kafka是否启动成功
在bin目录下面使用此命令发送消息
./kafka-console-producer.sh --broker-list 192.168.25.133:9092 --topic testTopic
在bin目录下面使用此命令接收消息
./kafka-console-consumer.sh --bootstrap-server 192.168.25.133:9092 --topic testTopic --from-beginning
能够接收消息发送消息,则证明kafka安装成功。
二、kafka和springboot整合
消费发送者和接收者都需要加入依赖,需要注意springboot的版本和spring-kafka之间的版本配合(目前我是用2.1.7和2.2.8版本配合)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
kafka生产者提供properties
spring.kafka.producer.bootstrap-servers=192.168.25.133:9092
kafka.test.topic=testTopic
# 指定消息key和消息体的编解码方式
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
# 每次批量发送消息的数量,produce积累到一定数据,一次发送
spring.kafka.producer.batch-size=16384
# produce积累数据一次发送,缓存大小达到buffer.memory就发送数据
spring.kafka.producer.buffer-memory=33554432
#procedure要求leader在考虑完成请求之前收到的确认数,用于控制发送记录在服务端的持久化,其值可以为如下:
#acks = 0 如果设置为零,则生产者将不会等待来自服务器的任何确认,该记录将立即添加到套接字缓冲区并视为已发送。在这种情况下,无法保证服务器已收到记录,并且重试配置将不会生效(因为客户端通常不会知道任何故障),为每条记录返回的偏移量始终设置为-1。
#acks = 1 这意味着leader会将记录写入其本地日志,但无需等待所有副本服务器的完全确认即可做出回应,在这种情况下,如果leader在确认记录后立即失败,但在将数据复制到所有的副本服务器之前,则记录将会丢失。
#acks = all 这意味着leader将等待完整的同步副本集以确认记录,这保证了只要至少一个同步副本服务器仍然存活,记录就不会丢失,这是最强有力的保证,这相当于acks = -1的设置。
#可以设置的值为:all, 0, 1
spring.kafka.producer.acks=1
发送端的
@RestController
@RequestMapping("/producer/kafka")
public class KafkaController {
@Autowired
private KafkaService kafkaService;
@PostMapping("/test/sendMessage")
public JsonVO sendKafkaMessage(@RequestBody LamdaVO lamdaVO) {
return kafkaService.sendMessage(lamdaVO);
}
}
发送端的service
@Service
public class KafkaServiceImpl implements KafkaService {
@Autowired
private KafkaTemplate kafkaTemplate;
@Autowired
private PropertyManager propertyManager;
@Override
public JsonVO sendMessage(LamdaVO lamdaVO) {
JsonVO jsonVO = new JsonVO(200, "success");
kafkaTemplate.send(propertyManager.getTestKafkaTopic(), JSON.toJSONString(lamdaVO));
return jsonVO;
}
}
kafka的配置
@Component
@Configuration
@Data
public class PropertyManager {
@Value("${kafka.test.topic}")
private String testKafkaTopic;
}
kafka消费者提供的properties文件
#kafka消费者
# kafka是否自动提交offset 如果自动提交容易造成session超时,造成重复消费,交由spring-kafka提交
spring.kafka.consumer.enable-auto-commit=false
#auto-commit-interval: 1000 #自动提交的间隔时间,自动提交去掉#号
# 指定默认消费者group id --> 由于在kafka中,同一组中的consumer不会读取到同一个消息,依靠groud.id设置组名
spring.kafka.consumer.group-id=customer-test
# earliest和largest才有效,如果earliest重新0开始读取,如果是largest从logfile的offset读取。一般情况下我们都是设置earliest
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.bootstrap-servers=192.168.25.133:9092
kafka.test.topic=testTopic
# 指定消息key和消息体的编解码方式
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
kafka的消费者代码
@Component
public class KafkaConsumer {
private static final Logger logger = LoggerFactory.getLogger(KafkaConsumer.class);
@KafkaListener(topics = "${kafka.test.topic}")
public void receive(ConsumerRecord<String, String> record) {
System.out.println(record.topic());
Optional<?> kafkaMessage = Optional.ofNullable(record.value());
if (kafkaMessage.isPresent()) {
logger.error("recevice a message :{}", record.value());
}
}
}
出现消息无法接收,可以采用几个比较方便定位方法
1、使用kafka直接发送命令
./kafka-console-producer.sh --broker-list 192.168.25.133:9092 --topic testTopic
2、使用kafka消费消息
./kafka-console-consumer.sh --bootstrap-server 192.168.25.133:9092 --topic testTopic --from-beginning
3、用telnet命令判断kafka是否存活
telnet 192.168.25.133 9092
一些常用kafka命令:
查看testTopic的topic的一些基本信息
./kafka-topics.sh --describe --zookeeper 192.168.25.133:2181 --topic testTopic
[root@localhost bin]# ./kafka-topics.sh --describe --zookeeper 192.168.25.133:2181 --topic testTopic
Topic:testTopic PartitionCount:1 ReplicationFactor:1 Configs:
Topic: testTopic Partition: 0 Leader: 0 Replicas: 0 Isr: 0
表明 testPopic 分区为在0,领导者在0 ,副本在0,也表明由程序直接创建的topic的主题的分区为1
对testTopic主题创建3个副本,2个分区,但由于副本的数量是不能超过broker的数量,故在此创建会失败
./kafka-topics.sh --create --zookeeper 192.168.25.133:2181 --replication-factor 3 --partitions 2 --topic testTopic
目前当前zookeeper管理的topic有哪些
./kafka-topics.sh --list --zookeeper 192.168.25.133:2181
删除topic2的主题
./kafka-topics.sh --delete --zookeeper 192.168.25.133:2181 --topic testTopic2
获取指定消费者组的topic消息积压情况
./kafka-consumer-groups.sh --describe --bootstrap-server 192.168.25.133:9092 --group breeno-proxy-service
查看有哪些消费者组
./kafka-consumer-groups.sh --bootstrap-server 192.168.25.133:9092 --list --new-consumer
消费者消费topic指定消费组名
./kafka-console-consumer.sh --bootstrap-server 192.168.25.133:9092 --new-consumer --consumer-property group.id=core_service --topic observerSecurity