阅读背景: 如有需要,尽情参看本空间的另外一篇文档

阅读目的:了解Storm 如何来封装kafka接口,如何处理Connection连接的封装性问题


参看 DynamicPartitionConnections class

package com.mixbox.storm.kafka;

import kafka.javaapi.consumer.SimpleConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mixbox.storm.kafka.trident.IBrokerReader;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 2014/07/22
 * 动态的【分区连接】
 * @author Yin Shuai
 */

public class DynamicPartitionConnections {

	public static final Logger LOG = LoggerFactory
			.getLogger(DynamicPartitionConnections.class);

	/**
	 * 持有了一个 kafka底层的SimpleConsumer对象
	 * 持有了  具体的分区
	 * 
	 * @author Yin Shuai
	 */
	
	
	static class ConnectionInfo {

		//内部维持了一个SimpleConsumer
		SimpleConsumer consumer;
		
		//分区
		Set<Integer> partitions = new HashSet();

		public ConnectionInfo(SimpleConsumer consumer) {
			this.consumer = consumer;
		}
	}

	/**
	 * 也就是kafka的每一个节点都维持了一个COnnectionInfo,ConnectionInfo
	 */
	Map<Broker, ConnectionInfo> _connections = new HashMap();

	// kafkaConfig
	KafkaConfig _config;

	/**
	 * IBrokerReader 基本上 IbroerReader这里初始化的是ZkBrokerReader
	 */

	IBrokerReader _reader;

	/**
	 * @param config
	 *            kafka配置
	 * @param brokerReader
	 *            IBrokerReader-用于拿到当前的接口
	 */
	public DynamicPartitionConnections(KafkaConfig config,
			IBrokerReader brokerReader) {
		_config = config;
		_reader = brokerReader;
	}

	/**
	 * @param partition  分区
	 * @return
	 */
	public SimpleConsumer register(Partition partition) {

		/**
		 * 依据你所拥有的partition号,拿到你所对应的Broker
		 * GlobalPartitionInformation中有Map<Integer, Broker>
		 * partitionMap,记录了分区号与Broker所对应的关系
		 */

		Broker broker = _reader.getCurrentBrokers().getBrokerFor(
				partition.partition);
		return register(broker, partition.partition);
	}

	/**
	 * @param host
	 *            主机
	 * @param partition
	 *            分区
	 * @return 底层的SimpleConsumer 对象,这里存在一个注册的行为,将主机和端口【broker】,和分区【partition】 注册到 connections连接之中
	 */
	public SimpleConsumer register(Broker host, int partition) {

		// Map<Broker, ConnectionInfo> _connections = new HashMap();


		//如果连接之中没有包含了Broker,那么建立一个新的连接,并且将这个  主机和连接注册到  _connections之中
		if (!_connections.containsKey(host)) {
			_connections.put(host, new ConnectionInfo(new SimpleConsumer(
					host.host, host.port, _config.socketTimeoutMs,
					_config.bufferSizeBytes, _config.clientId)));
		}
		
		// ---------   在这里,不管之前有没有都只取一次 -------------
		
		//当包含了,那就直接取出
		ConnectionInfo info = _connections.get(host);
		info.partitions.add(partition);
		return info.consumer;
	}

	public SimpleConsumer getConnection(Partition partition) {

		// ConnectionInfo 之中封装了一个simpleConsumer
		ConnectionInfo info = _connections.get(partition.host);
		if (info != null) {
			return info.consumer;
		}
		return null;
	}

	/**
	 * @param port    固定的Broker
	 * @param partition  固定的分区
	 */
	public void unregister(Broker port, int partition) {
		ConnectionInfo info = _connections.get(port);
		info.partitions.remove(partition);
		if (info.partitions.isEmpty()) {
			info.consumer.close();
			_connections.remove(port);
		}
	}

	public void unregister(Partition partition) {
		unregister(partition.host, partition.partition);
	}

	public void clear() {
		for (ConnectionInfo info : _connections.values()) {
			info.consumer.close();
		}
		_connections.clear();
	}
}
package com.mixbox.storm.kafka;

import kafka.javaapi.consumer.SimpleConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mixbox.storm.kafka.trident.IBrokerReader;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 2014/07/22
 * 动态的【分区连接】
 * @author Yin Shuai
 */

public class DynamicPartitionConnections {

	public static final Logger LOG = LoggerFactory
			.getLogger(DynamicPartitionConnections.class);

	/**
	 * 持有了一个 kafka底层的SimpleConsumer对象
	 * 持有了  具体的分区
	 * 
	 * @author Yin Shuai
	 */
	
	
	static class ConnectionInfo {

		//内部维持了一个SimpleConsumer
		SimpleConsumer consumer;
		
		//分区
		Set<Integer> partitions = new HashSet();

		public ConnectionInfo(SimpleConsumer consumer) {
			this.consumer = consumer;
		}
	}

	/**
	 * 也就是kafka的每一个节点都维持了一个COnnectionInfo,ConnectionInfo
	 */
	Map<Broker, ConnectionInfo> _connections = new HashMap();

	// kafkaConfig
	KafkaConfig _config;

