关闭

详述 Kafka 基本原理

标签: apachelinkedinKafaka分布式架构
984人阅读 评论(0) 收藏 举报
分类:

kafaka

1 简介

Apache Kafka 是分布式发布-订阅消息系统。它最初由 LinkedIn 公司开发,之后成为 Apache 项目的一部分。Kafka 是一种快速、可扩展的、设计内在就是分布式的,分区的和可复制的提交日志服务。

2 Kafka 架构

它的架构包括以下组件:

  • 话题(Topic):是特定类型的消息流。消息是字节的有效负载(Payload),话题是消息的分类名或种子(Feed)名。
  • 生产者(Producer):是能够发布消息到话题的任何对象。
  • 服务代理(Broker):已发布的消息保存在一组服务器中,它们被称为代理(Broker)或 Kafka 集群。
  • 消费者(Consumer):可以订阅一个或多个话题,并从 Broker 拉数据,从而消费这些已发布的消息。

2

3 Kafka 存储策略

  • kafka 以 topic 来进行消息管理,每个 topic 包含多个 partition,每个 partition 对应一个逻辑 log,有多个 segment 组成。
  • 每个 segment 中存储多条消息(见下图),消息 id 由其逻辑位置决定,即从消息 id 可直接定位到消息的存储位置,避免 id 到位置的额外映射。
  • 每个 part 在内存中对应一个 index,记录每个 segment 中的第一条消息偏移。
  • 发布者发到某个 topic 的消息会被均匀的分布到多个 partition 上(或根据用户指定的路由规则进行分布),broker 收到发布消息往对应 partition 的最后一个 segment 上添加该消息,当某个 segment 上的消息条数达到配置值或消息发布时间超过阈值时,segment 上的消息会被 flush 到磁盘,只有 flush 到磁盘上的消息订阅者才能订阅到,segment 达到一定的大小后将不会再往该 segment 写数据,broker 会创建新的 segment。

celue

4 Kafka 删除策略

  • N 天前的删除。
  • 保留最近的 MGB 数据。

5 Kafka broker

与其它消息系统不同,Kafka broker 是无状态的。这意味着消费者必须维护已消费的状态信息。这些信息由消费者自己维护,broker 完全不管(由 offset managerbroker 管理)。

从代理删除消息变得很棘手,因为代理并不知道消费者是否已经使用了该消息。Kafka 创新性地解决了这个问题,它将一个简单的基于时间的 SLA 应用于保留策略。当消息在代理中超过一定时间后,将会被自动删除。

这种创新设计有很大的好处,消费者可以故意倒回到老的偏移量再次消费数据。这违反了队列的常见约定,但被证明是许多消费者的基本特征。

6 kafka 官方文档

Kafka Design

  • 目标
    • 高吞吐量来支持高容量的事件流处理
    • 支持从离线系统加载数据
    • 低延迟的消息系统
  • 持久化
    • 依赖文件系统,持久化到本地
    • 数据持久化到 log
  • 效率
    • 解决small IO problem
      • 使用message set组合消息。
      • server 使用chunks of messages写到 log
      • consumer 一次获取大的消息块。
    • 解决byte copying
      • 在 producer、broker 和 consumer 之间使用统一的 binary message format
      • 使用系统的 pagecache
      • 使用 sendfile 传输 log,避免拷贝

端到端的批量压缩(End-to-end Batch Compression),Kafka 支持 GZIP 和 Snappy 压缩协议。

The Producer

  • 负载均衡
    • producer 可以自定义发送到哪个 partition 的路由规则。默认路由规则:hash(key)%numPartitions,如果keynull则随机选择一个 partition。
    • 自定义路由:如果key是一个user id,可以把同一个 user 的消息发送到同一个 partition,这时 consumer 就可以从同一个 partition 读取同一个 user 的消息。
  • 异步批量发送
    • 批量发送:配置不多于固定消息数目一起发送并且等待时间小于一个固定延迟的数据。

The Consumer

consumer 控制消息的读取。

