kafka是什么
Kafka是一种高吞吐量的分布式发布订阅消息系统
简单来说,kafka就是一个消息系统。
我们如何去设计一个消息系统
如果系统的功能很少,我们完全可以做一个单机应用,然后可以部署到单个或多个节点,每个单独管理,没问题。
但是系统规模逐渐庞大,功能越来越多,如果再采用单机应用的方式,那么维护的成本,部署的成本和出错的概率都会大大提高,这时候我们会想到把不同的功能拆分到不同的项目中,部署到不同的节点,就像排兵布阵一样,当我们要完成某个业务流程的时候,调兵遣将就可以了。这叫做微服务架构,或者soa(基于服务的架构)。
想想我们把不同的功能服务化了,那么之间怎么通信呢,很容易我们会想到可以通过rpc(远程方法调用)或者webservice的方式,调用一个远程的方法,把参数传过去,然后等待返回值。好的,服务之间可以通信了。
这样还有啥问题没有?我们是同步的调用远程服务,阻塞的等待,如果远程服务执行时间过长呢,我这边要一直等着它么,如果我还有很多别的请求要处理呢,如果一直这样等着,那我的吞吐量就上不去。servlet3.0加入了异步servlet,可以在接受请求后交给一个后台线程异步处理,然后接受请求的线程再去接受新的请求。我们的服务之间的消息传递,如果有一些不需要返回值,我们能不能把它异步化呢,应该怎么实现呢。
有句话说,计算机领域所有的问题都可以通过加一个中间层来解决。我们可以设置一个代理,或者叫中介者,英文叫broker,我们把消息传给这个中介者,中介者把这个消息保存在内存中或者持久化,另一个服务从这个中介者那拿消息,这样就实现了异步的通信。我们可以基于这个思路实现一个异步的消息系统了。
还有啥问题没?现在是两个服务之间异步传消息,通过这个中介者,或者叫中间件来做。如果是多个服务之间都互相传数据呢,我怎么知道哪个消息是哪个服务要的,我们要对消息分下类,消息的分类嘛,称它为主题。至此,我们更进了一步,我们的消息系统能够异步的传递消息,而且支持多个服务之间的消息通信,对消息分了类,提出了主题的概念。
然后呢?现在的broker是部署在单个节点,如果系统并发量上去了,我们的消息系统肯定要崩,咋办呢,加节点呗,我们可以把broker变成broker集群。
那主题和这些节点怎么对应呢,如果一个主题的消息特别多,一个broker装不下,需要很多broker怎么办?我们可以对topic再做细分,分成很多分区(partation),不同的分区可以放在不同的broker,只要逻辑上是同属于一个主题就可以了,这样broker和topic就没有那么强的关系了,只看topic和partation就行了。
进一步思考,我们现在因为并发量上去了,我们把broker变成了集群,变成了分布式,那么既然是分布式,就存在某个节点挂掉的问题,如果我们的某个broker挂掉了,或者某个partation的数据丢失了,咋办。想想我们数据库中的数据都会备份,这么重要的消息肯定要需要备个份。备份不需要针对broker备份了,因为我们已经把消息分成了各个主题下的一个个partation,我们只要备份partation就行了,我们把一个备份叫做Replica。备份不能都放在一个broker上,不然一个broker挂掉了,所有的备份都没了。我们要把partation的replica分散到不同的broker上,最好broker上不要有重复的副本。
有了备份,是解决了数据丢失的问题,容灾,可用性好了很多,但是这个问题解决了,又引入了别的问题,你想想,之前你给消息系统传一个消息,只要指定一个主题,然后随便找一个partation写就行了,现在呢,partation有了多个副本replica,你写了一个副本,另一个咋办,你得都写吧,人家读的时候从哪个读,调度起来太麻烦。我们把partation和他的replica们分个工,选出一个来写,其余的同步这个partation就行了,读的话其余的读,这样一分工职责就明确了,我们只需要写那一个partation就行了,读的时候从某一个读就行,也就是读写分离,数据库中是不是也听说过这个概念,其实解决思路都差不多的。
中介者、主题、分区、master、slaver我们都给了它们一个概念,对于发送消息的和使用消息的我们也得给它们个概念,称之为生产者、消费者。
jms(java消息服务)有两种模型,一种是消息队列,一种是发布订阅,一种可以一对一的传消息,一种可以一对多的传消息,我们现在这个消息系统其实就是第二种,发布订阅的模型,我们能不能把第一种也给实现了,同时兼容这两种模型呢?
其实一和多本来就是相对的,一可以分为多,多可以合为一,其实我们多个消费者可以把他们当成一个消费者,这就是一对一了,一个消费者也可以分成多个消费者,这就是一对多。换就话说就是把消费者分个组,每次组内只有一个消费者可以消费消息,这样就成了消息队列的模型了,而一组多个消费者的时候就是发布订阅模式。
至此,我们的消息系统挺完美的了,当然咱也可以继续思考、完善下去。下面认识我们今天的主角,kafka吧。
kafka都有哪些东西
关于这个其实有太多文章去讲了,kafka的架构,kafka的一些机制,kafka的各种客户端的api,这里只大体的过一下。
首先,概念:
生产者Producer,消费者Consumer,消费者组Consumer Group,代理Broker(我更喜欢叫他中介者),备份Replica,主题Topic,分区Partition,领导Leader,下属Fllower,这些概念还需要讲么,我觉得不需要了吧。
kafka还有一个isr的概念,isr(in sync replica)同步的备份,为什么引入了这个概念呢,因为生产者发送一个消息到broker集群,发送给某个topic的指定partation,partation要写入leader,然后同步fllower之后告诉生产者,我收到消息了,回送一个ack的消息。问题是broker和consumer都是通过zookeeper管理的,通过定时心跳包来检测是否活着,broker挂掉很正常,而我们的partaion和replica分散在不同broker上,我们不能保证一个partaion和他的所有replica都同步了这条消息,因为这本来就是动态变化的,如果等待了很久发现一个broker 挂掉了,这时候怎么办,这个replica其实本来就是不能用的了,这时候再确认这点的话已经等了很长时间了,性能肯定不行,所以我们需要动态的维护一个活着的同步了最新消息的replica的列表,就是in sync replica。
这个列表咋动态维护呢,很容易的想到如果它多长时间没有回复可以认为它死了,如果它的消息一直没更新可以认为它死了,这个时间和消息的条数都是可以配置的,分布式的读写分离,或者说主从模式一直有个问题,就是同步的一致性和异步的高效性两个该怎么平衡,如果完全同步,需要所有的副本都收到了才能告诉producer我收到了消息,但是明显可能出现性能不高的情况,就是某个broker死掉了,如果完全异步就是说leader收到了消息,写了log,就告诉producer收到了消息,这样性能是高了,但是leader死掉了就丢数据了,一致性不好。
kafka解决的很巧妙,isr是一个动态维护的列表,用的是同步的方式,但只要在这个isr内同步就行了,因为所有replica所在的broker都是活着的,所以回复很快,一致性和高效性都能保证。如果leader挂掉了,新leader就从isr中产生。所以说isr解决了两件事,一个是动态维护replica列表,保证了消息接受的高效性和一致性,一个是leader挂掉时选取新leader很容易。
然后看几个kafka的架构图。
kafka作为中介者:
kafka详细架构图: