Kafka(一)

KafKa架构图

在这里插入图片描述

简单说明什么是KafKa

Apache KafKa是消息中间件的一种。
举个例子:
生产者生产鸡蛋,消费者消费鸡蛋,生产者生产一个鸡蛋,消费者就消费一个鸡蛋,假设消费者消费鸡蛋的时候噎住了(系统宕机了),生产者还在生产鸡蛋,那新生产的鸡蛋就丢失了。再比如生产者很强劲(大交易量的情况),生产者1秒钟生产100个鸡蛋,消费者1秒钟只能吃50个鸡蛋,那要不了一会,消费者就吃不消了(消息堵塞,最终导致系统超时),消费者拒绝再吃了,”鸡蛋“又丢失了,这个时候我们放个篮子在它们中间,生产出来的鸡蛋都放到篮子里,消费者去篮子里拿鸡蛋,这样鸡蛋就不会丢失了,都在篮子里,而这个篮子就是”kafka“。
鸡蛋其实就是“数据流”,系统之间的交互都是通过“数据流”来传输的(就是tcp、http什么的),也称为报文,也叫“消息”。

KafKa的名词解释

producer:生产者,即生产鸡蛋的
consumer:消费者,消费鸡蛋的
topic: 可以理解为标签,生产 者生产出来的鸡蛋就贴上一个标签(topic),消费者并不是谁生产的“鸡蛋”都消费,这样不同 生产者生产出来的鸡蛋,消费者就可以选择性的吃了。
broker: 就是篮子
上面是从业务的角度,如果从技术的角度出发,topic标签实际上就是队列,生产者把所有 鸡蛋(消息)都放到对应的队列里面去,消费者到指定的队列里面取。

解释KafKa

1.kafka是一个发布订阅消息的分布式日志提交器,是个分布式消息队列系统
2.KafKa中的消息服务器都叫broker,
3.KafKa有两类客户端:Producer和Consumer
4.客户端和broker之间采用TCP协议,
5.KafKa中不同业务系统的消息可以通过topic进行区分,不同的业务系统,你给不同的topic就可以了,你生产者往这个topic里面写消息,我消费者可以指定哪个topic去拿消息,这样就可以把不同业务系统的消息区分开,而且每个topic还要进行分区,以分担消息读写的负载。
6.其实每一个分区都可以有多个副本,以防止数据的丢失,但是你有多个副本,数据的更新只能在其中一个副本上,否则多个副本之间的数据就不一致 了,
7.某一个分区中的数据如果需要更新,都必须通过该分区所有副本中的leader来更新,比如说你有一个分区叫t0,t0有三个副本,其中有一个肯定是个leader,另外一些事从节点或者从副本,那我们更新数据的时候必须通过leader来更新。
8.消费者在具体消费某个topic指定的分区时,可以指定起始偏移量,就是你从哪里开始消费起,这个topic可能有100个消息,你是从最前面消费,还是从后面消费,还是从中间某个地方开始消费起。

KafKa特点

1.快
一个单节点的KafKa 服务器(broker),就可以处理每秒数百兆字节的读写,而且可以响应数千个客户端。
2.可扩展的
kafka是被设计来用一个单一的集群来作为一个大型组织的中央数据总线,我们各个子系统,各个模块很多消息要传递,都可以通过Kafka来做,都可以把它输入到Kafka里面,其他的各个子系统啊,都可以到kafKa里面拿到这些消息。它可以非常简单的,透明化的扩展,而且不需要停止服务,数据流可以被分区到整个集群的很多机器上,也就是它的分布式。
3.持久的
写进去的消息是被持久化到磁盘上的,kafka并不是存内存的缓存,我们的消息其实是被存到磁盘上的,所以消息不会丢,而且它在这个集群上把我们的消息复制成很多份,以防止数据的丢失,这个就类似于HDFS,每个block会有多个副本,kafka也是,每个副本会有多个副本存在不同的机器上,而且每个broker可以用来处理T级别的消息,这么大的消息也不会有性能上的影响。
4.完全分布式
以分布式的思想来设计的

kafka应用场景里面的架构图

