Kafka详解安装

一:介绍

Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源 项目。

二:特性

  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作。
  • 可扩展性:kafka集群支持热扩展
  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
  • 高并发:支持数千个客户端同时读写

三:使用场景
- 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
- 消息系统:解耦和生产者和消费者、缓存消息等。
- 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
- 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
- 流式处理:比如spark streaming和storm
- 事件源
这里写图片描述

四:文件存储机制

Kafka中发布订阅的对象是topic。我们可以为每类数据创建一个topic,把向topic发布消息的客户端称作producer,从topic订阅消息的客户端称作consumer。Producers和consumers可以同时从多个topic读写数据。一个kafka集群由一个或多个broker服务器组成,它负责持久化和备份具体的kafka消息。
Broker:Kafka节点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群。
Topic:一类消息,消息存放的目录即主题,例如page view日志、click日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发。
Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列
Segment:partition物理上由多个segment组成,每个Segment存着message信息
Producer : 生产message发送到topic
Consumer : 订阅topic消费message, consumer作为一个线程来消费
Consumer Group:一个Consumer Group包含多个consumer, 这个是预先在配置文件中配置好的。各个consumer(consumer 线程)可以组成一个组(Consumer group ),partition中的每个message只能被组(Consumer group ) 中的一个consumer(consumer 线程 )消费,如果一个message可以被多个consumer(consumer 线程 ) 消费的话,那么这些consumer必须在不同的组。Kafka不支持一个partition中的message由两个或两个以上的consumer thread来处理,即便是来自不同的consumer group的也不行。它不能像AMQ那样可以多个BET作为consumer去处理message,这是因为多个BET去消费一个Queue中的数据的时候,由于要保证不能多个线程拿同一条message,所以就需要行级别悲观所(for update),这就导致了consume的性能下降,吞吐量不够。而kafka为了保证吞吐量,只允许一个consumer线程去访问一个partition。如果觉得效率不高的时候,可以加partition的数量来横向扩展,那么再加新的consumer thread去消费。这样没有锁竞争,充分发挥了横向的扩展性,吞吐量极高。这也就形成了分布式消费的概念。

五:拓扑结构
这里写图片描述
一个典型的Kafka集群中包含若干Producer(可以是web前端FET,或者是服务器日志等),若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干ConsumerGroup,以及一个Zookeeper集群。Kafka通过Zookeeper管理Kafka集群配置:选举Kafka broker的leader,以及在Consumer Group发生变化时进行rebalance,因为consumer消费kafka topic的partition的offsite信息是存在Zookeeper的。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。

六:搭建zk集群
Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群。
1、软件环境
(3台服务器-我的测试)
192.168.229.135 cluster1
192.168.229.130 cluster2
192.168.229.136 cluster3

推荐使用3.4.6 因为kafka在此版本上进行了大量测试 修复了很多bug,经生产环境验证,此版本很稳定。

搭建步骤:

请参考https://blog.csdn.net/qq_35314762/article/details/81463294
注意:

1.示例中使用的是3.4.5 请注意更换版本。
2.修改zoo.cfg 中clientPort=12181 默认是2181

启动ZK:
cd /usr/softAddress/zookeeper/zookeeper-3.4.6/bin

./zkServer.sh start

七:搭建kafka集群

1、软件环境
1、linux一台或多台,大于等于2
2、已经搭建好的zookeeper集群
3、软件版本kafka_2.11-0.9.0.1.tgz
2、创建目录并下载安装软件
cd /usr/softAddress;
mkdir kafka #创建项目目录
cd kafka
mkdir kafkalogs #创建kafka消息目录,主要存放kafka消息

下载软件

wget http://archive.apache.org/dist/kafka/0.9.0.1/kafka_2.11-0.9.0.1.tgz

解压软件

