kafka集群搭建

Kafka集群搭建

一、概念

  1. 说明

它是一个分布式消息系统,由linkedin使用scala编写,用作LinkedIn的活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础。具有高水平扩展和高吞吐量。

  1. 比较

kafka集群搭建_第1张图片

 

定义解释:

1、Java 和 scala都是运行在JVM上的语言。

2、erlang和最近比较火的和go语言一样是从代码级别就支持高并发的一种语言,所以RabbitMQ天生就有很高的并发性能,但是 有RabbitMQ严格按照AMQP进行实现,受到了很多限制。kafka的设计目标是高吞吐量,所以kafka自己设计了一套高性能但是不通用的协议,他也是仿照AMQP( Advanced Message Queuing Protocol   高级消息队列协议)设计的。 

3、事物的概念:在数据库中,多个操作一起提交,要么操作全部成功,要么全部失败。举个例子, 在转账的时候付款和收款,就是一个事物的例子,你给一个人转账,你转成功,并且对方正常行收到款项后,这个操作才算成功,有一方失败,那么这个操作就是失败的。 

对应消在息队列中,就是多条消息一起发送,要么全部成功,要么全部失败。3个中只有ActiveMQ支持,这个是因为,RabbitMQ和Kafka为了更高的性能,而放弃了对事物的支持 。

4、集群:多台服务器组成的整体叫做集群,这个整体对生产者和消费者来说,是透明的。其实对消费系统组成的集群添加一台服务器减少一台服务器对生产者和消费者都是无感之的。

5、负载均衡,对消息系统来说负载均衡是大量的生产者和消费者向消息系统发出请求消息,系统必须均衡这些请求使得每一台服务器的请求达到平衡,而不是大量的请求,落到某一台或几台,使得这几台服务器高负荷或超负荷工作,严重情况下会停止服务或宕机。

6、动态扩容是很多公司要求的技术之一,不支持动态扩容就意味着停止服务,这对很多公司来说是不可以接受的。 

注:

阿里巴巴的Metal,RocketMQ都有Kafka的影子,他们要么改造了Kafka或者借鉴了Kafka,最后Kafka的动态扩容是通过Zookeeper来实现的。 

Zookeeper是一种在分布式系统中被广泛用来作为:分布式状态管理、分布式协调管理、分布式配置管理、和分布式锁服务的集群。kafka增加和减少服务器都会在Zookeeper节点上触发相应的事件kafka系统会捕获这些事件,进行新一轮的负载均衡,客户端也会捕获这些事件来进行新一轮的处理。

 

  1. 工作原理

 

kafka集群搭建_第2张图片

二、搭建kafak

搭建kafka集群首先要搭建zookeeper集群

 

  1. 软件环境

 

Ip

系统类型

 

192.168.1.221

centos7

Server1

192.168.1.138

centos7

Server2

192.168.1.89

centos7

Server3

 

 

  1. Kafka需要在zookeeper上运行,所以先搭建zookeeper (每一台服务器都需要操作)
    1. 安装jdk
yum list java*

yum -y install java-1.7.0-openjdk*
    1. . 下载zookeeper
#进入文件夹下

cd /use/local/zookeeper

#快照日志

mkdir data

#事务日志

mkdir logs

#命令下载

 

    1. 修改配置文件
#进入conf目录
cd /usr/local/zookeeper/apache-zookeeper-3.5.6-bin/conf/



tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/logs
clientPort=2181
server.1=192.168.1.221:2888:3888
server.2=192.168.1.138:2888:3888
server.3=192.168.1.89:2888:3888
#server.1 这个1是服务器的标识也可以是其他的数字, 表示这个是第几号服务器,用来标识服务器,这个标识要写到快照目录下面myid文件里
#192.168.7.107为集群里的IP地址,第一个端口是master和slave之间的通信端口,默认是2888,第二个端口是leader选举的端口,集群刚启动的时候选举或者leader挂掉之后进行新的选举的端口默认是3888
 
    1. 创建myid文件(分别在每一个机器上)
#server1
echo "1" > /usr/local/zookeeper/data/myid
#server2
echo "2" > /usr/local/zookeeper/data/myid
#server3
echo "3" > /usr/local/zookeeper/data/myid
 
    1. 启动(三台机子都要操作)
