kafka之简介
什么是发布订阅消息系统
数据(消息)的发送者(发布者)不会直接把消息发送给接受者,这是发布与订阅消息系统的一个特点。发布者以某种方式对消息进行分类,接受者(订阅者)订阅他们,一遍接收特定类型的消息。发布与订阅系统一般会有一个broker,也就是发布消息的中心点。
什么kafka
Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Cloudera、Apache Storm、Spark等都支持与Kafka集成。
kafka是一款结余发布与订阅的消息系统。它一般被称为“分布式提交日志”或者“分布式流平台”。现在最新版本已经到2.x.x
kafka的架构
一个典型的Kafka体系架构包括若干Producer(可以是服务器日志,业务数据,页面前端产生的page view等等),若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干Consumer (Group),以及一个Zookeeper集群。Kafka通过Zookeeper管理集群配置,选举leader,以及在consumer group发生变化时进行rebalance。Producer使用push(推)模式将消息发布到broker,Consumer使用pull(拉)模式从broker订阅并消费消息。
kafka的优缺点
优点
- 主要有一下几个特点:
- 多个生产者:
- 多个消费者:
- 基于磁盘的数据存储:
- 伸缩性:支持水平扩展
- 高性能:
- 可靠性保证:
Kafka与传统MQ区别:
-
更快!单机上万TPS,高吞吐量、低延迟、高并发
-
持久性、可靠性。传统的MQ,消息被消化掉后会被mq删除,而kafka中消息被消化后不会被删除,而是到配置的expire时间后,才删除
-
传统的MQ,消息的Offset是由MQ维护,而kafka中消息的Offset是由客户端自己维护
-
分布式,可扩展性容错性,把写入压力均摊到各个节点。可以通过增加节点降低压力
为何要用消息系统
-
解耦
在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
-
冗余
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
-
扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。
-
灵活性 & 峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
-
可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
-
顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。Kafka保证一个Partition内的消息的有序性。
-
缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行———写入队列的处理会尽可能的快速。该缓冲有助于控制和优化数据流经过系统的速度。
-
异步通信
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
使用场景
- 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如Hadoop、Hbase、Solr等;
- 消息系统:解耦和生产者和消费者、缓存消息等;
- 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到Hadoop、数据仓库中做离线分析和挖掘;
- 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告;
- 流式处理:比如spark streaming和storm;
kafka中基本概念
消息和批次
kafka的数据单元被称为消息。消息由字节数组组成,所以对于kafa来说,消息里的数据没有特别的格式或含义。消息可以有一个可选的元数据,也就是键。键也是一个字节数组,与消息一样,对于kafka来说也没有特殊的含义。当消息以一种可控的方式写入不同的分区时,会用到键。例如:为建生成一个一致性散列值,然后使用散列值对主题分区数进行取模,为消息选择分区。这样可以保证具有相同键的消息总是被写到相同的分区上。
批次是一组消息,这些消息属于同一个主题和分区。为了提高效率,消息是分批次写入kafka。
生产者
kafka的客户端就是kafka系统的用户。一般被分为两种基本类型:生产者和消费者。
生产者创建消息。一般情况下,一个消息会被发布到一个特定的主题上。生产者在默认情况下把消息均衡的分布到主题的所有分区上,而并不关心特定消息会被写到哪个分区。不过,某些情况下,生产者会把消息直接写到指定的分区上。这通常是通过消息键和分区器来实现的,分区器为键生成一个散列值,并将其映射到指定的分区上。这样可以保证包含同一个键的消息被写到同一个分区上。生产者也可以使用自定义的分区器,根绝不同的业务规则将消息映射到分区。
消费者
消费者读取消息。消费者订阅一个或多个主题,按着消息生产的顺序来读取他们。消费者通过检查偏移量来区分已经读取的消息。偏移量是两一个元数据,它是一个不断递增的整数值。在创建消息时,kafka会把它添加到消息里。在给定的分区里,每个消息的偏移量都是唯一的。消费者把每个分区最后读取耳朵消息偏移量保存到zookeeper或者kafka上,如果消费者关闭或者重启,它的读取状态不会丢失。
消费者是消费者群组的一部分,也就是说,会有一个或者多个消费者共同读取一个主题。群组保证每个人去只能被一个消费者使用。消费者与分区之间的映射通常被称为消费者对分区的所有权关系。如果一个消费者失效,群组里的其他消费者可以接管失效的消费者工作。
broker和集群
一个独立的kafka服务器被称为broker。broker接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。broker为消费者提供服务,对读取的分区的请求作出响应,返回已经提交到磁盘上的消息。
broker是集群的组成部分。每个集群都有一个broker同事充当了集群控制器(自动从集群的活跃成员中选举出来)的角色。控制器负责管理工作,包括将分区分配给broker和监控broker。在集群中,一个分区从属于一个broker,该broker被称为分区的首领。
主题
kafka的消息通过主题进行分类。主题就好比数据库的表或者文件系统的文件夹。
分区
主题可以分为若干个分区,一个分区就是一个提交日志。消息以追加的方式写入分区,然后以先入先出的顺序读取。要注意,由于一个主题一般包含几个分区,因此无法在整个主题范围内保证消息的顺序,但是可以保证消息在单个分区内的顺序。
kafka消息物理存储
消息保留机制
消息保留有两个维度:根据时间保留数据和根据字节大小,无论哪个条件先满足,消息都会被删除。这两个维度通过下面配置参数来控制:
- log.retention.ms,log.retention.hours和log.retention.minutes
根据时间来决定数据可以被保留多久。这三个配置的效果是一样的,只是时间单位不一样,默认使用log.retention.hours配置,默认参数是168小时也就是一周。如果指定了不止一个参数,kafka有限使用具有最小值的那个参数。
根据时间保留数据是通过检查磁盘上日志片段文件的最后修改时间来实现的。一般来说,最后修改时间指定的就是日志片段的关闭时间,也就是文件里的最后一个消息的时间戳。不过,在某些特别的情况下,最后修改时间并不是最后一个消息的时间戳,例如:分区移动。
- log.retention.bytes
通过保留的消息字节数来判断消息是否过期。这个是作用在每个分区上的。例如:一个主题有8个分区,此参数设置1G,那么这个主题最多可以保留8G的数据,所以当分区增加时,真个主题可以保留的数据也会随之增加。
以上两个设置都作用在日志片段上,而不是作用在单个消息上。当消息到达broker时,他们被追加到分区的当前日志片段上。当日志片段大小达到log.segment.bytes设置的上限(默认是1G)时,当前日志片段就会被关闭,一个新的日志片段被打开。如果一个日志片段被关闭,就开始等待过期。log.segment.bytes值越小,就会越频繁的关闭和分配新文件,磁盘写入整体效率就会降低。另外还有一个参数log.segment.ms通过指定了多长时间之后日志片段会被关闭。日志片段会在大小或者时间达到上限时被关闭,就看哪个条件先满足。默认log.segment.ms没有设定值,所以只根据大小来关闭日志片段。
要特别注意,日志片段被关闭之前消息是不会过期的,因此日志片段在关闭之前也不会被删除。要等到日志片段的最后一个消息过期此日志片段才能被删除。
消息清理
暂略
索引
消费者可以从kafka的任意可用偏移量位置开始读取消息。我们从某个偏移量开始读取消息时,这个偏移量可能在某个分区的任意一个片段里,我们如何快速的找到这个偏移量以及这个偏移量对应的消息呢?kafka为每个分区维护了一个索引。索引把偏移量映射到片段文件和偏移量在文件里的位置。索引也被分成片段的。所以在删除消息时,也可以删除对应的索引。kafka不维护索引的校验。如果索引发生损坏或者被删除,kafka会通过重新读取消息并录制偏移量和位置自动重新生成这些索引。