kafka

Kafka是为大数据而生的消息中间件,在数据采集、传输、存储的过程中发挥着举足轻重的作用。

优点:

  1. 性能卓越,单机写入TPS约在百万条/秒,最大的优点,就是吞吐量高。
  2. 时效性:ms级
  3. 可用性:非常高,kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
  4. 消费者采用Pull方式获取消息, 消息有序, 通过控制能够保证所有消息被消费且仅被消费一次;
  5. 有优秀的第三方Kafka Web管理界面Kafka-Manager;
  6. 在日志领域比较成熟,被多家公司和多个开源项目使用;
  7. 功能支持:功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用。

 

缺点:

  1. Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长;
  2. 使用短轮询方式,实时性取决于轮询间隔时间; 消费失败不支持重试; 支持消息顺序,但是一台代理宕机后,就会产生消息乱序
  3. 存在丢消息可能:在设计层面上就有丢消息的可能(比如定时刷盘,如果掉电就会丢消息)。
  4. 错峰流控:上下游对于事情的处理能力是不同的。比如,Web前端每秒承受上千万的请求,并不是什么神奇的事情,只需要加多一点机器,再搭建一些LVS负载均衡设备和Nginx等即可。但数据库的处理能力却十分有限,即使使用SSD加分库分表,单机的处理能力仍然在万级。由于成本的考虑,我们不能奢求数据库的机器数量追上前端。 这种问题同样存在于系统和系统之间,如短信系统可能由于短板效应,速度卡在网关上(每秒几百次请求),跟前端的并发量不是一个数量级。但用户晚上个半分钟左右收到短信,一般是不会有太大问题的。如果没有消息队列,两个系统之间通过协商、滑动窗口等复杂的方案也不是说不能实现。但系统复杂性指数级增长,势必在上游或者下游做存储,并且要处理定时、拥塞等一系列问题。而且每当有处理能力有差距的时候,都需要单独开发一套逻辑来维护这套逻辑。所以,利用中间系统转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。

消息队列优点:低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。

分析设计一个消息队列时需要考虑到的问题,如RPC、高可用、顺序和重复消息、可靠投递、消费关系解析等。 当你需要使用消息队列时,首先需要考虑它的必要性。可以使用mq的场景有很多,最常用的几种,是做业务解耦/最终一致性/广播/错峰流控等。反之,如果需要强一致性,关注业务逻辑的处理结果,则RPC显得更为合适。

 

Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),

常见可以用于web/nginx日志、访问日志,消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为*开源项目。

Kakfa具有高吞吐、低延迟等特点,在大数据、日志收集等应用场景下被广泛使用。

Kafka部分名词解释如下:

  1. Broker:消息中间件处理结点,Kafka服务端,负责消息的存储和转发。一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群。
  2. Topic:一类消息,例如页面浏览日志、点击日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发。
  3. Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。
  4. Segment:partition物理上由多个segment组成,每个Segment存着消息信息。
  5. Offset:每个partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到partition中。partition中的每个消息都有一个连续的序列号叫做offset,用于partition唯一标识一条消息。
  6. Producer:消息生产者,负责将产生的消息发送到broker。
  7. Consumer:消息消费者,从broker中拉取消息进行消费。
  8. Consumer Group:消费者分组,消息的消费是以组为单位的,每个Consumer必须属于一个group。partition中的每个消息只能被组中的一个consumer(线程)消费,如果一个消息可以被多个consumer(线程)消费的话,那么这些consumer必须在不同的组。
  9. Zookeeper:保存着集群broker、topic、partition等meta数据;另外,还负责broker故障发现,partition leader选举,负载均衡等功能

 体系结构图:

kafka

 

kafka

 

 

 Topic

一个topic是对一组消息的归纳,一个topic可以认为是一类消息。对每个topic,它被分成多个partition,,每个partition在存储层面就是append log文件。也就是说Kafka通过partition对topic做了【日志分区】。

任何发布到此partition的消息都会被追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型的数字,它唯一标记分区中的一条消息。每条消息都被append到partition中,是顺序写磁盘,因此效率非常高(经验证,顺序写磁盘效率比随机写内存还要高,这是Kafka高吞吐率的一个很重要的保证)。连续追加到partition中的消息是有序的、不可变的。在一个可配置的时间段内,Kafka集群保留所有发布的消息,不管这些消息有没有被消费。比如,如果消息的保存策略被设置为2天,那么在一个消息被发布的两天时间内,它都是可以被消费的。之后它将被丢弃以释放空间。Kafka的性能是和数据量无关的常量级的,所以保留太多的数据并不是问题。

 

