0%

Kafka 消息生产及消费原理

开篇

关于客户端生产和消费不在本文中探讨,本文主要集中在Kafka服务器端对消息如何存储和如何读取消息。

本文主要探讨如下问题:

  1. 服务器端接收到消息后如何处理?
  2. 如果我指定了一个offset,Kafka怎么查找到对应的消息?
  3. 如果我指定了一个timestamp,Kafka怎么查找到对应的消息?

正文

服务器端接收到消息处理流程

Kafka Server接受消息处理流程

KafkaApis是Kafka server处理所有请求的入口,在 Kafka 中,每个副本(replica)都会跟日志实例(Log 对象)一一对应,一个副本会对应一个 Log 对象。副本由ReplicaManager管理,对于消息的写入操作在Log与LogSement中进行的。

阅读全文 »

Kafka 逻辑架构设计

开篇

本文主要探讨如下问题;

  1. Kafka架构设计
  2. Kafka的日志目录结构

正文

Kafka架构设计

kafka为分布式消息系统,由多个broker组成。消息是通过topic来分类的,一个topic下存在多个partition,每个partition又由多个segment构成。

发布订阅者模式

kafka集群架构

阅读全文 »

开篇

在开始这篇之前,先抛出问题,这章主要通过研究consumer源码解决如下问题:

消费再均衡的原理是什么?

正文

消费再均衡的原理

主要分为四步

1.FIND_COORDINATOR

根据hash(group_id)%consumerOffsetPartitionNum查找出对应的partition,再查找出该partitiom对应的leader所在的broker,即可获得GroupCoordinator

2.JOIN_GROUP

在这一步主要完成消费组leader选举(获取第一个加入的组为leader,如果没有,选择map中的第一个node)和分区分配策略

阅读全文 »

kafka consumer 源码分析(二)分区分配策略

开篇

在开始这篇之前,先抛出问题,这章主要通过研究consumer源码解决如下问题:

分区分配策略是什么样的?

正文

分区分配策略

这里的分区分配策略仅仅只讨论consumer,关于producer端的分区不在本次探讨范围内。

consumer端分区分配策略官方有三种:RangeAssignor(默认值),RoundRobinAssignor,StickyAssignor

通常是通过partition.assignment.strategy配置生效。

RangeAssignor

阅读全文 »

kafka consumer 源码分析(一)Consumer处理流程

开篇

在开始这篇之前,先抛出问题,这章主要通过研究consumer源码解决如下问题:

  1. consumer处理流程
  2. 消费者提交消费位移时提交的是当前消费到的最新消息的offset还是offset+1?

正文

Consumer处理流程

核心组件

ConsumerCoordinator: 消费者的协调者, 管理消费者的协调过程

  • 维持coordinator节点信息(也就是对consumer进行assignment的节点)
  • 维持当前consumerGroup的信息, 当前consumer已进入consumerGroup

Fetcher: 数据请求类

阅读全文 »

前言

零拷贝(英语:Zero-copy)技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。

零拷贝操作减少了在用户空间与内核空间之间切换模式的次数

举例来说,如果要读取一个文件并通过网络发送它,传统方式下如下图,传统的I/O操作进行了4次用户空间与内核空间的上下文切换,以及4次数据拷贝。其中4次数据拷贝中包括了2次DMA拷贝和2次CPU拷贝。通过零拷贝技术完成相同的操作,减少了在用户空间与内核空间交互,并且不需要CPU复制数据。

linux中零拷贝技术

Linux系统的“用户空间”和“内核空间”

从Linux系统上看,除了引导系统的BIN区,整个内存空间主要被分成两个部分:内核空间(Kernel space)、用户空间(User space)。

“用户空间”和“内核空间”的空间、操作权限以及作用都是不一样的。

内核空间是Linux自身使用的内存空间,主要提供给程序调度、内存分配、连接硬件资源等程序逻辑使用;用户空间则是提供给各个进程的主要空间。

阅读全文 »

Kafka producer源码分析

前言

在开始文章之前,需要解释是一下为什么要研究producer源码。

为什么要研究producer源码

通常producer使用都很简单,初始化一个KafkaProducer实例,然后调用send方法就好,但是我们有了解后面是如何发送到kafka集群的吗?其实我们不知道,其次,到底客户端有几个线程?我们不知道。还有producer还能做什么?我们同样不知道。本篇文章就是想回答一下上面提出的几个问题,能力有限,如有错误,欢迎指出!

架构

在介绍客户端架构之前,先回答一个问题

producer到底存在几个线程?2个 Main threadsender,其中sender线程负责发送消息,main 线程负责interceptor、序列化、分区等其他操作。

  • Producer首先使用用户主线程将待发送的消息封装进一个ProducerRecord类实例中。
  • 进行interceptor、序列化、分区等其他操作,发送到Producer程序中RecordAccumulator中。
  • Producer的另一个工作线程(即Sender线程),则负责实时地从该缓冲区中提取出准备好的消息封装到一个批次的内,统一发送给对应的broker中。
阅读全文 »

前言

为了深入研究kafka运行原理和架构,很有必要搭建开发环境,这样我们就很方便的debug 服务。

前期准备

  1. Gradle 5.0+
  2. jdk8
  3. Scala 2.12
  4. idea scale plugin

配置/运行

  • 首先执行在源码目录下执行gradle
  • 然后build ./gradlew jar
  • 最后生成idea工程./gradlew idea

运行MirrorMaker

运行kafka server

因为kafka依赖zookeeper,在开始之前请先启动一个zookeeper服务,本文章略。

阅读全文 »

前言

写这篇文章的目的是为了记录一下学习笔记,其次为了能够在复习的时候快速掌握相关知识。本篇记录java8系列专栏之Lambda与Stream API

正文

Lambda

什么是Lambda

1
2
List<String>list = Arrays.asList("a","c","b");
Collections.sort(list, (o1,o2)->o1.compareTo(o2));

以下方式都是常用的lambda使用方式

1
2
3
4
str->str.toLowerCase()
(o1,o2)->o1.compareTo(o2)
(o1,o2)->{return o1.compareTo(o2)}
(String o1,String o2)->{return o1.compareTo(o2)}

怎么用,哪里用

函数接口声明既可使用。例如Runnable,Comparator都是函数接口。用@FunctionalInterface声明的都是函数接口

阅读全文 »

Optional类的方法

方法 描述
empty 返回一个空的 Optional 实例
filter 如果值存在并且满足提供的断言, 就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象
map 如果值存在,就对该值执行提供的 mapping 函数调用
flatMap 如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返 回一个空的 Optional 对象
get 如果该值存在,将该值用 Optional 封装返回,否则抛出一个 NoSuchElementException 异常
ifPresent 如果值存在,就执行使用该值的方法调用,否则什么也不做
isPresent 如果值存在就返回 true,否则返回 false
of 将指定值用 Optional 封装之后返回,如果该值为 null,则抛出一个 NullPointerException 异常
ofNullable 将指定值用 Optional 封装之后返回,如果该值为 null,则返回一个空的 Optional 对象
orElse 如果有值则将其返回,否则返回一个默认值
orElseGet 如果有值则将其返回,否则返回一个由指定的 Supplier 接口生成的值
orElseThrow 如果有值则将其返回,否则抛出一个由指定的 Supplier 接口生成的异常