19 kafka消息队列

本文详细介绍了Kafka消息队列的基本概念、常用消息队列对比、Kafka的特点与应用场景。深入探讨了Kafka的架构、集群搭建过程、Java API操作,以及与Flume的整合。同时,讲解了Kafka的CAP机制、监控运维和实时看板案例,展示了Kafka在大数据领域的应用。
摘要由CSDN通过智能技术生成

文章目录

19 kafka消息队列

一、kafka介绍

1、消息队列基本介绍

消息:在应用系统之间,传递的数据叫做消息
队列:排队的模型 先进先出 类似于火车进隧道
消息(Message)是指在应用之间传送的数据,消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。
消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠专递,消息发布者只管把消息发布到MQ中而不管谁来取,消息使用者只管从MQ中取消息而不管谁发布的,这样发布者和使用者都不用知道对方的存在
在这里插入图片描述
在这里插入图片描述

2、常用的消息队列介绍

标注的消息队列实现
RabbitMQ: rabbit message queue
ActiveMQ:支持消息队列当中事务处理
RocketMQ: 阿里开源的消息队列 rocket
消息队列的模型:主要是基于pub/sub publish 、subscribe 发布与订阅模型
在这里插入图片描述
kafka:linkedin 公司开源提供的 吞吐量非常高,而且消息的处理速度非常快 大数据领域里面大部分都是使用kafka
kafka不是一个标准的消息队列的实现
消息队列模型:主要是基于push/poll 推送与拉取
在这里插入图片描述
在这里插入图片描述

3、消息队列的应用场景

消息队列在实际应用中包括如下四个场景:

应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;

异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;

在这里插入图片描述

	限流削峰:广泛应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况;

在这里插入图片描述

消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;

具体场景:用户新上传了一批照片, 人脸识别系统需要对这个用户的所有照片进行聚类,聚类完成后由对账系统重新生成用户的
人脸索引(加快查询)。这三个子系统间由消息队列连接起来,前一个阶段的处理结果放入队列中,
后一个阶段从队列中获取消息继续处理。

在这里插入图片描述

该方法有如下优点:
避免了直接调用下一个系统导致当前系统失败;
每个子系统对于消息的处理方式可以更为灵活,可以选择收到消息时就处理,可以选择定时处理,也可以划分时间段按
不同处理速度处理;

4、消息队列的两种模式

点对点(point to point, queue):两个人之间互相通信,都是点对点这种模型
在这里插入图片描述

点对点模式特点:

1.每个消息只有一个接收者(Consumer)(即一旦被消费,消息就不再在消息队列中);
2.发送者和接收者间没有依赖性,发送者发送消息之后,不管有没有接收者在运行,都不会影响到发送者下次发送消息;
3.接收者在成功接收消息之后需向队列应答成功,以便消息队列删除当前接收的消息;

发布订阅(publish/subscribe,topic):群聊
在这里插入图片描述
发布/订阅模式特点:

1.每个消息可以有多个订阅者;
2.发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息。
3.为了消费消息,订阅者需要提前订阅该角色主题,并保持在线运行;

5、kafka的基本介绍

官网:http://kafka.apache.org/
kafka是最初由linkedin公司开发的,使用scala语言编写,kafka是一个分布式,分区的,多副本的,多订阅者的日志系统(分布式MQ系统),可以用于搜索日志,监控日志,访问日志等

kafka是一个分布式的消息队列系统

分布式就是由多个节点组成,一个节点就是一个服务器
在kafka当中节点叫做broker ,一个节点就是一个broker,一个broker就是一个服务器
hadoop当中节点  datanode
hbase当中当中 HMaster以及HRegionServer

kafka的好处

可靠性:分布式的,分区,复制和容错的。
可扩展性:kafka消息传递系统轻松缩放,无需停机。
耐用性:kafka使用分布式提交日志,这意味着消息会尽可能快速的保存在磁盘上,因此它是持久的。 
性能:kafka对于发布和定于消息都具有高吞吐量。即使存储了许多TB的消息,他也爆出稳定的性能。 
kafka非常快:保证零停机和零数据丢失。
*磁盘顺序读写*

分布式的发布与订阅系统

apache kafka是一个分布式发布-订阅消息系统和一个强大的队列,可以处理大量的数据,并使能够将消息从一个端点传递到
另一个端点,kafka适合离线和在线消息消费。kafka消息保留在磁盘上,并在集群内复制以防止数据丢失。kafka构建在
zookeeper同步服务之上。它与apache和spark非常好的集成,应用于实时流式数据分析。

kafka的主要应用场景
指标分析

kafka   通常用于操作监控数据。这设计聚合来自分布式应用程序的统计信息,   以产生操作的数据集中反馈

日志聚合解决方法

kafka可用于跨组织从多个服务器收集日志,并使他们以标准的合适提供给多个服务器。

