关于Kafka的版本号

这个内容实在是太重要了,甚至是你能否用好 Kafka 的关键。

Kafka 流行的几种 Kafka 发行版本质上都内嵌了最核心的 Apache Kafka,也就是社区版 Kafka,那今天我们就来说说 Apache Kafka 版本号的问题。

那么现在你可能会有这样的疑问:我为什么需要关心版本号的问题呢?直接使用最新版本不就好了吗?当然了,这的确是一种有效的选择版本的策略,但我想强调的是这种策略并非在任何场景下都适用。如果你不了解各个版本之间的差异和功能变化,你怎么能够准确地评判某 Kafka 版本是不是满足你的业务需求呢?因此在深入学习 Kafka 之前,花些时间搞明白版本演进,实际上是非常划算的一件事。

Kafka 版本命名

当前 Apache Kafka 已经迭代到 2.6版本。但是很多人对于 Kafka 的版本命名理解存在歧义。比如我们在官网上下载 Kafka 时,会看到这样的版本:

于是有些同学就会纳闷,难道 Kafka 版本号不是 2.11 或 2.12 吗?其实不然,前面的版本号是编译 Kafka 源代码的 Scala 编译器版本。

现在你应该知道了对于 kafka-2.11-2.1.1 的提法,真正的 Kafka 版本号实际上是 2.1.1。前面的 2 表示大版本号,即 Major Version;中间的 1 表示小版本号或次版本号,即 Minor Version;最后的 1 表示修订版本号,也就是 Patch 号。

Kafka 版本演进

Kafka 目前总共演进了 7 个大版本,分别是 0.7、0.8、0.9、0.10、0.11、1.0 和 2.0,其中的小版本和 Patch 版本很多。

  • 0.7 大版本
    • “上古”版本,提供了最基础的消息队列功能,连副本机制都没有,不推荐。
  • 0.8大版本
    • 正式引入了副本机制,至此 Kafka 成为了一个真正意义上完备的分布式高可靠消息队列解决方案。有了副本备份机制,Kafka 就能够比较好地做到消息无丢失。
    • 建议你至少要升级到 0.8.2.2 这个版本,因为该版本中老版本消费者 API 是比较稳定的。另外即使你升到了 0.8.2.2,也不要使用新版本 Producer API,此时它的 Bug 还非常多。
  • 0.9大版本
    • 增加了基础的安全认证 / 权限功能,同时使用 Java 重写了新版本消费者 API,另外还引入了 Kafka Connect 组件用于实现高性能的数据抽取。
    • 新版本 Producer API 在这个版本中算比较稳定了。但不要使用新版本 Consumer API,因为此时很不稳定。
  • 0.10.0.0大版本
    • 里程碑式的大版本,因为该版本引入了 Kafka Streams。从这个版本起,Kafka 正式升级成分布式流处理平台,虽然此时的 Kafka Streams 还基本不能线上部署使用。
    • 如果你依然在使用 0.10 大版本,建议你至少升级到 0.10.2.2 然后使用新版本 Consumer API,另外此版本的 Producer 性能也更好。
  • 0.11.0.0 大版本
    • 主流的版本之一,引入了幂等性 Producer API 以及事务(Transaction) API;重构了 Kafka 消息格式。
    • 至少将你的环境升级到 0.11.0.3,因为这个版本的消息引擎功能已经非常完善了。
  • 1.0 和 2.0大版本的区别
    • 这两个大版本主要还是 Kafka Streams 的各种改进,如果你是 Kafka Streams 的用户,至少选择 2.0.0 版本吧。

建议不论你用的是哪个版本,都请尽量保持服务器端版本和客户端版本一致,否则你将损失很多 Kafka 为你提供的性能优化收益。

小结

每个 Kafka 版本都有它恰当的使用场景和独特的优缺点,不要一味追求最新版本,选择稳妥且合适的才是最好的。

Views: 172

APACHE KAFKA 快速起步

Kafka快速起步指南。

1、获取KAFKA

下载 最新版本的Kafka并解压:

$ tar -xzf kafka_2.13-2.6.0.tgz
$ cd kafka_2.13-2.6.0

2、准备Kafka环境

