kafka是啥

一、概述

  1. Kafka是由LinkedIn(领英)开发的一个分布式的消息系统,最初是用作LinkedIn的活动流(Activity Stream)和运营数据处理的基础
    1. 活动流数据包括页面访问量(Page View)、被查看内容方面的信息以及搜索情况等内容。这种数据通常的处理方式是先把各种活动以日志的形式写入某种文件,然后周期性地对这些文件进行统计分析
    2. 运营数据指的是服务器的性能数据(CPU、IO使用率、请求时间、服务日志等等数据)。运营数据的统计方法种类繁多。
  2. Kafka是一个分布式的流式处理平台,主要包含三个功能:
    1. 发布和订阅数据,类似于消息队列或者企业中的消息传递系统
    2. 存储数据的时候有容错(分布式+副本机制)和持久化机制
    3. 数据产生的时候处理记录(数据)
  3. 应用场景:
    1. 在系统或者应用程序之间构建可靠的数据传输的实时流管道
    2. 在转换或者响应数据流的时候构建实时流程序、
  1. Kafka使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Cloudera、Apache Storm、Spark都支持与Kafka集成
  2. Kafla之间传输数据是使用的零拷贝技术

 

二、适用场景

  1. Messaging
    1. 对于一些常规的消息系统,kafka是个不错的选择,partitons/replication和容错,可以使kafka具有良好的扩展性和性能优势
    2. kafka并没有提供JMS中的"事务性""消息传输担保(消息确认机制)""消息分组"等企业级特性;kafka只能使用作为"常规"的消息系统,在一定程度上,尚未确保消息的发送与接收绝对可靠(比如,消息重发,消息发送丢失等)
  2. Website activity tracking
    1. kafka可以作为"网站活性跟踪"的最佳工具;可以将网页/用户操作等信息发送到kafka中.并实时监控,或者离线统计分析等
  1. Metric
    1. Kafka通常被用于可操作的监控数据。这包括从分布式应用程序来的聚合统计用来生产集中的运营数据提要。
  1. Log Aggregatio
    1. kafka的特性决定它非常适合作为"日志收集中心";application可以将操作日志"批量""异步"的发送到kafka集群中,而不是保存在本地或者DB中;kafka可以批量提交消息/压缩消息等,这对producer端而言,几乎感觉不到性能的开支。此时consumer端可以使hadoop等其他系统化的存储和分析系统

三、特点

  1. 高吞吐率:在廉价的商用机器上单机可支持100W条/秒消息
  2. 消息持久化:所有的消息都会存储在磁盘上,不会产生消息的丢失
  3. 支持完全分布式
  4. 同时满足适应在线流处理和离线批处理

安装

# 给每一个Kafka节点配置编号

broker.id=0

# 消息的存储陌路

log.dirs=/home/software/kafka_2.11-1.0.0/kafka-logs

# Zookeeper的连接地址

zookeeper.connect=hadoop01:2181,hadoop02:2181,hadoop03:2181

  • 保存退出后
  • 配置其他两台虚拟机,更改配置文件的broker.id编号(不重复即可)
  • 启动zookeeper集群
  • 进入Kafka安装目录的bin目录下
  • 启动Kafaka,执行:sh kafka-server-start.sh ../config/server.properties
  • 上传或者下载安装包
  • 解压安装包:tar -xvf kafka_2.11-1.0.0.tgz
  • 进入安装目录的子目录config下:cd kafka_2.11-1.0.0/config/
  • 编辑server.properties:vim server.properties
  • 添加如下内容:
  • # 给每一个Kafka节点配置编号

    broker.id=0

    # 消息的存储陌路

    log.dirs=/home/software/kafka_2.11-1.0.0/kafka-logs

    # Zookeeper的连接地址

    zookeeper.connect=hadoop01:2181,hadoop02:2181,hadoop03:2181

  • 保存退出后
  • 配置其他两台虚拟机,更改配置文件的broker.id编号(不重复即可)
  • 启动zookeeper集群
  • 进入Kafka安装目录的bin目录下
  • 启动Kafaka,执行:sh kafka-server-start.sh ../config/server.properties

