Kafka学习笔记

Kafka学习笔记
1、参考
http://www.aboutyun.com/thread-12882-1-1.html
Kafka入门经典教程
下载地址:http://kafka.apache.org/downloads.html

2、消息系统术语
Kafka将消息以topic为单位进行归纳。
将向Kafka topic发布消息的程序成为producers.
将预订topics并消费消息的程序成为consumer.
Kafka以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个broker.
producers通过网络将消息发送到Kafka集群,集群向消费者提供消息。
客户端和服务端通过TCP协议通信。

3、topics
一个topic是对一组消息的归纳。对每个topic,Kafka 对它的日志进行了分区

每个分区都由一系列有序的、不可变的消息组成,这些消息被连续的追加到分区中。分区中的每个消息都有一个连续的序列号叫做offset,用来在分区中唯一的标识这个消息。
实际上每个consumer唯一需要维护的数据是消息在日志中的位置,也就是offset.这个offset有consumer来维护:一般情况下随着consumer不断的读取消息,这offset的值不断增加,但其实consumer可以以任意的顺序读取消息,比如它可以将offset设置成为一个旧的值来重读之前的消息。

将日志分区可以达到以下目的:首先这使得每个日志的数量不会太大,可以在单个服务上保存。另外每个分区可以单独发布和消费,为并发操作topic提供了一种可能。

分布式
每个分区都由一个服务器作为“leader”,零或若干服务器作为“followers”,leader负责处理消息的读和写,followers则去复制leader.如果leader down了,followers中的一台则会自动成为leader。集群中的每个服务都会同时扮演两个角色:作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。

Producers
Producer将消息发布到它指定的topic中,并负责决定发布到哪个分区。通常简单的由负载均衡机制随机选择分区,但也可以通过特定的分区函数选择分区。使用的更多的是第二种。

Consumers
发布消息通常有两种模式:队列模式(queuing)和发布-订阅模式(publish-subscribe)。
队列模式中,consumers可以同时从服务端读取消息,每个消息只被其中一个consumer读到;发布-订阅模式中消息被广播到所有的consumer中。

Consumers可以加入一个consumer 组,共同竞争一个topic,topic中的消息将被分发到组中的一个成员中。同一组中的consumer可以在不同的程序中,也可以在不同的机器上。如果所有的consumer都在一个组中,这就成为了传统的队列模式,在各consumer中实现负载均衡。如果所有的consumer都不在不同的组中,这就成为了发布-订阅模式,所有的消息都被分发到所有的consumer中。

相比传统的消息系统,Kafka可以很好的保证有序性。
将每个分区分只分发给一个consumer组,这样一个分区就只被这个组的一个consumer消费,就可以顺序的消费这个分区的消息。因为有多个分区,依然可以在多个consumer组之间进行负载均衡。注意consumer组的数量不能多于分区的数量,也就是有多少分区就允许多少并发消费。
Kafka只能保证一个分区之内消息的有序性,在不同的分区之间是不可以的,这已经可以满足大部分应用的需求。如果需要topic中所有消息的有序性,那就只能让这个topic只有一个分区,当然也就只有一个consumer组消费它。

4、数据持久化
使用文件系统,即使系统重启了,也不需要刷新数据。使用文件系统也简化了维护数据一致性的逻辑。所以与传统的将数据缓存在内存中然后刷到硬盘的设计不同,Kafka直接将数据写到了文件系统的日志中。
直观的讲,对于主要用于日志处理的消息系统,数据的持久化可以简单的通过将数据追加到文件中实现,读的时候从文件中读就好了。这样做的好处是读和写都是 O(1) 的,并且读操作不会阻塞写操作和其他操作。这样带来的性能优势是很明显的,因为性能和数据的大小没有关系了。
既然可以使用几乎没有容量限制(相对于内存来说)的硬盘空间建立消息系统,就可以在没有性能损失的情况下提供一些一般消息系统不具备的特性。比如,一般的消息系统都是在消息被消费后立即删除,Kafka却可以将消息保存一段时间(比如一星期),这给consumer提供了很好的机动性和灵活性,这点在今后的文章中会有详述。

5、消息传输的事务定义(这里有疑问?)
数据传输的事务定义通常有以下三种级别:

最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输。
最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.
精确的一次(Exactly once): 不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次,这是大家所期望的。

当发布消息时,Kafka有一个“committed”的概念,一旦消息被提交了,只要消息被写入的分区的所在的副本broker是活动的,数据就不会丢失。
如果producer发布消息时发生了网络错误,但又不确定实在提交之前发生的还是提交之后发生的,这种情况虽然不常见,但是必须考虑进去,现在Kafka版本还没有解决这个问题,将来的版本正在努力尝试解决。

并不是所有的情况都需要“精确的一次”这样高的级别,Kafka允许producer灵活的指定级别。比如producer可以指定必须等待消息被提交的通知,或者完全的异步发送消息而不等待任何通知,或者仅仅等待leader声明它拿到了消息(followers没有必要)。

