原本很早就想动笔写这篇文章,中间因为母亲生病住院,和请长假后单位工作积压,而一拖再拖。
首先总结下看了全书三分之二内容的我对这本书的整体印象:本书属于我阅读过的国产原创计算机类图书中为数不多的精品。
近期在实现单位物联网接入服务客户端、服务端的过程中,我就反复阅读了本书第3章和第4章,借鉴了许多书中讲解的kafka实现思路。
至于为什么要写导读,而不是写一篇读后感。
一则因为我觉得作者写这本书介绍Kafka源码无论从深度、还是语言组织上来说,都无可挑剔。至少我觉得自己不会比作者处理得更好。
二则我觉得这本书对初学者来说,确实存在一定的入门门槛,所以我就厚着脸皮为本书做一个入门前的导读,希望可以帮助一些购买本书的初学者更好地阅读本书。
众所周知,Kafka是一个高性能的分布式消息队列,那么在实际项目开发过程中我们什么时候才会用到它呢?
在这里我结合以往的项目经历和以前的一些读书体会,给大家简述下我个人的理解,恳请大家批评指正!
在当今项目开发中,已经很少能够遇到不需要和第三方项目交互协作自身独立完成所有业务的项目了,而真的去创建一个独立、大型的应用来完成一个企业的所有业务处理几乎也是越来越不可能的了,而一旦涉及和其他项目交互协作,就不得不面临企业项目集成的问题。
一般项目中的企业集成方式,大致分为以下四种:
文件传输
让每个应用生成共享数据文件,供其他应用使用,并使用其他应用生成的共享数据文件。文件传输的使用,能够很好地保持应用的解耦合,但在时间特性方面要付出代价:系统不能保持彼此的同步,协作行为太过缓慢。
共享数据库
让应用把要共享的数据存储在一个公共数据库中。共享数据库能按照响应式方式把数据集中在一起,但也要付出代价,这样会把所有应用与数据库耦合,且同样无法处理协作问题。
远程过程调用
让每个应用公开提供自己的一些过程,使他们能够被远程调用。应用通过这些过程来执行操作并交换数据。远程过程调用相比前两种看起来是一种更好的选择。但是把单个应用的模型扩展到应用集成中会产生很多其他的缺陷,这些缺陷都是由分布式开发造成的,尽管远程过程调用看起来像本地调用,但是表现完全不同。远程调用更慢,而且更容易失败。当多个应用跨企业通信时,我们不希望一个应用失败引发所有应用失败。另外避免外部每个应用都知道其他应用的细节,甚至只是接口方面的细节。
消息传递
让每个应用连接到一个公共的消息传递系统上,并通过消息来交换数据和调用行为。
在企业集成中,我们希望有一种类似于文件传输的方式,它能将大量的小数据包迅速地产生并且方便地传送。当有新的数据包到达时,接受应用会自动得到通知,数据传输过程中至少有一种重传机制,以确保传送的成功。存储数据的任何磁盘结构或数据库细节都对应用隐藏。这样一来,与共享数据库不同,存储模式和细节可以很容易地修改,从而反映企业不断变化的需求。
类似于远程过程调用。一个应用可以向另一个应用发送一个数据包,从而调用其他应用的相应操作。不过这里不容失败。要让发送者不必等待接受者,尤其是必须要重传数据时,应该采用异步传输。运用消息传递,可以使用可定制的格式频繁地、立即地、可靠地、异步地传输数据包。异步消息传递从根本上为了解决分布式系统面临的实际问题。发送一个消息时,不需要通信双方同时在线或者都准备好。消息传递系统同样能保持文件传输的解耦合性。消息能在传送中得到转换,发送者与接受者都不用了解具体的转换。
Kafka本质上的设计思路其实和非关系型数据库设计思路差不多。非关系型数据库的设计思路源于数据结构LSM [log structured merge tree] 日志结构合并树。首先明确一个计算机磁盘存储的特点,无论是传统机械硬盘HDD还是固态硬盘SSD,对磁盘顺序读写速度都远高于随机读写!基于这点日志结构的主要思想是将磁盘看作一个大的日志,每次都将新的数据索引结构添加到日志末端,以实现对磁盘顺序操作,提高索引性能(缺点是随机读取数据的效率很低)。日志合并树LSM-Tree吸收了日志结构方法的优点,又通过将数据文件排序改善了日志结构方法随机读性能差的问题。LSM树同时是用了两部分类树的数据结构来存储数据并同时提供查询。一部分数据存储在缓存中,负责接受新的数据插入更新以及读请求,并直接在内存中对数据排序。另一部分数据结构存在于硬盘上,由第一部分内存缓存冲刷而来,主要用来读取,有序而不可更改。除了使用以上两类数据结构外,还会使用日志文件来为数据恢复做保障。LSM-Tree结构非常利于数据的写入理论上可以接近磁盘顺序读取速度,但不利于随机读。
在Kafka中,每条消息都有类别,称为主题(Topic)。
PS:可以理解为NoSQL中的表
Kafka为每个主题都维护了分布式分区日志文件,分区日志中每个消息都会按照时间顺序被分配一个单调递增的编号。
PS:类似于NoSQL中的主键
Kafka保证同一个分区文件只能对应唯一的一个消费者。
消费者客户端只需要每次记录最后一条已经消费过的分区记录编号,就可以实时获得最新的消息。
基于LSM-Tree模型可知这种模型写数据的速度非常快,唯一的不足是随机读的能力,而消息系统都是连续读取,不存在随机读问题。这也就是Kafka能保持大并发量消息处理的根本原因。
当然除了算法模型外,Kafka在生产者和消费者API实现中做了许多的优化,这点在书中介绍得很详尽,在这里我也不过多赘述了,珠玉在前,就不班门弄斧了。
Kafka中采用自己封装JAVA NIO中IO复用的模式来提高客户端并发量,在这里我就简单地给了解相关方面不多的读者普及下什么是IO复用模型。大佬们请略过。Linux的内核将所有外部设备都看作一个文件来操作,对于文件的读写操作回会调用内核提供的系统命令,返回一个File Descriptor 简称:FD,文件描述符。对一个Socket的读写也会有相应的描述符(一个数字,它指向内核中一个结构体,文件路径、数据区等属性)称为:Socketfd(Socket描述符)。
Unix提供了5种I/O模型:
阻塞I/O。在进程空间调用recvfrom,其系统调用直到数据包到达且被复制到应用进程的缓冲区中或者发生错误才返回,在此期间会等待。
非阻塞I/O。recvfrom从应用层到内核时,如果该缓冲区没有数据,直接返回一个EwouldBlock错误,一般对非阻塞I/O轮询检查这个状态,看内核是不是有数据到来。
I/O复用模型。Linux提供Select/Poll,进程通过将一个或多个fd传递给Select或Poll系统调用,阻塞在Select上,这样,Select/Poll可以帮我们侦测多个fd是否处于就绪状态,Select/Poll顺序扫描fd是否就绪(支持fd有限,因此它的使用受到了一些制约)。Epoll使用基于事件驱动的方式代替顺序扫描,(性能高)当有fd就绪时,立即回调函数rollback。
信号驱动I/O模型。首先,开启套接口信息驱动I/O功能,并通过系统调用Sigaction执行信号处理函数。当数据准备就绪,为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据,并通知主循环函数处理数据。
异步I/O。告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核,复制到用户自己的缓冲区),通知我们。
作者:郑奇煌
定价:119.00元
图文详解Kafka的内部原理、设计与实现
全面分析以Kafka为中心的分布式流平台
Kafka新特性详解,包括连接器、流处理
阿里巴巴高级技术专家、Aliware MQ总架构师、Apache RocketMQ联合创始人、Linux OpenMessaging规范发起人冯嘉(Von Gosling),华为云主任工程师时金魁,过往记忆技术博客博主、Qunar数据架构师吴阳平倾力推荐
Kafka 自 LinkedIn 开源以来就以高性能、高吞吐量、分布式的特性著称,本书以 0.10 版本的源码为基础,深入分析了 Kafka 的设计与实现,包括生产者和消费者的消息处理流程,新旧消费者不同的设计方式,存储层的实现,协调者和控制器如何确保Kafka集群的分布式和容错特性,两种同步集群工具 MirrorMaker 和 uReplicator ,流处理的两种 API 以及 Kafka 的一些高级特性等。
推荐阅读:
作者:Neha Narkhede,Gwen Shapira,Todd Palino
译者:薛命灯
定价:69.00元
Kafka核心作者和业界一线人员共同执笔的作品
全面介绍Kafka设计原理和架构细节
列举非常流行的应用场景,帮助Kafka 用户在生产环境中运行Kafka 以及基于Kafka 构建健壮的高性能应用程序
本书是关于Kafka的全面教程,主要内容包括:
Kafka相对于其他消息队列系统的优点,主要是它如何完美匹配大数据平台开发;
详解Kafka内部设计;
用Kafka构建应用的最佳实践;
理解在生产中部署Kafka的最佳方式;
如何确保Kafka集群的安全。
↓↓↓点击阅读原文到京东购买《Kafka技术内幕》。