认识kafka

kafka是一个分布式的消息队列由scala编写,不同于传统的一些消息队列,kafka的设计理念与众不同。

1、kafka的特点

快速

单台kafka的broker实例能够支撑几千台机器每秒几百兆字节的读写,如果组成集群性能会更强进,从很多人的测试情况来看kafka的读写性能表现不输于当前流行的消息队,甚至领先很多。

扩展性

弹性透明的扩展,不需要停机,kafka的数据是分区的,可以分布在不同的server中,允许消费者并发的访问。

持久化

集群中的数据被持久化在磁盘上,以防止数据丢失。

分布式

kafka基于cluster-centric理念设计,有很好的容错性。

2、kafka集群架构

要熟悉kafka首先要了解一下kafka中的几个角色

Broker——上图中间kafka cluster的部分便是由多个Broker组成,每个Broker代表kafka的一个实例。

Producer——producer作为整个消息系统的输入部分,直接通过socket和Broker连接发布消息。

Consumer——consumer作为消息的消费者负责处理消息

无论是kafka集群,还是producer和consumer都依赖于zookeeper来保证系统可用性,zookeeper集群保存一些meta信息。

毋庸置疑何处理消息是一个消息系统核心的功能,比如生产者如何生产消息、消息怎么存储、消费者如何消费消息、消息的可靠性、重复性等等。

3、Topic

topic是kafka抽象出来的一个概念,一个Topic可以被认为是一类消息,每个topic被分成多个partition(区),每个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型数字,它唯一标记一条消息。同一个partition中的消息是有序的,但是针对整个topic中的所有消息kafka不保证有序,这是因为每个partition只允许一个group中的一个consumer消费。

4、kafka设计理念

本小结主要涉及到一些kafka的设计理念,试图从容错性、吞吐量等方面呈现一个比较清晰的kafka视图。

Partition——

kafka中partition的概念非常的巧妙,在某种程度上消费者能够并发的消费消息就是因为partition的存在。一个Topic可以被想象成一个queue,生产者将消息放入topic中,不同的是topic会被分成若干个partition(个数可配置),每个partition在物理上对应一个commit-log日志文件,每次发布消息都会以append的方式新增log,这是一个顺序写磁盘的过程性能上不会有太大的问题,同时在写日志前可以做buffer批量写磁盘。同一个topic的不同partition会分布在不同的server上从而将访问压力分散开发,同时一个partitioin只允许同一个group中的某个消费者消费,group的概念后面会提到。关于哪个partition存放在哪个server上等一些meta信息全部存储在zookeeper上。

消息存储——

kafka集群会保留所有已经发布过的消息,保存的时间可以通过配置文件指定,比如指定两天,则两天前发布的消息不管是否被消费都将被删除。从另一个角度看kafka允许消费者重复消费两天前的消息,这一点可能和很多消息系统不同,同时由于这个特性使得kafka也适合做离线的大数据分析。详细的存储格式可以去官网了解。

分布式——

为了提高kafka的容错性,kafka支持partition的复制策略,可以通过配置文件配置partition的副本个数,类似zookeeper的复制机制,kafka针对partition的复制同样需要选出一个leader,同时由该leader负责partition的读写操作,其他的副本节点只是负责数据的同步。如果leader失效,那么将会有其他follower来接管(成为新的leader),如果flower数据落后leader太多leader会把该flower剔除。由于leader的server承载了全部的请求压力,因此从集群的整体考虑,有多少个partitions就意味着有多少个leader,kafka会将leader均横的分散在每个实例上,来确保整体的性能稳定。一个kafka集群各个节点间可能互为leader和flower。

上图中针对partition-2、partition-4,Broker-1是Broker-2的flower,同理针对partition-1、partition-3,Broker-2是Broker-1的flower,这种设计能够最大化的降低节点宕机带来的风险,同时采用选取leader的方式能够降低代码实现的负责度,如果没有leader则需要考虑N*N的复制路径,一方面实现起来复杂另一方面效率也不一定会好。

Push和Pull——

kafka在获取消息方面采用了比较传统的模式,生产者负责push消息,消费者采用pull的方式拉取消息。push模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。push模式的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而pull模式则可以根据consumer的消费能力以适当的速率消费消息。而在scribe和flume系统中则完全使用的是另外一种模式。

zero-copy——

从kafka设计的特点可以看出网络操作和文件操作非常频繁,为了提高效率,kafka在push或者poll消息的时候通常会分成组也就是先buffer一下再批量的进行操作。与此同时为了更好地效率kafka使用了linux系统提供的senfile系统。在理解sendfile之前有必要了解一下传统的文件操作或者socket是怎么处理的,假设需要把本地磁盘的文件通过socket发送给远端,首先需要read到内存然后通过socket发送,整个过程可以用下面一张图表示:

               

