Kafka,构建TB级异步消息系统
一:阻塞队列
这个是Java自带的API,用于解决线程通信的问题
①BlockingQueue接口
- 解决线程通信的问题。
- 阻塞方法:put、take。
原理图:
线程Thread-1从左边存入数据
线程Thread-2从右边取出数据
阻塞队列Blocking Queue就在中间形成一道缓冲区,从而良好的解决线程通信的问题。
阻塞队列满足生产者消费者模式
②生产者消费者模式
- 生产者:产生数据的线程。
- 消费者:使用数据的线程。
③常见的实现类
- ArrayBlockingQueue
- LinkedBlockingQueue
- PriorityBlockingQueue、SynchronousQueue、DelayQueue等。
示例代码:模拟阻塞队列
public class BlockingQueueTests {
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(10); //队列中最多只能存10条数据
new Thread(new Producer(blockingQueue)).start();
new Thread(new Consumer(blockingQueue)).start();
new Thread(new Consumer(blockingQueue)).start();
new Thread(new Consumer(blockingQueue)).start();
}
}
//消息生产者
class Producer implements Runnable{
private BlockingQueue<Integer> blockingQueue;
public Producer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
for (int i = 0;i < 100;i++){
Thread.sleep(20);
blockingQueue.put(i);
System.out.println(Thread.currentThread().getName() + "生产:" + blockingQueue.size());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
//消息消费者
class Consumer implements Runnable{
private BlockingQueue<Integer> blockingQueue;
public Consumer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
while (true) {
Thread.sleep(new Random().nextInt(1000));
blockingQueue.take();
System.out.println(Thread.currentThread().getName() + "消费:" + blockingQueue.size());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
二:Kafka
Kafka官网:http://kafka.apache.org
Kafka常用的命令(快速入门):https://kafka.apache.org/documentation/#quickstart
Kafka简介
-Kafka是一个分布式的流媒体平台。
-应用:消息系统、日志收集、用户行为追踪、流式处理。
Kafka特点
-高吞吐量、消息持久化、高可靠性、高扩展性。
-采用发布订阅模式。
• Kafka术语
①Broker —> Kafka的服务器,Kafka集群中的每一台服务器称其为一个Broker。
②Zookeeper —> Kafka中内置Zookeeper来管理它的集群。
③Topic —> 消息的主题。(发布订阅模式)
④Partition —> 主题的分区,一个主题可以有多个分区。
每个分区是按照从前往后依次追加写入进去数据的。
⑤Offset —>消息在分区中的索引
⑥Leader Replica —> 主副本,负责相应请求
Replica :副本
Kafka集群中会以副本的形式把数据多存几份。
⑦Follower Replica —> 从副本,只负责从主副本中备份数据。
当某一时刻主副本挂掉了,系统会从从副本中选出一个充当主副本。
三:Spring整合Kafka
启动Kafka
①首先要启动Zookeeper
bin\windows\zookeeper-server-start.bat config\zookeeper.properties
②启动Kafka
bin\windows\kafka-server-start.bat config\server.properties
1、引入依赖
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
2、配置Kafka
# KafkaProperties
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=community-consumer-group
spring.kafka.consumer.enable-auto-commit=true
spring.kafka.consumer.auto-commit-interval=3000
3、访问Kafka
- 生产者
kafkaTemplate.send(topic, data);
- 消费者
@KafkaListener(topics = {"test"})
public void handleMessage(ConsumerRecord record) {
record.value()
}
实例代码:
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class KafkaTests {
@Autowired
private KafkaProducer kafkaProducer;
@Test
public void testKafka() {
kafkaProducer.sendMessage("test","你好");
kafkaProducer.sendMessage("test","在吗");
kafkaProducer.sendMessage("test","我是zzu");
try {
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Component
class KafkaProducer {
@Autowired
private KafkaTemplate kafkaTemplate;
public void sendMessage(String topic, String content) {
kafkaTemplate.send(topic, content);
}
}
@Component
class KafkaConsumer {
@KafkaListener(topics = {"test"})
public void handleMessage(ConsumerRecord record) {
System.out.println(record.value());
}
}