在这里插入图片描述
producer就相当于往kafka里面存东西
consumer相当于往kafka里面读东西
三者之间的连接采用的是TCP协议
客户端用什么语言:这个是有很多的

KafKa内部结构

分布式集群,里面有很多的server(broker–经纪人,中间商),KafKa的服务器都叫broker,broker在管理消息数据的时候,他是会对消息进行分区的,首先消息是分主题的,因为这个KafKa可能会给很多个子系统的服务 ,不同子系统发的消息应该区分一下
通过这个主题区分的,不同的子系统需要处理的消息放到不同主题(topic)里面去,然后不同的消息呢,里面是分区的,partition0,partition1…,分区的含义和意义在哪里呢?就是负载的均衡,读写都被分散到了更多的服务器上面去,就是同一个topic上面的东西,比如说我有0,1,2,3,4分区,那server1上管理 p0,p3分区,server2上管理P1,P2分区,那么读写的负载就被分散了,分散到不同机器上面去,所以它是把消息进行分区。
然后不同子系统打的消息,我们还可以用topic把它区分开。
在这里插入图片描述

消费者可以分组的,比如说我有一个topic,总共有两组消费者,那么每一组消费者只会消费这个topic里面的一部分数据,这两个组消费的数据永远也不会重复

关于KafKa

在这里插入图片描述
HDFS/Hbase/Project需要从LogServer中获取数据存储下来,需要使用到Flume,相当于flume从logServer中采集日志信息,存储到当前介子中,一般来说HDF/HBASE存储的都是海量,作为离线分析的依据
假设每一段时间就像LogServer进行一次日志采集,存储到HDFS/HBASE可以完成这个任务,提供一个定时任务即可。
在这里插入图片描述

若项目增加 ,需要Flume去请求LogServer中的数据,此时LogServer的压力就会增大

为了解决这个问题,可以引入一个消息中间件Kafka来完成这个任务Flume请求LogServer的压力就转嫁于Kafka
在这里插入图片描述

Flume不能这么做,它扛不住。Kafka能同时让多个消费者同时消费一个项目,是一对多模型。


Kafka是一个开源的项目是Apache基金会,由Scala编写,是一个消息项目,该设计目标是为了处理实时数据提供一个统一的高吞吐,低等待的一个平台。
Kafka是一个分布式消息队列,生产者和消费者的功能,他提供了类似于JMS的特性,但是在设计实现上完全不相同,此外它并不是JMS规范的实现

Kafka对消息的保存根据Topic进行归类,发送消息称weightProducer,接收消息的陈隔日Consumer
此外Kafka集群有多个Kafka实例组成,每个实例(server)称为broker
这些都依赖于zookeeper保存一些信息meta信息,用来保证系统的可用性

ps:Kafka是不提供生产者和消费者,这只是一个概念,并且Kafka的数据模型所提供

例如Flume从logServer中拉取数据到kafka,Flume就相当于生产者
SparkStreaming从Kafka中拉取数据,SparkStreaming就相当于消费者

官网:http://kafka.apache.org

1.什么是JMS(消息队列,ActiveEMQ,kafka)

1.1.JMS的基础
1).JMS是什么:JMS是Java提供的一套技术规范
2).JMS干什么用:用来异构系统 集成通信,缓解系统瓶颈,提高系统的伸缩性增强系统用户体验,使得系统模块化和组件化变得可行并更加灵活
3).通过什么方式:生产消费者模式(生产者、服务器、消费者)
在这里插入图片描述
jdk,kafka,active
1.2.JMS消息传输
1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
点对点模型通常是一个基于拉取或者轮询的消息传送模型,这种模型从队列中请求信息,而不是将消息推送到客户
端。这个模型的特点是发送到队列的消息被一个且只有一个接收者接收处理,即使有多个消息监听者也是如此。
2) 发布/订阅模式(一对多,数据生产后,推送给所有订阅者)

发布订阅模型则是一个基于推送的消息传送模型。发布订阅模型可以有多种不同的订阅者,临时订阅者只在主动监
听主题时才接收消息,而持久订阅者则监听主题的所有消息,即当前订阅者不可用,处于离线状态。

