巅峰迎来虚伪的拥护,黄昏见证真正的信徒。
在介绍kafka之前,先来了解下消息队列
一、消息队列(Message Queue)
1、概述:
消息队列顾名思义就是存储消息的队列,也就是在传输过程中保存消息的容器。同时消息队列是分布式系统中重要的组件。比如,我们为了分析某个网站的用户行为,我们就需要记录下来用户的访问日志,一条条日志,一条条消息,然后把这些都存储到消息队列中。
消息队列的出现主要是为了解决应用的耦合、异步处理等问题。
那我们现在使用比较多的消息队列有RabbitMQ、ActiveMQ、ZeroMQ、MetaMq等,但很多时候消息队列不是一个永久性当然我们这次要介绍的Kafak也是属于消息队列的。
2、 消息队列应用的场景
- 异步处理
- 应用耦合
- 限流削峰
- 消息驱动的系统
3、消息队列的模式
-
点对点模式
-
发布订阅模式
二、Kafka
1、概述:
kafka是一个分布式的、支持分区的(patition)、多副本的,是一个基于zookeeper协调的分布式消息系统。
2、kafka的特性
- 高吞吐量、低延迟
- 可拓展性
- 持久性、可靠性
- 容错性
- 高并发
3、生产者程序的开发
1、创建一个生产者对象KafkaProducer
2、调用send方法发送消息(ProducerRecord,封装是Key-value键值对)
3、调用Future.get表示等待服务端的响应。
4、关闭生产者
- bootstrap.servers:kafka的服务器地址。
- acks:表示当生产者生产数据到kafka中,kafka会以什么样的策略返回。
- key.serializer:kafka的消息是以可以、value键值对存储的,而且生产者生产的消息是在网络上传到的,这里指的就是StringSerializer方式,就是以字符创方式发送的(其他的一些序列化框架:Goole ProtoBuf\Avro)
- value.serializer:同上
public class KafkaProduceTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建用于 连接kafka的properties的配置
Properties props=new Properties();
props.put("bootstrap.servers","localhost:9092");
props.put("acks","all"); props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
// 创建一个生产者对象
KafkaProducer<String, String> KafkaProducer = new KafkaProducer<String, String>(props);
// 发送1-100的消息到指定topic
for (int i=0;i<100;i++){
// 构建一条消息。直接NEW produceRcord
ProducerRecord<String, String> producerRecord= new ProducerRecord<String, String>("test", null, i + "");
Future<RecordMetadata> future = KafkaProducer.send(producerRecord);
// 调用future的get方法等待响应
future.get();
System.out.println("第"+i+"条消息写入成功!");
}
// 关闭生产者
KafkaProducer.close();
}
4、消费者程序的开发
- group.id :消费者组的概念,可以在一个消费者组中包含多个消费者,如果若干个group.id是一样的,表示他们在一个组中,一个消费者者是共同消费kafka中topic的数据。
- kafka是一种拉消息模式的消息队列,在消费者中会有一个offset,表示从哪条消息开始拉取数据。
- kafkaConsumer.poll:kafka的消费者API是一批一批数据的拉取。
public class KafkaConsumerTest {
public static void main(String[] args) {
// 创建kafka消费者配置
Properties props=new Properties();
props.setProperty("bootstrap.servers","localhost:9092");
// 消费者组(可以使用消费者组将若干个消费者组织到一起,)共同消费kafka中topic的数据。
// 每一个消费者需要指定一个消费者组,如果消费者组的组名是一样,表示这几个消费者是一个组中的
props.setProperty("group.id","test");
// 自动提交offest
props.setProperty("enable.auto.commit","true");
// 自动提交offest的时间间隔
props.setProperty("auto.commit.interval.ms","1000");
// 拉取key、value数据
props.setProperty("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
// 创建kafka消费者
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(props);
// 订阅要消费的主题,
// 指定消费者是从哪个topic中拉取数据
kafkaConsumer.subscribe(Arrays.asList("test"));
// 使用一个whil循环,不断的从kafka中的topic中拉取数据
while (true){
ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(Duration.ofSeconds(5));
// 将记录的(record)中的offest 、key、value都打印出来
for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
// 主题
String topic = consumerRecord.topic();
// offest:这条消息处于kafka分区中的哪个位置
long offset = consumerRecord.offset();
// key/value
String key = consumerRecord.key();
String value = consumerRecord.value();
System.out.println(" topic: "+ topic +" offset: "+ offset +" key: "+ key +" value: "+ value);
}
}
}
}