一、Kafka搭建
1、上传并解压改名
tar -xvf kafka_2.11-1.0.0.tgz
mv kafka_2.11-1.0.0 kafka-1.0.0
2、配置环境变量
vim /etc/profile
export KAFKA_HOME=/usr/local/soft/kafka-1.0.0
export PATH=PATH:KAFKA_HOME/bin
source /etc/profile (使环境变量生效)
3、修改配置文件
vim config/server.properties
#将从节点的broker.id修改为1,2
broker.id=0
#指定数据存放的位置,包含了Kafka集群中所有topic的分区数据
log.dirs=/usr/local/soft/kafka-1.0.0/data
#指定Kafka如何连接到其依赖的ZooKeeper集群
zookeeper.connect=master:2181,node1:2181,node2:2181/kafka
4、将kafka文件同步到node1,node2
4.1 同步kafka文件
scp -r kafka-1.0.0/ node1:`pwd`
scp -r kafka-1.0.0/ node2:`pwd`
4.2 因为kafka不是主从架构的分布式组件,而是去中心化的架构,没有主从节点之分,所以也要将master中的而环境变量同步到node1和node2中
scp /etc/profile node1:/etc/
scp /etc/profile node2:/etc/
4.3 在ndoe1和node2中执行source
source /etc/profile
4.4 修改node1和node2中的broker.id为1,2
node1
broker.id=1
node2
broker.id=2
5、启动kafka
前提:已经安装了zookeeper,没安装可以参考以前的写的一个zookeeper的搭建文档
启动步骤:
5.1 因为kafka使用zookeeper保存元数据需要,所以需要先在三个节点上启动zookeeper(也是去中心化架构)
zkServer.sh start
5.2 查看zookeeper启动的状态
zkServer.sh status #一个节点Mode:leader,剩余节点Mode: follower说明启动成功
5.3 启动kafka,每个节点中都要启动(去中心化的架构)
-daemon后台启动
kafka-server-start.sh -daemon /usr/local/soft/kafka-1.0.0/config/server.properties
5.4 测试是否成功
#生产者
kafka-console-producer.sh --broker-list master:9092,node1:9092,node2:9092 --topic
二、Kafka的使用
1、创建topic
注意:在生产和消费数据时,如果topic不存在会自动创建一个分区为1,副本为1的topic
--replication-factor #每一个分区的副本数量, 同一个分区的副本不能放在同一个节点,副本的数量不能大于kafak集群节点的数量
--partition #分区数, 根据数据量设置
--zookeeper #zk的地址,将topic的元数据保存在zookeeper中
kafka-topics.sh --create --zookeeper master:2181,node1:2181,node2:2181/kafka --replication-factor 2 --partitions 3 --topic bigdata
删除topic
kafka-topics.sh --delete --topic bigdata--zookeeper master:2181,node1:2181,node2:2181/kafka
2、查看topic描述信息
kafka-topics.sh --describe --zookeeper master:2181,node1:2181,node2:2181/kafka --topic kfkuse
3、获取所有topic
kafka-topics.sh --list --zookeeper master:2181,node1:2181,node2:2181/kafka
__consumer_offsetsL是kafka自带的用于保存消费偏移量的topic
4、创建控制台生产者
kafka-console-producer.sh --broker-list master:9092,node1:9092,node2:9092 --topic kfkuse
5、创建控制台消费者
--from-beginning 从头消费,, 如果不在执行消费的新的数据
kafka-console-consumer.sh --bootstrap-server master:9092,node1:9092,node2:9092 --from-beginning --topic bigdata
6、kafka数据保存的方式及相关事项
1、保存的文件
/usr/local/soft/kafka_2.11-1.0.0/data
2、每一个分区每一个副本对应一个目录
3、每一个分区目录中可以有多个文件, 文件时滚动生成的
00000000000000000000.log
00000000000000000001.log
00000000000000000002.log
4、滚动生成文件的策略
log.segment.bytes=1073741824 #达到1GB左右滚动生成一个文件
log.retention.check.interval.ms=300000 #每隔5分钟检查一次文件数据是否被清理
5、文件删除的策略,默认为7天,以文件为单位删除
log.retention.hours=168
三、Flink整合kafka
1、IDEA中整合
1.1 根据自己的flink版本添加依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka</artifactId>
<version>1.15.2</version>
</dependency>
1.2 案例
案例1:编写flink代码,使用flink从kafka中读数据
java
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**
* 使用flink从kafka中读数据
*/
public class Demo1KafkaSource {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
/*
*内置的位点初始化器包括:
* // 从消费组提交的位点开始消费,不指定位点重置策略
* .setStartingOffsets(OffsetsInitializer.committedOffsets())
* // 从消费组提交的位点开始消费,如果提交位点不存在,使用最早位点
* .setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.EARLIEST))
* // 从时间戳大于等于指定时间戳(毫秒)的数据开始消费
* .setStartingOffsets(OffsetsInitializer.timestamp(1657256176000L))
* // 从最早位点开始消费
* .setStartingOffsets(OffsetsInitializer.earliest())
* // 从最末尾位点开始消费
* .setStartingOffsets(OffsetsInitializer.latest());
*/
//创建kafka source
KafkaSource<String> source = KafkaSource.<String>builder()
.setBootstrapServers("master:9092,node1:9092,node2:9092") //设置kafka集群列表
.setTopics("hash_students") //指定消费的topic
.setStartingOffsets(OffsetsInitializer.earliest()) //从最早点开始消费
.setValueOnlyDeserializer(new SimpleStringSchema()) //设置读取数据的编码格式utf-8
.build();
//使用kafka source
DataStreamSource<String> studentsDS = env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Source");
studentsDS.print();
env.execute();
}
}
案例2:使用flink从kafka中读json数据,解析json格式的数据
使用阿里的fastjson工具,要先添加fastjson依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
java
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class Demo3Json {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//创建kafka source
KafkaSource<String> source = KafkaSource.<String>builder()
.setBootstrapServers("master:9092,node1:9092,node2:9092") //设置kafka集群列表
.setTopics("cars") //指定消费的topic
.setGroupId("flink_group1") //指定消费者组
.setStartingOffsets(OffsetsInitializer.earliest()) //从最早尾位点开始消费
.setValueOnlyDeserializer(new SimpleStringSchema()) //设置读取数据的编码格式utf-8
.build();
//使用kafka source
DataStreamSource<String> kafkaSource = env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Source");
//解析json格式的数据
DataStream<car> cars = kafkaSource.map(line -> JSON.parseObject(line, car.class));
cars.print();
env.execute();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class car{
private String car;
private String city_code;
private String county_code;
private String card;
private String camera_id;
private String orientation;
private Long road_id;
private Long time;
private Double speed;
}
案例3:将本地文件的数据生产(写入)到kafka中
java
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.base.DeliveryGuarantee;
import org.apache.flink.connector.kafka.sink.KafkaRecordSerializationSchema;
import org.apache.flink.connector.kafka.sink.KafkaSink;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class Demo2FIleToKafkaSink {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<String> carsDS = env.readTextFile("flink/data/cars_sample.json");
//创建kafka sink
KafkaSink<String> sink = KafkaSink.<String>builder()
.setBootstrapServers("master:9092,node1:9092,node2:9092")//kafka集群列表
.setRecordSerializer(KafkaRecordSerializationSchema.builder()
.setTopic("cars")//指定topic
.setValueSerializationSchema(new SimpleStringSchema())//指定数据格式
.build()
)
//指定数据处理的语义
.setDeliverGuarantee(DeliveryGuarantee.AT_LEAST_ONCE)
.build();
//使用kafka sink
carsDS.sinkTo(sink);
env.execute();
}
}
2、集群中整合
将flink-sql-connector-kafka-1.15.2.jar包上传到Flink的lib目录下就行
注意:一些外部的依赖,比如说上述案例中使用的fastjson依赖也要上传,否则会报错或者会运行不成功。
至于在什么集群中运行,以及集群中运行的详细步骤,我在Flink系列三中以及详细写过,在此不再赘述了。