tar -zxvf kafka_2.11-0.9.0.1.tgz
3、修改三台机器的配置文件
进入到config目录
cd /usr/softAddress/kafka/kafka_2.11-0.9.0.1/config
这里写图片描述
有很多文件,这里可以发现有Zookeeper文件,我们可以根据Kafka内带的zk集群来启动,但是建议使用独立的zk集群
修改
cd /usr/softAddress/kafka/kafka_2.11-0.9.0.1/config
vi server.properties
broker.id=0 每台服务器的broker.id都不能相同 三台分别为0,1,2

hostname

host.name=192.168.229.135

advertised.host.name=192.168.229.130

log.dirs=/usr/softAddress/kafka/kafkalogs

在log.retention.hours=168 下面新增下面三项

message.max.byte=5242880
default.replication.factor=2
replica.fetch.max.bytes=5242880

设置zookeeper的连接端口

zookeeper.connect=192.168.229.135:12181,192.168.229.136:12181,192.168.229.130:12181
参数解释:了解即可

broker.id=0  #当前机器在集群中的唯一标识,和zookeeper的myid性质一样
port=9092 #当前kafka对外提供服务的端口默认是9092
host.name=192.168.7.100 #这个参数默认是关闭的,在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.7.100:12181,192.168.7.101:12181,192.168.7.107:1218 #设置zookeeper的连接端口

4.启动Kafka集群并测试
1、启动服务
从后台启动Kafka集群(3台都需要启动)

cd /usr/softAddress/kafka/kafka_2.11-0.9.0.1/bin

./kafka-server-start.sh -daemon ../config/server.properties

2、检查服务是否启动
执行命令jps
这里写图片描述
创建Topic来验证是否创建成功

创建Topic

./kafka-topics.sh –create –zookeeper 192.168.229.135:12181 –replication-factor 2 –partitions 1 –topic test
这里写图片描述

解释

–replication-factor 2 #复制两份
–partitions 1 #创建1个分区
–topic #主题为shuaige

”’在192.168.229.135服务器上创建一个发布者”’
./kafka-console-producer.sh –broker-list 192.168.229.135:9092 –topic test

”’在192.168.229.136服务器上创建一个订阅者”’
./kafka-console-consumer.sh –zookeeper 192.168.229.136:12181 –topic test –from-beginning

效果如下:

发送消息:
这里写图片描述
接收消息:
这里写图片描述

八:kafka生产者模型
8.1、同步生产模型
这里写图片描述
发送一条消息,如果没有收到kafka集群的确认收到的信号,则再次重发,直到发送次数超过设置的最大次数为止。其中有一次收到了确认,就接着发送下一条消息。
8.2异步生产模型
这里写图片描述
消息发送到客户端的缓冲队列中,如果队列中条数到了设置的队列最大数或存放时间达到最大值,就把队列中的消息打包,一次性发送给kafka服务端。
两种生产模型对比:
同步生产模型:
(1)低消息丢失率;
(2)高消息重复率(由于网络原因,回复确认未收到);
(3)高延迟
异步生产模型:
(1)低延迟;
(2)高发送性能;
(3)高消息丢失率(无确认机制,发送端队列满)

九:Kafka消费者模型
Kafka消息系统基于发布-订阅模式,相对于ActiveMQ,Rabbitmq没有点对点消息处理机制。
9.1、分区消费模型
这里写图片描述
2台kafka 服务器,4个分区(P0-P3) ,分区消费模型即为:1个分区对应1个消费实例,如图4个分区,需要4个消费者实例从分区中取数据。

9.2 分区消费编码思路
(1)获取分区的size,一共多少个分区;
(2)针对每一个分区,分别创建一个线程,去消费该分区的数据
(3)每个线程即为一个消费者实例,通过连接;执行消费者构建;消费offset (偏移量);记录消息偏移量。