流式处理:实时处理 数据从出现到产生,在一秒钟以内能够处理完成
流式计算:程序一旦启动,就会一直运行下去,一旦有数据,就能够马上被处理掉

生产者生产数据到kafka里面去  ,然后通过一些实时处理的框架例如storm或者sparkStreaming或者flink等等
一些实时处理的框架去处理kafka里面的数据

6、kafka的架构介绍

分布式:肯定是多节点,多台服务器,组织到一起形成一个集群
在这里插入图片描述
生产者:producer 主要负责生产数据到 topic里面去
topic:虚拟的概念,某一类消息的主题,某一类消息都是存放在某一个topic当中
一个topic有多个partition:一个partition里面有多个segment段,每个segment默认1GB
一个segment: 一个.index文件 + 一个.log文件
.log:存放用户真实的产生的数据
.index 存放的是.log文件的索引数据
消费者:consumer 主要就是消费topic里面的数据
conusmer消费到哪一条数据需要进行记录:offset来进行记录 数据的偏移量 每条数据都有唯一的offset
.index文件:存放的索引文件,用于查找.log文件里面的数据

7、kafka架构内部细节剖析

在这里插入图片描述
在这里插入图片描述

kafka需要依赖zk保存一些节点信息 kakfa紧耦合zookeeper
kafka当中数据消费的时候,消费者都需要指定属于哪一个消费组
一个消费组里面,可以有多个消费者

消费组:同一时间,一个分区里面的数据,只能被一个消费组里面的一个线程进行消费
调大分区的个数:可以加快数据的消费的速度

任意时刻,一个分区里面的数据,只能被一个消费组里面的一个线程进行消费
kafka当中的数据消费出现延迟:加大消费者线程数量,加大分区的个数

8、kafka主要组件说明

1、kafka当中的producer说明

producer主要是用于生产消息,是kafka当中的消息生产者,生产的消息通过topic进行归类,保存到kafka的
broker里面去

2、kafka当中的topic说明

1、kafka将消息以topic为单位进行归类
2、topic特指kafka处理的消息源(feeds of messages)的不同分类。
3、topic是一种分类或者发布的一些列记录的名义上的名字。kafka主题始终是支持多用户订阅的;也就是说,一 个主题可以有零个,一个或者多个消费者订阅写入的数据。
4、在kafka集群中,可以有无数的主题。
5、生产者和消费者消费数据一般以主题为单位。更细粒度可以到分区级别。

3、kafka当中的partition说明

kafka当中,topic是消息的归类,一个topic可以有多个分区,每个分区保存部分topic的数据,所有的partition当中的数据全部合并起来,就是一个topic当中的所有的数据,
一个broker服务下,是否可以创建多个分区?
可以的,broker数与分区数没有关系; 在kafka中,每一个分区会有一个编号:编号从0开始
每一个分区的数据是有序的
说明-数据是有序 如何保证一个主题下的数据是有序的?(生产是什么样的顺序,那么消费的时候也是什么样的顺序)

在这里插入图片描述

topic的Partition数量在创建topic时配置。

Partition数量决定了每个Consumer group中并发消费者的最大数量。

Consumer group A 有两个消费者来读取4个partition中数据;
Consumer group B有四个消费者来读取4个 partition中的数据

在这里插入图片描述

partition的个数与线程的个数
partition个数  = 线程的个数  刚刚好,一个线程消费一个分区
partition个数 >  线程的个数  有线程需要去消费多个分区里面的数据
partition个数  < 线程的个数  有线程在闲置 

4、kafka当中partition的副本数说明
在这里插入图片描述
副本数(replication-factor):控制消息保存在几个broker(服务器)上,一般情况下等于broker的个数

kakfa当中副本的策略:使用isr这种策略来维护一个副本列表

isr  synchronize  replication :同步完成的副本列表
主分区:可以有多个副本 ,为了最大程度的同步完成数据,使用多个副本,每个副本都启动线程去复制主分区上面的数据
尽量的保证副本分区当中的数据与主分区当中的数据一致的
如果副本分区当中的数据与主分区当中的数据差别太大,将副本分区移除ISR列表
如果副本分区的心跳时间比较久远,也会将副本分区移除ISR列表

5、kafka当中的segment说明

一个partition当中由多个segment文件组成,每个segment文件,包含两部分,
一个是.log文件,另外一个是.index文件,
其中.log文件包含了我们发送的数据存储,
.index文件,记录的是我们.log文件的数据索引值,以便于我们加快数据的查询速度

索引文件与数据文件的关系
比如索引文件中3,497代表:数据文件中的第三个message,它的偏移地址为497。
再来看数据文件中,Message 368772表示:在全局partiton中是第368772个message。

