一.消息对列
1.什么是消息对列
我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。比如生产者发送消息1,2,3...对于消费者就会按照1,2,3...的顺序来消费。
2.消息对列的应用场景
消息队列在实际应用中包括如下四个场景:
(1) 应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;
(2) 异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;
(3) 限流削峰:广泛应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况;
(4) 消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理
3.消息对列的两种模式
消息队列包括两种模式,点对点模式(point to point, queue)和发布/订阅模式(publish/subscribe,topic)
4.消息对列实现机制
一.JMS
JMS(JAVA Message Service,Java消息服务)是一个Java平台中关于面向消息中间件的API允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息是一个消息服务的标准或者说是规范,是 Java 平台上有关面向消息中间件的技术规范便于消息系统中的 Java 应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口,简化企业应用的开发。
JMS 消息机制主要分为两种模型:PTP 模型和 Pub/Sub 模型。
实现产品:Apache ActiveMQ
二.AMQP
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条
件的限制。Erlang中的实现有RabbitMQ等。
三.JMS VS AMQP
| JMS | AMQP |
定义 | Java api | Wire-protocol |
跨语言 | 否 | 是 |
跨语平台 | 否 | 是 |
Model | 提供两种消息模型/模式:(1)、Peer-2- Peer(2)、Pub/sub | 提供了五种消息模型:(1)、direct exchange(2)、fanout exchange(3)、topic change(4)、headers exchange(5)、system exchange本质来讲,后四种和JMS的pub/sub模型没有太大差别,仅是在路 由机制上做了更详细的划分; |
支持消息类型 | 多种消息类型:TextMessage、 MapMessage、BytesMessage、 StreamMessage、ObjectMessage、 Message (只有消息头和属性) | byte[]当实际应用时,有复杂的消息,可以将消息序列化后发送。 |
综合评价 | JMS 定义了JAVA API层面的标准;在java 体系中,多个client均可以通过JMS进行交 互,不需要应用修改代码,但是其对跨平 台的支持较差; | AMQP定义了wire-level层的协议标准;天然具有跨平台、跨语言特性。 |
5.常见的消息队列产品
RabbitMQ(https://www.rabbitmq.com/) 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。
ActiveMQ(http://activemq.apache.org/)是由Apache出品,ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。它非常快速,支持多种语言的客户端
和协议,而且可以非常容易的嵌入到企业的应用环境中,并有许多高级功能
RocketMQ(https://github.com/alibaba/RocketMQ)出自 阿里公司的开源产品,用 Java 语言实现,在设计时参考了 Kafka,并做出了自己的一些改进,消息可靠性上比 Kafka 更
好。RocketMQ在阿里集团被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理等。
Apache Kafka(http://kafka.apache.org/)是一个分布式消息发布订阅系统。它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统( a distributed
commit log),之后成为Apache项目的一部分。Kafka系统快速、可扩展并且可持久化。它的分区特性,可复制和可容错都是其不错的特性。
二.Kafka的基本介绍
1. Kafaka简介
Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志、访问日志,消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。
要应用场景是:日志收集系统和消息系统。
2.Kafaka的特点
(1)解耦。Kafka具备消息系统的优点,只要生产者和消费者数据两端遵循接口约束,就可以自行扩展或修改数据处理的业务过程。
(2)高吞吐量、低延迟。即使在非常廉价的机器上,Kafka也能做到每秒处理几十万条消息,而它的延迟最低只有几毫秒。
(3)持久性。Kafka可以将消息直接持久化在普通磁盘上,且磁盘读写性能优异。
(4)扩展性。Kafka集群支持热扩展,Kaka集群启动运行后,用户可以直接向集群添。
(5)容错性。Kafka会将数据备份到多台服务器节点中,即使Kafka集群中的某一台加新的Kafka服务节点宕机,也不会影响整个系统的功
能。
(6)支持多种客户端语言。Kafka支持Java、.NET、PHP、Python等多种语言。
(7) 支持多生产者和多消费者
3.Kafaka的应用场景
消息处理(MQ)
KafKa可以代替传统的消息队列软件,使用KafKa来实现队列有如下优点
(1)KafKa的append来实现消息的追加,保证消息都是有序的有先来后到的顺序,
(2)稳定性强队列在使用中最怕丢失数据,KafKa能做到理论上的写成功不丢失
(3)分布式容灾好
(4)容量大相对于内存队列,KafKa的容量受硬盘影响
(5)数据量不会影响到KafKa的速度
分布式日志系统(Log)
在很多时候我们需要对一些庞大的数据进行存留,日志存储这块会遇到巨大的问题,日志不能丢,日志存文件不好找,定位一条消息成本高(遍历当天日志文件),实时显示给用户难,这几类问题KafKa都能游刃有余
(1)KafKa的集群备份机制能做到n/2的可用,当n/2以下的机器宕机时存储的日志不会丢失
(2)KafKa可以对消息进行分组分片
( 3)KafKa非常容易做到实时日志查询
流式处理
(1)流式处理就是指实时地处理一个或多个事件流。
(2)流式的处理框架(spark, storm , flink) 从主题中读取数据, 对其进行处理, 并将处理后的结果数据写入新的主题, 供用户和应用程序使用,
(3)kafka的强耐久性在流处理的上下文中也非常的有用
三.Kafka架构剖析
1.kafka简略架构图
说明:kafka支持消息持久化,消费端为拉模型来拉取数据,消费状态和订阅关系有客户端负责维护,消息消费完 后,不会立即删除,会保留历史消息。因此支持多订阅时,消息只会存储一份就可以了。
2.内部细节剖析:
Broker:kafka集群中包含一个或者多个服务实例,这种服务实例被称为Broker。
Topic:每条发布到kafka集群的消息都有一个类别,这个类别就叫做Topic。
Partition:分区,物理上的概念,每个topic包含一个或多个partition,一个partition对应一个文件夹,这个文件夹下存储partition的数据和索引文件,每个partition内部是有序的。
3. Topic & Partition
1.Topic 就是数据主题,是数据记录发布的地方,可以用来区分业务系统。
2.Kafka中的Topics总是多订阅者模式,一个topic可以拥有一个或者多个消费者来订阅它的数据。
3.一个topic为一类消息,每条消息必须指定一个topic。
4.对于每一个topic, Kafka集群都会维持一个分区日志。如下图
5.每个分区都是有序且顺序不可变的记录集,并且不断地追加到结构化的commit log文件。
6.分区中的每一个记录都会分配一个id号来表示顺序,称之为offset,offset用来唯一的标识分区中每一条记录。
在每一个消费者中唯一保存的元数据是offset(偏移量)即消费在log中的位置,偏移量由消费者所控制:通常在读取记录后,消费者会以线性的方式增加偏移量,但是实际上,由于这个位置由消费者控制,所以消费者可以采用任何顺序来消费记录。例如,一个消费者可以重置到一个旧的偏移量,从而重新处理过去的数据;也可以跳过最近的记录,从"现在"开始消费。
这些细节说明Kafka 消费者是非常廉价的—消费者的增加和减少,对集群或者其他消费者没有多大的影响。
四.Docker中Kafka, Zookeeper环境搭建
1.在docker中拉取Kafka,Zookeeper镜像
# zookeeper镜像拉取命令 可能需要稍等片刻才能下载完
docker pull wurstmeister/zookeeper
# kafka镜像拉取命令 可能需要稍等片刻才能下载完
docker pull wurstmeister/kafka
2.查看镜像如下命令,看是否拉取成功
docker images
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 a70d36bc331a 7 weeks ago 449MB
wurstmeister/kafka latest cc59b78d943f 2 months ago 438MB
portainer/portainer latest 62771b0b9b09 7 months ago 79.1MB
kibana 7.6.2 f70986bc5191 11 months ago 1.01GB
elasticsearch 7.6.2 f29a1ee41030 11 months ago 791MB
wurstmeister/zookeeper latest 3f43f72cb283 2 years ago 510MB
centos 7 5182e96772bf 2 years ago 200MB
redis latest 4e8db158f18d 2 years ago 83.4MB
tomcat 7-jre7 fa2c33156fb9 2 years ago 357MB
nginx latest c82521676580 2 years ago 109MB
registry latest b2b03e9146e1 2 years ago 33.3MB
sheepkiller/kafka-manager latest 4e4a8c5dabab 2 years ago 463MB
3.安装zookeeper
命令入如下:
docker run -d --name zookeeper -p 2181:2181 wurstmeister/zookeeper
搭建时的记录如下:,命令成功返回一个字符串
[root@localhost ~]# docker run -d --name zookeeper -p 2181:2181 wurstmeister/zookeeper
926152d6415489220fbd1041a51ed6a153bd4fabcf053d72724896df427102db
4.安装kafaka 输入如下命令
(注意: 192.168.200.128是本机宿主机的ip依自己的而言)
docker run -d --name kafka \
--env KAFKA_ADVERTISED_HOST_NAME=localhost \
--env KAFKA_ZOOKEEPER_CONNECT=192.168.200.128:2181 \
--env KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.200.128:9092 \
--env KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
--env KAFKA_HEAP_OPTS="-Xmx256M -Xms128M" \
--net=host wurstmeister/kafka
搭建时的记录如下:,命令成功返回一个字符串
[root@localhost ~]# docker run -d --name kafka \
> --env KAFKA_ADVERTISED_HOST_NAME=localhost \
> --env KAFKA_ZOOKEEPER_CONNECT=192.168.200.128:2181 \
> --env KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.200.128:9092 \
> --env KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
> --env KAFKA_HEAP_OPTS="-Xmx256M -Xms128M" \
> --net=host wurstmeister/kafka
5cac1d0dbadfbeaf0c8a409905e2aaab222c7e62a77feb406ead3223a6df8566
5.进入kafaka容器,新建一个test主题,做为生产者,生产消息
(1)进入kafka容器命令: docker exec -it kafka /bin/bash
docker exec -it kafka /bin/bash
(2)进入到kafka的bin目录下: cd /opt/kafka_2.13-2.7.0/bin (注意自己kafka的版本,可以一层一层目录进入到bin目录下)
搭建时的记录如下:
bash-4.4# cd /opt
bash-4.4# ll
bash: ll: command not found
bash-4.4# ls
kafka kafka_2.13-2.7.0 overrides
bash-4.4# cd ./kafka_2.13-2.7.0
bash-4.4# cd ./bin
bash-4.4# ls
connect-distributed.sh kafka-console-producer.sh kafka-leader-election.sh kafka-run-class.sh trogdor.sh
connect-mirror-maker.sh kafka-consumer-groups.sh kafka-log-dirs.sh kafka-server-start.sh windows
connect-standalone.sh kafka-consumer-perf-test.sh kafka-mirror-maker.sh kafka-server-stop.sh zookeeper-security-migration.sh
kafka-acls.sh kafka-delegation-tokens.sh kafka-preferred-replica-election.sh kafka-streams-application-reset.sh zookeeper-server-start.sh
kafka-broker-api-versions.sh kafka-delete-records.sh kafka-producer-perf-test.sh kafka-topics.sh zookeeper-server-stop.sh
kafka-configs.sh kafka-dump-log.sh kafka-reassign-partitions.sh kafka-verifiable-consumer.sh zookeeper-shell.sh
kafka-console-consumer.sh kafka-features.sh kafka-replica-verification.sh kafka-verifiable-producer.sh
(3)新建一个test主题输入命令回车: ./kafka-topics.sh --create --zookeeper 192.168.200.128:2181 --replication-factor 1 --partitions 1 --topic test
以生产者身份开始生产消息命令回车:
bash-4.4# ./kafka-console-producer.sh --broker-list 192.168.200.128:9092 --topic test
启动后,测试下,输入hellokafaka 回车。
搭建时的记录如下:
bash-4.4# ./kafka-topics.sh --create --zookeeper 192.168.200.128:2181 --replication-factor 1 --partitions 1 --topic test
Created topic test.
bash-4.4# ./kafka-console-producer.sh --broker-list 192.168.200.128:9092 --topic test
>hellokafaka
>
接下来进行下面的步骤6
6. 打开一个新的ssh连接,消费者进行消息的消费
依然是先输入进入容器命令
docker exec -it kafka /bin/bash
通过命令进入到bin目录下
cd /opt/kafka_2.13-2.7.0/bin
启动消费者命令如下
./kafka-console-consumer.sh --bootstrap-server 192.168.200.128:9092 --topic test --from-beginning
结果可以看到生产者生产的 hellokafaka 消息
搭建时的记录如下:
[root@localhost ~]# docker exec -it kafka /bin/bash
bash-4.4# cd /opt/kafka_2.13-2.7.0/bin
bash-4.4# ./kafka-console-consumer.sh --bootstrap-server 192.168.200.128:9092 --topic test --from-beginning
hellokafaka