注意: 本地环境需要安装 Java 8+

运行下面命令开启Kafka中内置的Zookeeper服务

# 启动Kafka中内置的ZooKeeper服务
# 注意: ZooKeeper框架未来将从Kafka框架中分离出去
$ bin/zookeeper-server-start.sh config/zookeeper.properties

打开另一个终端运行Kafka代理服务:

# 开启Kafka代理服务
$ bin/kafka-server-start.sh config/server.properties

当所有服务都成功启动,一个简单的单机Kafka环境就准备好了.

3、创建一个消息主题

Kafka是一个分布式事件流平台,它允许您跨多台机器读、写、存储和处理消息(在官方文档中也称为事件 )。

示例事件有支付事务、来自移动电话的地理位置更新、发货订单、来自物联网设备或医疗设备的传感器测量等等。这些事件被组织并存储在 主题中。非常简单,主题类似于文件系统中的文件夹,事件是该文件夹中的文件。

因此,在编写第一个事件之前,必须创建一个主题。打开另一个终端会话并运行:

$ bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092

所有Kafka的命令行工具都有额外的选项: 运行Kafka -topic .sh命令而不带任何参数来显示使用信息。例如,它还可以显示详细信息,如新主题的分区数量:

$ bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092
Topic:quickstart-events  PartitionCount:1    ReplicationFactor:1 Configs:
    Topic: quickstart-events Partition: 0    Leader: 0   Replicas: 0 Isr: 0

4、向对应主题写入消息

Kafka客户端通过网络与Kafka代理服务通信以读写消息。一旦接收到这些消息,代理将以持久和容错的方式存储这些事件,您需要多长时间就存储多长时间——甚至永远存储。

运行控制台生成器客户端,在主题中写入一些事件。默认情况下,您输入的每一行都将导致向主题写入一个单独的消息。

$ bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
This is my first event
This is my second event

您可以在任何时候使用Ctrl-C停止生产者(producer)客户端

5、读取消息

打开另一个终端会话并运行控制台消费者客户端(kafka-console-consumer)来读取您刚刚创建的事件:

$ bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092
This is my first event
This is my second event

您可以在任何时候使用Ctrl-C停止客户端。

您可以自由试验: 例如,切换回您的生产者终端(上一步)来编写额外的事件,并查看事件如何立即显示在您的消费者终端中。

因为事件长期存储在Kafka中,所以它们可以被任意多的消费者读取。您可以通过打开另一个终端会话并再次运行之前的命令来轻松地验证这一点。

6、使用KAFKA CONNECT将数据导入/导出为消息流

您可能在关系数据库或传统消息传递系统等现有系统中拥有大量数据,以及许多已经使用这些系统的应用程序。Kafka Connect允许您不断地从外部系统摄取数据到Kafka,反之亦然。因此,与Kafka集成现有系统是非常容易的。为了使这个过程更容易,有数百个这样的连接器可用。

看一看Kafka Connect section部分,了解更多关于如何持续地导入/导出数据到Kafka和导出。

7、使用KAFKA STREAMS处理消息

一旦您的数据以消息的形式存储在Kafka中,您就可以使用 Kafka Streams 客户端的Java/Scala库处理数据。它允许您实现关键任务的实时应用程序和微服务,其中输入和/或输出数据存储在Kafka主题中。

Kafka Streams将客户端编写和部署标准Java和Scala应用程序的简单性与Kafka服务器端集群技术的优势结合在一起,使这些应用程序具有高度的可伸缩性(highly scalable)、弹性(elastic)、容错性(fault-tolerant)和分布式(distributed)。这个库完全支持精确一次处理(exactly-once processing)的原语、有状态(stateful )操作和聚合(aggregation)、窗口(windowing)、连接(join)、基于事件时间的处理等等。

给你一个初步的体验,这里是如何实现流行的WordCount算法:

KStream<String, String> textLines = builder.stream("quickstart-events");

KTable<String, Long> wordCounts = textLines
            .flatMapValues(line -> Arrays.asList(line.toLowerCase().split(" ")))
            .groupBy((keyIgnored, word) -> word)
            .count();

wordCounts.toStream().to("output-topic"), Produced.with(Serdes.String(), Serdes.Long()));

