kafka学习笔记5

1 kafka中topic的Partition

1.1 hadoop、storm、kafka中partion介绍

hadoop:默认是hashPartition分组策略,作用是每个maptask中相同的key数据发往同一
		的reduce上,避免数据统计时的唯一性;
storm:包含很多的分组策略(ShuffleGrouping、FieldGrouping...),作用是上游组件将
	   数据发往下游组件的分发机制;
kafka:默认是hashPartion,作用是数据平均分配到多个partition上。

1.2 Partition的简介

说明:在kafka文件存储中,同一个topic下有多个不同的partition,每个partition为一个目录,
	partition的命名规则为topic名称+有序序号,第一个partition的序号从0开始,序号最大为
	partition数量减1
示例: order_par3_topic-0
	 order_par3_topic-1
	 order_par3_topic-2

1.3 Partition的副本机制

说明:hdfs中副本机制,同样的kafka中每个partition分片都可以设置副本数,解决某个broker挂掉的
	 数据丢失问题。
问题:如果设置多个副本,生成数据和消费数据时发给那个副本?
解决:会从多个副本中选出一个leader,由leader接受数据,并由leader提供数据的消费。

1.4 Partition和副本的示例图

图解:a、连接broker-list中任意一台broker服务器;
	 b、发送数据是需要知道topic对应的partition的个数及leader所在的节点。这些信息的由
		broker提供,每一个broker都能提供一份元数据信息,该元数据信息包含:哪些broker是
		存活的,topic有多少分片,每个分片的副本中那个是leader;
	 c、数据生产时,数据发送到那个分片的leader上是由producer的代码指定的(轮询、随机、
		hash等等策略,默认是hashPartition);
	 d、数据通过socket连接直接发送到partition所在的broker。

1.5 自定义Partition

基本步骤:a、实现Partition类;
		b、添加构造器,该构造器主要为了校验Properties;
		c、将自定义的Partition加入到Properties中,
		   properties.put("partitioner.class","...");
		d、producer.send方法中必须指定一个PartitionKey,否则自定义的Partition不生效。