注:segment index file采取稀疏索引存储方式,它减少索引文件大小,通过mmap可以直接内存操作,
稀疏索引为数据文件的每个对应message设置一个元数据指针,它比稠密索引节省了更多的存储空间,
但查找起来需要消耗更多的时间。

在这里插入图片描述

二、kafka集群环境搭建

1、初始化环境准备

安装jdk,安装zookeeper并保证zk服务正常启动

2、下载安装包并上传解压

通过以下地址进行下载安装包
node1执行以下命令,下载并解压

cd /export/softwares
wget http://archive.apache.org/dist/kafka/1.0.0/kafka_2.11-1.0.0.tgz
tar –zxvf  kafka_2.11-1.0.0.tgz -C /export/servers/

3、node1服务器修改kafka配置文件

node1执行以下命令进入到kafka的配置文件目录,修改配置文件
node1执行以下命令创建数据文件存放目录

mkdir -p  /export/servers/kafka_2.11-1.0.0/logs 
cd /export/servers/kafka_2.11-1.0.0/config
vim server.properties
broker.id=0 #
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/export/servers/kafka_2.11-1.0.0/logs #
num.partitions=2
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.flush.interval.messages=10000
log.flush.interval.ms=1000
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
zookeeper.connect=node1:2181,node2:2181,node3:2181 # 
zookeeper.connection.timeout.ms=6000
group.initial.rebalance.delay.ms=0
delete.topic.enable=true #
host.name=node1 #

4、安装包分发到其他服务器上面去

node1执行以下命令,将node1服务器的kafka安装包发送到node2和node3服务器上面去

cd /export/servers/
scp -r kafka_2.11-1.0.0/ node02:$PWD
scp -r kafka_2.11-1.0.0/ node03:$PWD

5、node2与node3服务器修改配置文件

node2使用以下命令修改kafka配置文件(server.properties)

broker.id=1
host.name=node2

node3使用以下命令修改kafka配置文件(server.properties)

broker.id=2
host.name=node3

6、kafka集群启动与停止

注意事项:在kafka启动前,一定要让zookeeper启动起来。
node1执行以下命令将kafka进程启动在后台

cd /export/servers/kafka_2.11-1.0.0
nohup bin/kafka-server-start.sh config/server.properties 2>&1 &

node2执行以下命令将kafka进程启动在后台

cd /export/servers/kafka_2.11-1.0.0
nohup bin/kafka-server-start.sh config/server.properties 2>&1 &

node3执行以下命令将kafka进程启动在后台

cd /export/servers/kafka_2.11-1.0.0
nohup bin/kafka-server-start.sh config/server.properties 2>&1 &

三台机器也可以执行以下命令停止kafka集群

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-server-stop.sh

三、Kafka集群操作

1.基本命令

1、创建topic
创建一个名字为test的主题, 有三个分区,有两个副本
node1执行以下命令来创建topic

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-topics.sh --create --partitions 3 --replication-factor 2 --topic test --zookeeper node1:2181,node2:2181,node3:2181

2、查看主题命令
查看kafka当中存在的主题
node1使用以下命令来查看kafka当中存在的topic主题

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-topics.sh  --list --zookeeper node1:2181,node2:2181,node3:2181

3、生产者生产数据
模拟生产者来生产数据
node1服务器执行以下命令来模拟生产者进行生产数据

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-console-producer.sh --broker-list node1:9092,node2:9092,node3:9092 --topic test

4、消费者消费数据
node2服务器执行以下命令来模拟消费者进行消费数据

cd /export/servers/kafka_2.11-1.0.0
using the new consumer by passing [bootstrap-server] instead of [zookeeper]
bin/kafka-console-consumer.sh --from-beginning --topic test  --zookeeper node01:2181,node02:2181,node03:2181
bin/kafka-console-consumer.sh --bootstrap-server node1:9092,node2:9092,node3:9092 --from-beginning --topic test

5、运行describe topics命令

node1执行以下命令运行describe查看topic的相关信息

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-topics.sh --describe --zookeeper node1:2181 --topic test

6、增加topic分区数
任意kafka服务器执行以下命令可以增加topic分区数

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-topics.sh --zookeeper node1:2181 --alter --topic test --partitions 4

在这里插入图片描述
7、增加配置
动态修改kakfa的配置
任意kafka服务器执行以下命令可以增加topic分区数

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-topics.sh --zookeeper node1:2181 --alter --topic test --config flush.messages=1

8、删除配置
动态删除kafka集群配置

cd /export/servers/kafka_2.11-1.0.0
bin/kafka-topics.sh --zookeeper node1:2181 --alter --topic test --delete-config flush.messages

9、删除topic
目前删除topic在默认情况下知识打上一个删除的标记,在重新启动kafka后才删除。如果需要立即删除,则需要在

