Kafka Stream

https://blog.csdn.net/weixin_38910645/article/details/107252855

什么是Kafka Stream
Kafka Streams是一个用于处理和分析数据的客户端库。它先把存储在Kafka中的数据进行处理和分析,然后将最终所得的数据结果回写到Kafka或发送到外部系统去。它建立在一些非常重要的流式处理概念之上,例如:适当区分事件时间和处理时间、窗口支持,以及应用程序状态的简单(高效)管理。同时,它也基于Kafka中的许多概念,例如通过划分主题进行扩展。由于这个原因,它作为一个轻量级的库可以集成到应用程序中去。这个应用程序可以根据需要独立运行、在应用程序服务器中运行、作为Docker容器,或通过资源管理器(如Mesos)进行操作。通过利用Kafka的并行模型,Kafka Streams可以透明地处理同一应用程序的多个实例的负载平衡。
Kafka Streams的一些特点:

  • 设计为简单轻量级的客户端库,可以轻松地将其嵌入任何Java应用程序中,并与用户为其流式应用程序所拥有的任何现有打包,部署和操作工具集成
  • 除了Apache Kafka本身作为内部消息传递层之外,对系统没有任何外部依赖性
  • 使用Kafka的分区模型来水平扩展处理
  • 支持容错本地状态,该状态可以进行非常快速有效的状态操作,例如:窗口连接和聚合
  • 支持一次精确的处理语义,以确保在处理过程中Streams客户端或Broker发生故障时,每条记录也只处理一次
  • 采用一次一个记录的处理以实现毫秒级的处理延迟
  • 支持基于事件时间的窗口操作以及记录的无序到达
  • 提供必要的流处理原语,以及高级Streams DSL和低级Processor API

处理示例

public class KafkaWordCount {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "wordcount-application");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.105:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        StreamsBuilder builder = new StreamsBuilder();
        // 从输入主题TextLinesTopic构造一个KStream
        // 其中消息值代表文字行
        KStream<String, String> textLines = builder.stream("TextLinesTopic");
        KTable<String, Long> wordCounts = textLines
                // 用空格将每行文本分割成多个单词
                .flatMapValues(textLine -> Arrays.asList(textLine.toLowerCase().split("\\W+")))
                // 将文本单词分组为消息键
                .groupBy((key, word) -> word)
                // 计算每个单词(消息键)出现次数
                .count(Materialized.<String, Long, KeyValueStore<Bytes, byte[]>>as("counts-store"));
        // 将运行结果作为流存储到WordsWithCountsTopic主题
        wordCounts.toStream().to("WordCountTopic", Produced.with(Serdes.String(), Serdes.Long()));

        KafkaStreams streams = new KafkaStreams(builder.build(), props);
        streams.start();
    }
}

示例程序将从TextLinesTopic主题中读取内容,对每个读取的消息执行WordCount算法的计算,并将其当前结果连续写入输出主题流WordCountTopic中。因此,除了日志条目外,将没有任何STDOUT输出,因为结果将回写到Kafka中。

filter

public class StreamFilter {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "filter-application0");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.105:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        StreamsBuilder builder = new StreamsBuilder();
        KStream<String, String> kstream = builder.stream("topic-02");
        kstream.filter(new Predicate<String, String>() {
            @Override
            public boolean test(String key, String value) {
                return key.startsWith("keyB");
            }
        }).foreach(new ForeachAction<String, String>() {
            @Override
            public void apply(String key, String value) {
                System.out.println(key + " => " + value);
            }
        });

        KafkaStreams streams = new KafkaStreams(builder.build(), props);
        streams.start();
    }
}

flatmap

public class StreamFlatmap {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "flatmap-application");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.105:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        StreamsBuilder builder = new StreamsBuilder();
        KStream<String, String> kstream = builder.stream("topic-02");
        KStream<String, Integer> transformed = kstream.flatMap(
                (key, value) -> {
                    List<KeyValue<String, Integer>> result = new LinkedList<>();
                    result.add(KeyValue.pair(value.toUpperCase(), 1000));
                    result.add(KeyValue.pair(value.toLowerCase(), 9000));
                    return result;
                }
        );

        transformed.foreach((key, value) -> System.out.println(key + " => " + value));
        KafkaStreams streams = new KafkaStreams(builder.build(), props);
        streams.start();
    }
}

groupByKey

public class StreamGroupby {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "groupby-application");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.105:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        StreamsBuilder builder = new StreamsBuilder();
        KStream<String, String> kstream = builder.stream("topic-02");
        KTable<String, String> table = kstream.toTable();

        // 按新Key和其类型对流进行分组
        KGroupedStream<String, String> groupedStream = kstream.groupBy(
                new KeyValueMapper<String, String, String>() {
                    @Override
                    public String apply(String key, String value) {
                        return value;
                    }
                },
                Grouped.with(
                        // key 可以被修改
                        Serdes.String(),
                        Serdes.String())
        );

        // 按新的Key和其类型对表进行分组,同时修改值和值类型
        KGroupedTable<String, String> groupedTable = table.groupBy(
                new KeyValueMapper<String, String, KeyValue<String, String>>() {
                    @Override
                    public KeyValue<String, String> apply(String key, String value) {
                        return KeyValue.pair(key, key + "," + value);
                    }
                },
                Grouped.with(
                        // 类型可以被修改
                        Serdes.String(),
                        Serdes.String())
        );

        KafkaStreams streams = new KafkaStreams(builder.build(), props);
        streams.start();
    }
}

有状态转换

public class StreamLeftJoin {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "leftjoin-application");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.56.105:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        StreamsBuilder builder = new StreamsBuilder();
        KStream<String, String> left = builder.stream("topic-03");
        KStream<String, String> right = builder.stream("topic-04");

        KStream<String, String> joined = left.selectKey(((key, value) -> value.split(",")[0]))
                .leftJoin(right.selectKey((key, value) -> value.split(",")[0]),
                (leftValue, rightValue) -> "left=" + leftValue + ", right=" + rightValue, /* ValueJoiner */
                JoinWindows.of(Duration.ofMinutes(5)),
                Joined.with(
                        // key
                        Serdes.String(),
                        // left value
                        Serdes.String(),
                        // right value
                        Serdes.String())
        );

        joined.foreach((key, value) -> System.out.println(key + " => " + value));
        KafkaStreams streams = new KafkaStreams(builder.build(), props);
        streams.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值