kafka四 kafka producer的ack机制和kafka集群

一、前几节讲了简单的数据发送接收,忘了说一个点,就是producer发送数据的时候怎么保证数据成功发送到kafka服务器上。

org.apache.kafka.clients.producer.Producer的send()方法有三个重载,其中一个如下:

producer.send(new ProducerRecord<String, Object>(TOPIC, data), new Callback() {
					
					@Override
					public void onCompletion(RecordMetadata metadata, Exception e) {
						if (metadata!=null) {
							//success
							System.out.println("发送成功");
						}else {
							//fail
							System.err.println("发送失败");
						}
						
					}
				});

1、这个方法有一个回调函数,metadata参数不空则表明数据安全发送成功,否则发送失败。

二、kafka集群搭建。

1、kafka集群搭建,推荐一个 https://blog.csdn.net/a807557328/article/details/78272989 讲的挺详细

2、这个博客讲的是不同服务器上集群搭建,如果在同一个服务器上不同磁盘搭建集群,该怎么办?

     kafka配置不变,zookeeper的配置ip一样,端口改变即可。

server.1=192.168.131.130:2888:3888
server.2=192.168.131.130:2889:3889
server.3=192.168.131.130:2887:3880

3、如果不想搭建那么多服务,只需搭建搭建单服务,多节点,那么只需在单个kafka中将config/server.properties文件复制几份,如:config/server-1.properties,config/server-2.properties,

修改配置文件,只需把broker.id,listeners,log.dir三个配置项目修改,broker.id一定不能一样,这是节点的唯一标示。

config/server-1.properties:
    broker.id=1
    listeners=PLAINTEXT://:9093
    log.dir=/tmp/kafka-logs-1
  •  
修改配置文件config/server-2.properties:
config/server-2.properties:
    broker.id=2
    listeners=PLAINTEXT://:9094
    log.dir=/tmp/kafka-logs-2

搭建完成后,实现Java代码的生产与消费。

1、生产端代码基本不变,bootstrap.servers=192.168.169.128:9092 主要是这个配置项配置集群即可,主要是消费端,有两种不同的消费方式,(1):直接去zookeeper服务中取数据,由zookeeper和kafka交互。(2):直接去对准kafka消费数据。

所需jar包可点此链接下载:

https://download.csdn.net/download/hezhihuahzh/10647743

三、直接去zookeepe集群服务中取数据:

初始化配置文件

	public  Properties getProperties() {
			Properties propertie = new Properties();
			String groupId=type + "_" + prjcode;
			//准备连接kafka的参数,主要是zookeeper地址和topic名称
			propertie.put("zookeeper.connect", "192.168.39.50:2181,192.168.39.50:2182");
                        //groupId,自己定义
			propertie.put(ConsumerConfig.GROUP_ID_CONFIG ,groupId) ;
			propertie.put("zookeeper.sync.time.ms", "2000");//zookeeper follower可以落后zookeeper leader的最大时间
			propertie.put("auto.offset.reset", "smallest");
	        //zookeeper中没有初始化offset时,smallest:自动复位offset为smallest的offset
			 //largest:自动复位offset为largest的offset
			 //anything else:向consumer抛出异常
			propertie.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");//consumer向zookeeper提交offset的频率,单位是秒
			propertie.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
			propertie.put("topic", "mytopic");
			return propertie;
		}

接收数据

public void get() {
		TOPIC = "mytopic"
		String sqlData="";
		KafkaStream<String, String> kafkastream =null;
		try {
			props = getProperties();
			ConsumerConnector connector = (ConsumerConnector) Consumer.createJavaConsumerConnector(new kafka.consumer.ConsumerConfig(props));
	        Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
	        topicCountMap.put(props.getProperty("topic"), 1);
	        StringDecoder keyDecoder = new StringDecoder(new VerifiableProperties());
	        StringDecoder valueDecoder = new StringDecoder(new VerifiableProperties());
	        Map<String, List<KafkaStream<String, String>>> consumerMap = connector.createMessageStreams(topicCountMap, keyDecoder, valueDecoder);
	        List<KafkaStream<String, String>> streamList = consumerMap.get(props.getProperty("topic"));
	        //得到的数据流
	        kafkastream = streamList.get(0);
		} catch (Exception e) {
			e.printStackTrace();
		}
		while (kafkastream.iterator().hasNext()) {
			//获取数据
			sqlData = kafkastream.iterator().next().message();
		}		
	}

重点:此方式获取数据,好多方法属于过时方法,不能用。比如这个方法:kafkastream.iterator().hasNext(),一旦数据流没有数据,就会停在此处,不会往下执行。说是socket阻塞,反正不好用。就拿接收sql语句入库来说吧,肯定要批量入库。但是批量入库规格订好后,没有达规格且数据流没有数据也要入库,这个时候这个方法就不行了,根本不会往下执行啊,程序停了。怎么办?

还好想到了方法,在项目中跑的是多线程,那么需要再启动配套的监听线程监听批量入库存储容器的状态。

四、顺带说一下监听线程。

1、先是一个被监听线程。

import java.util.ArrayList;
import java.util.List;

public class DoThread implements Runnable{
	String name = "";
	public List<String> list=new ArrayList<>();
	public DoThread(String name) {
		this.name = name;
	}
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			list.add(name+"==="+i);
			System.out.println(name+"==="+i);
		}
		if ("wukong".equals(name)) {
			for (int i = 0; i < list.size(); i++) {
				list.remove(i);
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
}

2、一个监听线程

public class MonitorThread implements Runnable {
	DoThread name = null;

	public MonitorThread(DoThread name) {
		this.name = name;
	}

	@Override
	public void run() {
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		while (true) {
			System.err.println("====================" + name.name);
			System.err.println(name.name + " " + name.list.size());
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

3、启动类

public class StartThread {

	public static void main(String[] args) {
		DoThread wukong=new DoThread("wukong");
		DoThread bajie=new DoThread("bajie");
		DoThread shaceng=new DoThread("shaseng");
		new Thread(wukong).start();
		new Thread(bajie).start();
		new Thread(shaceng).start();
		new Thread(new MonitorThread(wukong)).start();
		new Thread(new MonitorThread(bajie)).start();
		new Thread(new MonitorThread(shaceng)).start();
	}

}

这个demo很好的应用到上面的sql监控。当数据流没有数据的时候,被监听线程会阻塞,监听线程监听sql存储容器,只要容器内有数据就执行入库,此时要注意线程安全问题,要加synchronized处理。

五、直接从kafka服务中消费数据,跟之前消费数据一样,唯一变的就是

propertie.put("bootstrap.servers", ConfParser.bootstrap_servers);这个配置项配置成集群即可。其他完全一样。

希望能给大家带来帮助。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值