基本指令

命令

作用

sh kafka-topics.sh --create --zookeeper hbase01:2181 --replication-factor 1 --partitions 1 --topic englishbook

创建主题

在创建的时候,副本数量要小于等于节点数量

sh kafka-topics.sh --list --zookeeper hbase01:2181

查看所有的topic

sh kafka-console-producer.sh --broker-list hbase01:9092 --topic englishbook

启动生产者

 sh kafka-console-consumer.sh --zookeeper hbase01:2181 --topic englishbook --from-beginning

启动消费者

sh kafka-topics.sh --delete --zookeeper hbase01:2181 --topic  englishbook

删除topic

sh kafka-topics.sh --describe --zookeeper hbase01:2181 --topic englishbook

描述topic的信息

可以通过配置 config目录下的 server.properties文件,加入如下的配置:

 配置示例:

 

delete.topic.enable=true

消息系统语义

一、概述

  1. 在一个分布式发布订阅消息系统中,组成系统的计算机总会由于各自的故障而不能工作。在Kafka中,一个单独的broker,可能会在生产者发送消息到一个topic的时候宕机,或者出现网络故障,从而导致生产者发送消息失败。根据生产者如何处理这样的失败,产生了不同的语义:
    1. 至少一次语义(At least once semantics:如果生产者收到了Kafka broker的确认(acknowledgement,ack),并且生产者的acks配置项设置为all(或-1),这就意味着消息已经被精确一次写入Kafka topic了。然而,如果生产者接收ack超时或者收到了错误,它就会认为消息没有写入Kafka topic而尝试重新发送消息。如果broker恰好在消息已经成功写入Kafka topic后,发送ack前,出了故障,生产者的重试机制就会导致这条消息被写入Kafka两次,从而导致同样的消息会被消费者消费不止一次。每个人都喜欢一个兴高采烈的给予者,但是这种方式会导致重复的工作和错误的结果
    2. 至多一次语义(At most once semantics):如果生产者在ack超时或者返回错误的时候不重试发送消息,那么消息有可能最终并没有写入Kafka topic中,因此也就不会被消费者消费到。但是为了避免重复处理的可能性,导致接受有些消息可能被遗漏处理
    3. 精确一次语义(Exactly once semantics):即使生产者重试发送消息,也只会让消息被发送给消费者一次。精确一次语义是最令人满意的保证,但也是最难理解的。因为它需要消息系统本身和生产消息的应用程序还有消费消息的应用程序一起合作。比如,在成功消费一条消息后,又把消费的offset重置到之前的某个offset位置,那么将收到从那个offset到最新的offset之间的所有消息。这解释了为什么消息系统和客户端程序必须合作来保证精确一次语义

二、新版本Kafka的幂等性实现

  1. 一个幂等性的操作就是一种被执行多次造成的影响和只执行一次造成的影响一样的操作。现在生产者发送的操作是幂等的了。如果出现导致生产者重试的错误,同样的消息,仍由同样的生产者发送多次,将只被写到kafka broker的日志中一次
  2. 对于单个分区,幂等生产者不会因为生产者或broker故障而发送多条重复消息。想要开启这个特性,获得每个分区内的精确一次语义,需要设置producer配置中的”enable.idempotence=true”
  3. 在底层,它和TCP的工作原理有点像:每发送到Kafka的消息都将包含一个序列号,broker将使用这个序列号来删除重复的发送。和只能在瞬态内存中的连接中保证不重复的TCP不同,这个序列号被持久化到副本日志,所以,即使分区的leader挂了,其他的broker接管了leader,新leader仍可以判断重新发送的是否重复了。这种机制的开销非常低:每批消息只有几个额外的字段
  4. 此外,Kafka除了构建于生产者—>broker的幂等性之外,从broker->消费者的精确一次流处理现在可以通过Apache Kafka的流处理API实现,仅需要设置配置:“processing.guarantee = exact_once。 这可以保证消费者的所有处理恰好发生一次。这就是为什么Kafka的Streams API提供的精确一次性保证是迄今为止任何流处理系统提供的最强保证
  5. Kafka为流处理应用程序提供端到端的一次性保证,从Kafka读取的数据,Streams应用程序物化到Kafka的任何状态,到写回Kafka的最终输出。 仅依靠外部数据系统来实现状态支持的流处理系统对于精确一次的流处理提供了较少的保证。 即使他们使用Kafka作为流处理的源并需要从失败中恢复,他们也只能倒回他们的Kafka偏移量来重建和重新处理消息,但是不能回滚外部系统中的关联状态,导致状态不正确,更新不是幂等的。

 

三、通过代码来设置消息系统语义

Producer

@Test
public void producer() throws ExecutionException {

Properties props = new Properties();

props.put("key.serializer", "org.apache.kafka.common.serialization.IntegerSerializer");

props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.150.137:9092,192.168.150.138:9092");

// 至多一次

props.put("acks", 0);

// 至少一次

props.put("acks", 1);

// 精确一次

props.put("acks", "all");

props.put("enable.idempotence", "true");

Producer<Integer, String> kafkaProducer = new KafkaProducer<Integer, String>(props);

for (int i = 0; i < 100; i++) {

ProducerRecord<Integer, String> message = new ProducerRecord<Integer, String>("jpbook", "" + i);

kafkaProducer.send(message);

}

while (true) ;

}

Consumer的至多一次

概述

kafka consumer是默认至多一次,consumer的配置是:

  1.  设置enable.auto.commit 为 true
  2. 设置 auto.commit.interval.ms为一个较小的值
  3. consumer不去执行 consumer.commitSync(), 这样, Kafka 会每隔一段时间自动提交offset

代码

@Test
public void consumer_2() {

Properties props = new Properties();

props.put("bootstrap.servers", "192.168.150.137:9092,192.168.150.138:9092");

props.put("group.id", "g1");

props.put("key.deserializer", StringDeserializer.class.getName());

props.put("value.deserializer", StringDeserializer.class.getName());

props.put("enable.auto.commit", "true");

props.put("auto.commit.interval.ms", "101");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(Arrays.asList("enbook", "t2"));

try {

while (true) {

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);

for (ConsumerRecord<String, String> record : records)

System.out.println("g1组c2消费者,分区编号:" + record.partition() + "offset:" + record.offset() + ":" + record.value());

}

} catch (Exception e) {

} finally {

consumer.close();

}

}