server.properties中配置:
delete.topic.enable=true
然后执行以下命令进行删除topic
kafka-topics.sh --zookeeper node1:2181--delete --topic test

2.kafka的JavaAPI操作

1、创建maven工程并添加jar包

创建maven工程并添加以下依赖jar包的坐标到pom.xml

<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>1.0.0</version>
</dependency>    
    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-streams</artifactId>
        <version>1.0.0</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <!-- java编译插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.2</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

2、生产者代码

package cn.itcast.kafka.demo1;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.util.Properties;

/**
 * 向test topic里面发送数据
 */
public class MyProducer {
   
    public static void main(String[] args) {
   
        Properties props = new Properties();
        //指定Kafka的服务器地址
        props.put("bootstrap.servers", "node1:9092,node2:9092,node3:9092");
        //消息确认机制
        props.put("acks", "all");
        //重试机制
        props.put("retries", 0);
        //批量发送的大小
        props.put("batch.size", 16384);
        //消息的延迟
        props.put("linger.ms", 1);
        //消息缓冲区大小
        props.put("buffer.memory", 33554432);
        //定义key和value的序列化
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        //第四种自定义分区需要添加,自定义类
        props.put("partitioner.class","cn.itcast.kafka.demo1.MyPartitioner");

        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(props);
        for (int i=0;i<100;i++){
   
        	//第一种:既没有指定key,也没有指定分区号,使用轮询的方式
            kafkaProducer.send(new ProducerRecord<>("test","这是第" + i + "条数据"));
            //第二种:指定数据key,使用key的hashCode码值来进行分区,一定要注意,key要变化
            kafkaProducer.send(new ProducerRecord<>("test", "mykey"+i,"这是第" + i + "条数据"));
            //第三种:指定分区号来进行分区
            kafkaProducer.send(new ProducerRecord<>("test", 1,"mykey"+i,"这是第" + i + "条数据"));
            //第四种:自定义分区策略,不需要指定分区号,如果指定了分区号还是会发送到指定的分区
            kafkaProducer.send(new ProducerRecord<>("test","mykey"+i,"这是第" + i + "条数据"));
        }
        kafkaProducer.close();

    }
}
package cn.itcast.kafka.demo1;

import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;

import java.util.Map;

public class MyPartitioner implements Partitioner {
   
    /**
     * 通过这个方法来自定义我们数据的分区规则
     * @param topic
     * @param key
     * @param keyBytes
     * @param value
     * @param valueBytes
     * @param cluster
     * @return 返回int值,这个值就是分区号
     */
    @Override
    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
   
        return 3;
    }

    @Override
    public void close() {
   

    }

    @Override
    public void configure(Map<String, ?> configs) {
   

    }
}

在这里插入图片描述

kafka的数据的分区策略:
kafka五个分区:由于某种原因 0,1,2三个分区里面的数据太多,3,4分区里面的数据太少。

ProducerRecord源码翻译:
如果指定了分区号,直接将数据发送到指定的分区里面去
如果没有指定分区号,数据带了发送的key,通过key取hashCode决定数据究竟发送到哪一个分区里面去
如果既没有指定分区号,也没有指定数据key,使用 round-robin fashion  轮询策略
如果使用key来作为分区的依据,key一定要是变化的,保证数据发送到不同的分区里面去

分区方式:

第一种:既没有指定key,也没有指定分区号,使用轮询的方式
第二种:指定数据key,使用key的hashCode码值来进行分区,一定要注意,key要变化
第三种:指定分区号来进行分区
第四种:自定义分区策略

3、消费者代码

3.1、自动提交offset
package cn.itcast.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.util.Arrays;
import java.util.Properties;

public class MyConsumer {
   
    public static void main(String[] args) {
   
        Properties props = new Properties();
        //指定Kafka的服务器地址
        props.put("bootstrap.servers", "node1:9092,node2:9092,node3:9092");
        //指定消费组的名字
        props.put("group.id", "testGroup");
        //允许程序自动提交offset 提交offset保存到了Kafka当中的一个topic中取
        props.put("enable.auto.commit", "true");
        //每隔多长时间提交一次offset的值
        /**
         * 157 hello offset 上一秒提交的offset
         *
         * 287 hello world
         * 295 abc test 900ms 宕机了怎么办?
         * 351 hello abc 1000ms
         *
         * 有可能造成重复消费的一些问题
         *
         */
        props.put("auto.commit.interval.ms", "1000");
        //定义key和value的序列化
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        //定义KafkaConsumer
        KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(props);
        //订阅test这个topic,去消费这个topic里面的数据
        kafkaConsumer.subscribe(Arrays.asList("test"));
        //使用死循环拉取数据
        while(true){
   
            //所有拉取的数据都封装在了ConsumerRecords
            ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(1000);
            //consumerRecord就是我们每一条数据
            
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值