queue.put(object) 数据生产
queue.take(object) 数据消费

1.3、JMS核心组件
1)Destination:消息发送的目的地,也就是前面说的Queue和Topic。
2)Message :从字面上就可以看出是被发送的消息。
3)Producer: 消息的生产者,要发送一个消息,必须通过这个生产者来发送。
4)MessageConsumer: 与生产者相对应,这是消息的消费者或接收者,通过它来接收一个消息

通过与ConnectionFactory可以获得一个connection
通过connection可以获得一个session会话。

1.4、常见的类JMS消息服务器
1.4.1、JMS消息服务器 ActiveMQ
ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的。
主要特点:
1) 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,StompREST,WS Notification,XMPP,AMQP
2) 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
3) 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
4) 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors
的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
5) 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
6) 支持通过JDBC和journal提供高速的消息持久化
7) 从设计上保证了高性能的集群,客户端-服务器,点对点
8) 支持Ajax
9) 支持与Axis的整合
10) 可以很容易得调用内嵌JMS provider,进行测试
1.4.2、分布式消息中间件 Metamorphosis
Metamorphosis (MetaQ) 是一个高性能、高可用、可扩展的分布式消息中间件,类似于LinkedIn的Kafka,具有消息存储顺序写、吞吐量大和支持本地和XA事务等特性,适用于大吞吐量、顺序消息、广播和日志数据传输等场景,在淘宝和支付宝有着广泛的应用,现已开源。
主要特点:
l 生产者、服务器和消费者都可分布
l 消息存储顺序写
l 性能极高,吞吐量大
l 支持消息顺序
l 支持本地和XA事务
l 客户端pull,随机读,利用sendfile系统调用,zero-copy ,批量拉数据
l 支持消费端事务
l 支持消息广播模式
l 支持异步发送消息
l 支持http协议
l 支持消息重试和recover
l 数据迁移、扩容对用户透明
l 消费状态保存在客户端
l 支持同步和异步复制两种HA
l 支持group commit
1.4.3、分布式消息中间件 RocketMQ
RocketMQ 是一款分布式、队列模型的消息中间件,具有以下特点:
l 能够保证严格的消息顺序
l 提供丰富的消息拉取模式
l 高效的订阅者水平扩展能力
l 实时的消息订阅机制
l 亿级消息堆积能力
l Metaq3.0 版本改名,产品名称改为RocketMQ
1.4.4、其他MQ
l .NET消息中间件 DotNetMQ
l 基于HBase的消息队列 HQueue
l Go 的 MQ 框架 KiteQ
l AMQP消息服务器 RabbitMQ
l MemcacheQ 是一个基于 MemcacheDB 的消息队列服务器。

2、为什么需要消息队列(重要、了解)
1)消息系统的核心作用就是三点:解耦,异步和并行
2)以用户注册的案列来说明消息系统的作用
2.1、用户注册的一般流程
在这里插入图片描述

问题:随着后端流程越来越多,每步流程都需要额外的耗费很多时间,从而会导致用户更长的等待延迟。

2.2、用户注册的并行执行
在这里插入图片描述

问题:系统并行的发起了4个请求,4个请求中,如果某一个环节执行1分钟,其他环节再快,用户也需要等待1分钟。如果其中一个环节异常之后,整个服务挂掉了。
在这里插入图片描述
3.3、用户注册的最终一致
在这里插入图片描述

 1、 保证主流程的正常执行、执行成功之后,发送MQ消息出去。
 2、 需要这个destination的其他系统通过消费数据再执行,最终一致。

Kafka中重要的角色

在这里插入图片描述
在这里插入图片描述
1)不同consumer不能消费同一个分区数据
若一个consumer已经请求了分区中的数据,另外一个consumer就需要进入等待状态,统一组内的consumer消费完数据之后,它会修改其偏移量–offset
其它consumer获取的就是消费过后的偏移量,还是要消费这个数据,可以进行修改组名的方式,这种方式还可以处理consumer的数据丢失问题。