Consumer的至少一次

概述

  1. 设置enable.auto.commit 为 false 或者
  2. 设置enable.auto.commit为 true 并设置auto.commit.interval.ms为一个较大的值.
  3. 处理完后consumer调用 consumer.commitSync()

代码

@Test
public void consumer_2() {

Properties props = new Properties();

props.put("bootstrap.servers", "192.168.150.137:9092,192.168.150.138:9092");

props.put("group.id", "g1");

props.put("key.deserializer", StringDeserializer.class.getName());

props.put("value.deserializer", StringDeserializer.class.getName());

props.put("enable.auto.commit", "false");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(Arrays.asList("enbook", "t2"));

try {

while (true) {

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);

for (ConsumerRecord<String, String> record : records)

// Process……

// 处理完成后,用户自己手动提交offset

consumer.commitAsync();

}

} catch (Exception e) {

} finally {

consumer.close();

}

}

Consumer的精确一次

@Test
public void consumer_2() {

Properties props = new Properties();

props.put("bootstrap.servers", "192.168.150.137:9092,192.168.150.138:9092");

props.put("group.id", "g1");

props.put("key.deserializer", StringDeserializer.class.getName());

props.put("value.deserializer", StringDeserializer.class.getName());

props.put("enable.auto.commit", "false");

props.put("processing.guarantee", "exact_once");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(Arrays.asList("enbook", "t2"));

try {

while (true) {

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);

for (ConsumerRecord<String, String> record : records)

consumer.commitAsync();

}

} catch (Exception e) {

} finally {

consumer.close();

}

}