Push vs Pull

  1. producer push data to broker,consumer pull data from broker
  2. consumer pull 的优点:consumer 自己控制消息的读取速度和数量
  3. consumer pull 的缺点:如果 broker 没有数据,则可能要 pull 多次忙等待,Kafka 可以配置 consumer long pull 一直等到有数据

Consumer Position

  1. 大部分消息系统由 broker 记录哪些消息被消费了,但 Kafka 不是
  2. Kafka 由 consumer 控制消息的消费,consumer 甚至可以回到一个 old offset 的位置再次消费消息

Message Delivery Semantics

  1. At most once — Messages may be lost but are never redelivered.
  2. At least once — Messages are never lost but may be redelivered.
  3. Exactly once — this is what people actually want, each message is delivered once and only once.

Producer:有个acks配置可以控制接收的 leader 的在什么情况下就回应 producer 消息写入成功。

Consumer

  • 读取消息,写 log,处理消息。如果处理消息失败,log 已经写入,则无法再次处理失败的消息,对应At most once
  • 读取消息,处理消息,写 log。如果消息处理成功,写 log 失败,则消息会被处理两次,对应At least once
  • 读取消息,同时处理消息并把 result 和 log 同时写入,这样保证 result 和 log 同时更新或同时失败,对应Exactly once

Kafka 默认保证at-least-once delivery,容许用户实现at-most-once语义,exactly-once的实现取决于目的存储系统,kafka 提供了读取 offset,实现也没有问题。

复制(Replication)

  1. 一个 partition 的复制个数(replication factor)包括这个 partition 的 leader 本身。
  2. 所有对 partition 的读和写都通过 leader。
  3. Followers 通过 pull 获取 leader上log(message 和 offset)
  4. 如果一个 follower 挂掉、卡住或者同步太慢,leader 会把这个 follower 从in sync replicas(ISR)列表中删除。
  5. 当所有的in sync replicas的 follower 把一个消息写入到自己的 log 中时,这个消息才被认为是committed的。
  6. 如果针对某个 partition 的所有复制节点都挂了,Kafka 选择最先复活的那个节点作为 leader(这个节点不一定在 ISR 里)。

日志压缩(Log Compaction)

  1. 针对一个 topic 的 partition,压缩使得 Kafka 至少知道每个 key 对应的最后一个值。
  2. 压缩不会重排序消息。
  3. 消息的 offset 是不会变的。
  4. 消息的 offset 是顺序的。

Distribution

  • Consumer Offset Tracking
  • High-level consumer 记录每个 partition 所消费的 maximum offset,并定期 commit 到 offset manager(broker)。
  • Simple consumer 需要手动管理 offset。现在的 Simple consumer Java API 只支持 commit offset 到 zookeeper。

  • Consumers and Consumer Groups

  • consumer 注册到 zookeeper
  • 属于同一个 group 的 consumer(group id 一样)平均分配 partition,每个 partition 只会被一个 consumer 消费。
  • 当 broker 或同一个 group 的其他 consumer 的状态发生变化的时候,consumer rebalance 就会发生。

Zookeeper 协调控制

  • 管理 broker 与 consumer 的动态加入与离开。
  • 触发负载均衡,当 broker 或 consumer 加入或离开时会触发负载均衡算法,使得一个 consumer group 内的多个 consumer 的订阅负载平衡。
  • 维护消费关系及每个 partition 的消费信息。

7 代码示例

生产者代码示例:

import java.util.*;

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

public class TestProducer {
    public static void main(String[] args) {
        long events = Long.parseLong(args[0]);
        Random rnd = new Random();

        Properties props = new Properties();
        props.put("metadata.broker.list", "broker1:9092,broker2:9092 ");
        props.put("serializer.class", "kafka.serializer.StringEncoder");
        props.put("partitioner.class", "example.producer.SimplePartitioner");
        props.put("request.required.acks", "1");

        ProducerConfig config = new ProducerConfig(props);

        Producer<String, String> producer = new Producer<String, String>(config);

        for (long nEvents = 0; nEvents < events; nEvents++) { 
               long runtime = new Date().getTime();  
               String ip = “192.168.2.” + rnd.nextInt(255); 
               String msg = runtime + “,www.example.com,” + ip; 
               KeyedMessage<String, String> data = new KeyedMessage<String, String>("page_visits", ip, msg);
               producer.send(data);
        }
        producer.close();
    }
}

