Apache kafka官网上对kafka的简单别成为 a distributed streaming platform 即一个分布式流平台
主要有三大功能 :
- publish and subscribe 发布和订阅 像消息系统一样读写数据流
- process(kafka stream ) 处理数据
- Storage 存储系统
配置环境
安装JDK
https://www.oracle.com/java/technologies/javase-downloads.html
安装Zookeeper
Zookeeper官网下载地址
http://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/
运行Zookeeper
修改conf\zoo_sample.cfg
为\conf.cfg
再执行bin\zkServer.sh
安装Kafka
Kafka官网下载地址
http://kafka.apache.org/downloads
运行Kafka
bin\kafka-server-start.sh config\server.properties
Spring Boot整合Kafka
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Spring Boot配置文件 application.properties
# 连接kafka的地址,多个地址用逗号分隔
spring.kafka.bootstrap-servers=localhost:9092
# 消费组
spring.kafka.consumer.group-id=test-consumer
# latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)
spring.kafka.consumer.auto-offset-reset=latest
生产者配置 KafkaProducerConfig
@Configuration
public class KafkaProducerConfig {
@Value("${spring.kafka.bootstrap-servers}")
private String bootstrapServers;
@Bean
public ProducerFactory<String, Message> producerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(
ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
bootstrapServers);
configProps.put(
ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
StringSerializer.class);
configProps.put(
ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
JsonSerializer.class);
return new DefaultKafkaProducerFactory<>(configProps);
}
@Bean
public KafkaTemplate<String, Message> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
消费者配置 KafkaConsumerConfig
@EnableKafka
@Configuration
public class KafkaConsumerConfig {
@Value("${spring.kafka.bootstrap-servers}")
private String bootstrapServers;
@Value("${spring.kafka.consumer.group-id}")
private String consumerGroupId;
@Value("${spring.kafka.consumer.auto-offset-reset}")
private String autoOffsetReset;
@Bean
public ConsumerFactory<String, Message> consumerFactory() {
Map<String, Object> props = new HashMap<>();
props.put(
ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
bootstrapServers);
props.put(
ConsumerConfig.GROUP_ID_CONFIG,
consumerGroupId);
props.put(
ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,
autoOffsetReset);
// props.put(
// ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
// StringDeserializer.class);
// props.put(
// ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
// StringDeserializer.class);
return new DefaultKafkaConsumerFactory<>(
props,
new StringDeserializer(),
new JsonDeserializer<>(Message.class));
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, Message> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, Message> factory
= new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
// factory.setRecordFilterStrategy(
// r -> r.value().contains("fuck")
// );
return factory;
}
}
初始化 KafkaInitialConfiguration
初始化Topic
@Configuration
public class KafkaInitialConfiguration {
// 创建一个名为test的Topic并设置分区数为8,分区副本数为2
@Bean
public NewTopic initialTopic() {
return new NewTopic("test", 8, (short) 2);
}
// 如果要修改分区数,只需修改配置值重启项目即可
// 修改分区数并不会导致数据的丢失,但是分区数只能增大不能减小
@Bean
public NewTopic updateTopic() {
return new NewTopic("test", 10, (short) 2);
}
}
实体类 Message
public class Message implements Serializable {
private static final long serialVersionUID = 6678420965611108427L;
private String from;
private String message;
public Message() {
}
public Message(String from, String message) {
this.from = from;
this.message = message;
}
@Override
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", message='" + message + '\'' +
'}';
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
生产者 SendMessageController
@RestController
public class SendMessageController {
@Autowired
private KafkaTemplate<String, Message> kafkaTemplate;
@GetMapping("send/{message}")
public void sendMessage(@PathVariable String message) {
this.kafkaTemplate.send("test", new Message("demo", message));
}
}
消费者 KafkaMessageListener
@Component
public class KafkaMessageListener {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@KafkaListener(topics = "test", groupId = "test-consumer")
public void listen(Message message) {
logger.info("接收消息: {}", message);
}
}
效果
GET http://localhost:8080/send/你好kafka
2021-03-16 11:34:38.782 INFO 14040 --- [nio-8080-exec-2] o.a.k.clients.producer.ProducerConfig : ProducerConfig values:
acks = 1
batch.size = 16384
bootstrap.servers = [localhost:9092]
buffer.memory = 33554432
client.dns.lookup = use_all_dns_ips
client.id = producer-1
compression.type = none
connections.max.idle.ms = 540000
delivery.timeout.ms = 120000
enable.idempotence = false
interceptor.classes = []
internal.auto.downgrade.txn.commit = true
key.serializer = class org.apache.kafka.common.serialization.StringSerializer
linger.ms = 0
max.block.ms = 60000
max.in.flight.requests.per.connection = 5
max.request.size = 1048576
metadata.max.age.ms = 300000
metadata.max.idle.ms = 300000
metric.reporters = []
metrics.num.samples = 2
metrics.recording.level = INFO
metrics.sample.window.ms = 30000
partitioner.class = class org.apache.kafka.clients.producer.internals.DefaultPartitioner
receive.buffer.bytes = 32768
reconnect.backoff.max.ms = 1000
reconnect.backoff.ms = 50
request.timeout.ms = 30000
retries = 2147483647
retry.backoff.ms = 100
sasl.client.callback.handler.class = null
sasl.jaas.config = null
sasl.kerberos.kinit.cmd = /usr/bin/kinit
sasl.kerberos.min.time.before.relogin = 60000
sasl.kerberos.service.name = null
sasl.kerberos.ticket.renew.jitter = 0.05
sasl.kerberos.ticket.renew.window.factor = 0.8
sasl.login.callback.handler.class = null
sasl.login.class = null
sasl.login.refresh.buffer.seconds = 300
sasl.login.refresh.min.period.seconds = 60
sasl.login.refresh.window.factor = 0.8
sasl.login.refresh.window.jitter = 0.05
sasl.mechanism = GSSAPI
security.protocol = PLAINTEXT
security.providers = null
send.buffer.bytes = 131072
ssl.cipher.suites = null
ssl.enabled.protocols = [TLSv1.2]
ssl.endpoint.identification.algorithm = https
ssl.engine.factory.class = null
ssl.key.password = null
ssl.keymanager.algorithm = SunX509
ssl.keystore.location = null
ssl.keystore.password = null
ssl.keystore.type = JKS
ssl.protocol = TLSv1.2
ssl.provider = null
ssl.secure.random.implementation = null
ssl.trustmanager.algorithm = PKIX
ssl.truststore.location = null
ssl.truststore.password = null
ssl.truststore.type = JKS
transaction.timeout.ms = 60000
transactional.id = null
value.serializer = class org.springframework.kafka.support.serializer.JsonSerializer
2021-03-16 11:34:38.810 INFO 14040 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser : Kafka version: 2.6.0
2021-03-16 11:34:38.810 INFO 14040 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser : Kafka commitId: 62abe01bee039651
2021-03-16 11:34:38.811 INFO 14040 --- [nio-8080-exec-2] o.a.kafka.common.utils.AppInfoParser : Kafka startTimeMs: 1615865678810
2021-03-16 11:34:38.817 INFO 14040 --- [ad | producer-1] org.apache.kafka.clients.Metadata : [Producer clientId=producer-1] Cluster ID: OIXt1kWTR4CKrRi_PxifGw
2021-03-16 11:34:38.878 INFO 14040 --- [ntainer#0-0-C-1] c.s.listener.KafkaMessageListener : 接收消息: Message{from='demo', message='你好kafka'}