先谈Kafka
为了方便通过kafka和zookeeper都通过docker来安装
1. 由于目前Kafka依赖zookeeper所以先安装zookeeper
-
拉取镜像
docker pull zookeeper:latest -
启动zookeeper,端口映射和文件挂载
docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper
2.搭建Kafka
-
拉取镜像
docker pull wurstmeister/kafka -
启动Kafka
docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=10.9.44.11:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://10.9.44.11:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -t wurstmeister/ -
参数说明
-e KAFKA_BROKER_ID=0 在kafka集群中,每个kafka都有一个BROKER_ID来区分自己
-e KAFKA_ZOOKEEPER_CONNECT=10.9.44.11:2181/kafka 配置zookeeper管理kafka的路径10.9.44.11:2181/kafka
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://10.9.44.11:9092 把kafka的地址端口注册给zookeeper
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 配置kafka的监听端口
-v /etc/localtime:/etc/localtime 容器时间同步虚拟机的时间
再谈springboot
springboot跟kafka的关系就像与redis,mysql一样,可借助的外部力量。
- 引入kafka的依赖来连接kafka
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.8.4</version>
</dependency>
- 通过application.yml来连接Kafka
spring:
application:
name: kafka-demo
kafka:
#kafka的地址
bootstrap-servers: 192.168.234.129:19092
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
group-id: test
enable-auto-commit: true
auto-commit-interval: 1000
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
- 向Kafka推送消息
//注入kafka模板
@Autowired
private KafkaTemplate kafkaTemplate;
//向kafka推送消息
public void send(){
String msg = "hello kafka";
kafkaTemplate.send("test_topic",msg);
}
- 通过注解消费Kafka消息
@Component
public class TestConsumer {
//监听的主题名
@KafkaListener(topics = "test_topic")
public void listen (ConsumerRecord<?, ?> record) throws Exception {
System.out.printf("coupon topic = %s, offset = %d, value = %s \n", record.topic(), record.offset(), record.value());
}
}
- 编程式使用kafka
@Test
void testPoll(){
//手动创建配置文件
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.234.129:19092");
props.put("group.id", "test");
//如果value合法,则自动提交偏移量
props.put("enable.auto.commit", "true");
//设置多久一次更新被消费消息的偏移量
props.put("auto.commit.interval.ms", "1000");
//设置会话响应的时间,超过这个时间kafka可以选择放弃消费或者消费下一条消息
props.put("session.timeout.ms", "30000");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer consumer = new KafkaConsumer<String, String>(props);
//配置发送的主题
List<String> topics = Arrays.asList("test_topic","test_topic2");
consumer.subscribe(topics);
while (true){
//拉取kafka的消息,此方式相较于注解可以获取多个主题的消息
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
if(!records.isEmpty()){
for(ConsumerRecord<String,String> record : records){
//获取消费的值、偏移量、主题名
System.out.println("membert value:"+record.value()+" "+"offset:"+record.offset()+" "+record.topic());
}
}
}
}
再谈Kafka
kafka的整体架构
Producer:Producer即生产者,消息的产生者,是消息的入口。
kafka cluster:
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来保存集群的的元信息,来保证系统的可用性。
主题分区与消费组
- 以上步骤,已经初步体验了通过kakfa进行了发收消息
- 下面介绍一下kafka的特性
-
上图(借图,如有侵犯望告知撤掉),描述了Kafka的P(分区)与C(消费者)之间发送消息的方式。
- 可以看出每个分区只会向一组里面一个消费者发送消息
-
总之:
-
如果所有的消费者都隶属于同一个消费组,那么所有的消息都会被均衡地投递给每一个消费者,即每条消息只会被一个消费者处理,这就相当于点对点模式的应用。
-
如果所有的消费者都隶属于不同的消费组,那么所有的消息都会被广播给所有的消费者,即每条消息会被所有的消费者处理,这就相当于发布/订阅模式的应用。