kafka是一种高吞吐量的分布式发布订阅消息系统。和rabbitMq各占半臂江山
消息队列中间件(简称消息中间件)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步等等功能
RabbitMQ 是采用 Erlang 语言实现的 AMQP 协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。RabbitMQ 发展到今天,被越来越多的人认可,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。
Kafka 起初是由 LinkedIn 公司采用 Scala 语言开发的一个分布式、多分区、多副本且基于 zookeeper 协调的分布式消息系统,现已捐献给 Apache 基金会。它是一种高吞吐量的分布式发布订阅消息系统,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如 Cloudera、Apache Storm、Spark、Flink 等都支持与 Kafka 集成。
1.Rabbitmq在与routing 而kafka在于streaming
2.kafka不支持延迟队列,死信队列 rabbitmq支持死信队列
3.都支持持久化
4.kafka不支持多租户,rabbitmq支持
5.广播消费 kafka支持较好,更加正统
6.rabbitmq支持优先级队列,优先级设置在0-10之间
7.消息堆积,kafka比rabbitmq要好很多
8.消息跟踪 kafka不支持 rabbitmq支持 但大幅度影响性能
9.kafka消息直接写入磁盘,而不是内存当中,kafka的log文件目录就是kafka数据文件。
不写入内存,消息不容易丢失。
rabbitMQ安装请参考
juejin.im/post/5cce82…
kafka特点:
1.以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。 2.高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒 100K 条以上消息的传输
kafka设计思想
1.Consumergroup:各个consumer可以组成一个组,每个消息只能被组中的一个consumer消费,如果一个消息可以被多个consumer消费的话,那么这些consumer必须在不同的组。
2.消息状态:在Kafka中,消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。
3.消息持久化:Kafka中会把消息持久化到本地文件系统中,并且保持极高的效率。
4.消息有效期:Kafka会长久保留其中的消息,以便consumer可以多次消费,其中很多细节是可配置的。
5.批量发送:Kafka支持以消息集合为单位进行批量发送,以提高push效率。
6.push-and-pull : Kafka中的Producer和consumer采用的是push-and-pull模式,即Producer只管向broker push消息,consumer只管从broker pull消息,两者对消息的生产和消费是异步的。
7.Kafka集群中broker之间的关系:不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。
8.负载均衡方面: Kafka提供了一个 metadata API来管理broker之间的负载(对Kafka0.8.x而言,对于0.7.x主要靠zookeeper来实现负载均衡)。
9.同步异步:Producer采用异步push方式,极大提高Kafka系统的吞吐率(可以通过参数控制是采用同步还是异步方式)。
10.分区机制partition:Kafka的broker端支持消息分区,Producer可以决定把消息发到哪个分区,在一个分区中消息的顺序就是Producer发送消息的顺序,一个主题中可以有多个分区,具体分区的数量是可配置的。分区的意义很重大,后面的内容会逐渐体现。
11.离线数据装载:Kafka由于对可拓展的数据持久化的支持,它也非常适合向Hadoop或者数据仓库中进行数据装载。
12.插件支持:现在不少活跃的社区已经开发出不少插件来拓展Kafka的功能,如用来配合Storm、Hadoop、flume相关的插件。
kafka 应用场景
1.日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
2.消息系统:解耦和生产者和消费者、缓存消息等。
3.用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
4.运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
5.流式处理:比如spark streaming和storm
6.事件源
官网kafka实例版本的问题。
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
当kafka的版本是 kafka_2.12-2.1.1,不支持bootstrap-server
报错"bootstrap-server is not a recognized option"
option,换成版本kafka_2.12-2.2.0就ok了。应该是2.2.0的新特性。
kafka isr机制
isr的全称是In-Sync Replicas isr(已同步的副本) 是一个副本的列表,里面存储的都是能跟leader 数据一致的副本,确定一个副本在isr列表中,有2个判断条件
条件1:根据副本和leader 的交互时间差,如果大于某个时间差 就认定这个副本不行了,就把此副本从isr 中剔除,此时间差根据
配置参数rerplica.lag.time.max.ms=10000 决定 单位ms
条件2:根据leader 和副本的信息条数差值决定是否从isr
中剔除此副本,此信息条数差值根据配置参数rerplica.lag.max.messages=4000 决定单位条
isr 中的副本删除或者增加 都是通过一个周期调度来管理的
request.required.acks 的参数说明:
0:生产者只管发送,不管服务器,消费者是否收到信息
1:只有当leader 确认了收到消息,才确认此消息发送成功
-1:只有isr 中的n-1个副本(leader 除外所以n-1)都同步了消息 此消息才确认发送成功
生产者发送的消息只有在确认发送成功后 才能被消费者消费
kafka设计
一个Topic可以认为是一类消息,每个topic将被分成多个partition(区),每个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型数字,它是唯一标记一条消息。它唯一的标记一条消息。kafka并没有提供其他额外的索引机制来存储offset,因为在kafka中几乎不允许对消息进行“随机读写” offset 是保存在zookeeper之中的。
kafka消费
对于consumer而言,它需要保存消费消息的offset,对于offset的保存和使用,有consumer来控制;当consumer正常消费消息时,offset将会"线性"的向前驱动,即消息将依次顺序被消费.事实上consumer可以使用任意顺序消费消息,它只需要将offset重置为任意值。
kafka状态
kafka集群几乎不需要维护任何consumer和producer状态信息,这些信息有zookeeper保存;因此producer和consumer的实现非常轻量级,它们可以随意离开,而不会对集群造成额外的影响。
kafka的leader选举规则
当leader失效时,需在followers中选取出新的leader,可能此时follower落后于leader,因此需要选择一个"up-to-date"的follower.选择follower时需要兼顾一个问题,就是新leader上所已经承载的partition leader的个数,如果一个server上有过多的partition leader,意味着此server将承受着更多的IO压力.在选举新leader,需要考虑到"负载均衡"。
kafka日志删除
日志文件的删除策略非常简单:启动一个后台线程定期扫描log file列表,把保存时间超过阀值的文件直接删除(根据文件的创建时间).为了避免删除文件时仍然有read操作(consumer消费),采取copy-on-write方式。
CopyOnWrite机制
当我们往容器中添加一个元素的时候,不是直接添加,而是对当前容器copy,复制一个容器,在这个复制的容器中添加元素,添加完之后,再将引用指向这个新容器。
优点:CopyOnWrite容器可以并发的进行读操作,而不需要加锁,因为 当前容器不会添加任何元素,所以这也是一种读写分离的思想,读和写的操作分开了。
缺点:
1.内存占用问题,产生了两个容器
2.只能保持数据的最终一致性,无法保持 实时性,所以如果希望读到新数据,不要用copyOnWrite
RabbitMQ与kafka的消息队列模式
1.生产端发送一条消息通过路由投递到Queue,只有一个消费者能消费到。
当RabbitMQ需要支持多订阅时,发布者发送的消息通过路由同时写到多个Queue,不同订阅组消费不同的Queue。所以支持多订阅时,消息会多个拷贝。
kafka
Kafka只支持消息持久化,消费端为拉模型,消费状态和订阅关系由客户端端负责维护,消息消费完后不会立即删除,会保留历史消息。因此支持多订阅时,消息只会存储一份就可以了。但是可能产生重复消费的情况。
如下图,kafka集群中,leader标识的是brokerid,后面的Isr(已同步的副本)也是brokerid。 从后面的一条记录可以看出,当其中一个broker down了以后会从Isr列表中清除掉。但是Replicas仍然保存。
kafka Connect 导入导出数据
kafka Connect是kafka附带的一个工具,用于将数据导入和导出到kafka。是一个可扩展的工具,运行连接器,实现与外部系统的交互的自定义逻辑。
官网的例子分为以下几个步骤:(以单个broker为例)
- 启动zookeeper
bin/zookeeper-server-start.sh config/zookeeper.properties - 启动broker server
bin/kafka-server-start.sh config/server.properties - 在kafka目录创建文件test.txt 文件名若更改,配置文件需要同步修改
echo -e "foo\nbar" > test.txt - 启动connect
bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-source.properties config/connect-file-sink.properties - 查看kafka
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic connect-test --from-beginning - 查看kafka对应的目录
kafka Streams
kafka Streams是kafka的0.10提供的新能力,用于实时处理kafka中的数据流。和现有的流处理技术如SparkStreaming,Storm,Flink还是有些区别的。
Kafka Streams是一套处理分析Kafka中存储数据的客户端类库,处理完的数据或者写回Kafka,或者发送给外部系统。它构建在一些重要的流处理概念之上:区分事件时间和处理时间、开窗的支持、简单有效的状态管理等。
Kafka Streams入门的门槛很低:很容易编写单机的示例程序,然后通过在多台机器上运行多个实例即可水平扩展从而达到高吞吐量。Kafka Streams利用Kafka的并发模型以实现透明的负载均衡。
Kafka Streams的价值体现在以下几点,首先它提供了两套轻量且易用的API有效降低了Kafka数据流处理的开发成本,在这之前可以使用SparkStreaming(不支持单条消费)、Storm(必须使用Trident才支持时间窗),或者自己写consumer(以前高层API还好,低层API是初学者的噩梦,最欢乐的是官方将低层API称为“Simple API”),现在至少又多了一种选择。其次用它开发的应用支持跑在Yarn、Mesos、Docker或者纯Java应用内,比较灵活。再次是数据流的两种抽象比较有意思,目前我还没有深入研究,但觉得用来处理不去重/去重的场景简直太方便了。当然缺点也有,首先目前不支持异步操作,这就需要开发者小心在处理方法中不能有高开销动作,否则整个处理线程阻塞。另外如果需要SQL接口或者ML能力,那还是去找SparkStreaming吧。
下图展示了Kafka Streams应用程序的解剖图,让我们来看一些细节。
kafka的流实例参考
juejin.im/post/5cd50a…
kafka 消费的时候为什么每个consumer只能消费一个partition? 为什么每个partition只能有一个consumer。
kafka参数理解
在老的版本中仅只能用--zookeeper,在最新的版本中支持bootstrap-server。
bootstrap-server指定了kafka的server地址,就无需再指定zookeeper地址。
zookeeper已经是不建议使用的参数。
登录zookeeper客户端,查看zookeeper中存储的信息
linux IO过程
kafka实现高吞吐量的零拷贝机制
传统的IO机制
以将磁盘文件通过网络发送为例。传统模式下,一般使用如下伪代码所示的方法先将文件数据读入内存,然后通过Socket将内存中的数据发送出去。
buffer = File.read
Socket.send(buffer)
这一过程实际上发生了四次数据拷贝。首先通过系统调用将文件数据读入到内核态Buffer(DMA拷贝),然后应用程序将内存态Buffer数据读入到用户态Buffer(CPU拷贝),接着用户程序通过Socket发送数据时将用户态Buffer数据拷贝到内核态Buffer(CPU拷贝),最后通过DMA拷贝将数据拷贝到NIC Buffer。
传统的如下图所示
这一过程实际上发生了四次数据拷贝。首先通过系统调用将文件数据读入到内核态 Buffer(DMA 拷贝),然后应用程序将内存态 Buffer 数据读入到用户态 Buffer(CPU 拷贝),接着用户程序通过 Socket 发送数据时将用户态 Buffer 数据拷贝到内核态 Buffer(CPU 拷贝),最后通过 DMA 拷贝将数据拷贝到 NIC Buffer。同时,还伴随着四次上下文切换.
kafka在zookeeper中存储结构
ActiveMQ
基于java开发,是Apache出品的、采用Java语言编写的完全基于JMS1.1规范的面向消息的中间吗件。其最新架构被命名为Apollo,京东的消息中间件就是基于activeMQ开发的。
优点:
- 夸平台
- 可以用JDBC:可以将数据持久化到数据库
- 支持JMS :支持JMS的统一接口
- 支持自动重连
- 有安全机制:支持基于shiro,jaas等多种安全配置机制,可以对Queue/Topic进行认证和授权
- 监控完善:拥有完善的监控,包括Web Console,JMX,Shell命令行,Jolokia的REST API
- 界面友善:提供的Web Console可以满足大部分情况,还有很多第三方的组件可以使用,如hawtio
缺点:
- 社区活跃度不及RabbitMQ高
- 会出莫名其妙的问题,会丢失消息
- 不适合用于上千个队列的应用场景
zeroMQ
基于C开发,号称史上最快的队列。虽然大多数时候我们习惯将其归入消息队列家族之中,但是其和前面的几款有着本质的区别,ZeroMQ本身就不是一个消息队列服务器,更像是一组底层网络通讯库,对原有的Socket API上加上一层封装而已。
优点:
- 号称最快的消息队列系统,尤其针对大吞吐量的需求场景
- 单独部署或集成到应用中使用,不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演了这个服务角色
- 能够实现高级/复杂的队列,但是开发人员需要自己组合多种技术框架
- 跨平台,多语言支持
- 可作为Socket通信库使用
缺点:
- 仅提供非持久性的队列,也就是说如果down机,数据将会丢失
RocketMQ
基于java开发的,阿里消息中间。件目前已经捐献个Apache基金会,它是由Java语言开发的,具备高吞吐量、高可用性、适合大规模分布式系统应用等特点,经历过双11的洗礼。
优点 :
- 单机支持 1 万以上持久化队列
- RocketMQ 的所有消息都是持久化的,先写入系统pagecache(页高速缓冲存储器),然后刷盘,可以保证内存与磁盘都有一份数据 ,访问时,直接从内存读取
- 模型简单,接口易用
- 性能非常好,可以大量堆积消息在broker(集群中包含一个或多个服务器,这些服务器被称为broker)中
- 支持多种消费,包括集群消费、广播消费等
- 各个环节分布式扩展设计,主从HA(高可用性集群)
- 开发度较活跃,版本更新很快
选取理由:
- 强调集群无单点,任意一点高可用,可水平扩展
- 海量消息堆积能力,消息堆积后, 写入低延迟
- 支持上万个队列
- 消息失败自动重试机制 特点: 设计不遵循任何规范,不遵循JMS规范,但是参考了各种规范,与同类产品的设计思想。
在1.0版本与2.0版本也是采用zookeeper做集群。在3.0的时候抛弃了zookeeper自己内部实现了一个组件nameserver,比zookeeper更加轻量级,更加的稳定。也支持cousumer group。只有一种模式,发布->订阅,不存在点对点的机制。支持持久化,开源的只支持持久到mysql,阿里估计能支持持久到OceanBase 。 存储没有边界的,当存储满的时候会剔除掉最早的记录。
缺点:
- 支持的客户端语言不多,目前是java及c++,其中c++不成熟
- RocketMQ社区关注度及成熟度也不高
- 没有web管理界面,提供了一个CLI(命令行界面)管理工具带来查询、管理和诊断各种问题
- 没有在MQ核心中去实现JMS等接口
Jafka 是在 Kafka 之上孵化而来的,即 Kafka 的一个升级版。具有以下特性:快速持久化,可以在 O(1) 的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到 10W/s 的吞吐速率;完全的分布式系统,Broker、Producer、Consumer 都原生自动支持分布式,自动实现负载均衡;支持 Hadoop 数据并行加载,对于像 Hadoop 的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。