#进入到Zookeeper的bin目录下
cd /opt/zookeeper/zookeeper-3.4.6/bin
#启动服务(3台都需要操作)
./zkServer.sh start
#检查服务器状态
./zkServer.sh status
#执行命令jps
Jps
QuorumPeerMain 

 

  1. 搭建kafka集群
进入目录下 cd /use/local/kafka 
创建消息目录 mkdir logs,主要存放 kafka消息
在线下载 wget https://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.4.0/ kafka_2.13-2.4.0.tgz 
解压 tar -zxvf  kafka_2.13-2.4.0.tgz

 

      1. 修改配置文件
进入到config目录

cd /usr/local/kafka/kafka_2.13-2.4.0/config/

编辑server.poperties

vim server.poperties

             
broker.id=0  #当前机器在集群中的唯一标识,和zookeeper的myid性质一样
port=9092 #当前kafka对外提供服务的端口默认是9092
host.name=192.168.1.221 #这个参数默认是关闭的,在0.8.1有个bug,DNS解析问题,失败率的问题。
num.network.threads=3 #这个是borker进行网络处理的线程数
num.io.threads=8 #这个是borker进行I/O处理的线程数
log.dirs=/opt/kafka/kafkalogs/ #消息存放的目录,这个目录可以配置为“,”逗号分割的表达式,上面的num.io.threads要大于这个目录的个数这个目录,如果配置多个目录,新创建的topic他把消息持久化的地方是,当前以逗号分割的目录中,那个分区数最少就放那一个
socket.send.buffer.bytes=102400 #发送缓冲区buffer大小,数据不是一下子就发送的,先回存储到缓冲区了到达一定的大小后在发送,能提高性能
socket.receive.buffer.bytes=102400 #kafka接收缓冲区大小,当数据到达一定大小后在序列化到磁盘
socket.request.max.bytes=104857600 #这个参数是向kafka请求消息或者向kafka发送消息的请请求的最大数,这个值不能超过java的堆栈大小
num.partitions=1 #默认的分区数,一个topic默认1个分区数
log.retention.hours=168 #默认消息的最大持久化时间,168小时,7天
message.max.byte=5242880  #消息保存的最大值5M
default.replication.factor=2  #kafka保存消息的副本数,如果一个副本失效了,另一个还可以继续提供服务
replica.fetch.max.bytes=5242880  #取消息的最大直接数
log.segment.bytes=1073741824 #这个参数是:因为kafka的消息是以追加的形式落地到文件,当超过这个值的时候,kafka会新起一个文件
log.retention.check.interval.ms=300000 #每隔300000毫秒去检查上面配置的log失效时间(log.retention.hours=168 ),到目录查看是否有过期的消息如果有,删除
log.cleaner.enable=false #是否启用log压缩,一般不用启用,启用的话可以提高性能
zookeeper.connect=192.168.1.221: 2181,192.168.1.138:2181,192.168.1.89:218 #设置zookeeper的连接端口

 

 

      1. 启动服务
#从后台启动Kafka集群(3台都需要启动)
cd  /usr/local/kafka/kafka_2.13-2.4.0/bin #进入到kafka的bin目录 
#前台启动看看报错不
./kafka-server-start.sh  ../config/server.properties
#后台启动
./kafka-server-start.sh -daemon ../config/server.properties
#是否启动
Jps
QuorumPeerMain
Kafka
 

三、Springboot测试kafka

1.jar包依赖  

        
            org.springframework.kafka
            spring-kafka
        

        
        
            io.springfox
            springfox-swagger2
            2.8.0
        

        
        
            io.springfox
            springfox-swagger-ui
            2.8.0
        
2.yml配置
server:

  port: 18888



topinfo:

  # kafka集群配置 ,bootstrap-servers 是必须的

  kafka:

    # 生产者的kafka集群地址

    bootstrap-servers:  192.168.1.221:9092,192.168.1.138:9092,192.168.1.89:9092

    producer:

      topic-name:  topinfo-01

    consumer:

      group-id:  ci-data

3.yml变实体类

import com.uximt.kaa.kafka.bean.Consumer;

import com.uximt.kaa.kafka.bean.Producer;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;



@ConfigurationProperties(prefix = "topinfo.kafka")

@Component

public class KafKaConfiguration {



    /**

     * @Fields bootstrapServer : 集群的地址

     */

    private String bootstrapServers;



    private Producer producer;



