從京東雲上面購買了三臺服務器,作爲kafka集羣搭建環境。下面的不是本人真實ip地址
服務器簡介:
服務器名稱 服務器ip地址 服務器角色 備註
Jd1 190.168.161.26 節點
Jd2 190.168.161.25 節點
Jd3 190.168.161.24 節點
雲服務器開通端口:
一、安裝java環境
選擇java1.8+ 及以上版本,我使用的是jdk-8u221-linux-x64.tar.gz。每臺服務器均安裝
上傳到centos系統上,然後解壓軟件:
[root@jd3 software]# tar zxvf jdk-8u221-linux-x64.tar.gz
得到一個文件夾,移動到/usr/local目錄下:
[root@jd3 software]# mv jdk1.8.0_221/ /usr/local/java
配置java環境變量:
[root@jd3 software]# vim /etc/profile
export JAVA_HOME=/usr/local/java
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JRE_HOME=$JAVA_HOME/jre
重新加載環境變量配置:
[root@jd3 software]# source /etc/profile
測試java環境是否安裝成功
[root@jd3 software]# java -version
二、安裝zookeeper環境
選擇zookeeper版本,我使用的是apache-zookeeper-3.6.0-bin.tar.gz。每臺服務器都安裝
上傳到centos系統上,然後解壓軟件:
[root@jd3 software]# tar zxvf apache-zookeeper-3.6.0-bin.tar.gz
修改文件夾名稱爲zookeeper,也可以不修改
[root@jd3 software]# mv /opt/zookeeper-3.6.0 /opt/zookeeper
得到一個文件夾,進入到其/conf目錄下:
我解壓後的目錄位置在/opt下面
[root@jd3 software]# cd /opt/zookeeper/conf
創建一個配置文件:
[root@jd3 software]# cp zoo_sample.cfg zoo.cfg
修改配置文件:
[root@jd3 software]# vim zoo.cfg
#只需要修改下面這幾個地方
dataDir=/opt/zookeeper/zkdata
dataLogDir=/opt/zookeeper/zkdataLog
clientPort=12181
server.1=190.168.161.26:12888:13888
server.2=190.168.161.25:12888:13888
server.3=190.168.161.24:12888:13888
爲了便於講解上面的配置,這裏抽象出一個公式,即
server.A=B:C:D。其中 A 是一個數字,代表服務器的編號,就是前面所說的myid文件裏面的值。集羣中每臺服務器的編號都必須唯一,所以要保證每臺服務器中的myid文件中的值不同。B代表服務器的IP地址。C表示服務器與集羣中的 leader 服務器交換信息的端口。D 表示選舉時服務器相互通信的端口。
創建文件目錄
[root@jd3 software]# mkdir /opt/zookeeper/zkdata
[root@jd3 software]# mkdir /opt/zookeeper/zkdataLog
創建服務器的編號:(每臺服務器上面執行,注意數字要和配置文件對應)
[root@jd1 software]# echo “1” > /opt/zookeeper/zkdata/myid
進入到/opt/zookeeper/bin 目錄,三臺機器都啓動:
[root@jd3 software]# cd /opt/zookeeper/bin
[root@jd3 software]# ./zkServer.sh start
查看運行狀態,其中一個爲leader,另外兩個爲follower
[root@jd3 software]# ./zkServer.sh status
注意問題:雲服務器搭建zookeeper集羣,因爲虛擬化的問題導致無法啓動集羣。在每個Zookeeper節點上的zoo.cfg裏面添加上quorumListenOnAllIPs=true
dataDir=/opt/zookeeper/zkdata
dataLogDir=/opt/zookeeper/zkdataLog
clientPort=12181
quorumListenOnAllIPs=true
server.1=190.168.161.26:12888:13888
server.2=190.168.161.25:12888:13888
server.3=190.168.161.24:12888:13888
三、安裝kafka環境
選擇kafka版本爲scala2.12版本的,我使用的版本爲kafka_2.12-2.4.1.tgz
解壓kafka軟件:
[root@jd3 software]# tar -zxvf kafka_2.12-2.4.1.tgz
修改文件夾名稱爲kafka,也可以不修改
[root@jd3 software]# mv /opt/kafka_2.12-2.4.1 /opt/kafka
得到一個文件夾,進入到其/config目錄下:
我解壓後的目錄位置在/opt下面
[root@jd3 config]# cd /opt/kafka/config
修改配置文件server.properties文件:
[root@jd3 config]# vim /opt/kafka/config/server.properties
#主要修改下面幾點:
broker.id=0# 如果其他幾個節點,也要安裝kafka,則這裏需要改動爲1、2、3....。不能重複
advertised.listeners=PLAINTEXT://190.168.161.26:9092 #其他節點,需要改爲本機ip地址
advertised.host.name=190.168.161.26 #其他節點,需要改爲本機ip地址
advertised.port=9092
zookeeper.connect=190.168.161.26:12181,190.168.161.25:12181,190.168.161.24:12181
log.dirs=/opt/kafka/kafkalogs
#在配置文件找到 log.retention.hours=168 ,然後再後面加上這三行
message.max.byte=5242880
default.replication.factor=2
replica.fetch.max.bytes=5242880
注意:PLAINTEXT://190.168.161.26:9092 代表這個kafka服務器,ip地址爲190.168.161.26端口爲9092 。程序代碼裏面消費者和生產者就可以直接指定這臺服務器地址和端口。
創建日誌目錄:
[root@jd3 software]# mkdir /opt/kafka/kafkalogs
進入kafka的bin目錄下面啓動kafka:
[root@jd3 bin]# ./kafka-server-start.sh -daemon ../config/server.properties
測試:
創建一個topic:
[root@jd3 bin]#./kafka-topics.sh --zookeeper 190.168.161.26:12181/kafka --create --topic topic-demo --replication-factor 3 --partitions 4
創建一個生產者:
[root@jd3 bin]#./kafka-console-producer.sh --broker-list 190.168.161.26:9092 --topic topic-demo
(可以在執行後的界面,輸入信息)
創建一個消費者:
[root@jd3 bin]# ./kafka-console-consumer.sh --bootstrap-server 190.168.161.26:9092 --topic topic-demo
(可以在這個界面,看到上面輸入的內容)
後續
免密操作:
設置sshd免密碼登陸
執行命令:
[root@jd3 root]# ssh-keygen
執行該命令前,需要把/root/.ssh/id_rsa.pub文件刪除
[root@jd3 root]# cd /root/.ssh
[root@jd3 .ssh]# ssh-copy-id [email protected]
Java代碼案例:
生產者代碼:SimpleKafkaProducer.java
package io.test.kafka;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class SimpleKafkaProducer {
private static KafkaProducer<String, String> producer;
private final static String TOPIC = "topic-demo";
public SimpleKafkaProducer(){
Properties props = new Properties();
props.put("bootstrap.servers", "190.168.161.26:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//設置分區類,根據key進行數據分區
producer = new KafkaProducer<String, String>(props);
}
public void produce(){
for (int i = 30;i<40;i++){
String key = "表名:DUAL,主鍵:"+String.valueOf(i);
String data = "id:1 name:小明 age:"+String.valueOf(i);
producer.send(new ProducerRecord<String, String>(TOPIC,key,data));
System.out.println(data);
}
producer.close();
}
public static void main(String[] args) {
new SimpleKafkaProducer().produce();
}
}
消費者案例:
package io.test.kafka;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.log4j.Logger;
import java.util.Arrays;
import java.util.Properties;
public class SimpleKafkaConsumer {
private static KafkaConsumer<String, String> consumer;
private final static String TOPIC = "topic-demo";
public SimpleKafkaConsumer(){
Properties props = new Properties();
props.put("bootstrap.servers", "190.168.161.26:9092");
//每個消費者分配獨立的組號
props.put("group.id", "test2");
//如果value合法,則自動提交偏移量
props.put("enable.auto.commit", "true");
//設置多久一次更新被消費消息的偏移量
props.put("auto.commit.interval.ms", "1000");
//設置會話響應的時間,超過這個時間kafka可以選擇放棄消費或者消費下一條消息
props.put("session.timeout.ms", "30000");
//自動重置offset
props.put("auto.offset.reset","earliest");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
consumer = new KafkaConsumer<String, String>(props);
}
public void consume(){
consumer.subscribe(Arrays.asList(TOPIC));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records){
System.out.printf("offset = %d, key = %s, value = %s",record.offset(), record.key(), record.value());
System.out.println();
}
}
}
public static void main(String[] args) {
new SimpleKafkaConsumer().consume();
}
}
啓動消費者代碼之後,程序會一直運行,持續監聽這個topic的數據信息。
再啓動生產者代碼,生產數據。