滴滴云部署 ZooKeeper + Kafka

Kafka 是一种分布式的流处理平台,流处理平台有以下三个特点:

  1. 发布和订阅流记录,类似于消息队列和企业消息系统。
  2. 流记录的存储具有容错性。
  3. 实时处理流记录。

Kafka 广泛应用于以下两方面:

  1. 为系统和应用之间的数据可靠传输建立实时的流式数据通道。
  2. 为传输或响应数据流建立实时的流式应用。

Kafka 以集群的方式运行在一台或跨机房的多台服务器上,储存在 Kafka 集群上的流记录用不同的 topic 进行分类,每一条记录包含一个 key(键),一个 value(值)和一个 timestamp(时间戳)。

ZooKeeper 是一个针对大型分布式系统的可靠的协调系统,提供的功能包括命名服务、配置维护、分布式同步、组服务等。ZooKeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题。

本文中 Kafka 正是利用了 ZooKeeper 的协调作用,管理、协调 Kafka 实例(broker)。每个 Kafka 实例都通过 ZooKeeper 协调其它 Kafka 实例。

当 Kafka 系统中新增了实例或者某个代理故障失效时,ZooKeeper 服务将通知消息记录的生产者和消费者。生产者和消费者据此开始与其它实例协调工作。

本例集群架构如下:

在这里插入图片描述

此处我们使用的是滴滴云主机内网 IP,在本文的 Java 示例需要外部访问 Kafka,需要绑定公网 IP 即 EIP。有关滴滴云 EIP 的使用请参考以下链:https://help.didiyun.com/hc/kb/section/1035272/

部署 ZooKeeper

以下操作在三台节点进行。
登录滴滴云虚拟主机 DC2,滴滴云 DC2 默认登陆用户 dc2-user,本文部署过程将使用 root,输入 sudo su 命令切换到 root用户,进入 /usr/local 文件夹下载 ZooKeeper 和 JDK。

sudo su
cd /usr/local
wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz

wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u191-b12/2787e4a523244c269598db4e85c51e0c/jdk-8u191-linux-x64.tar.gz
tar -zxf jdk-8u191-linux-x64.tar.gz

解压 JDK 并配置 Java 环境变量:

tar zxvf jdk-8u191-linux-x64.tar.gz

在 /etc/profile 文件末尾添加以下内容:

vi /etc/profile
export JAVA_HOME=/usr/local/jdk1.8.0_191
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

使环境变量生效:

source /etc/profile

输入 java -version,如果看到以下输出说明 Java 环境变量配置成功:

java -version

java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

安装配置 ZooKeeper:

tar zxvf zookeeper-3.4.12.tar.gz
cd  zookeeper-3.4.12/conf
vi zoo.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181
server.101=zk101:2888:3888
server.102=zk102:2888:3888
server.103=zk103:2888:3888

创建配置文件中的 dataDir 目录和 myid 文件:

mkdir /tmp/zookeeper
touch /tmp/zookeeper/myid
echo 101 > /tmp/zookeeper/myid   #此处的101来源于配置文件中server.101,例外两台节点分别为102,103

将三台节点的主机名与 IP 映射添加到 /etc/hosts 文件中:

vi /etc/hosts

10.254.116.249	zk101
10.254.125.48	zk102
10.254.237.61	zk103

分别在三台节点启动 ZooKeeper:

/usr/local/zookeeper-3.4.12/bin/zkServer.sh start

查看 ZooKeeper 是否启动成功:

jps
5249 QuorumPeerMain   #此进程为zookeeper集群的启动入口类
5864 Jps

在三台节点分别查看 ZooKeeper 角色,一个 leader 两个 follower:

/usr/local/zookeeper-3.4.12/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.12/bin/../conf/zoo.cfg
Mode: follower

/usr/local/zookeeper-3.4.12/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.12/bin/../conf/zoo.cfg
Mode: follower


/usr/local/zookeeper-3.4.12/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.12/bin/../conf/zoo.cfg
Mode: leader

关于 ZooKeeper 的选举机制可以参考以下链接:https://zookeeper.apache.org/doc/current/recipes.html#sc_leaderElection

至此 ZooKeeper 启动成功。

部署 Kafka

本例使用两个节点部署 Kafka,在 zk101 和 zk102 解压 Kafka:

cd /usr/local
tar zxvf kafka_2.12-0.10.2.1.tgz 
cd kafka_2.12-0.10.2.1/config

编辑 server.properties:

vi server.properties