现在从consumer的方面考虑这个问题,所有的副本都有相同的日志文件和相同的offset,consumer维护自己消费的消息的offset,如果consumer不会崩溃当然可以在内存中保存这个值,当然谁也不能保证这点。如果consumer崩溃了,会有另外一个consumer接着消费消息,它需要从一个合适的offset继续处理。这种情况下可以有以下选择:

consumer可以先读取消息,然后将offset写入日志文件中,然后再处理消息。这存在一种可能就是在存储offset后还没处理消息就crash了,新的consumer继续从这个offset处理,那么就会有些消息永远不会被处理,这就是上面说的“最多一次”。
consumer可以先读取消息,处理消息,最后记录offset,当然如果在记录offset之前就crash了,新的consumer会重复的消费一些消息,这就是上面说的“最少一次”。
“精确一次”可以通过将提交分为两个阶段来解决:保存了offset后提交一次,消息处理成功之后再提交一次。但是还有个更简单的做法:将消息的offset和消息被处理后的结果保存在一起。比如用Hadoop ETL处理消息时,将处理后的结果和offset同时保存在HDFS中,这样就能保证消息和offser同时被处理了。

6、性能优化

Kafka建立了“消息集(message set)”的概念,将消息组织到一起,作为处理的单位。以消息集为单位处理消息,比以单个的消息为单位处理,会提升不少性能。Producer把消息集一块发送给服务端,而不是一条条的发送;服务端把消息集一次性的追加到日志文件中,这样减少了琐碎的I/O操作。consumer也可以一次性的请求一个消息集。

另外一个性能优化是在字节拷贝方面。Kafka使用了标准的二进制消息格式,这个格式可以在producer,broker和producer之间共享而无需做任何改动。

zero copy
Broker维护的消息日志仅仅是一些目录文件,消息集以固定队的格式写入到日志文件中,这个格式producer和consumer是共享的,这使得Kafka可以一个很重要的点进行优化:消息在网络上的传递。
现代的unix操作系统提供了高性能的将数据从页面缓存发送到socket的系统函数,在linux中,这个函数是sendfile.

为了更好的理解sendfile的好处,我们先来看下一般将数据从文件发送到socket的数据流向:
操作系统把数据从文件拷贝内核中的页缓存中
应用程序从页缓存从把数据拷贝自己的内存缓存中
应用程序将数据写入到内核中socket缓存中
操作系统把数据从socket缓存中拷贝到网卡接口缓存,从这里发送到网络上。

这显然是低效率的,有4次拷贝和2次系统调用。Sendfile通过直接将数据从页面缓存发送网卡接口缓存,避免了重复拷贝,大大的优化了性能。

在一个多consumers的场景里,数据仅仅被拷贝到页面缓存一次而不是每次消费消息的时候都重复的进行拷贝。这使得消息以近乎网络带宽的速率发送出去。这样在磁盘层面你几乎看不到任何的读操作,因为数据都是从页面缓存中直接发送到网络上去了。

Kafka采用了端到端的压缩:因为有“消息集”的概念,客户端的消息可以一起被压缩后送到服务端,并以压缩后的格式写入日志文件,以压缩的格式发送到consumer,消息从producer发出到consumer拿到都被是压缩的,只有在consumer使用的时候才被解压缩,所以叫做“端到端的压缩”。
Kafka支持GZIP和Snappy压缩协议。


7、Producer和Consumer

Kafka Producer消息发送
客户端控制消息将被分发到哪个分区。可以通过负载均衡随机的选择,或者使用分区函数。Kafka允许用户实现分区函数,指定分区的key,将消息hash到不同的分区上。

异步发送
批量发送可以很有效的提高发送效率。Kafka producer的异步发送模式允许进行批量发送,先将消息缓存在内存中,然后一次请求批量发送出去。这个策略可以配置的,比如可以指定缓存的消息达到某个量的时候就发出去,或者缓存了固定的时间后就发送出去(比如100条消息就发送,或者每5秒发送一次)。这种策略将大大减少服务端的I/O次数。
Kafka 0.9可能会增加这样的回调函数。

producer将消息推送到broker,consumer从broker拉取消息。
Pull拉取模式下,consumer就可以根据自己的消费能力去决定这些策略。
Pull有个缺点是,如果broker没有可供消费的消息,将导致consumer不断在循环中轮询,直到新消息到t达。为了避免这点,Kafka有个参数可以让consumer阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发送)。

Kafka采用了不同的策略。Topic被分成了若干分区,每个分区在同一时间只被一个consumer消费。这意味着每个分区被消费的消息在日志中的位置仅仅是一个简单的整数:offset。这样就很容易标记每个分区消费状态就很容易了,仅仅需要一个整数而已。这样消费状态的跟踪就很简单了。
这带来了另外一个好处:consumer可以把offset调成一个较老的值,去重新消费老的消息。

离线处理消息
高级的数据持久化允许consumer每个隔一段时间批量的将数据加载到线下系统中比如Hadoop或者数据仓库。

8、主从同步
Kafka允许topic的分区拥有若干副本,这个数量是可以配置的,你可以为每个topci配置副本的数量。Kafka会自动在每个个副本上备份数据,所以当一个节点down掉时数据依然是可用的。