Kafka 流处理演示演示和应用程序部署教程演示了如何从头到尾编写和运行这样的流处理应用程序。

8、停止KAFKA

既然你已经完成了《快速起步》,那么你可以随时停止Kafka运行——或者继续练习。

  1. 使用Ctrl-C停止生产者和消费者客户端。

  2. Ctrl-C停止Kafka代理服务器。

  3. 最后,用Ctrl-C停止ZooKeeper服务器。

如果您还想删除您本地Kafka环境的任何数据,包括您在此过程中创建的任何事件,运行命令:

$ rm -rf /tmp/kafka-logs /tmp/zookeeper

恭喜你!

您已经成功地完成了Apache Kafka快速启动。

为了解更多详情,我们建议以下步骤:

Views: 447

3-使用storm-starter测试集群

安装maven

官方示例位于storm安装文件夹下面example下的storm-starter下

安装maven3.6 (3.5也可)

下载地址

配置环境变量 vi ~/.bash_profile

#MAVEN
export M2_HOME=/home/hadoop/app/apache-maven-3.6.3
PATH=$M2_HOME/bin:$PATH

修改配置

/conf/settings.xml

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository>/home/hadoop/app/apache-maven-repo/</localRepository>
  <pluginGroups>
    <pluginGroup>org.mortbay.jetty</pluginGroup>
  </pluginGroups>
  <proxies></proxies>
  <servers></servers>
  <mirrors>
    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
    <mirror>
      <id>clojars</id>
      <name>clojar-maven</name>
      <!--url>http://clojars.org/repo/</url-->
      <url>https://mirrors.tuna.tsinghua.edu.cn/clojars/</url>
      <mirrorOf>clojars</mirrorOf>
    </mirror>
  </mirrors>
  <profiles>
  <profile>
    <id>jdk-1.4</id>
    <activation>
      <jdk>1.4</jdk>
    </activation>
    <repositories>
      <repository>
        <id>alimaven</id>
        <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <releases>
          <enabled>true</enabled>
        </releases>
        <snapshots>
          <enabled>false</enabled>
        </snapshots>
      </repository>
      <repository>
        <id>clojars</id>
        <url>https://mirrors.tuna.tsinghua.edu.cn/clojars/</url>
      </repository>
    </repositories>
  </profile>
  </profiles>
</settings>

注意:
默认的本地仓库(localRepository)是在~/.m2/repository/
也可以根据需要自定义在合适的位置。

编译打包starter项目

编译前,如果你的虚拟机可用内存小于4G,需要首先修改一下文件的并行度,避免虚拟机资源不足.

starter项目根目录/src/jvm/org.apache.storm.starter.WordCountTopology

image-20200915002404862

在storm-starter下面执行

mvn clean

此时会启动依赖下载过程,根据网络情况可能十几分钟到半个小时...

mvn package -Dmaven.test.skip=true

一定要忽略测试过程,不然一定会报错

找到build出来的胖包(体积最大的那个)

image-20200915002448201

运行项目

首先运行集群,保证相应的进程都开启

image-20200915002535892

本地模式运行

[hadoop@hadoop00 target]$ storm local original-storm-starter-2.1.0.jar org.apache.storm.starter.WordCountTopology WCTopology

file

上传到集群运行

[hadoop@hadoop00 target]$ storm jar original-storm-starter-2.1.0.jar org.apache.storm.starter.WordCountTopology WCTopology

image-20200915002609935

过一会显示上传成功

image-20200915002623430

image-20200915002637640

查看UI界面

查看UI

file

由于开启了logviewer点击worker端口号可以查看日志(如果没有开启日志则打开链接显示无法访问)

file

如果关闭了logviewer, 则ui界面中nimbus日志不能看

日志分析

要注意的是:

分配worker进程数量, 日志中显示的slots就是worker进程数, 这里是2个

分配executor线程, 此时注意每一个线程里面都有两个数字[m,n] 代表这个线程里面会执行n-m+1个任务, 编号分别为n~m

一个是6个任务线程, 任务线程编号可以从后面的日志分析出来分别是51-56

img

Spout Executor只有1个, 任务号为11

img

