最近参与的项目小结

参与实现的模块的功能:

基于Kafka low level API实现一个消费者,消费到消息先反序列化,之后通过HTTPClient发送给指定的url。

一、KafkaConsumer

KafkaConsumer基于之前项目中的HadoopConsumer的框架实现,但一个partition开启了一个消费者线程,同时修改了持续消费的实现逻辑:不停地轮询offsetRange是否改变,是否生成了新的消息;

DataGenerator:

从配置文件中获取topic、brokerlist等信息,给每个topic的每个partition创建文件offset.dat,保存offset值;写入的是leader broker;

KafkaConsumerMain:

维护一个线程池,线程数为topicCount * brokerCount;

为每个topic创建一个SimpleKafkaETLJob对象,SimpleKafkaETLJob类中,给topic的每个分区创建一个线程,启动一个消费者消费消息;

类KafkaETLRecordReader继承了thread,实现run方法,在run中:

1)  首先,读取offset.dat,得到上一次消费的offset值,继续消费,每个线程操作自己的partition自己的文件,不存在线程安全问题;

2)  创建一个KafkaETLContext对象,该对象中创建了consumer,并消费消息;

3)  死循环,不停地消费消息:函数hasMoreNewMessages获取该分区最新的offsetrange,看是否生产了新的消息,如果没有,休眠interval;有新的消息,则调用currContext.getNext()一条一条循环消费消息,get()中操作具体的消息,把消息放入message_list中,并更新offset;

4)  现在的逻辑是:第一次消费完累积的所有消息,之后,每隔interval消费一次,如果一个interval过后没有新消息,则再等一个interval;也就是按照固定的时间间隔消费消息并更新offset。

5)  先把消息反序列化发送之后,再更新offset,可能的异常是:消息已经发出去了,写offset文件的时候宕机,重启后会重复消费,所以Restful server端会收到重复的消息,是否需要去重;可靠性保证是,至少消费一次;

二、使用Log4j写日志

maven依赖:

<dependency>
    	<groupId>commons-logging</groupId>
    	<artifactId>commons-logging</artifactId>
    	<version>1.2</version>
</dependency>
<dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.17</version>
</dependency>
两个配置文件:


使用:Log logger = LogFactory.getLog(DataGenerator.class);

三、使用Maven管理依赖的jar包并将程序打包

<build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <archive>
          	<manifest>
          		<mainClass>consumer.projectkafka.KafkaConsumerMain</mainClass> 
          	</manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- bind to the packaging phase -->
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
直接在Run as中 Maven install 即可。标签 manifest用来指定导出的Jar包中main函数所在的类。

四、把String类型的json串转换为JSONobject并输出至Map

Maven依赖:注意要指定JDK版本
<dependency>
    	<groupId>net.sf.json-lib</groupId>
    	<artifactId>json-lib</artifactId>
    	<classifier>jdk15</classifier>
    	<version>2.4</version>
</dependency>
public Map<String, String> parserToMap(String s){
		Map<String, String> map = new HashMap<String, String>();
		JSONObject json=JSONObject.fromObject(s);
		@SuppressWarnings("unchecked")
		Iterator<String> keys=json.keys();
		while(keys.hasNext()){
			String key=(String) keys.next();
			String value=json.get(key).toString();
			map.put(key, value);
		}
		return map;
}

设置jdk18不成功,还不知道原因

五、使用HTTPClient把消息发送给Server

消费有两类,一类是byte[],对应ByteArrayEntity,一类是文件,对应MultipartEntityBuilder。发送文件时,使用FileEntity并没有成功。
同时为了性能,主线程中创建了一个PoolingHttpClientConnectionManager,每个子线程中创建一个CloseableHttpClient连接,用它发送多个消息。不知这样的设计是否合理?
public CloseableHttpResponse msgSendbyHttpClient(String url, Map<String,String> map,byte[] messagebody) throws ParseException, IOException{
		//创建httpclient对象
		//CloseableHttpClient client = HttpClients.createDefault();
		//创建post方式请求对象
		System.out.println("msgSendbyHttpClient");
		RequestConfig config = RequestConfig.custom().setConnectTimeout(60*1000) // 创建连接的最长时间  
                .setConnectionRequestTimeout(5000) // 从连接池中获取到连接的最长时间  
                .setSocketTimeout(60 * 1000) // 数据传输的最长时间  
                .setStaleConnectionCheckEnabled(true) // 提交请求前测试连接是否可用  
                .build();
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(config);
		for (Entry<String, String> entry : map.entrySet()) {
			httpPost.addHeader(entry.getKey(), entry.getValue());
		}
		ByteArrayEntity myEntity = new ByteArrayEntity(messagebody); 
		httpPost.setEntity(myEntity);
		//执行请求操作,并拿到结果(同步阻塞)
		CloseableHttpResponse response = client.execute(httpPost);
        return response;
	}
	
	
	public CloseableHttpResponse fileSendbyHttpClient(String url, Map<String,String> map,File file) throws ParseException, IOException{
		System.out.println("fileSendbyHttpClient");
		if (!file.exists() || file.isDirectory()) {
            return null;
        }
		String contenttype = map.get("Content-Type");
		String boundary = contenttype.substring(contenttype.indexOf("boundary")+9);
		//System.out.println("boundary:"+boundary);
		HttpEntity myentity = MultipartEntityBuilder.create().addBinaryBody("file", file)
				.setBoundary(boundary).build();
		//创建post方式请求对象
		HttpPost httpPost = new HttpPost(url);
		RequestConfig config = RequestConfig.custom().setConnectTimeout(60*1000) // 创建连接的最长时间  
                .setConnectionRequestTimeout(5000) // 从连接池中获取到连接的最长时间  
                .setSocketTimeout(60 * 1000) // 数据传输的最长时间  
                .setStaleConnectionCheckEnabled(true) // 提交请求前测试连接是否可用  
                .build();
		httpPost.setConfig(config);
		for (Entry<String, String> entry : map.entrySet()) {
			httpPost.addHeader(entry.getKey(), entry.getValue());
		}
		httpPost.setEntity(myentity);
		//执行请求操作,并拿到结果(同步阻塞)
		CloseableHttpResponse response = client.execute(httpPost);
        return response;
	}







评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值