linux系统分为内核态和用户态分别对应上图的kernel context和appliaction context,在这两种形态之间发生切换是很消耗资源的,但是一个发送文件的过程确发生了四次这样的切换,用户态对应应用程序的空间,首先由应用程序发出read请求,切换到内核态,由内核完成数据的读取,然后返回给应用,此时发生两次切换和数据的两次拷贝DMA copy和CPU copy。但这仅仅是发送数据准备的过程,发送的过程同样发生上下文的两次切换和数据的两次拷贝,来来回回发生了很多次的拷贝,zero-copy的出现就是消除不必要的copy动作。java已经提供了类似的api比如FileChannel的transferTo(),类似的api在高性能的通讯框架中应用的很广泛比如Netty。下面两张图描述了早期zero-copy的流程:

                                 

transferTo()方法免去了内核到用户态数据的copy,从而直接将读取到的buffer传输到socket buffer,拷贝过程省去了一次,上下文切换少了两次。但是事情到此还没有结束,后面经过代码的优化数据复制的次数还能减少,只是2.4版本以上的linux才支持,优化后的流程类似下面:

上图内核的操作少了一步,原先需要内核将read buffer的数据传输到socket buffer然后由DMA拷贝到NIC buffer由网卡发送,现在是在read buffer加上一些描述符,从而由DMA直接拷贝read buffer对应的发送数据到NIC buffer,整个拷贝过程减少到了两次,性能大大的提高了。

Producer——

producer负责生产消息,producer会和topic中所有的partition leader保持socket,然后直接将消息发送到对应的broker上,因此消息的负载均衡完全由producer测来负责,默认kafka提供了轮询的方式。kafka中的producer和consumer都是非常轻量级的,因为producer不需要保存客户端消费消息的记录,这些数据由consumer维护,实际上consumer也仅仅维护一个叫做offset的东西。

Consumer——

针对消息系统通常都会有两种模式一种类似Queue,就是消息队列中的消息只会由一个消费者消费,另一种是订阅——发布模式,只要订阅该消息的消费者都会收到广播的消息。Kafka才用了consumer group的概念来支持这两种方式,一个consumer group包含若干个consumer,topic中的消息只会被订阅该topic的group中的一个consumer消费。如果所有的消费者拥有相同的group则类似Queue的方式,topic中的消息将在consumer中达到负载均衡。如果每个consumer都属于不同的group则很类似订阅——发布,消息会广播给所有的消费者。consumer消费消息的方式是通过改变offset来实现的,offset和partition一一对应并且保存在zookeeper上,consumer会定期的更新offset的值到zookeeper上。consumer默认支持reblance,该特性很好的达到了consumer的容错和扩展功能,举例来说:

上面就是reblance的过程,但是它有一个明显的缺点是消费者可能负载会不均衡,同时kafka建议partition的个数不能少于consumer的个数,如果不满足会出现有的consumer永远不会消费到消息。如果reblance算法不能满足使用需求,可以使用simple level api自己定义均衡算法,这种方式更灵活,同时应用的可能也更广泛。

消息传输机制——

1) at most once:最多一次,消息只发送一次,不管是否成功处理都不会重发。

考虑消费者从broker获取到消息后然后触发commit动作,该动作会将offset的值写入到zk,下一次获取消息的时候会根据此偏移量获取,如果在commit后消费者处理消息失败则消费者永远不会再处理到该消息(offset以持久到zk)。

2) at least once::消息至少发送一次,如果消息未能成功处理,可能会重发直到成功。

考虑消费者从broker获取消息后先进行处理,等处理完在commit,但是在commit之前系统崩溃,这会导致系统下次还会再一次处理该消息,因此如果对消息的重复处理有严格的要求,比如扣费,则需要慎重使用该项,可以从接口设计方面改善,比如将扣费接口设计成幂等性的操作,从而避免消息重复发送造成的重复扣费。

3) exactly once:消息只会发送一次。

kafka中并没有严格的去实现(基于2阶段提交,事务),如果一定要做到exactly once ,就需要协调offset和实际操作的输出。精典的做法是引入两阶段提交,但是如果能让offset和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,consumer拿到数据后可能把数据放到HDFS,如果把最新的offset和数据本身一起写到HDFS,那就可以保证数据的输出和offset的更新要么都完成,要么都不完成,间接实现exactly once。offset的处理可以使用simple
level api自定义去完成。

两阶段提交的实现比较麻烦,它需要事务的协调者和事务的所有参与者之间经过多次消息的确认才能完成一个完成的事务提交动作,

中间任何一步出错,所有参与者的事务都需要回滚。

时间: 2024-10-11 22:20:23

认识kafka的相关文章

Kafka----Apache Kafka官网首页

Apache Kafka  是发布-订阅机制的消息系统,可以认为具有分布式日志提交功能. Fast-快速 一个单独的Kafka  broker每秒可以处理来自成千上万个客户端的数百兆字节的读写操作. Scalable-可扩展性 对于大规模系统来说,一个单独的kafka集群从设计上就实现了数据中心的功能,而且无需宕机就能提供弹性而又透明的扩展,在数据存储方式上,kafka采用了分区设计理念,它通过将数据分别存储在集群中服务器这种方式,使得集群存储能力远大于单个服务器,这样也使得消费者可以从集群中不

