确保kafka的有相应的topic
案例所需要的表格
这里topic数据是从flume中获取的。
下面是将数据从本地文件夹中传入Kafka中指定的topic消息队列中。
#定义source、channel、sink
user_friends.sources = userFriendSource
user_friends.channels = userFriendChannel
user_friends.sinks = userFriendSink
# 指定source的类型
user_friends.sources.userFriendSource.type = spooldir
# 指定source监控的目录
user_friends.sources.userFriendSource.spoolDir = /opt/kb07file/flumeFile/data/tablecsv
#指定一个把文件中的数据行解析成Event的解析器。默认是把每一行当做一个Event进行解析,所有解析器必须实现EventDeserializer.Builder接口
user_friends.sources.userFriendSource.deserializer = LINE
# 设定一行最大长度为60000
user_friends.sources.userFriendSource.deserializer.maxLineLength = 60000
#用正则表达式指定所需要接收的文件的文件名,文件名符合的才会被接收
user_friends.sources.userFriendSource.includePattern = userFriends_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
# 指定channe的类型
user_friends.channels.userFriendChannel.type = file
# 指定检查点所在目录
user_friends.channels.userFriendChannel.checkpointDir = /opt/kb07file/flumeFile/checkpoint/userFriends
#逗号分隔的目录列表,用于存储日志文件。 在不同物理磁盘上使用多个目录可以提高文件channel的性能
user_friends.channels.userFriendChannel.dataDirs = /opt/kb07file/flumeFile/data/userFriends
#指定sink类型
user_friends.sinks.userFriendSink.type = org.apache.flume.sink.kafka.KafkaSink
#每次批量发送的 Event 数
user_friends.sinks.userFriendSink.batchSize = 640
#所需要传输的机器的ip
user_friends.sinks.userFriendSink.brokerList = 192.168.222.115:9092
#所需要存放的kafka topic 需要指定
user_friends.sinks.userFriendSink.topic = user_friends_raw
#source连接channel
#sorce连接sink
user_friends.sources.userFriendSource.channels = userFriendChannel
user_friends.sinks.userFriendSink.channel = userFriendChannel
再Kafka中创建一个flume中指定的topic用来接收传来的消息
- 注释: 如果没有配置环境变量,所有涉及到kafka的命令,请在kafka的bin目录下执行一下代码
启动Kafka
kafka-server-start.sh -daemon ./config/server.properties
创建符合flume指定的kafka的topic
- 注释:这里因为使用的是单机版的kafka,所以建议分区设为1就好了
kafka-topics.sh --create --zookeeper 192.168.222.115:2181 --topic user_friends_raw --partitions 1 --replication-factor 1
启动flume相关配置,然后查看kafka中topic的变化
kafka topic执行前查看数据行数
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 192.168.222.115:9092 --topic user_friends_raw -time -1 --offsets 1
#结果为
user_friends_raw:0:0
启动flume相关配置
flume-ng agent --conf ./ --conf-file userfriends-flume-kafka.conf --name user_friends -Dflume.root.logger = INFO,console
再次查看topic中的数据行数
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 192.168.222.115:9092 --topic user_friends_raw -time -1 --offsets 1
#结果为
user_friends_raw:0:29500
#说明数据已经进入kafka对应的topic中
使用KafkaStreaming API 拿到topic数据,处理完放回Kafka新的topic中
- 注释:代码写好先不要执行
- 业务代码解说
这段代码实现的是将原本userid 后面跟的数据拆分编程一个userid对应拆分后的一条数据,然后再放回kafka中。
这样操作虽然消息数量变多了,但是方便了后期的提取和管理。
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.*;
import org.apache.kafka.streams.kstream.KStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
public class MyUserFriends {
public static void main(String[] args) {
Properties prop = new Properties();
prop.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.222.115:9092");
prop.put(StreamsConfig.APPLICATION_ID_CONFIG,"kb07");
prop.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
prop.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG,Serdes.String().getClass());
// TODO: 2020/8/27 将定义的Streams应用程序的计算逻辑
// TODO: 2020/8/27 在kafka的流中,这种计算逻辑被定义为连接处理器节点的拓扑。
// TODO: 2020/8/27 我们可以使用拓扑构建器来构造这样的拓扑。
StreamsBuilder builder = new StreamsBuilder();
// TODO: 2020/8/27 然后设置一个输入流的主题
final KStream<Object, Object> user_friends_raw = builder.stream("user_friends_raw")
.filter((k, v) -> (!v.toString().startsWith("user,")
&& v.toString().split(",").length == 2));
// TODO: 2020/8/27 可以根据业务逻辑需要,从输入流主题中源源不断的获取数据,处理完成后发。
user_friends_raw.flatMap((k,v)->{
System.out.println(k+" "+v);
List<KeyValue<String,String>> keyValues = new ArrayList<>();
String[] split = v.toString().split(",");
String userId = split[0];
String[] friends = split[1].split(" ");
for(String friend: friends){
KeyValue<String,String> keyValue=new KeyValue<>(null,userId+" "+friend);
keyValues.add(keyValue);
}
return keyValues;
// 下面字符串是新建的kafka topic
}).to("user_friends");
// TODO: 2020/8/27 我们可以通过一下步骤来检查构建器所创建的拓扑结构
Topology topo = builder.build();
// TODO: 2020/8/27 有了拓扑结构和属性配置后,就可以构造一个KafkaStream对象
KafkaStreams streams = new KafkaStreams(topo, prop);
// TODO: 2020/8/24 java1.5以后 提供的一个线程构造器
CountDownLatch countDownLatch = new CountDownLatch(1);
// TODO: 2020/8/24 加一个关闭的钩子
Runtime.getRuntime().addShutdownHook(new Thread("kb07"){
@Override
public void run() {
streams.close();
countDownLatch.countDown();
}
});
streams.start();
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//todo 线程脱钩
System.exit(0);
}
}
再kafka中创建新的topic,用来接收KafkaStreaming清理后的数据
kafka-topics.sh --create --zookeeper 192.168.222.115:2181 --topic user_friends --partitions 1 --replication-factor 1
查看创建的topic中的数据行数
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 192.168.222.115:9092 --topic user_friends -time -1 --offsets 1
#结果为:
user_friends:0:0
在idea执行Kafka Streaming
再次查看新的topic中的数据行数
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 192.168.222.115:9092 --topic user_friends -time -1 --offsets 1
#结果为:
user_friends:0:30386403