producer向Kafka存储数据的时候,对Kafka做一个镜像服务,镜像服务和原有Kafka服务器中数据是完全相同,若consumer中的数据需要重新消费或者是丢失们可以去镜像服务器中获取。

2)producer:生产者
1.生产者主要负责采集数据,并把数据存储到Kafka集群中
生产者 往往会监控一个目录或一个服务负责把数据传输到Kafka
2.生产者不仅是一个,它可以是一个生产者集群(组)是由多个进程组成,
一个生产者是一个独立的进程
3.多个生产者发送的数据可以存同一个topic中,也可以存储到同一个partition中
4.一个生产者生产的数据可以同时传输给多个topic中
5.单个生产者就具备数据分发能力

3)kafka集群
1.Kafka集群可以保存多中数据类型,通常一种数据类型可以放到一个topic中,一个Kafka集群可以创建多个topic
2.每个topic可以创建多个分区和副本,在创建topic许指定,可以在后去代码中修改分区数和副本
3.每个分区的数据,就是由多个segment组成的一个segment文件中有多个index和数据文件,而index文件和数据文件一一对应
4.一个topic的分区可以有多个副本,原始数据和副本可以不再同一个节点
量大,消费者不多,需要实时更改–Kafka

4)consumer组:
1.消费者负责消费数据(拉取) 比如:Storm,SparkStreaming
2.消费者是有组(group)的概念,在同一个组中,多个消费者可以同时消费同一个topic中不同分区中数据
3.新增或减少consumer的数据量就会触发Kafka的负载均衡
4.一个分区中的数据在同一时刻只能被一个consumer来消费,如果别的consumer想消费数据,需要等到上一个consumer在消费之后(前一个consumer没有将数据完全消费完)
5.consumer成员之间的消费数据各不相同,在同一个组中可以 重复消费

Kafka名词解释和工作方式

Producer :消息生产者,就是向kafka broker发消息的客户端。
Consumer :消息消费者,向kafka broker拉取消息的客户端
Topic :我们可以理解为一个队列。
Consumer Group (CG):这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个partion只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic.
Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。Offset:kafka的存储文件都是按照offset.kafka来命名,用offset做名字的好处是方便查找。例如你想找位于2049的位置,只要找到2048.kafka的文件即可.当然the first offset就是00000000000.kafka

kafka常见问题

1.segment的概念
topic中会有一个到多个分区,每个分区中会有多个segment
segment的大小是在Kafka文件中进行配置的

segment的大小是相等的,每个segment有多个index文件和数据文件是一一对应的
ps:index文件中存储的是索引,也就是文件存储的位置
2.数据存储机制
首先是broker接收到数据,将数据放到操作系统中(Linux)的缓存中(pagecache)
pagecache会尽可能的使用空闲内存会使用sendfile技术尽可能减少操作系统和应用程序之间重复缓存
写入数据的时候还会用到顺序写入的方式
写入数据的速度达到600m/s(300-400之间是合理的) 读取数据 20m/s - 30m/s
3.consumer是怎么解决负载均衡
当同一个组的consumer数据发生改变的时候,触发Kafka的负载均衡
首先会获取consumer消费的起始分区号,在计算出consumer要消费的分区数量
最后用起始分区号的hashCode值取余分区数

consumer负载均衡

当一个group中,有consumer加入或者离开时,会触发partitions负载均衡.负载均衡的最终目的,是提升topic的并发消费能力,步骤如下:
1、 假如topic1,具有如下partitions: P0,P1,P2,P3
2、 加入group中,有如下consumer: C1,C2
3、 首先根据partition索引号对partitions排序: P0,P1,P2,P3
4、 根据consumer.id排序: C1,C2
5、 计算倍数: M = [P0,P1,P2,P3].size / [C1,C2].size,本例值M=2(向上取整)
6、 然后依次分配partitions: C1 = [P0,P3],C2=[P1,P2],即Ci = [P(i * M),P((i + 1) * M -1)]

4.数据的分发策略
Kafka默认会调用自己的分区器(DefaultPartition)进行分区,也可以自定义分区器
自定义分区器需要实现partitioner(特质),实现Partition方法

key.hashCode % numPartition