    private Consumer consumer;



    public String getBootstrapServers() {

        return bootstrapServers;

    }



    public void setBootstrapServers(String bootstrapServers) {

        this.bootstrapServers = bootstrapServers;

    }



    public Producer getProducer() {

        return producer;

    }



    public void setProducer(Producer producer) {

        this.producer = producer;

    }



    public Consumer getConsumer() {

        return consumer;

    }



    public void setConsumer(Consumer consumer) {

        this.consumer = consumer;

    }

}

 

4.topic配置

import org.apache.kafka.clients.admin.AdminClient;
import org.apache.kafka.clients.admin.AdminClientConfig;
import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.KafkaAdmin;
import java.util.HashMap;
import java.util.Map;


/**

* @date: 2019/12/31 14:36

 * @Explanation:

 */

@Configuration

public class KafKaTopicConfig {


    @Autowired

    private KafKaConfiguration configuration;


    /**

     *@Description: kafka管理员,委派给AdminClient以创建在应用程序上下文中定义的主题的管理员。

     *@return

     */

    @Bean

    public KafkaAdmin kafkaAdmin() {

        Map props = new HashMap<>();

        // 配置Kafka实例的连接地址

        props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, configuration.getBootstrapServers());

        KafkaAdmin admin = new KafkaAdmin(props);

        return admin;

    }



    /**

     *@Description: kafka的管理客户端,用于创建、修改、删除主题等

     *@return

     */

    @Bean

    public AdminClient adminClient() {

        return AdminClient.create(kafkaAdmin().getConfig());

    }


    /**

     * @Description: 创建一个新的 topinfo 的Topic,如果kafka中topinfo 的topic已经存在,则忽略。

     * @return

     */

    @Bean

    public NewTopic topinfo() {

        // 主题名称

        String topicName = configuration.getProducer().getTopicName();

        // 第二个参数是分区数, 第三个参数是副本数量,确保集群中配置的数目大于等于副本数量

        return new NewTopic(topicName, 2, (short) 2);

    }


}

 

5.配置kafka生产者消费者

 

import org.apache.kafka.clients.consumer.ConsumerConfig;

import org.apache.kafka.clients.producer.ProducerConfig;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;

import org.springframework.kafka.config.KafkaListenerContainerFactory;

import org.springframework.kafka.core.*;

import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;



import java.util.HashMap;

import java.util.Map;



/**

* @date: 2019/12/31 14:30

 * @Explanation: kafka配置类

 */

@Configuration

public class KafKaConfig {



    @Autowired

    private KafKaConfiguration configuration;







    /**

     * @Description: 生产者的配置

     * @return

     */

    public Map producerConfigs() {



        Map props = new HashMap<>();

        // 集群的服务器地址

        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, configuration.getBootstrapServers());

        //  消息缓存

        props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 40960);

        // 生产者空间不足时,send()被阻塞的时间,默认60s

        props.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, 6000);

        // 生产者重试次数

        props.put(ProducerConfig.RETRIES_CONFIG, 0);

        // 指定ProducerBatch(消息累加器中BufferPool中的)可复用大小

        props.put(ProducerConfig.BATCH_SIZE_CONFIG,  4096);

        // 生产者会在ProducerBatch被填满或者等待超过LINGER_MS_CONFIG时发送

        props.put(ProducerConfig.LINGER_MS_CONFIG, 1);

        // key 和 value 的序列化

        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");

        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,

                "org.apache.kafka.common.serialization.StringSerializer");

        // 客户端id

        props.put(ProducerConfig.CLIENT_ID_CONFIG, "producer.client.id.topinfo");



        return props;

    }



    /**

     * @Description: 生产者工厂

     * @return

     */

    @Bean

    public ProducerFactory producerFactory() {

        return new DefaultKafkaProducerFactory<>(producerConfigs());

    }



    /**

     * @Description: KafkaTemplate

     * @return

     */

    @Bean

    public KafkaTemplate kafkaTemplate() {

        return new KafkaTemplate(producerFactory());

    }





    // ------------------------------------------------------------------------------------------------------------



    /**

     * @Description: 消费者配置

     * @return

     */

    public Map consumerConfigs() {

        Map props = new HashMap();

        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, configuration.getBootstrapServers());

        // 消费者组

        props.put(ConsumerConfig.GROUP_ID_CONFIG, configuration.getConsumer().getGroupId());

        // 自动位移提交

        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);

        // 自动位移提交间隔时间

        props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 100);

        // 消费组失效超时时间

        props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 10000);

        // 位移丢失和位移越界后的恢复起始位置

        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");

        // key 和 value 的反序列化

        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,

                "org.apache.kafka.common.serialization.StringDeserializer");

        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,

                "org.apache.kafka.common.serialization.StringDeserializer");

        return props;

    }



    /**

     * @Description: 消费者工厂

     * @return

     */

    @Bean

    public ConsumerFactory consumerFactory() {

        return new DefaultKafkaConsumerFactory<>(consumerConfigs());

    }


    /**

     * @Description: kafka 监听容器工厂

     * @return

     */

    @Bean

    public KafkaListenerContainerFactory> kafkaListenerContainerFactory() {


        ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();

        // 设置消费者工厂
        factory.setConsumerFactory(consumerFactory());
        // 要创建的消费者数量(10 个线程并发处理)
        factory.setConcurrency(10);
        return factory;

    }



}