Kafka的副本功能不是必须的,你可以配置只有一个副本,这样其实就相当于只有一份数据。
创建副本的单位是topic的分区,每个分区都有一个leader和零或多个followers.所有的读写操作都由leader处理,一般分区的数量都比broker的数量多的多,各分区的leader均匀的分布在brokers中。所有的followers都复制leader的日志,日志中的消息和顺序都和leader中的一致。flowers向普通的consumer那样从leader那里拉取消息并保存在自己的日志文件中。

Kafka判断一个节点是否活着有两个条件:
节点必须可以维护和ZooKeeper的连接,Zookeeper通过心跳机制检查每个节点的连接。
如果节点是个follower,他必须能及时的同步leader的写操作,延时不能太久。
Leader会追踪所有“同步中”的节点,一旦一个down掉了,或是卡住了,或是延时太久,leader就会把它移除。至于延时多久算是“太久”,是由参数replica.lag.max.messages决定的,怎样算是卡住了,怎是由参数replica.lag.time.max.ms决定的。

Leader的选择
Kafaka动态维护了一个同步状态的副本的集合(a set of in-sync replicas),简称ISR,在这个集合中的节点都是和leader保持高度一致的,任何一条消息必须被这个集合中的每个节点读取并追加到日志中了,才回通知外部这个消息已经被提交了。
因此这个集合中的任何一个节点随时都可以被选为leader.ISR在ZooKeeper中维护。ISR中有f+1个节点,就可以允许在f个节点down掉的情况下不会丢失消息并正常提供服。ISR的成员是动态的,如果一个节点被淘汰了,当它重新达到“同步中”的状态时,他可以重新加入ISR.这种leader的选择方式是非常快速的,适合kafka的应用场景。

副本管理
以上仅仅以一个topic一个分区为例子进行了讨论,但实际上一个Kafka将会管理成千上万的topic分区.Kafka尽量的使所有分区均匀的分布到集群所有的节点上而不是集中在某些节点上,另外主从关系也尽量均衡这样每个几点都会担任一定比例的分区的leader.
优化leader的选择过程也是很重要的,它决定了系统发生故障时的空窗期有多久。Kafka选择一个节点作为“controller”,当发现有节点down掉的时候它负责在游泳分区的所有节点中选择新的leader,这使得Kafka可以批量的高效的管理所有分区节点的主从关系。如果controller down掉了,活着的节点中的一个会备切换为新的controller.

9、客户端API
Kafka Producer APIs
Procuder API有两种:kafka.producer.SyncProducer和kafka.producer.async.AsyncProducer.它们都实现了同一个接口:
class Producer {
/* 将消息发送到指定分区 */
publicvoid send(kafka.javaapi.producer.ProducerData<K,V> producerData);
/* 批量发送一批消息 */
publicvoid send(java.util.List<kafka.javaapi.producer.ProducerData<K,V>> producerData);
/* 关闭producer */
publicvoid close();
}