5.kafka是怎么保证数据不丢失
镜像服务器,成本比较高,Kafka接收数据会创建topic指定副本的数量
副本的数量是由Kafka自己进行同步的,多副本就保证了安全性

6.kafka可以保证topic里面的数据全局有序吗?
kafka可以做到分区内有序,分区之间是无序的
若需要做到全局有序,创建topic的时候指定分区数

Consumer与topic的关系

本质上kafka只支持Topic;
每个group中可以有多个consumer,每个consumer属于一个consumer group;
通常情况下,一个group中会包含多个consumer,这样不仅可以提高topic中消息的并发消费能力,而且还能提高"故障容错"性,如果group中的某个consumer失效那么其消费的partitions将会有其他consumer自动接管。对于Topic中的一条特定的消息,只会被订阅此Topic的每个group中的其中一个consumer消费,此消息不会发送给一个group的多个consumer;那么一个group中所有的consumer将会交错的消费整个Topic,每个group中consumer消息消费互相独立,我们可以认为一个group是一个"订阅"者。
在kafka中,一个partition中的消息只会被group中的一个consumer消费(同一时刻);
一个Topic中的每个partition,只会被一个"订阅者"中的一个consumer消费,不过一个consumer可以同时消费多个partition中的消息。
kafka的设计原理决定,对于一个topic,同一个group中不能有多于partition个数的consumer同时消费,否则将意味着某些consumer将无法得到消息。
kafka只能保证一个partition中的消息被某个consumer消费时是顺序的;事实上,从Topic角度来说,当有多个partitions时,消息仍不是全局有序的。

Kafka消息的分发

Producer客户端负责消息的分发
kafka集群中的任何一个broker都可以向producer提供metadata信息,这些metadata中包含"集群中存活的servers列表"/"partitions leader列表"等信息;

当producer获取到metadata信息之后, producer将会和Topic下所有partition leader保持socket连接;

消息由producer直接通过socket发送到broker,中间不会经过任何"路由层",事实上,消息被路由到哪个partition上由producer客户端决定;

比如可以采用"random"“key-hash”"轮询"等,如果一个topic中有多个partitions,那么在producer端实现"消息均衡分发"是必要的。

l 在producer端的配置文件中,开发者可以指定partition路由的方式。
Producer消息发送的应答机制

设置发送数据是否需要服务端的反馈,有三个值0,1,-1
0: produce不会等待broker发送ack
1: 当leader接收到消息之后发送ack
-1: 当所有的follower都同步消息成功后发送ack
request.required.acks=0

搭建集群

需要搭建zookeeper和关闭防火墙
1.上传安装包Kafka到hadoop1
2.解压到/opt/software
3.进入到Kafka安装路径下的conf目录
cd /opt/software/kafka_2.11-0.9.0.1/config
ps:因为配置过多 不建议手写,所以提供配置文件代替,需要将原有的文件备份
4.件producer,server,consumer进行备份
mv ./consumer.properties ./producer.properties.bak
mv ./consumer.properties ./consumer.properties.bak
mv ./consumer.properties ./server.properties.bak

将下面的配置上传到kafka安装目录下的config文件夹下:
1.producer.properties

#指定kafka节点列表,用于获取metadata,不必全部指定(这里需要改)
metadata.broker.list=hadoop1:9092,hadoop3:9092,hadoop4:9092

# 指定分区处理类。默认kafka.producer.DefaultPartitioner,表通过key哈希到对应分区
#partitioner.class=kafka.producer.DefaultPartitioner

# 是否压缩,默认0表示不压缩,1表示用gzip压缩,2表示用snappy压缩。压缩后消息中会有头来指明消息压缩类型,故在消费者端消息解压是透明的无需指定。
compression.codec=none

# 指定序列化处理类
serializer.class=kafka.serializer.DefaultEncoder

# 如果要压缩消息,这里指定哪些topic要压缩消息,默认empty,表示不压缩。
#compressed.topics=

# 设置发送数据是否需要服务端的反馈,有三个值0,1,-1
# 0: producer不会等待broker发送ack 
# 1: 当leader接收到消息之后发送ack 
# -1: 当所有的follower都同步消息成功后发送ack. 
request.required.acks=0 