示例代码:
	//自定义的Partition
	package com.kafka.simple;
	import kafka.producer.Partitioner;
	import kafka.utils.VerifiableProperties;
	public class PartitionerWrapper implements Partitioner {
		/**
		 * Properties配置文件校验器
		 * 
		 * @param verifiableProperties
		 */
		public PartitionerWrapper(VerifiableProperties verifiableProperties) {
			super();
		}
		@Override
		public int partition(Object key, int numPartitions) {
			return 2;
		}
	
	}
    //消费者代码
	package com.kafka.simple;
	import java.util.Properties;
	import kafka.javaapi.producer.Producer;
	import kafka.producer.KeyedMessage;
	import kafka.producer.ProducerConfig;
	/**
	 * kafka Producer API
	 */
	public class KafkaProducerSimple {
		public static void main(String[] args) {
			// 指定当前kafka producer生产数据的目的地
			String topic = "self-part-topic";
			// 读取配置文件
			Properties props = new Properties();
			// 指定序列化编码(key.serializer.class默认为serializer.class)
			props.put("serializer.class", "kafka.serializer.StringEncoder");
			// kafka broker对应的主机,格式为:host:port,host:port,host:port
			props.put("metadata.broker.list", "hdp01:9092,hdp02:9092,hdp03:9092");
			// request.required.acks,设置发送数据是否需要服务端的反馈,有三个值0,1,-1
			// 0:意味着producer永远不会等待一个来自broker的ack,这就是0.7版本的行为。
			// 这个选项提供了最低的延迟,但是持久化的保证是最弱的,当server挂掉的时候会丢失一些数据。
			// 1:意味着在leader replica已经接收到数据后,producer会得到一个ack。
			// 这个选项提供了更好的持久性,因为在server确认请求成功处理后,client才会返回。
			// 如果刚写到leader上,还没来得及复制leader就挂了,那么消息才可能会丢失。
			// -1:意味着在所有的ISR都接收到数据后,producer才得到一个ack。
			// 这个选项提供了最好的持久性,只要还有一个replica存活,那么数据就不会丢失
			props.put("request.required.acks", "1");
			props.put("partitioner.class", "com.kafka.simple.PartitionerWrapper");
			// 通过配置文件创建生产者
			Producer<String, String> producer = new Producer<String, String>(new ProducerConfig(props));
			// 通过for循环生成数据
			int msgNo = 0;
			while (true) {
				String msg = "self-part-topic:"+System.currentTimeMillis();
				// 5、调用producer的send方法发送数据
				// 注意:这需要指定partitionKey,用来配合自定义的的partition进行数据分发
				producer.send(new KeyedMessage<String, String>(topic, ++msgNo + "", msg));
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

2 Kafka消息的分发

2.1 Producer客户端负责消息的分发

说明:a、kafka集群中任何一个broker都可以向producer提供metadata信息,这些metadata包
	   含"集群中存活的servers列表、partition leader列表等信息";
	b、当producer获取到metadata信息之后,producer将会和Topic下所有partition 
	   leader保持Socket连接;
	c、消息由producer直接通过socket发送到broker,中间不经过任何"路由层",消息被路由
	   到哪个partition上由producer客户端决定的,如果一个topic中有多个partitions,
       那么producer端实现"消息均衡分发"是必要的;
	d、在producer端的配置文件中,开发者可以指定partition的路由方式。

3 Consumer与Topic的关系

说明:a、每个group中可以有多个consumer,每个consumer属于一个consumer group,通常情
	   况下,一个group会包含多个consumer,这样不仅仅可以提高topic中消息的并发消费
       能力,而且还能提高"故障容错"性,如果group中某个consumer失效那么其消费的
	   partitions将会由其他consumer自动接管;
	b、对于topic中一条特定的消息,只会被订阅此topic的每个group中的其中一个consumer
	   消费,此消息不会发送给一个group的多个consumer。由此知道一个group中所有的
	   consumer将会交错的消费整个topic,每个group中consumer消息消费相互独立的,
       可以认为一个group是一个"订阅者";
	c、在kafka中,一个partition中的消息只会被group中的一个consumer消费(同一时刻)
	   ,一个topic中的每个partitions,只会被一个"订阅者"中的一个consumer消费,不过
	   一个consumer可以同时消费多个partitions的消息;
	d、kafka设计原理决定,对于一个topic,同一个group中不能有多于partitions的个数的
	   consumers同时消费,否则将意味着某些consumer将无法得到消息。
注:kafka只能保证一个partition中的消息被某个consumer消息是顺序的,事实上,从topic角
   度来说,当有多个partitions时,消息仍不是全局有序的。

4 Consumer的负载均衡图

当一个group中,有consumer加入或者离开时,会触发partitions均衡.均衡的最终目的,是提升topic的并发消费能力,步骤如下:
1、假如order_topic,具有如下partitions: P0,P1,P2,P3
2、加入group中,有如下consumer: C0,C1
3、首先根据partition索引号对partitions排序: P0,P1,P2,P3
4、根据consumer.id排序: C0,C1
5、计算倍数: M = [P0,P1,P2,P3].size / [C0,C1].size,本例值M=2(向上取整)
然后依次分配partitions: C0 = [P0,P1],C1=[P2,P3],即Ci = [P(i * M),P((i + 1) * M -1)]	

4.1 Consumer的总结

说明:1、consumerGroup之间消费的数据互不干扰;
	 2、每个consumer对应一个或多个分片,一个分片对应一个consumer;
	 3、多于分片数的consumer,是没有分片的数据可以被消费的,多于的consumer等到其中一
	    个或多个consumer挂掉的时候才有机会消费到数据。这个过程叫做rebalance。
posted @ 2018-04-11 15:38  我亦在  阅读(275)  评论(0编辑  收藏  举报