rabbitMQ、activeMQ、zeroMQ、Kafka、Redis 比较

Kafka作为时下最流行的开源消息系统,被广泛地应用在数据缓冲.异步通信.汇集日志.系统解耦等方面.相比较于RocketMQ等其他常见消息系统,Kafka在保障了大部分功能特性的同时,还提供了超一流的读写性能. 针对Kafka性能方面进行简单分析,相关数据请参考:https://segmentfault.com/a/1190000003985468,下面介绍一下Kafka的架构和涉及到的名词: Topic:用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上. Parti

kafka入门:简介、使用场景、设计原理、主要配置及集群搭建(转)

问题导读: 1.zookeeper在kafka的作用是什么? 2.kafka中几乎不允许对消息进行"随机读写"的原因是什么? 3.kafka集群consumer和producer状态信息是如何保存的? 4.partitions设计的目的的根本原因是什么? 一.入门 1.简介 Kafka is a distributed,partitioned,replicated commit logservice.它提供了类似于JMS的特性,但是在设计实现上完全不同,此外它并不是JMS规范的实现.k

kafka producer实例及原理分析

1.前言 首先,描述下应用场景: 假设,公司有一款游戏,需要做行为统计分析,数据的源头来自日志,由于用户行为非常多,导致日志量非常大.将日志数据插入数据库然后再进行分析,已经满足不了.最好的办法是存日志,然后通过对日志的分析,计算出有用的数据.我们采用kafka这种分布式日志系统来实现这一过程. 步骤如下: 搭建KAFKA系统运行环境 如果你还没有搭建起来,可以参考我的博客: http://zhangfengzhe.blog.51cto.com/8855103/1556650 设计数据存储格式

windows 下部署kafka 日记 转

windows 下部署kafka 日记 转一.下载去apache 的官网(http://kafka.apache.org/downloads.html)下载最新的二进制版的压缩包.目前的最新版本是kafka_2.11-0.8.2.1.tgz.二.解压直接解压到D 盘根目录下.三.修改配置文件注意版本不同,可能配置文件不同.请参照实际情况修改.1.修改log4j.properties 文件中的“kafka.logs.dir=logs ”为“kafka.logs.dir=/tmp/logs”.2.修

Kafka Server写数据的时候报错org.apache.kafka.common.errors.RecordTooLargeException

向Kafka中输入数据,抛异常org.apache.kafka.common.errors.RecordTooLargeException 官网两个参数描述如下: message.max.bytes The maximum size of message that the server can receive int 1000012 [0,...] high fetch.message.max.bytes 1024 * 1024 The number of byes of messages to

kafka Consumer分区数与多线程消费topic

单线程消费数据适合在本地跑. 参考文档: http://kafka.apache.org/documentation.html 对于一个topic,可以发送给若干个partitions. partition在创建topic的时候就指定分区的数目. 分区.Offset.消费线程.group.id的关系 1)一组(类)消息通常由某个topic来归类,我们可以把这组消息"分发"给若干个分区(partition),每个分区的消息各不相同: 2)每个分区都维护着他自己的偏移量(Offset),记

kafka中处理超大消息的一些考虑

Kafka设计的初衷是迅速处理短小的消息,一般10K大小的消息吞吐性能最好(可参见LinkedIn的kafka性能测试).但有时候,我们需要处理更大的消息,比如XML文档或JSON内容,一个消息差不多有10-100M,这种情况下,Kakfa应该如何处理? 针对这个问题,有以下几个建议: 最好的方法是不直接传送这些大的数据.如果有共享存储,如NAS, HDFS, S3等,可以把这些大的文件存放到共享存储,然后使用Kafka来传送文件的位置信息. 第二个方法是,将大的消息数据切片或切块,在生产端将数

跟我一起学kafka(一)

从昨天下午接到新任务,要采集一个法院网站得所有公告,大概是需要采集这个网站得所有公告列表里得所有txt内容,txt文件里边是一件件赤裸裸得案件,记录这案由,原告被告等相关属性(不知道该叫什么就称之为属性吧,汗),把这些文件放到本地某个目录,并把一个案件作为一条数据放入数据库中.本以为很轻松得用Jsoup就可以完成,但是我还是低估了政府部门填写数据得人得不规范性,你妹啊,一会英文冒号,一会中文冒号,一会当事人,一会原告人得......气死我了,昨天晚回家了一个钟头,今天又忙活到下午3点才算采集完毕

kafka无法发送消息问题处理

背景 在服务器上搭建了一个单机环境的kafka broker,在服务器上使用命令生产消息时,一切正常.当在本地使用JAVA程序发送消息时,一直出错. 抛出的错误为: Exception in thread "main" Failed to send requests for topics test with correlation ids in [0,12] kafka.common.FailedToSendMessageException: Failed to send messag