	/**
	 * IBrokerReader 基本上 IbroerReader这里初始化的是ZkBrokerReader
	 */

	IBrokerReader _reader;

	/**
	 * @param config
	 *            kafka配置
	 * @param brokerReader
	 *            IBrokerReader-用于拿到当前的接口
	 */
	public DynamicPartitionConnections(KafkaConfig config,
			IBrokerReader brokerReader) {
		_config = config;
		_reader = brokerReader;
	}

	/**
	 * @param partition  分区
	 * @return
	 */
	public SimpleConsumer register(Partition partition) {

		/**
		 * 依据你所拥有的partition号,拿到你所对应的Broker
		 * GlobalPartitionInformation中有Map<Integer, Broker>
		 * partitionMap,记录了分区号与Broker所对应的关系
		 */

		Broker broker = _reader.getCurrentBrokers().getBrokerFor(
				partition.partition);
		return register(broker, partition.partition);
	}

	/**
	 * @param host
	 *            主机
	 * @param partition
	 *            分区
	 * @return 底层的SimpleConsumer 对象,这里存在一个注册的行为,将主机和端口【broker】,和分区【partition】 注册到 connections连接之中
	 */
	public SimpleConsumer register(Broker host, int partition) {

		// Map<Broker, ConnectionInfo> _connections = new HashMap();


		//如果连接之中没有包含了Broker,那么建立一个新的连接,并且将这个  主机和连接注册到  _connections之中
		if (!_connections.containsKey(host)) {
			_connections.put(host, new ConnectionInfo(new SimpleConsumer(
					host.host, host.port, _config.socketTimeoutMs,
					_config.bufferSizeBytes, _config.clientId)));
		}
		
		// ---------   在这里,不管之前有没有都只取一次 -------------
		
		//当包含了,那就直接取出
		ConnectionInfo info = _connections.get(host);
		info.partitions.add(partition);
		return info.consumer;
	}

	public SimpleConsumer getConnection(Partition partition) {

		// ConnectionInfo 之中封装了一个simpleConsumer
		ConnectionInfo info = _connections.get(partition.host);
		if (info != null) {
			return info.consumer;
		}
		return null;
	}

	/**
	 * @param port    固定的Broker
	 * @param partition  固定的分区
	 */
	public void unregister(Broker port, int partition) {
		ConnectionInfo info = _connections.get(port);
		info.partitions.remove(partition);
		if (info.partitions.isEmpty()) {
			info.consumer.close();
			_connections.remove(port);
		}
	}

	public void unregister(Partition partition) {
		unregister(partition.host, partition.partition);
	}

	public void clear() {
		for (ConnectionInfo info : _connections.values()) {
			info.consumer.close();
		}
		_connections.clear();
	}
}


     与前文有关

DynamicPartitionConnections之中,我们持有了一个 IBrokerReader的接口对象。

                2 :       由于IBrokerReader 派生出了  

                                                    2.1 StaticBrokerReader

                                                    2.2 ZBrokerReader

       在这个序列的一系列博文之中,ZBrokerReader已经进行了详尽的分析,并且在赋值的过程之中,IBrokerReader也是实例化为ZBrokerReader了。

     内部类:

                DynamicPartitionConnections 持有了一个 CinnectionInfo的内部类

      

static class ConnectionInfo {

		//内部维持了一个SimpleConsumer
		SimpleConsumer consumer;
		
		//分区
		Set<Integer> partitions = new HashSet();

		public ConnectionInfo(SimpleConsumer consumer) {
			this.consumer = consumer;
		}
	}
static class ConnectionInfo {

		//内部维持了一个SimpleConsumer
		SimpleConsumer consumer;
		
		//分区
		Set<Integer> partitions = new HashSet();

		public ConnectionInfo(SimpleConsumer consumer) {
			this.consumer = consumer;
		}
	}

      1:  对于每一个Connection内部都维持了一个SimpleConsumer ,以及一个 Set集合 partitions

      

2 :在DynamicPartitionConnections里面我们维持了一个_connections的对象

Map<Broker, ConnectionInfo> _connections = new HashMap();
Map<Broker, ConnectionInfo> _connections = new HashMap();

      3 :在连接维护之中,关键的地方是维护一个 register注册的行为:

     

public SimpleConsumer register(Broker host, int partition) {
public SimpleConsumer register(Broker host, int partition) {

     4: 如果_connections之中没有包含Broker,那么将会再建立一个新的连接,并且将Broker和Connection 注册到_connections之中

    

    5:在注册的过程之中,不包含就注册,最后都直接取出SimpleConsumer,这个SimpleConsumer

封装了

new ConnectionInfo(new SimpleConsumer(

host.host, host.port, _config.socketTimeoutMs,

_config.bufferSizeBytes, _config.clientId)):

 


最后总结:在DynamicPartitionConn之中 ZBrokerReader的实例变量_reader 只是用于处理当前的Broker没有指定的时候,我们在构建simpleConsumer的过程之中,动态的依据partition号去load对应的Broker而已。


    那么?如何进行下一步的抽象过程,如何使用DynamicPartitionConnections?

   



Storm-kafka【接口实现】4 - KafkaSpout