Partitioning Code:

import kafka.producer.Partitioner;
import kafka.utils.VerifiableProperties;

public class SimplePartitioner implements Partitioner {
    public SimplePartitioner (VerifiableProperties props) {

    }

    public int partition(Object key, int a_numPartitions) {
        int partition = 0;
        String stringKey = (String) key;
        int offset = stringKey.lastIndexOf('.');
        if (offset > 0) {
           partition = Integer.parseInt( stringKey.substring(offset+1)) % a_numPartitions;
        }
       return partition;
  } 
}

消费者代码示例:

import kafka.consumer.ConsumerConfig;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ConsumerGroupExample {
    private final ConsumerConnector consumer;
    private final String topic;
    private  ExecutorService executor;

    public ConsumerGroupExample(String a_zookeeper, String a_groupId, String a_topic) {
        consumer = kafka.consumer.Consumer.createJavaConsumerConnector(
                createConsumerConfig(a_zookeeper, a_groupId));
        this.topic = a_topic;
    }

    public void shutdown() {
        if (consumer != null) consumer.shutdown();
        if (executor != null) executor.shutdown();
        try {
            if (!executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
                System.out.println("Timed out waiting for consumer threads to shut down, exiting uncleanly");
            }
        } catch (InterruptedException e) {
            System.out.println("Interrupted during shutdown, exiting uncleanly");
        }
   }

    public void run(int a_numThreads) {
        Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
        topicCountMap.put(topic, new Integer(a_numThreads));
        Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
        List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic);

        // now launch all the threads
        //
        executor = Executors.newFixedThreadPool(a_numThreads);

        // now create an object to consume the messages
        //
        int threadNumber = 0;
        for (final KafkaStream stream : streams) {
            executor.submit(new ConsumerTest(stream, threadNumber));
            threadNumber++;
        }
    }

    private static ConsumerConfig createConsumerConfig(String a_zookeeper, String a_groupId) {
        Properties props = new Properties();
        props.put("zookeeper.connect", a_zookeeper);
        props.put("group.id", a_groupId);
        props.put("zookeeper.session.timeout.ms", "400");
        props.put("zookeeper.sync.time.ms", "200");
        props.put("auto.commit.interval.ms", "1000");

        return new ConsumerConfig(props);
    }

    public static void main(String[] args) {
        String zooKeeper = args[0];
        String groupId = args[1];
        String topic = args[2];
        int threads = Integer.parseInt(args[3]);

        ConsumerGroupExample example = new ConsumerGroupExample(zooKeeper, groupId, topic);
        example.run(threads);

        try {
            Thread.sleep(10000);
        } catch (InterruptedException ie) {

        }
        example.shutdown();
    }
}

ConsumerTest:

import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;

public class ConsumerTest implements Runnable {
    private KafkaStream m_stream;
    private int m_threadNumber;

    public ConsumerTest(KafkaStream a_stream, int a_threadNumber) {
        m_threadNumber = a_threadNumber;
        m_stream = a_stream;
    }

    public void run() {
        ConsumerIterator<byte[], byte[]> it = m_stream.iterator();
        while (it.hasNext())
            System.out.println("Thread " + m_threadNumber + ": " + new String(it.next().message()));
        System.out.println("Shutting down Thread: " + m_threadNumber);
    }
}

转载声明:本文转自博客园「阿凡卢」,Kafka基本原理

2
1
查看评论

kafka基本原理

KAFKA   Kafka是一个分布式的、可分区、可复制的消息系统。   基本术语: broker:一个kafka集群由一个或者多个broker组成; topic:Kafka中用来维护的一类消息; partition:每个topic包含多个分区,每一个分区都存在各个...
  • ch648966459
  • ch648966459
  • 2016-06-14 13:57
  • 1646

