Kafka的生产者和消费者代码解析
1:Kafka名词解释和工作方式 1.1:Producer :消息生产者,就是向kafka broker发消息的客户端。 1.2:Consumer :消息消费者,向kafka broker取消息的客户端 1.3:Topic :可以理解为一个队列。 1.4:Consumer Group (CG):这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个partion只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic。 1.5:Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。 1.6:Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。 1.7:Offset:kafka的存储文件都是按照offset.kafka来命名,用offset做名字的好处是方便查找。例如你想找位于2049的位置,只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka。
2:Consumer与topic关系?本质上kafka只支持Topic。
2.1:每个group中可以有多个consumer,每个consumer属于一个consumer group;
通常情况下,一个group中会包含多个consumer,这样不仅可以提高topic中消息的并发消费能力,而且还能提高"故障容错"性,如果group中的某个consumer失效那么其消费的partitions将会有其他consumer自动接管。
2.2:对于Topic中的一条特定的消息,只会被订阅此Topic的每个group中的其中一个consumer消费,此消息不会发送给一个group的多个consumer;
那么一个group中所有的consumer将会交错的消费整个Topic,每个group中consumer消息消费互相独立,我们可以认为一个group是一个"订阅"者。
2.3:在kafka中,一个partition中的消息只会被group中的一个consumer消费(同一时刻);
一个Topic中的每个partions,只会被一个"订阅者"中的一个consumer消费,不过一个consumer可以同时消费多个partitions中的消息。
2.4:kafka的设计原理决定,对于一个topic,同一个group中不能有多于partitions个数的consumer同时消费,否则将意味着某些consumer将无法得到消息。
2.5:kafka只能保证一个partition中的消息被某个consumer消费时是顺序的;事实上,从Topic角度来说,当有多个partitions时,消息仍不是全局有序的。
3:Kafka消息的分发,Producer客户端负责消息的分发。
3.1:kafka集群中的任何一个broker都可以向producer提供metadata信息,这些metadata中包含"集群中存活的servers列表"/"partitions leader列表"等信息;
3.2:当producer获取到metadata信息之后, producer将会和Topic下所有partition leader保持socket连接;
3.3:消息由producer直接通过socket发送到broker,中间不会经过任何"路由层",事实上,消息被路由到哪个partition上由producer客户端决定;
比如可以采用"random""key-hash""轮询"等,如果一个topic中有多个partitions,那么在producer端实现"消息均衡分发"是必要的。
3.4:在producer端的配置文件中,开发者可以指定partition路由的方式。
3.5:Producer消息发送的应答机制:
设置发送数据是否需要服务端的反馈,三个值0,1,-1。
0: producer不会等待broker发送ack。
1: 当leader接收到消息之后发送ack。
-1: 当所有的follower都同步消息成功后发送ack。
request.required.acks=0。
4:Consumer的负载均衡:
当一个group中,有consumer加入或者离开时,会触发partitions均衡.均衡的最终目的,是提升topic的并发消费能力:
步骤如下:
a、假如topic1,具有如下partitions: P0,P1,P2,P3。
b、加入group中,有如下consumer: C1,C2。
c、首先根据partition索引号对partitions排序: P0,P1,P2,P3。
d、根据consumer.id排序: C0,C1。
e、计算倍数: M = [P0,P1,P2,P3].size / [C0,C1].size,本例值M=2(向上取整)。
f、然后依次分配partitions: C0 = [P0,P1],C1=[P2,P3],即Ci = [P(i * M),P((i + 1) * M -1)]。
6:Kafka文件存储基本结构:
6.1:在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。
6.2:每个partion(目录)相当于一个巨型文件被平均分配到多个大小相等segment(段)数据文件中。但每个段segment file消息数量不一定相等,这种特性方便old segment file快速被删除。默认保留7天的数据。
6.3:每个partiton只需要支持顺序读写就行了,segment文件生命周期由服务端配置参数决定。(什么时候创建,什么时候删除)。
1:使用Idea进行开发,源码如下所示,首先加入Kafka必须依赖的包,这句话意味着你必须要先在Idea上面搭建好的你的maven环境:
pom.xml如下所示内容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.bie</groupId> 8 <artifactId>storm</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 <!-- storm的依赖关系 --> 12 <dependencies> 13 <!--storm依赖的包--> 14 <dependency> 15 <groupId>org.apache.storm</groupId> 16 <artifactId>storm-core</artifactId> 17 <version>0.9.5</version> 18 <!--<scope>provided</scope>--> 19 </dependency> 20 <!-- kafka依赖的包--> 21 <dependency> 22 <groupId>org.apache.kafka</groupId> 23 <artifactId>kafka_2.8.2</artifactId> 24 <version>0.8.1</version> 25 <exclusions> 26 <exclusion> 27 <artifactId>jmxtools</artifactId> 28 <groupId>com.sun.jdmk</groupId> 29 </exclusion> 30 <exclusion> 31 <artifactId>jmxri</artifactId> 32 <groupId>com.sun.jmx</groupId> 33 </exclusion> 34 <exclusion> 35 <artifactId>jms</artifactId> 36 <groupId>javax.jms</groupId> 37 </exclusion> 38 <exclusion> 39 <groupId>org.apache.zookeeper</groupId> 40 <artifactId>zookeeper</artifactId> 41 </exclusion> 42 <exclusion> 43 <groupId>org.slf4j</groupId> 44 <artifactId>slf4j-log4j12</artifactId> 45 </exclusion> 46 <exclusion> 47 <groupId>org.slf4j</groupId> 48 <artifactId>slf4j-api</artifactId> 49 </exclusion> 50 </exclusions> 51 </dependency> 52 </dependencies> 53 54 <!--如果依赖外部包,就打不进去外部包,所以需要引入下面所示--> 55 <build> 56 <plugins> 57 <plugin> 58 <!--把其他外部依赖的jar包打成一个大jar包--> 59 <artifactI