Kafka — 概述

接触Kafka之前需要首先理解几个概念。

0、分布式系统

比较常见的概念:建立在计算机网络之上的软件系统,若干独立计算机的集合,这计算机对用户来说就像是单个相关系统。

1、中间件

中间件为软件应用提供了操作系统所提供服务之外的服务,可以把中间件描述为“软件胶水”,让开发者能够方便的处理通信、输入输出、能专注于自己应用的部分。

2、消息中间件

面向消息的中间件是侧重于在分布式系统之间发送和接收消息的软件基础设施。

3、消息队列

存放消息一种队列,常用于分布式应用间信息交换,使生产者与消费者接耦。

4、JMS

Java Message Service 是一种Java 平台关于面向消息中间件的API 规范,用于两个应用程序或者分布式系统之间发送消息完成异步通信。JMS中定义了点对点(Point to point) 、发布订阅(Publish/Subscribe)两种模式。

5、EMS

企业消息引擎系统,是企业发布的一组规范,公司使用这组规范实现在不同系统之间传递语义明确的消息。 Kafka是一种类似于消息中间件或者消息队列的消息系统,由Java实现的具有JMS特点的但又不完全遵循JMS规范的一种消息系统,来实现生产者消费者解耦、可集成进任意系统、异步消息传输。 到这里,已经知道kafka是什么,解决什么问题,接下来是kafka相对于RabbitMQ这些有哪些特点,kafka该如何快速开始。 Kafka 是由linkedIn公司开发,然后之后贡献给Apache 交付开源(Apache kafka),当初设计和实现Kafka的那三位创始人已经用这个项目创业(Confluent),专门针对Kafka实现各种场景的解决方案(可以理解为发行版,也推出了一款社区版)当初针对的问题是业务系统产生的业务、性能日志等操作信息及用户行为大数据的收集及分析。 就现状而言,kafka最大特点应该是其高吞吐、成功提交后的消息的持久性保证(极少丢消息)、负载均衡&故障转移、伸缩性等。

一、吞吐量高的不像是个消息系统

Kafka 高吞吐依赖的主要有三点: 1、micro-batch处理方式,也就是当前Spark Streaming(实时流处理框架)所使用的模式,不是一条条的发送消息,而是一小批一小批的处理。通过微乎其微的延时消耗换取吞吐量几百倍的提升。这种方式也更让Kafka像是一个流处理框架,并且现在Kafka也已经被用于一些流处理的场景了。 2、使用追加写的方式(顺序写): 这一点至关重要,我们知道在普通的机械硬盘中随机读写和顺序读写速度差异完全不是一个数量级的,SSD顺序读、机械硬盘顺序读的速度甚至比内存的随机读速度还要高。熟知操作系统的话,都很清楚磁盘读写操作的主要时间消耗是因为机械操作的循道等消耗。 3、Linux中的sendfile的零拷贝加持,所谓的零拷贝其实就是原本一份数据的IO是需要经过多次copy操作&内核态与用户态的上下文切换,读内核态缓存到应用程序缓存在从应用程序缓存到Socket缓存完成具体的IO操作,而sendFile系统调用零拷贝就是避免了上下文切换带来的copy操作,同时利用直接存储器访问技术(DMA)执行IO操作,避免了内核缓冲区之前的数据拷贝操作。上升到上层的语言操作,就是使用的Java中的FileChannel.transferTo方法进行实现的。(Kafka 1版本使用的是Scala,2版本开始就是使用Java 了这两者都是在JVM上执行的,本质.class 文件解析执行阶段其实是一致的)

二、对“丢消息”的保证

Kafka 对于提交成功的消息提供保证策略(消息交付承诺),在Kafka中存在ISR(in-sync replica,与leader replica保持同步的replica集合),replica是Kafka中消息的一种日志备份,而leader replica就是领导者replica,对应的还有follower replica,Kafka维护着这样一个replica集合(ISR),当消息提交时,leader 备份完成及配置的follower同步完成时才返回成功,然后采用这些互备的备份完成消息的不丢失保证。所以这样去理解Kafka的交付承诺:对没有提交成功的消息不做任何交付保证,而对于ISR正常工作的情况下的“成功提交”的消息保证不会丢失。这里有一个参数来控制这种策略:acks(0,-1,1)“0”的时候不理睬备份的处理结果,消息发送后立即返回成功,马上开始发送下一条消息(毫无疑问这种方式吞吐量是最高的),“-1” 等所有的(leader&follower)都写入成功后返回提交成功,“1”当leader 写入成功时,无需等待ISR其他写入成功就返回成功(注意一点:这里的参数值都是字符串)。需要根据具体的场景来选择对应的要求,对于持久性(对消息的保证)和吞吐量的取舍关系。

三、负载均衡&故障转移

先说负载均衡,kafka是一种分布式的消息系统,要做负载均衡,也就是要做到均匀分配到所有参与工作的服务器。这里Kafka使用的是分区只能领导者选举,也就是来均匀的选择分区,保证各个分区收到的请求消息都是大致均匀的。Kafka中有一个叫做partition的概念,也就是分区选择器,默认使用的是murmur2Hash 算法计算消息key值的hash值,然后对于总分区数进行求模得到对应的目标分区号,murmur2Hash是一种比较先进的Hash算法,并且在有规律的输入时也能保证分布较为均匀,使用这个算法的还有redis(当字典被用作数据库的底层实现或者hash键的底层实现时,来计算键的哈希值)、nginx、Hadoop。除此之外,使用者可以自定义对应的 常见的故障转移实现策略的关键通常是故障发现,常见的方式有会话机制、心跳机制,Kafka依赖的是会话机制,当一台Kafka服务器启动后将会话注册到Zookeeper中,故障发生时与Zookeeper的会话无法维持导致连接超时从而发现故障,此时请求就不再打到这台机器,并且选举出一台新的Kafka服务器来替代这台故障的Kafka服务器。

四、伸缩性

如何轻易的向kafka集群中增加计算资源,并且保证计算资源尽可能的线形叠加。在分布式系统中伸缩性一直是一个较大的问题,因为仅仅是增加机器资源通常会因为一些隐藏的单点瓶颈导致无法线线形扩容,比如说最大的因素就是服务状态的保存。“状态的处理”比如一致性,需要维持状态的一致性就需要浪费大量的cpu资源,所以为了降低这种消耗,Kafka将绝大部分的状态保存及维持相关的交给zookeeper 统一管理。Kafka 服务器内部仅维持少量暂时需要的状态。 后续会针对kafka细节进行更新~ 随缘更新、随缘更新~