- 解压缩
kafka_2.11-2.0.0.tgz
- 配置jdk
- Zookeeper
本例使用kafka自带zookeeper
可使用自定义的zookeeper,需要修改kafka:server.properties
- 配置
server.properties:
broker.id=0
advertised.listeners=PLAINTEXT://192.168.166.2:9092
log.dirs=/opt/kafka/log
zookeeper.connect=localhost:2181
consumer.properties:
group.id的值
- 以次启动测试:
Zookeeper启动:
[root@node122 bin]# nohup ./zookeeper-server-start.sh /opt/kafka/config/zookeeper.properties &
Kafka启动:
[root@node122 bin]#nohup ./kafka-server-start.sh /opt/kafka/config/server.properties &
5、测试:
[root@node122 bin]# ./kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
Created topic "test".
[root@node122 bin]# ./kafka-topics.sh --list --zookeeper localhost:2181
生产者和消费者测试:
./kafka-console-producer.sh --broker-list localhost:9092 --topic mytopic
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytopic
6、创建启动和停止脚本
启动脚本:
#!/bin/sh
# start zookeeper
nohup sh /opt/kafka/bin/zookeeper-server-start.sh /opt/kafka/config/zookeeper.properties &
#wait 4s
sleep 4
#start kafka
nohup sh /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties &
停止脚本:
#!/bin/sh
#stop zookeeper
sh /opt/kafka/bin/zookeeper-server-stop.sh /opt/kafka/config/zookeeper.properties
#wait 4s
sleep 4
#stop kafka
sh /opt/kafka/bin/kafka-server-stop.sh /opt/kafka/config/server.properties
添加执行权限
chmod +x kafkastart.sh
chmod +x kafkastop.sh
7、随开机启动配置
vi /etc/rc.d/rc.local #编辑,在最后添加一行
nohup sh /opt/kafka/kafkastart.sh & #设置开机自动在后台运行脚本
:wq! #保存退出
8、java api使用 (创建maven项目)
- Pom.xml:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>2.0.0</version>
</dependency>
2)生产者工具类
public class KafkaProduceUtil {
private static KafkaProduceUtil kafkaProduceUtil = null;
public Producer<String, String> producer = null;
private KafkaProduceUtil(){
if(producer == null) {
Properties props = new Properties();
// 配置
props.put("bootstrap.servers","192.168.166.2:9092");
// 配置value的序列化类
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 配置key的序列化类
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
/**
* 判别请求是否为完整的条件(就是是判断是不是成功发送了)。
* 我们指定了“all”将会阻塞消息,这种设置性能最低,但是是最可靠的
*/
props.put("acks", "-1");
/**
* 如果请求失败,生产者会自动重试,我们指定是0次,
* 如果启用重试,则会有重复消息的可能性
*/
props.put("retries", 0);
props.put("batch.size", 16384);
/**
* 减少请求的数量,可以设置linger.ms大于0。
* 这将指示生产者发送请求之前等待一段时间,希望更多的消息填补到未满的批中
*/
props.put("linger.ms", 1);
/**
* 控制生产者可用的缓存总量,如果消息发送速度比其传输到服务器的快,将会耗尽这个缓存空间。
* 当缓存空间耗尽,其他发送调用将被阻塞,阻塞时间的阈值通过max.block.ms设定,之后它将抛出一个TimeoutException
*/
props.put("buffer.memory", 33554432);
producer = new KafkaProducer<String, String>(props);
}
}
/**
* 并发单例模式
* @return
*/
public static synchronized KafkaProduceUtil getInstance(){
if(kafkaProduceUtil == null) {
kafkaProduceUtil = new KafkaProduceUtil();
}
return kafkaProduceUtil;
}
public void closeConnect() {
if(producer != null){
producer.close();
}
}
3)消费者工具类
public class KafkaConsumeUtile {
private static KafkaConsumeUtile kafkaConsumeUtile = null;
public KafkaConsumer<String, String> consumer = null;
private KafkaConsumeUtile(){
if(consumer == null) {
Properties props = new Properties();
/**
* 进程池瓜分消费和处理消息的工作。这些进程可以在同一台机器运行,
* 也可分布到多台机器上,增加可扩展性和容错性,相同group.id的消费者将视为同一个消费者组,
* group.id的值 与config中consumer.properties的值一致
*/
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.166.2:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG ,"test-consumer-group") ;
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
consumer = new KafkaConsumer<>(props);
}
}
public static synchronized KafkaConsumeUtile getInstance() {
if(kafkaConsumeUtile == null) {
kafkaConsumeUtile = new KafkaConsumeUtile();
}
return kafkaConsumeUtile;
}
}
4)生产者测试类
public class KafkaProduce {
public static void testProduce() {
KafkaProduceUtil kafkaProduceUtil = KafkaProduceUtil.getInstance();
/**
* send是异步的,并且一旦消息被保存在等待发送的消息缓存中,此方法就立即返回。
* 这样并行发送多条消息而不阻塞去等待每一条消息的响应。
* 发送的结果是一个RecordMetadata,它指定了消息发送的分区,分配的offset和消息的时间戳。
*/
for(int i = 0; i < 100; i++){
kafkaProduceUtil.producer.send(new ProducerRecord<String, String>("pp","pp:"+i,"pp:"+i),
new Callback() {
@Override
public void onCompletion(RecordMetadata metadata, Exception e) {
if (e != null) {
// 如果在centos上测试没问题;这里发送超时时,一般时因为server.properties中;
//
e.printStackTrace();
} else {
System.out.println("The offset of the record we just sent is: " + metadata.offset());
}
}
});
}
kafkaProduceUtil.closeConnect();
}
public static void main(String[] args) {
testProduce();
}
}
5)消费者测试类
public class KafkaConsume {
public static void testConsume() {
KafkaConsumeUtile kafkaConsumeUtile = KafkaConsumeUtile.getInstance();
kafkaConsumeUtile.consumer.subscribe(Arrays.asList("pp"));
while (true) {
/**
* 调用poll(long)时,消费者将自动加入到组中。
* 只要持续的调用poll,消费者将一直保持可用,并继续从分配的分区中接收消息。
* 此外,消费者向服务器定时发送心跳。 如果消费者崩溃或无法在session.timeout.ms配置的时间内发送心跳,
* 则消费者将被视为死亡,并且其分区将被重新分配
*/
ConsumerRecords<String, String> records = kafkaConsumeUtile.consumer.poll(100);
for(ConsumerRecord<String, String> record : records) {
System.out.println("收到消息:" + record.key() + ":" +record.value());
}
}
}
public static void main(String[] args) {
testConsume();
}
}