Producer API提供了以下功能:
可以将多个消息缓存到本地队列里,然后异步的批量发送到broker,可以通过参数producer.type=async做到。缓存的大小可以通过一些参数指定:queue.time和batch.size。一个后台线程((kafka.producer.async.ProducerSendThread)从队列中取出数据并让kafka.producer.EventHandler将消息发送到broker,也可以通过参数event.handler定制handler,在producer端处理数据的不同的阶段注册处理器,比如可以对这一过程进行日志追踪,或进行一些监控。只需实现kafka.producer.async.CallbackHandler接口,并在callback.handler中配置。
自己编写Encoder来序列化消息,只需实现下面这个接口。默认的Encoder是kafka.serializer.DefaultEncoder。
interface Encoder<T> {
public Message toMessage(T data);
}
提供了基于Zookeeper的broker自动感知能力,可以通过参数zk.connect实现。如果不使用Zookeeper,也可以使用broker.list参数指定一个静态的brokers列表,这样消息将被随机的发送到一个broker上,一旦选中的broker失败了,消息发送也就失败了。
通过分区函数kafka.producer.Partitioner类对消息分区。
interface Partitioner<T> {
int partition(T key, int numPartitions);
}

分区函数有两个参数:key和可用的分区数量,从分区列表中选择一个分区并返回id。默认的分区策略是hash(key)%numPartitions.如果key是null,就随机的选择一个。可以通过参数partitioner.class定制分区函数。


KafKa Consumer APIs

Consumer API有两个级别。低级别的和一个指定的broker保持连接,并在接收完消息后关闭连接,这个级别是无状态的,每次读取消息都带着offset。

低级别的API

class SimpleConsumer {
/*向一个broker发送读取请求并得到消息集 */
public ByteBufferMessageSet fetch(FetchRequest request);
/*向一个broker发送读取请求并得到一个相应集 */
public MultiFetchResponse multifetch(List<FetchRequest> fetches);
/**
* 得到指定时间之前的offsets
* 返回值是offsets列表,以倒序排序
* @param time: 时间,毫秒,
* 如果指定为OffsetRequest$.MODULE$.LATIEST_TIME(), 得到最新的offset.
* 如果指定为OffsetRequest$.MODULE$.EARLIEST_TIME(),得到最老的offset.
*/
publiclong[] getOffsetsBefore(String topic, int partition, long time, int maxNumOffsets);
}



高级别的API

/* 创建连接 */
ConsumerConnector connector = Consumer.create(consumerConfig);
interface ConsumerConnector {
/**
* 这个方法可以得到一个流的列表,每个流都是MessageAndMetadata的迭代,通过MessageAndMetadata可以拿到消息和其他的元数据(目前之后topic)
* Input: a map of <topic, #streams>
* Output: a map of <topic, list of message streams>
*/
public Map<String,List<KafkaStream>> createMessageStreams(Map<String,Int> topicCountMap);
/**
* 你也可以得到一个流的列表,它包含了符合TopicFiler的消息的迭代,
* 一个TopicFilter是一个封装了白名单或黑名单的正则表达式。
*/
public List<KafkaStream> createMessageStreamsByFilter(
TopicFilter topicFilter, int numStreams);
/* 提交目前消费到的offset */
public commitOffsets()
/* 关闭连接 */
public shutdown()
}


这个API围绕着由KafkaStream实现的迭代器展开,每个流代表一系列从一个或多个分区多和broker上汇聚来的消息,每个流由一个线程处理,所以客户端可以在创建的时候通过参数指定想要几个流。一个流是多个分区多个broker的合并,但是每个分区的消息只会流向一个流。

每调用一次createMessageStreams都会将consumer注册到topic上,这样consumer和brokers之间的负载均衡就会进行调整。API鼓励每次调用创建更多的topic流以减少这种调整。createMessageStreamsByFilter方法注册监听可以感知新的符合filter的tipic。


10、消息和日志
消息由一个固定长度的头部和可变长度的字节数组组成。头部包含了一个版本号和CRC32校验码。

/**
* 具有N个字节的消息的格式如下
*
* 如果版本号是0
*
* 1. 1个字节的 "magic" 标记
*
* 2. 4个字节的CRC32校验码
*
* 3. N - 5个字节的具体信息
*
* 如果版本号是1
*
* 1. 1个字节的 "magic" 标记
*
* 2.1个字节的参数允许标注一些附加的信息比如是否压缩了,解码类型等
*
* 3.4个字节的CRC32校验码
*
* 4. N - 6 个字节的具体信息
*
*/


日志一个叫做“my_topic”且有两个分区的的topic,它的日志有两个文件夹组成,my_topic_0和my_topic_1,每个文件夹里放着具体的数据文件,每个数据文件都是一系列的日志实体,每个日志实体有一个4个字节的整数N标注消息的长度,后边跟着N个字节的消息。每个消息都可以由一个64位的整数offset标注,offset标注了这条消息在发送到这个分区的消息流中的起始位置。每个日志文件的名称都是这个文件第一条日志的offset.所以第一个日志文件的名字就是00000000000.kafka.所以每相邻的两个文件名字的差就是一个数字S,S差不多就是配置文件中指定的日志文件的最大容量。
消息的格式都由一个统一的接口维护,所以消息可以在producer,broker和consumer之间无缝的传递。存储在硬盘上的消息格式如下所示:
消息长度: 4 bytes (value: 1+4+n)
版本号: 1 byte
CRC校验码: 4 bytes
具体的消息: n bytes


写操作消息被不断的追加到最后一个日志的末尾,当日志的大小达到一个指定的值时就会产生一个新的文件。对于写操作有两个参数,一个规定了消息的数量达到这个值时必须将数据刷新到硬盘上,另外一个规定了刷新到硬盘的时间间隔,这对数据的持久性是个保证,在系统崩溃的时候只会丢失一定数量的消息或者一个时间段的消息。

读操作
读操作需要两个参数:一个64位的offset和一个S字节的最大读取量。S通常比单个消息的大小要大,但在一些个别消息比较大的情况下,S会小于单个消息的大小。这种情况下读操作会不断重试,每次重试都会将读取量加倍,直到读取到一个完整的消息。可以配置单个消息的最大值,这样服务器就会拒绝大小超过这个值的消息。也可以给客户端指定一个尝试读取的最大上限,避免为了读到一个完整的消息而无限次的重试。
在实际执行读取操纵时,首先需要定位数据所在的日志文件,然后根据offset计算出在这个日志中的offset(前面的的offset是整个分区的offset),然后在这个offset的位置进行读取。定位操作是由二分查找法完成的,Kafka在内存中为每个文件维护了offset的范围。

删除
日志管理器允许定制删除策略。目前的策略是删除修改时间在N天之前的日志(按时间删除),也可以使用另外一个策略:保留最后的N GB数据的策略(按大小删除)。

------------------------------------------------------------------------------
Kafka安装和环境搭建
一、参考:
http://www.aboutyun.com/thread-12882-1-1.html
http://kafka.apache.org/downloads.html

二、环境搭建
1、下载Kafka
sacala版本
14:49 [[email protected]]$ echo $SCALA_HOME
/opt/scala-2.10.5
http://mirror.bit.edu.cn/apache/kafka/0.8.2.1/kafka_2.10-0.8.2.1.tgz
Download the 0.8.2.0 release and un-tar it.
> tar -xzf kafka_2.10-0.8.2.1.tgz
> cd kafka_2.10-0.8.2.1

单机版参考官网

分布式集群,3台服务器:
参考:
http://liyonghui160com.iteye.com/blog/2084354

Step 2: 启动服务
Kafka用到了Zookeeper,所有首先启动Zookper,下面简单的启用一个单实例的Zookkeeper服务。
10.10.72.182上Zookeeper已有

15:07 [[email protected]]$ ps -ef | grep zookeeper
root     12587     1  0 Jul01 ?        03:05:20 /opt/jdk/bin/java -Dzookeeper.log.dir=. -Dzookeeper.root.logger=INFO,CONSOLE -cp /opt/zookeeper-3.4.6/bin/../build/classes:/opt/zookeeper-3.4.6/bin/../build/lib/*.jar:/opt/zookeeper-3.4.6/bin/../lib/slf4j-log4j12-1.6.1.jar:/opt/zookeeper-3.4.6/bin/../lib/slf4j-api-1.6.1.jar:/opt/zookeeper-3.4.6/bin/../lib/netty-3.7.0.Final.jar:/opt/zookeeper-3.4.6/bin/../lib/log4j-1.2.16.jar:/opt/zookeeper-3.4.6/bin/../lib/jline-0.9.94.jar:/opt/zookeeper-3.4.6/bin/../zookeeper-3.4.6.jar:/opt/zookeeper-3.4.6/bin/../src/java/lib/*.jar:/opt/zookeeper-3.4.6/bin/../conf: -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /opt/zookeeper-3.4.6/bin/../conf/zoo.cfg
root     14365 14231  0 15:07 pts/0    00:00:00 grep zookeeper

分布式集群,3台服务器:
15:08 [[email protected]]$ cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
#"10.10.69.253"                    localhost.localdomain
#10.10.69.252                    localhost.localdomain
#10.10.72.182                    10.10.69.252

10.10.72.182    cloud01
10.10.72.183    cloud02
10.10.72.184    cloud03

1、每台机器
安装kafka
15:27 [[email protected]]$ tar -xzf kafka_2.10-0.8.2.1.tgz
tty:[0] jobs:[0] cwd:[/opt]
15:27 [[email protected]]$ ll
drwxr-xr-x  5 root root     4096 Feb 27  2015 kafka_2.10-0.8.2.1

15:32 [[email protected]]$ tar -xzf kafka_2.10-0.8.2.1.tgz
tty:[0] jobs:[0] cwd:[/opt]
15:32 [[email protected]]$ ll
drwxr-xr-x  5 root root     4096 Feb 27  2015 kafka_2.10-0.8.2.1

编辑3台服务器的/etc/profile文件
$ vim /etc/profile
export KAFKA_HOME=/opt/kafka_2.10-0.8.2.1
export PATH=$KAFKA_HOME/bin:$PATH

15:37 [[email protected]]$ source /etc/profile  
tty:[0] jobs:[0] cwd:[/opt/kafka_2.10-0.8.2.1]
15:37 [[email protected]]$ echo $KAFKA_HOME
/opt/kafka_2.10-0.8.2.1
同理:
183,184
tty:[0] jobs:[0] cwd:[/opt]
15:45 [[email protected]]$ source /etc/profile  
tty:[0] jobs:[0] cwd:[/opt]
15:45 [[email protected]]$ echo $KAFKA_HOME
/opt/kafka_2.10-0.8.2.1

2、配置$KAFKA_HOME/config/server.properties

我们安装3个broker,分别在3个vm上:cloud01,cloud02,cloud03:
------------------------------------------------------------------------------------------
14:43 [[email protected]]$ cat /opt/kafka_2.10-0.8.2.1/config/server.properties
# The id of the broker. This must be set to a unique integer for each broker.
broker.id=0
# The port the socket server listens on
port=9092
# Hostname the broker will bind to. If not set, the server will bind to all interfaces
host.name=cloud01
# Hostname the broker will advertise to producers and consumers. If not set, it uses the
# value for "host.name" if configured.  Otherwise, it will use the value returned from
# java.net.InetAddress.getCanonicalHostName().
#advertised.host.name=<hostname routable by clients>
advertised.host.name=cloud01

# The port to publish to ZooKeeper for clients to use. If this is not set,
# it will publish the same port that the broker binds to.
#advertised.port=<port accessible by clients>

# The number of threads handling network requests
num.network.threads=3

# The number of threads doing disk I/O
num.io.threads=8

# The send buffer (SO_SNDBUF) used by the socket server
socket.send.buffer.bytes=102400

# The receive buffer (SO_RCVBUF) used by the socket server
socket.receive.buffer.bytes=102400

# The maximum size of a request that the socket server will accept (protection against OOM)
socket.request.max.bytes=104857600

# A comma seperated list of directories under which to store log files
log.dirs=/tmp/kafka-logs

# The default number of log partitions per topic. More partitions allow greater
# parallelism for consumption, but this will also result in more files across
# the brokers.
num.partitions=2

# The number of threads per data directory to be used for log recovery at startup and flushing at shutdown.
# This value is recommended to be increased for installations with data dirs located in RAID array.
num.recovery.threads.per.data.dir=1

# The number of messages to accept before forcing a flush of data to disk
#log.flush.interval.messages=10000

# The maximum amount of time a message can sit in a log before we force a flush
#log.flush.interval.ms=1000

# The minimum age of a log file to be eligible for deletion
log.retention.hours=168

# A size-based retention policy for logs. Segments are pruned from the log as long as the remaining
# segments don't drop below log.retention.bytes.
#log.retention.bytes=1073741824

# The maximum size of a log segment file. When this size is reached a new log segment will be created.
log.segment.bytes=1073741824

# The interval at which log segments are checked to see if they can be deleted according
# to the retention policies
log.retention.check.interval.ms=300000

# By default the log cleaner is disabled and the log retention policy will default to just delete segments after their retention expires.
# If log.cleaner.enable=true is set the cleaner will be enabled and individual logs can then be marked for log compaction.
log.cleaner.enable=false

############################# Zookeeper #############################

# Zookeeper connection string (see zookeeper docs for details).
# This is a comma separated host:port pairs, each corresponding to a zk
# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002".
# You can also append an optional chroot string to the urls to specify the
# root directory for all kafka znodes.
zookeeper.connect=cloud01:2181,cloud02:2181,cloud03:2181

# Timeout in ms for connecting to zookeeper
zookeeper.connection.timeout.ms=6000
-------------------------------------------------------------------------
182上配置:
broker.id=0
port=9092
host.name=cloud01
advertised.host.name=cloud01
num.partitions=2
zookeeper.connect=cloud01:2181,cloud02:2181,cloud03:2181

183上配置:
broker.id=1
port=9092
host.name=cloud02
advertised.host.name=cloud02
num.partitions=2
zookeeper.connect=cloud01:2181,cloud02:2181,cloud03:2181

184上配置:
broker.id=2
port=9092
host.name=cloud03
advertised.host.name=cloud03
num.partitions=2
zookeeper.connect=cloud01:2181,cloud02:2181,cloud03:2181

3、启动Kafka服务:
4)启动kafka服务, 在zk1,zk2,zk3上分别运行:
$ kafka-server-start.sh $KAFKA_HOME/config/server.properties
后台运行
nohup /opt/kafka_2.10-0.8.2.1/bin/kafka-server-start.sh /opt/kafka_2.10-0.8.2.1/config/server.properties & (用&是为了能退出命令行)

nohup /opt/kafka_2.10-0.8.2.1/bin/kafka-server-start.sh /opt/kafka_2.10-0.8.2.1/config/server.properties > /opt/myout.file 2>&1 &
[1] 19427
tty:[0] jobs:[1] cwd:[/opt/kafka_2.10-0.8.2.1/config]
15:06 [[email protected]]$ [2015-09-25 15:06:46,663] INFO Verifying properties (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,778] INFO Property advertised.host.name is overridden to cloud01 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,778] INFO Property broker.id is overridden to 0 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,779] INFO Property host.name is overridden to cloud01 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,779] INFO Property log.cleaner.enable is overridden to false (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,780] INFO Property log.dirs is overridden to /tmp/kafka-logs (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,780] INFO Property log.retention.check.interval.ms is overridden to 300000 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,781] INFO Property log.retention.hours is overridden to 168 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,781] INFO Property log.segment.bytes is overridden to 1073741824 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,782] INFO Property num.io.threads is overridden to 8 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,782] INFO Property num.network.threads is overridden to 3 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,783] INFO Property num.partitions is overridden to 2 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,783] INFO Property num.recovery.threads.per.data.dir is overridden to 1 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,784] INFO Property port is overridden to 9092 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,785] INFO Property socket.receive.buffer.bytes is overridden to 102400 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,785] INFO Property socket.request.max.bytes is overridden to 104857600 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,786] INFO Property socket.send.buffer.bytes is overridden to 102400 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,786] INFO Property zookeeper.connect is overridden to cloud01:2181,cloud02:2181,cloud03:2181 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,787] INFO Property zookeeper.connection.timeout.ms is overridden to 6000 (kafka.utils.VerifiableProperties)
[2015-09-25 15:06:46,892] INFO [Kafka Server 0], starting (kafka.server.KafkaServer)
[2015-09-25 15:06:46,898] INFO [Kafka Server 0], Connecting to zookeeper on cloud01:2181,cloud02:2181,cloud03:2181 (kafka.server.KafkaServer)
[2015-09-25 15:06:46,927] INFO Starting ZkClient event thread. (org.I0Itec.zkclient.ZkEventThread)
[2015-09-25 15:06:46,947] INFO Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,947] INFO Client environment:host.name=cloud01 (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,947] INFO Client environment:java.version=1.7.0_67 (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,947] INFO Client environment:java.vendor=Oracle Corporation (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:java.home=/opt/jdk/jre (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:java.class.path=:/opt/kafka_2.10-0.8.2.1/bin/../core/build/dependant-libs-2.10.4*/*.jar:/opt/kafka_2.10-0.8.2.1/bin/../examples/build/libs//kafka-examples*.jar:/opt/kafka_2.10-0.8.2.1/bin/../contrib/hadoop-consumer/build/libs//kafka-hadoop-consumer*.jar:/opt/kafka_2.10-0.8.2.1/bin/../contrib/hadoop-producer/build/libs//kafka-hadoop-producer*.jar:/opt/kafka_2.10-0.8.2.1/bin/../clients/build/libs/kafka-clients*.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/jopt-simple-3.2.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka-clients-0.8.2.1.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-javadoc.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-scaladoc.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-sources.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-test.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/log4j-1.2.16.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/lz4-1.2.0.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/metrics-core-2.2.0.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/scala-library-2.10.4.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/slf4j-api-1.7.6.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/slf4j-log4j12-1.6.1.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/snappy-java-1.1.1.6.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/zkclient-0.3.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/zookeeper-3.4.6.jar:/opt/kafka_2.10-0.8.2.1/bin/../core/build/libs/kafka_2.10*.jar (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:java.io.tmpdir=/tmp (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:java.compiler=<NA> (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:os.name=Linux (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:os.arch=amd64 (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,948] INFO Client environment:os.version=2.6.32-220.el6.x86_64 (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,949] INFO Client environment:user.name=root (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,949] INFO Client environment:user.home=/root (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,949] INFO Client environment:user.dir=/opt/kafka_2.10-0.8.2.1/config (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:46,951] INFO Initiating client connection, connectString=cloud01:2181,cloud02:2181,cloud03:2181 sessionTimeout=6000 watcher=org.I0Itec.zkclient.ZkClient@4ea9ed1f (org.apache.zookeeper.ZooKeeper)
[2015-09-25 15:06:47,004] INFO Opening socket connection to server cloud02/10.10.72.183:2181. Will not attempt to authenticate using SASL (unknown error) (org.apache.zookeeper.ClientCnxn)
[2015-09-25 15:06:47,016] INFO Socket connection established to cloud02/10.10.72.183:2181, initiating session (org.apache.zookeeper.ClientCnxn)
[2015-09-25 15:06:47,034] INFO Session establishment complete on server cloud02/10.10.72.183:2181, sessionid = 0x24fb94a457b0000, negotiated timeout = 6000 (org.apache.zookeeper.ClientCnxn)
[2015-09-25 15:06:47,040] INFO zookeeper state changed (SyncConnected) (org.I0Itec.zkclient.ZkClient)
[2015-09-25 15:06:47,195] INFO Loading logs. (kafka.log.LogManager)
[2015-09-25 15:06:47,214] INFO Logs loading complete. (kafka.log.LogManager)
[2015-09-25 15:06:47,216] INFO Starting log cleanup with a period of 300000 ms. (kafka.log.LogManager)
[2015-09-25 15:06:47,224] INFO Starting log flusher with a default period of 9223372036854775807 ms. (kafka.log.LogManager)
[2015-09-25 15:06:47,300] INFO Awaiting socket connections on cloud01:9092. (kafka.network.Acceptor)
[2015-09-25 15:06:47,303] INFO [Socket Server on Broker 0], Started (kafka.network.SocketServer)
[2015-09-25 15:06:47,479] INFO Will not load MX4J, mx4j-tools.jar is not in the classpath (kafka.utils.Mx4jLoader$)
[2015-09-25 15:06:47,595] INFO 0 successfully elected as leader (kafka.server.ZookeeperLeaderElector)
[2015-09-25 15:06:47,799] INFO Registered broker 0 at path /brokers/ids/0 with address cloud01:9092. (kafka.utils.ZkUtils$)
[2015-09-25 15:06:47,831] INFO [Kafka Server 0], started (kafka.server.KafkaServer)
[2015-09-25 15:06:48,030] INFO New leader is 0 (kafka.server.ZookeeperLeaderElector$LeaderChangeListener)
^C
tty:[0] jobs:[1] cwd:[/opt/kafka_2.10-0.8.2.1/config]

16:09 [[email protected]]$ jps
399 Jps
11802 DFSZKFailoverController
11505 JournalNode
11906 NodeManager
338 Kafka
11417 QuorumPeerMain
11600 NameNode
1077 Worker
11692 DataNode

16:07 [[email protected]]$ ps -ef | grep kafka
root      4277  4137  6 16:04 pts/1    00:00:09 /opt/jdk/bin/java -Xmx1G -Xms1G -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSScavengeBeforeRemark -XX:+DisableExplicitGC -Djava.awt.headless=true -Xloggc:/opt/kafka_2.10-0.8.2.1/bin/../logs/kafkaServer-gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dkafka.logs.dir=/opt/kafka_2.10-0.8.2.1/bin/../logs -Dlog4j.configuration=file:/opt/kafka_2.10-0.8.2.1/bin/../config/log4j.properties -cp :/opt/kafka_2.10-0.8.2.1/bin/../core/build/dependant-libs-2.10.4*/*.jar:/opt/kafka_2.10-0.8.2.1/bin/../examples/build/libs//kafka-examples*.jar:/opt/kafka_2.10-0.8.2.1/bin/../contrib/hadoop-consumer/build/libs//kafka-hadoop-consumer*.jar:/opt/kafka_2.10-0.8.2.1/bin/../contrib/hadoop-producer/build/libs//kafka-hadoop-producer*.jar:/opt/kafka_2.10-0.8.2.1/bin/../clients/build/libs/kafka-clients*.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/jopt-simple-3.2.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka-clients-0.8.2.1.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-javadoc.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-scaladoc.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-sources.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1-test.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/kafka_2.10-0.8.2.1.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/log4j-1.2.16.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/lz4-1.2.0.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/metrics-core-2.2.0.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/scala-library-2.10.4.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/slf4j-api-1.7.6.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/slf4j-log4j12-1.6.1.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/snappy-java-1.1.1.6.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/zkclient-0.3.jar:/opt/kafka_2.10-0.8.2.1/bin/../libs/zookeeper-3.4.6.jar:/opt/kafka_2.10-0.8.2.1/bin/../core/build/libs/kafka_2.10*.jar kafka.Kafka /opt/kafka_2.10-0.8.2.1/config/server.properties

启动后在Zookeeper中
[zk: localhost:2181(CONNECTED) 1] ls /brokers
[topics, ids]
[zk: localhost:2181(CONNECTED) 2] ls /brokers/topics
[]
[zk: localhost:2181(CONNECTED) 3] ls /brokers/ids  
[0]
[zk: localhost:2181(CONNECTED) 4] ls /brokers/ids/0

[zk: localhost:2181(CONNECTED) 10] ls /brokers/ids
[2, 1, 0]
3个brokers都启动了。
tty:[0] jobs:[1] cwd:[/tmp/kafka-logs]
15:12 [[email protected]]$ ll
total 0
-rw-r--r-- 1 root root 0 Sep 25 15:03 recovery-point-offset-checkpoint
-rw-r--r-- 1 root root 0 Sep 25 15:03 replication-offset-checkpoint

Kafka集群启动完成。
------------------------------------------------------

4、新建一个TOPIC(replication-factor=num of brokers)
在cloud01上
/opt/kafka_2.10-0.8.2.1/bin/kafka-topics.sh --create --zookeeper cloud01:2181 --replication-factor 1 --partitions 1 --topic test1
Created topic "test1".

查看topic列表
15:49 [[email protected]]$ /opt/kafka_2.10-0.8.2.1/bin/kafka-topics.sh --list --zookeeper cloud01:2181
test
test1
5、假设我们在cloud02上,开一个终端,发送消息至kafka(zk2模拟producer)
/opt/kafka_2.10-0.8.2.1/bin/kafka-console-producer.sh --broker-list cloud01:9092 --topic test1
输入
this is a message
shit is another message

6、假设我们在zk3上,开一个终端,显示消息的消费(zk3模拟consumer)
15:54 [[email protected]]$ /opt/kafka_2.10-0.8.2.1/bin/kafka-console-consumer.sh --zookeeper cloud01:2181 --topic test1 --from-beginning
[2015-09-25 15:55:25,196] INFO Closing socket connection to /10.10.72.184. (kafka.network.Processor)
this is a message
shit is another message

7、
Now create a new topic with a replication factor of three:
/opt/kafka_2.10-0.8.2.1/bin/kafka-topics.sh --create --zookeeper cloud01:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic

/opt/kafka_2.10-0.8.2.1/bin/kafka-topics.sh --describe --zookeeper cloud01:2181 --topic my-replicated-topic
ATopic:my-replicated-topic   PartitionCount:1        ReplicationFactor:3     Configs:
Topic: my-replicated-topic      Partition: 0    Leader: 2       Replicas: 2,1,0 Isr: 2,1,0

leader:负责处理消息的读和写,leader是从所有节点中随机选择的.
replicas:列出了所有的副本节点,不管节点是否在服务中.
isr:是正在服务中的节点.

183:producer:
/opt/kafka_2.10-0.8.2.1/bin/kafka-console-producer.sh --broker-list cloud01:9092 --topic my-replicated-topic
184:consumers
/opt/kafka_2.10-0.8.2.1/bin/kafka-console-consumer.sh --zookeeper cloud01:2181 --from-beginning --topic my-replicated-topic

bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic my-topic --partitions 1 --replication-factor 1 --config max.message.bytes=64000 --config flush.messages=1

------------------------
开发环境
代码主要参考:
http://www.aboutyun.com/thread-12882-1-1.html
官网例子:
https://cwiki.apache.org/confluence/display/KAFKA/Consumer+Group+Example
https://cwiki.apache.org/confluence/display/KAFKA/0.8.0+Producer+Example

添加maven依赖:
<!--kafka-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.10</artifactId>
<version>0.8.0</version>
</dependency>

运行结果如下:

Send:Message_1
receive:Message_1
Send:Message_2
receive:Message_2
Send:Message_3
receive:Message_3
Send:Message_4
receive:Message_4
---------------------------------------------------------------
Kafka 高性能吞吐揭秘
http://bbs.umeng.com/thread-12086-1-1.html

你可能感兴趣的:(Kafka学习笔记)