# 在向producer发送ack之前,broker允许等待的最大时间 ,如果超时,broker将会向producer发送一个error ACK.意味着上一次消息因为某种原因未能成功(比如follower未能同步成功) 
request.timeout.ms=10000

# 同步还是异步发送消息,默认“sync”表同步,"async"表异步。异步可以提高发送吞吐量,也意味着消息将会在本地buffer中,并适时批量发送,但是也可能导致丢失未发送过去的消息
producer.type=sync

# 在async模式下,当message被缓存的时间超过此值后,将会批量发送给broker,默认为5000ms
# 此值和batch.num.messages协同工作.
queue.buffering.max.ms = 5000

# 在async模式下,producer端允许buffer的最大消息量
# 无论如何,producer都无法尽快的将消息发送给broker,从而导致消息在producer端大量沉积
# 此时,如果消息的条数达到阀值,将会导致producer端阻塞或者消息被抛弃,默认为10000
queue.buffering.max.messages=20000

# 如果是异步,指定每次批量发送数据量,默认为200
batch.num.messages=500

# 当消息在producer端沉积的条数达到"queue.buffering.max.meesages"后 
# 阻塞一定时间后,队列仍然没有enqueue(producer仍然没有发送出任何消息) 
# 此时producer可以继续阻塞或者将消息抛弃,此timeout值用于控制"阻塞"的时间 
# -1: 无阻塞超时限制,消息不会被抛弃 
# 0:立即清空队列,消息被抛弃 
queue.enqueue.timeout.ms=-1


# 当producer接收到error ACK,或者没有接收到ACK时,允许消息重发的次数 
# 因为broker并没有完整的机制来避免消息重复,所以当网络异常时(比如ACK丢失) 
# 有可能导致broker接收到重复的消息,默认值为3.
message.send.max.retries=3

# producer刷新topic metada的时间间隔,producer需要知道partition leader的位置,以及当前topic的情况 
# 因此producer需要一个机制来获取最新的metadata,当producer遇到特定错误时,将会立即刷新 
# (比如topic失效,partition丢失,leader失效等),此外也可以通过此参数来配置额外的刷新机制,默认值600000 
topic.metadata.refresh.interval.ms=60000

2.consumer.properties

# zookeeper连接服务器地址(这个里需要修改)
zookeeper.connect=hadoop2:2181,hadoop3:2181,hadoop4:2181

# zookeeper的session过期时间,默认5000ms,用于检测消费者是否挂掉
zookeeper.session.timeout.ms=5000

#当消费者挂掉,其他消费者要等该指定时间才能检查到并且触发重新负载均衡
zookeeper.connection.timeout.ms=10000

# 指定多久消费者更新offset到zookeeper中。注意offset更新时基于time而不是每次获得的消息。一旦在更新zookeeper发生异常并重启,将可能拿到已拿到过的消息
zookeeper.sync.time.ms=2000

#指定消费组
group.id=xxx

# 当consumer消费一定量的消息之后,将会自动向zookeeper提交offset信息 
# 注意offset信息并不是每消费一次消息就向zk提交一次,而是现在本地保存(内存),并定期提交,默认为true
auto.commit.enable=true

# 自动更新时间。默认60 * 1000
auto.commit.interval.ms=1000

# 当前consumer的标识,可以设定,也可以由系统生成,主要用来跟踪消息消费情况,便于观察
conusmer.id=xxx

# 消费者客户端编号,用于区分不同客户端,默认客户端程序自动产生
client.id=xxxx

# 最大取多少块缓存到消费者(默认10)
queued.max.message.chunks=50

# 当有新的consumer加入到group时,将会reblance,此后将会有partitions的消费端迁移到新的consumer上,如果一个consumer获得了某个partition的消费权限,那么它将会向zk注册 "Partition Owner registry"节点信息,但是有可能此时旧的consumer尚没有释放此节点, 此值用于控制,注册节点的重试次数. 
rebalance.max.retries=5