参数配置

属性

默认值

说明

broker.id

每个broker都可以用一个唯一的非负整数id进行标识;这个id可以作为broker的“名字”,并且它的存在使得broker无须混淆consumers就可以迁移到不同的host/port上。你可以选择任意你喜欢的数字作为id,只要id是唯一的即可。

log.dirs

/tmp/kafka-logs

kafka存放数据的路径。这个路径并不是唯一的,可以是多个,路径之间只需要使用逗号分隔即可;每当创建新partition时,都会选择在包含最少partitions的路径下进行。

zookeeper.connect

localhost:2181

ZooKeeper连接字符串的格式为:hostname:port,此处hostname和port分别是ZooKeeper集群中某个节点的host和port;为了当某个host宕掉之后你能通过其他ZooKeeper节点进行连接,你可以按照一下方式制定多个hosts:

hostname1:port1, hostname2:port2, hostname3:port3.

ZooKeeper 允许你增加一个“chroot”路径,将集群中所有kafka数据存放在特定的路径下。当多个Kafka集群或者其他应用使用相同ZooKeeper集群时,可以使用这个方式设置数据存放路径。这种方式的实现可以通过这样设置连接字符串格式,如下所示:

hostname1:port1,hostname2:port2,hostname3:port3/chroot/path

这样设置就将所有kafka集群数据存放在/chroot/path路径下。注意,在你启动broker之前,你必须创建这个路径,并且consumers必须使用相同的连接格式。

num.partitions

1

如果创建topic时没有给出划分partitions个数,这个数字将是topic下partitions数目的默认数值。
主题的分区数直接决定了消费的并行度,所以在实际生产中,分区数一般都在几十个或几百个。
此外注意:提供分区的副本数,并不能提高并发度,因为无论是生成者还是消费者,都是和副本的Leader交互。

log.segment.bytes

1024*1024*1024

topic  partition的日志存放在某个目录下诸多文件中,这些文件将partition的日志切分成一段一段的;这个属性就是每个文件的最大尺寸;当尺寸达到这个数值时,就会创建新文件。此设置可以由每个topic基础设置时进行覆盖

log.roll.hours

24 * 7

即使文件没有到达log.segment.bytes,只要文件创建时间到达此属性,就会创建新文件。这个设置也可以有topic层面的设置进行覆盖;

log.index.size.max.bytes

10*1024*1024

每个log segment的最大尺寸。注意,如果log尺寸达到这个数值,即使尺寸没有超过log.segment.bytes限制,也需要产生新的log  segment。

replica.lag.time.max.ms

10000

如果一个follower在这个时间内没有发送fetch请求,leader将从ISR中移除这个follower

replica.fetch.max.bytes

1024*1024

备份时每次fetch的最大值

unclean.leader.election.enable

true

指明了是否能够使不在ISR中replicas设置用来作为leader

delete.topic.enable

false

能够删除topic

boostrap.servers

用于建立与kafka集群连接的host/port组。数据将会在所有servers上均衡加载,不管哪些server是指定用于bootstrapping。这个列表仅仅影响初始化的hosts(用于发现全部的servers)。这个列表格式:

host1:port1,host2:port2,...

因为这些server仅仅是用于初始化的连接,以发现集群所有成员关系(可能会动态的变化),这个列表不需要包含所有的servers(你可能想要不止一个server,尽管这样,可能某个server宕机了)。如果没有server在这个列表出现,则发送数据会一直失败,直到列表可用。

acks

1