Bolt Executor有10个

其中

split 开启2个线程, 一共4个任务, 因此1个线程分配有2个任务

count 开启3个线程, 一共6个任务, 因此1个线程分配有2个任务

img

比如这里是分词bolt的日志

img

统计bolt的日志

img

代码分析

package org.apache.storm.starter;

import java.util.HashMap;
import java.util.Map;
import org.apache.storm.starter.spout.RandomSentenceSpout;
import org.apache.storm.task.ShellBolt;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.ConfigurableTopology;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;

/**
  * This topology demonstrates Storm's stream groupings and multilang
  * capabilities.
  */

public class WordCountTopology extends ConfigurableTopology {
    public static void main(String[] args) throws Exception {
        ConfigurableTopology.start(new WordCountTopology(), args);
    }

    @Override
    protected int run(String[] args) throws Exception {
        TopologyBuilder builder = new TopologyBuilder();
        builder.setSpout("spout", new RandomSentenceSpout(), 5);
        builder.setBolt("split", new SplitSentence(), 8).shuffleGrouping("spout");
        builder.setBolt("count", new WordCount(), 12).fieldsGrouping("split", new Fields("word"));
        conf.setDebug(true);
        String topologyName = "word-count";
        conf.setNumWorkers(3);

        if (args != null && args.length > 0) {
            topologyName = args[0];
        }

        return submit(topologyName, conf, builder);

    }

    public static class SplitSentence extends ShellBolt implements IRichBolt {

        public SplitSentence() {
            super("python", "splitsentence.py");
        }

        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("word"));
        }

        @Override
        public Map<String, Object> getComponentConfiguration() {
            return null;
        }
    }

    public static class WordCount extends BaseBasicBolt {
        Map<String, Integer> counts = new HashMap<String, Integer>();

        @Override
        public void execute(Tuple tuple, BasicOutputCollector collector) {
            String word = tuple.getString(0);
            Integer count = counts.get(word);
            if (count == null) {
                count = 0;
            }
            count++;
            counts.put(word, count);
            collector.emit(new Values(word, count));
        }

        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("word", "count"));
        }
    }
}

file

问题解决

运行storm-starter项目的WordCountTopplogy实例出现如下报错

java.lang.RuntimeException: backtype.storm.multilang.NoOutputException: Pipe to subprocess seems to be broken! No output read. Serializer Exception: Traceback (most recent call last): File "splitsentence.py", line 16, in import storm ImportError: No module named storm

解决方案

下载storm.py 放在目录 /apache-storm-2.1.0/examples/storm-starter/multilang/resources/下面 , 修改WordCountTopology.java的主函数如下:

public static void main(String[] args) throws Exception {

    SplitSentence pythonSplit = new SplitSentence();
    Map env = new HashMap();
    env.put("PYTHONPATH", "/apache-storm-2.1.0/examples/storm-starter/multilang/resources/");
    pythonSplit.setEnv(env);

    TopologyBuilder builder = new TopologyBuilder();

    builder.setSpout("spout", new RandomSentenceSpout(), 5);

    builder.setBolt("split",pythonSplit, 8).shuffleGrouping("spout");
    builder.setBolt("count", new WordCount(), 12).fieldsGrouping("split", new Fields("word"));

    Config conf = new Config();
    conf.setDebug(true);

    if (args != null && args.length > 0) {
      conf.setNumWorkers(3);

      StormSubmitter.submitTopologyWithProgressBar(args[0], conf, builder.createTopology());
    }
    else {
      conf.setMaxTaskParallelism(3);

      LocalCluster cluster = new LocalCluster();
      cluster.submitTopology("word-count", conf, builder.createTopology());

      Thread.sleep(600000);

      cluster.shutdown();
    }
  }

修改完上述文件后, maven构建报错

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin:3.0.0:checdate) on project storm-starter: You have 5 Checkstyle violations. -> [Help 1]

解决方案:

修改pom.xml, 放开代码风格检查插件的限制即可

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-checkstyle-plugin</artifactId>
  <!--Note - the version would be inherited-->
  <configuration>
      <maxAllowedViolations>100</maxAllowedViolations>
  </configuration>
</plugin>

Views: 376