LOG consumer offset

每个consumer唯一需要维护的数据是消息在【日志】中的位置,也就是offset。

这个offset由consumer来维护:一般情况下随着consumer不断的读取消息,offset的值会不断增加,其实consumer可以以任意的顺序读取消息,

比如它可以将offset设置成为一个旧的值来重读之前的消息。这使得consumer非常的轻量级:它们可以在不对集群和其他consumer造成影响的情况下读取消息。

使用命令行来'tail'消息而不会对其他正在消费消息的consumer造成影响。 将日志分区可以达到以下目的:首先这使得每个日志的数量不会太大,可以在单个服务上保存。另外每个分区可以单独发布和消费,为并发操作topic提供了一种可能。

 

分布式

每个分区在Kafka集群的若干服务中都有副本,这样这些持有副本的服务可以共同处理数据和请求,副本数量是可以配置的。副本使Kafka具备了容错能力。

每个分区都由一个服务器作为"leader",零或若干服务器作为"followers",leader负责处理消息的读和写,followers则去复制leader。

如果leader 宕机了,followers中的一台则会自动成为leader。集群中的每个服务节点都会【同时】扮演两个角色:作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。

 

Producer

Producer将消息发布到它指定的topic中,并负责决定发布到哪个分区。通常简单的由负载均衡机制随机选择分区,但也可以通过特定的分区函数选择分区。一般使用的更多的是第二种。 每一条消息被发送到broker中,会根据partition规则选择被存储到哪一个partition。如果partition规则设置的合理,所有消息可以均匀分布到不同的partition里,这样就实现了水平扩展。(如果一个topic对应一个文件,那这个文件所在的机器I/O将会成为这个topic的性能瓶颈,而partition解决了这个问题)。在创建topic时可以'$KAFKA_HOME/config/server.properties'中指定这个partition的数量,当然可以在topic创建之后去修改partition的数量。 在发送一条消息时,可以指定这个消息的key,producer根据这个key和partition机制来判断这个消息发送到哪个partition。partition机制可以通过指定producer的partition.class这一参数来指定,该class必须实现'kafka.producer.Partitioner'接口。

 

Consumer

发布消息通常有两种模式:队列模式(queuing)和发布/订阅模式(publish-subscribe)。 1)队列模式:consumers可以同时从服务端读取消息,每个消息只被其中一个consumer读到; 2)发布/订阅模式:消息被广播到所有的consumer中,每个consumer都能收到。 Consumers可以加入一个consumer组,在同一个组内共同竞争一个topic,topic中的消息将被分发到组中的一个成员中。同一组中的consumer可以在不同的程序中,也可以在不同的机器上。如果所有的consumer都在一个组中,都抢一个topic,这就成为了传统的队列模式,只有一个会收到消息,在各consumer中实现负载均衡。如果所有的consumer都在不同的组中,这就成为了发布/订阅模式,消息会被分发到所有的consumer中。更常见的是,每个topic都有若干数量的consumer组,每个组都是一个逻辑上的"订阅者",为了容错和更好的稳定性,每个组由若干consumer组成。这其实就是一个发布/订阅模式,只不过订阅者是个组而不是单个consumer。

 

有序性

相比传统的消息系统,Kafka可以很好的保证有序性。传统的队列在服务器上保存有序的消息,如果多个consumers同时从这个服务器消费消息,服务器就会以消息存储的顺序向consumer分发消息。虽然服务器按顺序发布消息,但是消息是被异步的分发到各consumer上,所以当消息到达时可能已经失去了原来的顺序,这意味着并发消费将导致顺序错乱。为了避免故障,这样的消息系统通常使用"专用consumer"的概念,其实就是只允许一个消费者消费消息,当然这就意味着失去了并发性。

Kafka通过分区的概念,可以在多个consumer组并发的情况下提供较好的有序性和负载均衡。将每个分区分只分发给一个consumer组,这样一个分区就只被这个组的一个consumer消费,就可以顺序的消费这个分区的消息。因为有多个分区,依然可以在多个consumer组之间进行负载均衡。注意consumer组中consumer的数量不能多于分区的数量,也就是有多少分区就允许多少并发消费。 Kafka只能保证一个分区之内消息的有序性,在不同的分区之间是不可以的,这已经可以满足大部分应用的需求。如果需要topic中所有消息的有序性,那就只能让这个topic只有一个分区,当然也就只有一个consumer组消费它。

上一篇:rocketmq源码解析namesrvController启动③


下一篇:Kafka面试题