9.3 组消费模型
这里写图片描述
同样4个分区,P0-P3,这里使用GroupA,GroupB,GroupA可获取0,3,1,2分区的数据,GourpB也是。分组消费模型中,每个组都能拿到kafka集群当前全量数据。
4、组消费实现思路
(1)获取group里有多少个consumer实例
(2)根据实例个数,创建线程
(3)执行run方法,启动消费
两种消费模型对比:
分区消费模型更加灵活但是:
(1)需要自己处理各种异常情况;
(2)需要自己管理offset(以实现消息传递的其他语义);
组消费模型更加简单,但是不灵活:
(1)不需要自己处理异常情况,不需要自己管理offset;
(2)只能实现kafka默认的最少一次消息传递语义;

十:Java编写生产者和消费者
生产者:

10.1 创建maven工程,pom.xml中增加如下

 <dependency>  
          <groupId>org.apache.kafka</groupId>  
          <artifactId>kafka_2.10</artifactId>  
          <version>0.8.2.0</version>  
   </dependency> 

10.2.向主题test内写入数据

package com.kafka;

import java.util.Properties;  
import java.util.concurrent.TimeUnit;  

import kafka.javaapi.producer.Producer;  
import kafka.producer.KeyedMessage;  
import kafka.producer.ProducerConfig;  
import kafka.serializer.StringEncoder;  




public class kafkaProducer extends Thread{  

    private String topic;  

    public kafkaProducer(String topic){  
        super();  
        this.topic = topic;  
    }  


    @Override  
    public void run() {  
        Producer producer = createProducer();  
        int i=0;  
        while(true){  
            producer.send(new KeyedMessage<Integer, String>(topic, "message: " + i++));  
            try {  
                TimeUnit.SECONDS.sleep(1);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

    private Producer createProducer() {  
        Properties properties = new Properties();  
        properties.put("zookeeper.connect", "192.168.229.130:12181,192.168.229.136:12181,192.168.229.135:12181");//声明zk  
        properties.put("serializer.class", StringEncoder.class.getName());  
        properties.put("metadata.broker.list", "192.168.229.130:9092,192.168.229.135:9092,192.168.229.136:9092");// 声明kafka broker  
        return new Producer<Integer, String>(new ProducerConfig(properties));  
     }  


    public static void main(String[] args) {  
        new kafkaProducer("test").start();// 使用kafka集群中创建好的主题 test   

    }  

}  

消费者:

package com.kafka;
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
import java.util.Properties;  

import kafka.consumer.Consumer;  
import kafka.consumer.ConsumerConfig;  
import kafka.consumer.ConsumerIterator;  
import kafka.consumer.KafkaStream;  
import kafka.javaapi.consumer.ConsumerConnector;  
public class kafkaConsumer extends Thread{  

    private String topic;  

    public kafkaConsumer(String topic){  
        super();  
        this.topic = topic;  
    }  


    @Override  
    public void run() {  
        ConsumerConnector consumer = createConsumer();  
        Map<String, Integer> topicCountMap = new HashMap<String, Integer>();  
        topicCountMap.put(topic, 1); // 一次从主题中获取一个数据  
         Map<String, List<KafkaStream<byte[], byte[]>>>  messageStreams = consumer.createMessageStreams(topicCountMap);  
         KafkaStream<byte[], byte[]> stream = messageStreams.get(topic).get(0);// 获取每次接收到的这个数据  
         ConsumerIterator<byte[], byte[]> iterator =  stream.iterator();  
         while(iterator.hasNext()){  
             String message = new String(iterator.next().message());  
             System.out.println("接收到: " + message);  
         }  
    }  

    private ConsumerConnector createConsumer() {  
        Properties properties = new Properties();  
        properties.put("zookeeper.connect", "192.168.229.130:12181,192.168.229.136:12181,192.168.229.135:12181");//声明zk  
        properties.put("group.id", "group1");// 必须要使用别的组名称, 如果生产者和消费者都在同一组,则不能访问同一组内的topic数据  
        return Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));  
     }  


    public static void main(String[] args) {  
        new kafkaConsumer("test").start();// 使用kafka集群中创建好的主题 test   

    }  

}  

测试:
运行生产者和消费者
查看消费者输出
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值