producer需要server接收到数据之后发出的确认接收的信号,此项配置就是指procuder需要多少个这样的确认信号。此配置实际上代表了数据备份的可用性。以下设置为常用选项:

(1)acks=0: 设置为0表示producer不需要等待任何确认收到的信息。副本将立即加到socket  buffer并认为已经发送。没有任何保障可以保证此种情况下server已经成功接收数据,同时重试配置不会发生作用(因为客户端不知道是否失败)回馈的offset会总是设置为-1;

(2)acks=1: 这意味着至少要等待leader已经成功将数据写入本地log,但是并没有等待所有follower是否成功写入。这种情况下,如果follower没有成功备份数据,而此时leader又挂掉,则消息会丢失。

(3)acks=all: 这意味着leader需要等待所有备份都成功写入日志,这种策略会保证只要有一个备份存活就不会丢失数据。这是最强的保证。

(4)其他的设置,例如acks=2也是可以的,这将需要给定的acks数量,但是这种策略一般很少用。

batch.size

16384(字节)
即:16kb

producer将试图批处理消息记录,以减少请求次数。这项配置控制默认的批量处理消息字节数。

此参数控制的是生成者的批处理大小,此参数越大,会使生成的吞吐量越大,同时也会占用过大的内存空间。
注意:调节测试是1024整数倍

linger.ms

0
 

Producer默认会把两次发送时间间隔内收集到的所有Requests进行一次聚合然后再发送,以此提高吞吐量,而linger.ms则更进一步,这个参数为每次发送增加一些delay,以此来聚合更多的Message。官网解释翻译:producer会将request传输之间到达的所有records聚合到一个批请求。通常这个值发生在欠负载情况下,record到达速度快于发送。但是在某些场景下,client即使在正常负载下也期望减少请求数量。这个设置就是如此,通过人工添加少量时延,而不是立马发送一个record,producer会等待所给的时延,以让其他records发送出去,这样就会被聚合在一起。这个类似于TCP的Nagle算法。该设置给了batch的时延上限:当我们获得一个partition的batch.size大小的records,就会立即发送出去,而不管该设置;但是如果对于这个partition没有累积到足够的record,会linger指定的时间等待更多的records出现。该设置的默认值为0(无时延)

CAP理论

一、CAP概述

  1. Consistency - 一致性:
    1. 通过某个节点的写操作结果对后面通过其它节点的读操作可见
    2. 如果更新数据后,并发访问情况下可立即感知该更新,称为强一致性
    3. 如果允许之后部分或者全部感知不到该更新,称为弱一致性
    4. 若在之后的一段时间(通常该时间不固定)后,一定可以感知该更新,称为最终一致性
  2. Availability - 可用性:
    1. 任何一个没有发生故障的节点必须在有限的时间内返回合理的结果
  3. Partition tolerance - 分区容忍性:
    1. 部分节点宕机或者无法与其它节点通信时,各分区间还可保持分布式系统的功能
  4. 分布式系统中,CAP最多可以同时满足两个,而实际开发中,分区容忍性是必须保障的,因此很多情况下是在一致性和可用性之间进行权衡

二、一致性方案

  1. Master-Slave
    1. EDBMS的读写分离就是典型的M/S方案
    2. 同步复制可保证强一致性但会影响可用性
    3. 异步复制可提供高可用性但会降低一致性
  2. WNR
    1. 主要用于去中心化( P2P)的分布式系统中。 DynamoDB与Cassandra即采用此方案
    2. N代表副本数, W代表每次写操作要保证的最少写成功的副本数, R代表每次读至少读取的副本数:当W+R>N时,可保证每次读取的数据至少有一个副本具有最新的更新
    3. 多个写操作的顺序难以保证,可能导致多副本间的写操作顺序不一致, Dynamo通过向量时钟保证最终一致性
  3. Paxos及其变种
    1. Google的Chubby, Zookeeper的ZAB, RAFT等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值