一、关于消息队列
消息队列是一种应用间的通信方式,消息就是是指在应用之间传送的数据,它也是进程通信的一种重要的方式。
1.消息队列的基本架构
producer:消息生产者。
broker:消息处理中心。
consumer:消息消费者
2.消息队列常用场景
系统之间的解耦。
高并发下的流量消峰(电商抢购活动)。
异步通信(串行变并行)。
3.消息队列的特点
基本上都基于生产者消费者模式。
必须保证数据的可靠性传输。
4、点对点消息系统
在点对点系统中,消息被保留在队列中。 一个或多个消费者可以消耗队列中的消息,但是特定消息只能由最多一个消费者消费。 一旦消费者读取队列中的消息,它就从
该队列中消失。
5、发布 - 订阅消息系统
在发布 - 订阅系统中,消息被保留在主题中。 与点对点系统不同,消费者可以订阅一个或多个主题并使用该主题中的所有消息。
6、为什么需要消息队列
1、解耦 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。 2、冗余 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前, 需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。 3、扩展性 因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。 4、灵活性 & 峰值处理能力 在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息 队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。 5、可恢复性 系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。 6、顺序保证 在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka保证一个Partition内的消息的有序性) 7、缓冲: 有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。 8、异步通信: 很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在 需要的时候再去处理它们
二、kafka
1、kafka架构
1、Producer,消息和数据的生产者,向Kafka的一个topic发布消息的进程/代码/服务,就是向kafka broker发消息的客户端; 2、Consumer,消息和数据的消费者,订阅数据(Topic)并且处理其发布的消息的进程/代码/服务,向kafka broker取消息的客户端; 3、Consumer Group (CG),逻辑概念,这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。 topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个partion只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立 的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic 4、Broker,物理概念,一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic 5、Topic,逻辑概念,Kafka消息的类别,对数据进行分区,隔离,可以理解为一个队列 6、Partition,物理概念,Kafka下数据存储的基本单元,为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition, 每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证 一个topic的整体(多个partition间)的顺序,消费者数目少于或等于Partition的数目。 7、Replication,同一个Partition可能会有多个Replica,多个Replica之间数据是一样的,当集群中有Broke挂掉的情况,系统可以主动的使Replicas提供服务。系统默认 设置每一个Topic的replication系数为1,可以在常见Topic时单独设置,Replication的基本单位是Topic的Partition,所有的读和写都从Leader进,Followers只是作为 备份,Follower必须能够及时复制Leader的数据 8、Replication Leader,一个Partition的多个Replica上,需要一个Leader负责该, Partition上与Producer和Consumer交互,有且只有一个Replication Leader; 9、ReplicaManager,负责管理当前broker所有分区和副本的信息,处理KafkaController发送的一些请求,副本状态切换,添加/读取信息等。
2、Kafka消息结构
1、Offset,message在partition内的偏移量 2、length,消息长度 3、CRC32,校验字段,校验消息的完整性 4、Magic,标志位 5、attribute,可选字段,消息的属性 6、Timestamp,时间戳 7、key length,key的长度 8、key,key 9、Value Length,值的长度 10、Value,值
3、kafka的消息存储和生产消费模型
• 一个topic分成多个partition
• 每个partition内部消息强有序,其中的每个消息都有一个序号叫offset
• 一个partition只对应一个broker,一个broker可以管多个partition
• 消息直接写入文件,并不是存储在内存中
• 根据时间策略(默认一周)删除,而不是消费完就删除
• producer自己决定往哪个partition写消息,可以是轮询的负载均衡,或者是基于hash的partition策略
• kafka里面的消息是有topic来组织的,简单的我们可以想象为一个队列,一个队列就是一个topic,然后它把每个topic又分为很多个partition,这个是为了做并行的,
在每个partition里面是有序的,相当于有序的队列,其中每个消息都有个序号,比如0到12,从前面读往后面写。
• 一个partition对应一个broker,一个broker可以管多个partition,比如说,topic有6个partition,有两个broker,那每个broker就管3个partition。
• 这个partition可以很简单想象为一个文件,当数据发过来的时候它就往这个partition上面append,追加就行,kafka和很多消息系统不一样,很多消息系统是消费完了
就把它删掉,而kafka是根据时间策略删除,而不是消费完就删除,在kafka里面没有一个消费完这么个概念,只有过期这样一个概念
• consumer自己维护消费到哪个offset
• 每个consumer都有对应的group
• group内是queue消费模型
– 各个consumer消费不同的partition
– 一个消息在group内只消费一次
• 各个group各自独立消费,互不影响
4、kafka有哪些特点
• 消息系统的特点:生产者消费者模型,FIFO – partition内部是FIFO的,partition之间呢不是FIFO的,当然我们可以把topic设为一个partition,这样就是严格的FIFO • 高性能:单节点支持上千个客户端,百MB/s吞吐 • 持久性:消息直接持久化在普通磁盘上且性能好 – 直接写到磁盘里面去,就是直接append到磁盘里面去,这样的好处是直接持久话,数据不会丢,第二个好处是顺序写, 然后消费数据也是顺序的读,所以持久化的同时还能保证顺序读写 • 分布式:数据副本冗余、流量负载均衡、可扩展 – 分布式,数据副本,也就是同一份数据可以到不同的broker上面去,也就是当一份数据,磁盘坏掉的时候,数据不会丢失, 比如3个副本,就是在3个机器磁盘都坏掉的情况下数据才会丢。 • 很灵活:消息长时间持久化+Client维护消费状态 – 消费方式非常灵活,第一原因是消息持久化时间跨度比较长,一天或者一星期等,第二消费状态自己维护消费到哪个地方了,可以自定义消费偏移量
5、kafka与其他消息队列对比
• RabbitMQ:分布式,支持多种MQ协议,重量级
• ActiveMQ:与RabbitMQ类似
• ZeroMQ:以库的形式提供,使用复杂,无持久化
• redis:单机、纯内存性好,持久化较差
• kafka:分布式,较长时间持久化,高性能,轻量灵活
• RabbitMQ也是常见的消息对列,它支持多种MQ的协议,jms啊,等多种协议等等,它的缺点比较重
• ActiveMQ也和RabbitMQ类似,支持的协议比较多
• ZeroMQ是一个socket的通信库,它是以库的形式提供的,所以说你需要写程序来实现消息系统,它只管内存和通信那一块,持久化也得自己写,
还是那句话它是用来实现消息队列的一个库,其实在storm里面呢,storm0.9之前,那些spout和bolt,bolt和bolt之间那些底层的通信就是由ZeroMQ
来通信的,它并不是一个消息队列,就是一个通信库,在0.9之后呢,因为license的原因,ZeroMQ就由Netty取代了,Netty本身就是一个网络通信库嘛,
所以说更合适是在通信库这一层,不应该是MessageQueue这一层;
• Redis,本身是一个内存的KV系统,但是它也有队列的一些数据结构,能够实现一些消息队列的功能,当然它在单机纯内存的情况下,性能会比较好,持久化做的稍差,
当持久化的时候性能下降的会比较厉害
• Kafka的亮点,天生是分布式的,不需要你在上层做分布式的工作,另外有较长时间持久化,前面的几个MQ基本消费就干掉了,另外在长时间持久化下性能还比较高,
顺序读和顺序写,另外还通过sendFile这样0拷贝的技术直接从文件拷贝到网络,减少内存的拷贝,还有批量读批量写来提高网络读取文件的性能。
消费状态维护:
6、零拷贝
• 从WIKI的定义中,我们看到“零拷贝”是指计算机操作的过程中,CPU不需要为数据在内存之间的拷贝消耗资源。而它通常是指计算机在网络上发送文件时,
不需要将文件内容拷贝到用户空间(User Space)而直接在内核空间(Kernel Space)中传输到网络的方式。
• 零拷贝技术减少了用户态与内核态之间的切换,让拷贝次数降到最低,从而实现高性能。
• Kafka使用零拷贝技术来进行文件的传输。