Kafka基本原理

http://www.cnblogs.com/luxiaoxun/p/5492646.html 简介 Apache Kafka是分布式发布-订阅消息系统。它最初由LinkedIn公司开发,之后成为Apache项目的一部分。Kafka是一种快速、可扩展的、设计内在就是分布式的,...
  • zdy0_2004
  • zdy0_2004
  • 2016-05-14 22:10
  • 280

Kafka 基本原理

简介 Apache Kafka是分布式发布-订阅消息系统。它最初由LinkedIn公司开发,之后成为Apache项目的一部分。Kafka是一种快速、可扩展的、设计内在就是分布式的,分区的和可复制的提交日志服务。 Kafka架构 它的架构包括以下组...
  • jek123456
  • jek123456
  • 2017-06-25 09:32
  • 152

单点登录基本原理详述

单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。 1 最简单实现SSO的方法就是用Cookie,实现流程如下所示: 发现以上的方案是把信任存储在客户端...
  • sl0007
  • sl0007
  • 2012-07-26 10:40
  • 731

了解产品设计中的BRD、MRD、PRD、FSD需求文档

BRD   Business Requirements Document,商业需求文档。这是产品声明周期中最早的问的文档,再早就应该是脑中的构思了,其内容涉及市场分析,销售策略,盈利预测等,通常是和老大们过的ppt,所以也就比较短小精炼,没有产品细节。   商业需求文档重点放在定义项目的...
  • u012858744
  • u012858744
  • 2014-01-05 22:23
  • 1749

Kafka简介、基本原理、执行流程与使用场景

一、简介Apache Kafka是分布式发布-订阅消息系统,在 kafka官网上对 kafka 的定义:一个分布式发布-订阅消息传递系统。 它最初由LinkedIn公司开发,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。Kafka是一种快速、可扩展的、设计内在就是分布式的...
  • u010870518
  • u010870518
  • 2017-08-16 20:22
  • 11311

垃圾回收器的基本原理

GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。垃圾回收的优点和...
  • Amen_Wu
  • Amen_Wu
  • 2017-01-09 23:25
  • 1362

【SSH】——Struts由来以及基本原理

Struts,最初的意思是:框架的,支杆。用来支持JSP,Servlet等技术在Web项目中的应用。它的目的是帮助我们减少在运用MVC设计模型来开发Web应用的时间。          在使用Struts之前...
  • u013035538
  • u013035538
  • 2016-07-06 22:44
  • 449

EM算法解析

本文介绍EM算法的相关推导过程,同时会介绍混合高斯模型。 1.EM算法 1.1 EM算法的推导 观测数据(不完全数据)X关于参数θ\theta的对数似然函数为: L(θ)=logP(x|θ)=log∑zP(x,z|θ)=log∑z[q(z)P(x,z|θ)q(z)]≥∑zq(z)logP(x...
  • u010189459
  • u010189459
  • 2018-01-21 13:53
  • 38

MapReduce的基本原理

MapReduce是一个软件框架,可方便的编写应用程序,以并行的方式在数千商用硬件组成的集群节点中处理数TB的数据,并且提供了可靠性和容错的能力。 MapReduce处理模型包括两个独立的步骤: 1.并行Map阶段,输入数据被分割成离散块以便可以单独处理; 1.5shuffle阶段,每个R...
  • u013063153
  • u013063153
  • 2016-11-10 15:50
  • 633
    个人资料
    • 访问:957422次
    • 积分:12879
    • 等级:
    • 排名:第1271名
    • 原创:258篇
    • 转载:85篇
    • 译文:11篇
    • 评论:954条
    博主的 GitHub 账号
    GitHub : Charies Gavin

        鉴于 CSDN 糟糕的用户体验,博主会将一些优质的文章迁移到 Charies Gavin's Blog  欢迎大家在 GitHub 上 Follow 博主,以及 Fork、Star、Watch 博主的项目。


      青春不老 奋斗不止


      好学若饥虚心若愚
    博客专栏