# 获取消息的最大尺寸,broker不会像consumer输出大于此值的消息chunk 每次feth将得到多条消息,此值为总大小,提升此值,将会消耗更多的consumer端内存
fetch.min.bytes=6553600

# 当消息的尺寸不足时,server阻塞的时间,如果超时,消息将立即发送给consumer
fetch.wait.max.ms=5000
socket.receive.buffer.bytes=655360

# 如果zookeeper没有offset值或offset值超出范围。那么就给个初始的offset。有smallest、largest、anything可选,分别表示给当前最小的offset、当前最大的offset、抛异常。默认largest
auto.offset.reset=smallest

# 指定序列化处理类
derializer.class=kafka.serializer.DefaultDecoder

3.server.properties

#broker的全局唯一编号,不能重复(每台服务器不能相同依次类推)
broker.id=0

#用来监听链接的端口,producer或consumer将在此端口建立连接
port=9092

#处理网络请求的线程数量
num.network.threads=3

#用来处理磁盘IO的线程数量
num.io.threads=8

#发送套接字的缓冲区大小
socket.send.buffer.bytes=102400

#接受套接字的缓冲区大小
socket.receive.buffer.bytes=102400

#请求套接字的缓冲区大小
socket.request.max.bytes=104857600

#kafka消息存放的路径(需要设置)
log.dirs=/opt/software/logs/kafka

#topic在当前broker上的分片个数
num.partitions=2

#用来恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1

#segment文件保留的最长时间,超时将被删除
log.retention.hours=168

#滚动生成新的segment文件的最大时间
log.roll.hours=168

#日志文件中每个segment的大小,默认为1G
log.segment.bytes=1073741824

#周期性检查文件大小的时间
log.retention.check.interval.ms=300000

#日志清理是否打开
log.cleaner.enable=true

#broker需要使用zookeeper保存meta数据(这个需要修改)
zookeeper.connect=hadoop2:2181,hadoop3:2181,hadoop4:2181

#zookeeper链接超时时间
zookeeper.connection.timeout.ms=6000

#partion buffer中,消息的条数达到阈值,将触发flush到磁盘
log.flush.interval.messages=10000

#消息buffer的时间,达到阈值,将触发flush到磁盘
log.flush.interval.ms=3000

#删除topic需要server.properties中设置delete.topic.enable=true否则只是标记删除
delete.topic.enable=true

#此处的host.name为本机IP(重要),如果不改,则客户端会抛出:Producer connection to localhost:9092 unsuccessful 错误!
host.name=hadoop1

5.将目录进行分发
scp -r ./kafka_2.11-0.9.0.1/ root@hadoop3: P W D s c p r . / k a f k a 2 . 11 0.9.0.1 / r o o t @ h a d o o p 4 : PWD scp -r ./kafka_2.11-0.9.0.1/ root@hadoop4: PWD
6.进入到分发过后的节点,进入Kafka安装路径中config路径修改server文件
hadoop3中将broker.id = 1
hadoop4中将broker.id = 2

7.启动kafka集群(必须先启动zk)
进入kafka bin目录下进行启动
因为kafka前台启动不方便,启动到后台
8.在每一台节点上启动broker
nohup kafka-server-start.sh /opt/software/kafka_2.11-0.9.0.1/config/server.properties &

Kafka的常用命令

进入到安装目录bin目录下
1.查看服务器中所有topic
kafka-topics.sh --list --zookeeper hadoop2:2181
2.创建topic
replication指定副本数量 partition 分区
kafka-topics.sh --create --zookeeper hadoop2:2181 --replication-factor 1 --partition 1 --topic test
3.通过shell发送消息
1)其中一台kafka模拟生产者
kafka-console-producer.sh --broker-list hadoop1:9092 --topic test
2)其中一台kafka模拟消费者
kafka-console-consumer.sh --zookeeper hadoop2:2181 from-begining --topic test
4.查看信息:
kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper hadoop2:2181 --group testGroup
5.删除topic
kafka-topics.sh --delete --zookeeper hadoop2:2181 --topic test
对分区数进行修改:
kafka-topics.sh --zookeeper hadoop2:2181 hadoop1 --alter --partitions 15 --topic test
ps:尽量不要修改,在创建的时候一般会指定好