auto.create.topics.enable=false
broker.id=101       #此处为zk101的id
delete.topic.enable=true
num.network.threads=3
num.io.threads=8
listeners=PLAINTEXT://zk101:9092
advertised.listeners=PLAINTEXT://116.85.55.205:9092  #此处为zk101的公网IP

hostname=zk101
advertised.host.name=116.85.55.205   #此处为zk101的公网IP
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600

log.dirs=/tmp/kafka-logs

num.partitions=6
num.recovery.threads.per.data.dir=1

log.retention.hours=72
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000


zookeeper.connect=zk101:2181,zk102:2181
zookeeper.connection.timeout.ms=6000
group.initial.rebalance.delay.ms=0

zk102 的配置文件更改相应 IP 即可。

在 zk101 和 zk102 上启动 Kafka:

nohup /usr/local/kafka_2.12-0.10.2.1/bin/kafka-server-start.sh /usr/local/kafka_2.12-0.10.2.1/config/server.properties &

jps
24994 QuorumPeerMain
28675 Kafka         #Kafka已经启动
28974 Jps

测试 Kafka

以 zk101 作为 producer,创建 topic:

/usr/local/kafka_2.12-0.10.2.1/bin/kafka-topics.sh --create --zookeeper zk101:2181 --replication-factor 2 --partitions 1 --topic test
Created topic "test".

同样在 zk101 上创建一个生产者:

/usr/local/kafka_2.12-0.10.2.1/bin/kafka-console-producer.sh --broker-list zk101:9092 --topic test

在 zk102 上创建一个消费者:

/usr/local/kafka_2.12-0.10.2.1/bin/kafka-console-consumer.sh --zookeeper zk102:2181 --topic test --from-beginning

在 zk101 上输入内容,可以在 zk102 上看到:

zk101

[root@10-254-116-249 kafka_2.12-0.10.2.1]# /usr/local/kafka_2.12-0.10.2.1/bin/kafka-console-producer.sh --broker-list zk101:9092 --topic test
hello world
this is hello from didiyun

zk102
[root@10-254-125-48 config]# /usr/local/kafka_2.12-0.10.2.1/bin/kafka-console-consumer.sh --zookeeper zk102:2181 --topic test --from-beginning
Using the ConsoleConsumer with old consumer is deprecated and will be removed in a future major release. Consider using the new consumer by passing [bootstrap-server] instead of [zookeeper].
hello world
this is hello from didiyun

Kafka 测试代码(Java)

下面的 Java 测试代码中会用到 zk101 节点的 EIP 和对应的 9092 端口,因此要在安全组中打开 9092 端口,有关安全组的使用请参照以下链接:https://help.didiyun.com/hc/kb/article/1091031/

创建 mave 项目,编辑 pom.xml,解决依赖:

<dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>0.10.2.1</version>
</dependency>
<dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-nop</artifactId>
        <version>1.7.2</version>
</dependency>

生产者代码 ProducerTest.java:

import java.util.Properties;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;

public class ProducerTest {
    public static void main(String[] args){
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "116.85.55.205:9092");
        properties.put("acks", "all");
        properties.put("retries", 0);
        properties.put("batch.size", 16384);
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        Producer<String, String> producer = null;
        try {
            producer = new KafkaProducer<String, String>(properties);

            for (int i = 0; i < 20; i++) {
                String msg = "This is hello Message " + i;
                producer.send(new ProducerRecord<String, String>("test2", msg));
                System.out.println("Sent:" + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            producer.close();
        }

    }

}

消费者代码 Consumer.java:

import java.util.Properties;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Arrays;
public class Consumer {
    public static void main(String[] s) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "116.85.55.205:9092");
        props.put("group.id", "1");
        props.put("enable.auto.commit", "true");
        props.put("auto.commit.interval.ms", "1000");
        props.put("session.timeout.ms", "30000");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        KafkaConsumer<String, String> consumer = new KafkaConsumer(props);
        consumer.subscribe(Arrays.asList("test2"));
        System.out.println("poll start...");
        while (true) {

            ConsumerRecords<String, String> records = consumer.poll(100);
           
            for (ConsumerRecord<String, String> record : records)
               record.offset(), record.key(), record.value());
                System.out.println(record.value());
        }
    }
}

先运行 Consumer:
在这里插入图片描述
运行 ProducerTest,发送消息:
在这里插入图片描述
在 Consumer 上可以收到消息:
在这里插入图片描述

参考链接:
https://www.cnblogs.com/skying555/p/7873345.html
https://kafka.apache.org/intro
https://zookeeper.apache.org/

猜你喜欢

转载自blog.csdn.net/java060515/article/details/84769777