6.swagger配置

package com.uximt.kaa.kafka.config;



import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;

import springfox.documentation.builders.PathSelectors;

import springfox.documentation.builders.RequestHandlerSelectors;

import springfox.documentation.service.ApiInfo;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spring.web.plugins.Docket;

import springfox.documentation.swagger2.annotations.EnableSwagger2;



/**

 * Swagger配置

 * @ClassName: Swagger2Config

 */

@Configuration

@EnableSwagger2

@ConditionalOnProperty(name = "enabled", prefix = "swagger", havingValue = "true", matchIfMissing = true)

public class Swagger2Config {

    @Bean

    public Docket docket() {

        return new Docket(DocumentationType.SWAGGER_2)

                .apiInfo(apiInfo())

                .select()

                .apis(RequestHandlerSelectors.basePackage("com"))

                .paths(PathSelectors.any())

                .build();

    }



    private ApiInfo apiInfo() {

        return new ApiInfoBuilder()

                .title("Springboot Swagger项目文档")

                .version("1.0")

                .build();

    }

}

 

7.消费者和生产者实体建立

public class Consumer {

    private String groupId;

    public String getGroupId() {

        return groupId;

    }

    public void setGroupId(String groupId) {

        this.groupId = groupId;

    }

}



public class Producer {


    private String topicName;


    public String getTopicName() {

        return topicName;

    }

    public void setTopicName(String topicName) {

        this.topicName = topicName;

    }

}

8.建立发送者controller

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.kafka.core.KafkaTemplate;

import org.springframework.kafka.support.SendResult;

import org.springframework.util.concurrent.ListenableFuture;

import org.springframework.util.concurrent.ListenableFutureCallback;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**

 * @Author:hemingzhu

 * @date: 2019/12/31 14:38

 * @Explanation:

 */

@RestController

@RequestMapping("kafka")

public class TestKafKaProducerController {

    @Autowired

    private KafkaTemplate kafkaTemplate;

    @PostMapping("send")

    public String send(String name) {

        ListenableFuture>  future = kafkaTemplate.send("topinfo", name);

        future.addCallback(new ListenableFutureCallback>() {

            @Override

            public void onSuccess(SendResult result) {

                System.out.println("生产者-发送消息成功:" + result.toString());

            }

            @Override

            public void onFailure(Throwable ex) {

                System.out.println("生产者-发送消息失败:" + ex.getMessage());

            }

        });

        return "test-ok";

    }

9.消费者监听器

import org.apache.kafka.clients.consumer.ConsumerRecord;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.kafka.annotation.KafkaListener;

import org.springframework.stereotype.Component;

/**

* @date: 2019/12/31 14:39

 * @Explanation:

 */

@Component

public class KafKaConsumer {


    private final Logger logger = LoggerFactory.getLogger(KafKaConsumer.class);

    /**

     * @Description: 可以同时订阅多主题,只需按数组格式即可,也就是用“,”隔开

     * @param record

     */

    @KafkaListener(topics = { "topinfo" })

    public void receive(ConsumerRecord record) {


        logger.info("消费得到的消息---key: " + record.key());

        logger.info("消费得到的消息---value: " + record.value().toString());


    }

}

 

你可能感兴趣的:(kafka,springboot,后台,kafka,kafka测试,kafka集群)