生产者:

import java.util.Properties

import kafka.javaapi.producer.Producer
import kafka.producer.{KeyedMessage, ProducerConfig}

object KafkaProducerDemo {
  def main(args: Array[String]): Unit = {
    //定义一个topic
    val topic = "test"
    //创建一个配置类
    val prop  = new Properties()
    //指定序列化器
    prop.put("serializer.class","kafka.serializer.StringEncoder")
    prop.put("metadata.broker.list","hadoop1:9092,hadoop3:9092,hadoop4:9092")
   //设置发送数据后的响应方式
    prop.put("request.required.acks","1")
    //调用分区器
    prop.put("partitioner.class","kafka.producer.DefaultPartitioner")
    //自定义分区器
//    prop.put("partitioner.class","自定义分区器")
    //把配置信息封装到ProducerConfig中
    val config = new ProducerConfig(prop)
    //ProducerConfig来创建Producer实例
    //创建 Producer对象
    val p: Producer[String, String] = new Producer(config)
    //模拟数据产生
    for(i <- 1 to 10000){
      val msg = i + "Producer send data"
      //发送数据
      p.send(new KeyedMessage[String,String](topic,msg))
      //延迟 不然太过迅猛
      Thread.sleep(500)
    }
  }
}

消费者

import kafka.consumer.{Consumer, ConsumerConfig, ConsumerConnector, KafkaStream}
import kafka.message.MessageAndMetadata

import scala.actors.threadpool.{ExecutorService, Executors}
import scala.collection.mutable

class  KafkaConsumerDemo(val consumer:String ,val stream:KafkaStream[Array[Byte], Array[Byte]]) extends Runnable{
  override def run(): Unit = {
    //转换成迭代器对象
    val it = stream.iterator()
    while (it.hasNext()){
      val data: MessageAndMetadata[Array[Byte], Array[Byte]] = it.next()
      val topic = data.topic
      val offset = data.offset
      val partition: Int = data.partition
      val msg: String = new String(data.message())
      println("Consumer: "+consumer+topic+offset+partition+"msg:"+msg)
    }
  }
}

/**
  * 模拟消费者
  */
object KafkaConsumerDemo {
  def main(args: Array[String]): Unit = {
    //读取topic的名称
    val topic = "test"
    //定义一个map,用来存储多个topic 第二个参数是使用多个线程来读取topic
    val topics = new mutable.HashMap[String,Int]();
    topics.put(topic,2)
    //创建配置信息
    val prop = new  Properties()
    //指定consumer组
    prop.put("group.id","group01")
    //指定zookeeper列表,获取数据的offset
    prop.put("zookeeper.connect","hadoop2:2181,hadoop3:2181,hadoop4:2181")

    /**
      * 如果zookeeper没有offset值或offset值超出范围,那么就给个初始的offset
      * 有smallest、largest、auto.offset.reset = smallsest
      *
      * 如果zookeeper没有offset值或offset值超出范围。那么就给个初始的offset。有smallest、largest、anything可选,
      * 分别表示给当前最小的offset、当前最大的offset、抛异常。默认largest
      */
    prop.put("auto.offset.reset","smallest")
    //创建ConsumerConfig对象
    val config: ConsumerConfig = new ConsumerConfig(prop)
    //创建Consumer实例
    val consumer: ConsumerConnector = Consumer.create(config)
    //获取数据 map的key是topic名称 value获取来的数据
    val streams: collection.Map[String, List[KafkaStream[Array[Byte], Array[Byte]]]] = consumer.createMessageStreams(topics)
    //获取指定的topic数据
    val stream: Option[List[KafkaStream[Array[Byte], Array[Byte]]]] = streams.get(topic)

    //创建一个线程池
    val pool: ExecutorService = Executors.newFixedThreadPool(3)
    for (i <- 0 until stream.size){
      pool.execute(new KafkaConsumerDemo(i+"",stream.get(i)))
    }
    //Kafka中必须有test的topic
  }
}

猜你喜欢

转载自blog.csdn.net/qq_35078688/article/details/84981455