hadoop各组件工作流程分析

Hadoop生态圈中各组件工作流程分析

HDFS YARN MapReduce三者关系

关系图

在这里插入图片描述

文字描述

  1. 客户端提交文件给Hadoop -> Yarn -> ResourceManager
  2. ResourceManager启动App Master
  3. App Master 申请资源给Container
  4. 在Container中跑MapTask(数据分成了几片就有几个Map Task)
  5. Map Task 中的数据从DataNode中来
  6. Map Task 跑完把数据结果传给Reducer Task
  7. Reducer Task跑完把结果存入HDFS

HDFS写数据流程

流程图

HDFS写数据流程

过程描述

  1. 客户端创建一个 分布式文件系统对象 通过它向NameNode请求上传文件D:\io\input\a.txt
  2. NameNode检查目录树是否可以上传(权限、目录是否已经存在等),响应可以上传
  3. 客户端向NameNode请求上传Block(0-128M)
  4. NameNode返回dn1 dn2 dn3节点 (副本节点选择:本地节点 其他机架一个节点 其他机架另一个节点 选距离最近的 拓扑)
  5. 客户端和DataNode1建立传输通道,然后DataNode1和DataNode2建立传输通道,DataNode2和DataNode3建立传输通道,应答成功就可以开始传输数据了
  6. 从本地读取数据后开始传输,一个包一个包的传。Packet 64k 含 chunk512byte + chunksum4byte
  7. DataNode节点会一个一个的把Packet写在磁盘上(落盘)
  8. 传输完成后若还有块er没传完,回到第三步直到所以块都传输完成

HDFS读数据流程

流程图

读数据流程图

过程描述

  1. 客户端创建文件系统对象 Distributed FileSystem 向NameNode发送读数据请求
  2. NameNode看客户端有没有读权限并看看自己有没有该数据,返回目标文件的 元数据
  3. 客户端创建流 读数据流
  4. 向目标DataNode节点发送读数据请求(块信息等)
  5. 目标节点向客户端传输数据
  6. 传输完成若还有块等待读取数据就重复步骤4直到数据都读完
  7. 将文件改名后关闭流

切片源码

/*
 getFormatMinSplitSize() : 返回1
 
 getMinSplitSize(job) :如果配置了mapreduce.input.fileinputformat.split.minsize参数返回参数设置的值
	否则返回默认值1
*/
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));

/*
如果设置了mapreduce.input.fileinputformat.split.maxsize参数那么返回该参数设置的值
	否则返回Long.MAX_VALUE
*/
long maxSize = getMaxSplitSize(job);


//该集合用来存放切片信息(一个切片就是一个对象)
//放入到该集合的对象是FileSplit 但是泛型是InputSplit 说明FileSplit和InputSplit有继承关系
//FileSplit是InputSplit的子类
List<InputSplit> splits = new ArrayList<InputSplit>();

//获取输入目录中所有的文件或目录状态
List<FileStatus> files = listStatus(job);

//获取文件的路径
Path path = file.getPath();

//获取文件的大小
long length = file.getLen();

//块大小
long blockSize = file.getBlockSize();

/*
  切片大小
  
  默认 : 片大小 = 块大小
  需求:
	  片大小 > 块大小 :修改minSize大小
	  片大小 < 块大小 :修改maxSize大小
  
  protected long computeSplitSize(long blockSize, long minSize,
                                  long maxSize) {
    return Math.max(minSize, Math.min(maxSize, blockSize));
  }
*/          
long splitSize = computeSplitSize(blockSize, minSize, maxSize);

//剩余文件大小
long bytesRemaining = length;

/*
 开始切片 : 
	((double) bytesRemaining)/splitSize > SPLIT_SLOP : 剩余文件大小 / 切片大小 > 1.1  (为了防止最后1片太小)
*/
 while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
			
			/*
				makeSplit : 创建FileSplit对象
				参数length-bytesRemaining :片的起始位置
				参数splitSize :切片大小
				
				将FileSplit对象放入到splits集合中
			*/
            splits.add(makeSplit(path, length-bytesRemaining, splitSize,
                        blkLocations[blkIndex].getHosts(),
                        blkLocations[blkIndex].getCachedHosts()));
			//重新计算剩余文件大小 :将片大小从剩余文件大小减掉
            bytesRemaining -= splitSize;
}

//将剩余文件大小整体切一片
if (bytesRemaining != 0) {
	int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
	splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,
			   blkLocations[blkIndex].getHosts(),
			   blkLocations[blkIndex].getCachedHosts()));
}


 not splitable
//如果文件不可切整个文件是1片
splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),
		  blkLocations[0].getCachedHosts()));

InputFormat

InputFormat : 抽象类
	作用 :①切片 ②读取数据
	
	//切片
	public abstract 
    List<InputSplit> getSplits(JobContext context
                               ) throws IOException, InterruptedException;

   //创建RecordReader对象 该对象用来读取数据
   public abstract 
    RecordReader<K,V> createRecordReader(InputSplit split,
                                         TaskAttemptContext context
                                        ) throws IOException, 
                                                InterruptedException;InputFormat的继承树
	|-----InputFormat 抽象类
		|------FileInputFormat 抽象类
			|-------TextInputFormat 默认使用的InputFormat的类
			
			
三 FileInputFormat 抽象类
	1.FileInputFormat是抽象类 继承了 InputFormat 
	2.FileInputFormat实现了父类的getSplits方法
	
四 TextInputFormat 默认使用的InputFormat的类
	1.TextInputFormat是默认使用的InputFormat的类 继承了FileInputFormat
	2.TextInputFormat实现了createRecordReader方法
	3.createRecordReader方法返回了LineRecordReaderLineRecordReaderRecordReader的子类
	4.LineRecordReader是真正用来读取文件中的数据的那个对象的所属类
	
	public RecordReader<LongWritable, Text> 
		createRecordReader(InputSplit split,
						   TaskAttemptContext context) {
		return new LineRecordReader(recordDelimiterBytes);
   }	

conbineTextInputFormat切片机制
将大量的小文件合并成一个大的Map Task的过程
虚拟存储过程 切片过程

MapReduce工作流程

概念图

maperduce详细工作流程

过程描述

  1. 准备待处理数据a.txt 200M 块大小是128M 切两片(若想改变切片大小就设置conf参数,具体修改见切片源码)
  2. InputFormat -> FileInputFormat -> TextInputFormat -> getSplit 对数据进行切片处理,上传jar包,提交job信息给YarnRunner 创建App Master
  3. App Master 申请资源,生成两个Map Task
  4. Map Task 用 InputFormat -> RecordReader -> LineRecondReader 读数据
  5. 然后使用Mapper的map方法进行数据处理
  6. 接下来就是shuffle过程,在下一章节详细讲解

shuffle机制

shuffle流程图解

黑夜

文字描述

  1. map方法写出的数据流向了缓冲区
    • 该缓冲区在数据量达到80%时会进行排序,排序完成的数据会形成多个分区直接写入磁盘,每轮数据都会按该分区算法进行分区,方便下一步归并
    • 所有数据都处理完成后就会进行归并排序,相同分区的数据进行归并
    • 归并完成后按分区进行combiner合并压缩即:将1万条aaa 1 -> aaa 10000
    • 将处理结果写入磁盘
  2. 进行过上述操作后将所有 Map Task 的相同分区放在一起进行的归并排序
  3. 最后数据进入 reduce 方法

Yarn工作机制

流程图

在这里插入图片描述

调度算法

先进先出调度器(FIFO)

容量调度器(Capacity Scheduler)

在这里插入图片描述

在这里插入图片描述

公平调度器(Fair Scheduler)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Map Task工作机制

流程图

在这里插入图片描述

Reduce Task 工作机制

流程图

在这里插入图片描述

MapReduce工作机制

流程图

在这里插入图片描述
在这里插入图片描述

MapReduce优化性能

map优化

在这里插入图片描述

Reduce优化

在这里插入图片描述

数据倾斜问题

在这里插入图片描述
在这里插入图片描述

Hadoop小文件解决方案

  1. Hadoop Archive(HAR归档)
    是一个高效的将小文件放入HDFS块中的文件存档工具,能够将多个小文件打包成一个HAR文件,从而达到减少NameNode的内存使用。
  2. CombineTextInputFormat
    CombineTextInputFormat用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片。

ZooKeeper

ZooKeeper工作机制

在这里插入图片描述

ZooKeeper特点

在这里插入图片描述

Leader选举机制

在这里插入图片描述
zkCli.sh进入zk客户端

HA

HDFS-HA核心问题

  1. 怎么保证三台namenode的数据一致
  • Fsimage:让一台nn生成数据,让其他机器nn同步。
  • Edits:需要引进新的模块JournalNode来保证edtis的文件的数据一致性。
  1. 怎么让同时只有一台nn是active,其他所有是standby的
    Zookeeper居中协调,选举active
  2. 2nn在ha架构中并不存在,定期合并fsimage和edtis的活谁来干
    由standby的nn来干。
  3. 如果nn真的发生了问题,怎么让其他的nn上位干活
    自动故障转移

自动故障转移工作机制

在这里插入图片描述

Yarn-HA工作机制

在这里插入图片描述

Hadoop-HA集群最终规划

hadoop102hadoop103hadoop104
NameNodeNameNodeNameNode
JournalNodeJournalNodeJournalNode
DataNodeDataNodeDataNode
ZookeeperZookeeperZookeeper
ZKFCZKFCZKFC
ResourceManagerResourceManagerResourceManager
NodeManagerNodeManagerNodeManager
  • NameNode:HDFS中存储元数据信息的服务
  • JournalNode:保证edtis的文件的数据一致性的服务
  • DataNode:HDFS中真正存储数据的节点服务
  • Zookeeper:文件系统+通知机制的服务
  • ZKFC:ZooKeeper Failover Controller,监视和管理 Hadoop 的 NameNode 服务的高可用性
  • ResourceManager:Yarn中处理客户端请求、监控NodeManager、启动或监控ApplicationMaster、资源的分配与调度的服务
  • NodeManager:Yarn中管理单个节点上的资源、处理来自ResourceManager的命令、处理来自ApplicationMaster的命令的服务

Hive

基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。

Hive架构原理

在这里插入图片描述

抽象语法树

在这里插入图片描述

逻辑计划与物理计划

在这里插入图片描述

hiveserver2

Hive的hiveserver2服务的作用是提供jdbc/odbc接口,为用户提供远程访问Hive数据的功能,例如用户期望在个人电脑中访问远程服务中的Hive数据,就需要用到Hiveserver2。
在这里插入图片描述
Hive的metastore服务的作用是为Hive CLI或者Hiveserver2提供元数据访问接口。

在这里插入图片描述

语法

基础语法和MySQL相同

炸裂函数

在这里插入图片描述
案例演示:
数据准备

moviecategory
《疑犯追踪》悬疑,动作,科幻,剧情
《Lie to me》悬疑,警匪,动作,心理,剧情
《战狼2》战争,动作,灾难
create table movie_info(
    movie string,     --电影名称
    category string   --电影分类
) 
row format delimited fields terminated by "\t";

insert overwrite table movie_info
values ("《疑犯追踪》", "悬疑,动作,科幻,剧情"),
       ("《Lie to me》", "悬疑,警匪,动作,心理,剧情"),
       ("《战狼2》", "战争,动作,灾难");

需求说明:根据上述电影信息表,统计各分类的电影数量,期望结果如下:

类型数量
剧情2
动作3
心理1
悬疑2
战争1
灾难1
科幻1
警匪1
select
    cate,
    count(*)
from
(
    select
        movie,
        cate
    from
    (
        select
            movie,
            split(category,',') cates
        from movie_info
    )t1 lateral view explode(cates) tmp as cate
)t2
group by cate;

窗口函数(开窗函数)

按照功能,常用窗口可划分为如下几类:聚合函数、跨行取值函数、排名函数。
1)聚合函数
max:最大值。
min:最小值。
sum:求和。
avg:平均值。
count:计数。
2)跨行取值函数
(1)lead和lag
在这里插入图片描述

(2)first_value last_value
在这里插入图片描述
(3)排名函数

在这里插入图片描述

自定义函数

1)Hive自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展。
2)当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
3)根据用户自定义函数类别分为以下三种:
(1)UDF(User-Defined-Function)
一进一出。
(2)UDAF(User-Defined Aggregation Function)
用户自定义聚合函数,多进一出。
类似于:count/max/min
(3)UDTF(User-Defined Table-Generating Functions)
用户自定义表生成函数,一进多出。
如lateral view explode()
4)官方文档地址
https://cwiki.apache.org/confluence/display/Hive/HivePlugins

分区表(分目录)和分桶表(分文件)

create table dept_partition(
    deptno int,    --部门编号
    dname  string, --部门名称
    loc    string  --部门位置
)
partitioned by (day string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/hive/datas/dept_20220401.log' into table dept_partition partition(day='20220401');

按day分区,day是一个新列,里面可以是空的导数据的时候再写20220401,但创建表时必须有day这个字段类型也不能错!是string
insert

insert overwrite table dept_partition partition (day = '20220402')
select deptno, dname, loc
from dept_partition
where day = '2020-04-01';

分区表基本操作
(1)查看所有分区信息
hive> show partitions dept_partition;
(2)增加分区
①创建单个分区
hive (default)>
alter table dept_partition
add partition(day=‘20220403’);
②同时创建多个分区(分区之间不能有逗号)
hive (default)>
alter table dept_partition
add partition(day=‘20220404’) partition(day=‘20220405’);
(3)删除分区
①删除单个分区
hive (default)>
alter table dept_partition
drop partition (day=‘20220403’);
②同时删除多个分区(分区之间必须有逗号)
hive (default)>
alter table dept_partition
drop partition (day=‘20220404’), partition(day=‘20220405’);

二级分区表

思考:如果一天内的日志数据量也很大,如何再将数据拆分?答案是二级分区表,例如可以在按天分区的基础上,再对每天的数据按小时进行分区。
1)二级分区表建表语句
hive (default)>
create table dept_partition2(
deptno int, – 部门编号
dname string, – 部门名称
loc string – 部门位置
)
partitioned by (day string, hour string)
row format delimited fields terminated by ‘\t’;
2)数据装载语句
hive (default)>
load data local inpath ‘/opt/module/hive/datas/dept_20220401.log’
into table dept_partition2
partition(day=‘20220401’, hour=‘12’);
3)查询分区数据
hive (default)>
select
*
from dept_partition2
where day=‘20220401’ and hour=‘12’;

动态分区

动态分区是指向分区表insert数据时,被写往的分区不由用户指定,而是由每行数据的最后一个字段的值来动态的决定。使用动态分区,可只用一个insert语句将数据写入多个分区。
1)动态分区相关参数
(1)动态分区功能总开关(默认true,开启)
set hive.exec.dynamic.partition=true
(2)严格模式和非严格模式
动态分区的模式,默认strict(严格模式),要求必须指定至少一个分区为静态分区,nonstrict(非严格模式)允许所有的分区字段都使用动态分区。
set hive.exec.dynamic.partition.mode=nonstrict
(3)一条insert语句可同时创建的最大的分区个数,默认为1000。
set hive.exec.max.dynamic.partitions=1000
(4)单个Mapper或者Reducer可同时创建的最大的分区个数,默认为100。
set hive.exec.max.dynamic.partitions.pernode=100
(5)一条insert语句可以创建的最大的文件个数,默认100000。
hive.exec.max.created.files=100000
(6)当查询结果为空时且进行动态分区时,是否抛出异常,默认false。
hive.error.on.empty.partition=false

分桶表基本语法

1)建表语句
hive (default)>
create table stu_buck(
id int,
name string
)
clustered by(id)
into 4 buckets
row format delimited fields terminated by ‘\t’;
2)数据装载
(1)数据准备
在/opt/module/hive/datas/路径上创建student.txt文件,并输入如下内容。
1001 student1
1002 student2
1003 student3
1004 student4
1005 student5
1006 student6
1007 student7
1008 student8
1009 student9
1010 student10
1011 student11
1012 student12
1013 student13
1014 student14
1015 student15
1016 student16
(2)导入数据到分桶表中
说明:Hive新版本load数据可以直接跑MapReduce,老版的Hive需要将数据传到一张表里,再通过查询的方式导入到分桶表里面。
hive (default)>
load data local inpath ‘/opt/module/hive/datas/student.txt’
into table stu_buck;

文件格式和压缩

text file和sequence file都是基于行存储的,orc和parquet是基于列式存储的。

Hadoop压缩概述

压缩格式算法文件扩展名是否可切分
DEFLATEDEFLATE.deflate
GzipDEFLATE.gz
bzip2bzip2.bz2
LZOLZO.lzo
SnappySnappy.snappy

压缩性能的比较:

压缩算法原始文件大小压缩文件大小压缩速度解压速度
gzip8.3GB1.8GB17.5MB/s58MB/s
bzip28.3GB1.1GB2.4MB/s9.5MB/s
LZO8.3GB2.9GB49.3MB/s74.6MB/s

为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器,如下表所示:
Hadoop查看支持压缩的方式hadoop checknative。
Hadoop在driver端设置压缩。

压缩格式对应的编码/解码器
DEFLATEorg.apache.hadoop.io.compress.DefaultCodec
gziporg.apache.hadoop.io.compress.GzipCodec
bzip2org.apache.hadoop.io.compress.BZip2Codec
LZOcom.hadoop.compression.lzo.LzopCodec
Snappyorg.apache.hadoop.io.compress.SnappyCodec

以TextFile为例
若一张表的文件类型为TextFile,若需要对该表中的数据进行压缩,多数情况下,无需在建表语句做出声明。直接将压缩后的文件导入到该表即可,Hive在查询表中数据时,可自动识别其压缩格式,进行解压。
需要注意的是,在执行往表中导入数据的SQL语句时,用户需设置以下参数,来保证写入表中的数据是被压缩的。
–SQL语句的最终输出结果是否压缩
set hive.exec.compress.output=true;
–输出结果的压缩格式(以下示例为snappy)
set mapreduce.output.fileoutputformat.compress.codec =org.apache.hadoop.io.compress.SnappyCodec;
2)ORC
若一张表的文件类型为ORC,若需要对该表数据进行压缩,需在建表语句中声明压缩格式如下:
create table orc_table
(column_specs)
stored as orc
tblproperties (“orc.compress”=“snappy”);

Hive的企业级调优(面试重点)

Flume

概述

在这里插入图片描述

组成

1.2.1 Agent
Agent是一个JVM进程,它以事件的形式将数据从源头送至目的地。
Agent主要有3个部分组成,Source、Channel、Sink。
1.2.2 Source
Source是负责接收数据到Flume Agent的组件。Source组件可以处理各种类型、各种格式的日志数据
1.2.3 Sink
Sink不断地轮询Channel中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统、或者被发送到另一个Flume Agent。
1.2.4 Channel
Channel是位于Source和Sink之间的缓冲区。因此,Channel允许Source和Sink运作在不同的速率上。Channel是线程安全的,可以同时处理几个Source的写入操作和几个Sink的读取操作。
Flume自带两种Channel:Memory Channel和File Channel。
Memory Channel是内存中的队列。Memory Channel在不需要关心数据丢失的情景下适用。如果需要关心数据丢失,那么Memory Channel就不应该使用,因为程序死亡、机器宕机或者重启都会导致数据丢失。
File Channel将所有事件写到磁盘。因此在程序关闭或机器宕机的情况下不会丢失数据。
1.2.5 Event
传输单元,Flume数据传输的基本单元,以Event的形式将数据从源头送至目的地。Event由Header和Body两部分组成,Header用来存放该event的一些属性,为K-V结构,Body用来存放该条数据,形式为字节数组。

事务

在这里插入图片描述
doCommit:检查channel内队列是否足够合并 的意思是 当前putlist中的数据是否可以放到channel中,可以就放,不可以就不放,然后都清空putList

https://flume.apache.org/releases/content/1.10.0/FlumeUserGuide.html

Kafka

消息队列,基础架构
在这里插入图片描述

  • (1)Producer:消息生产者,就是向Kafka broker发消息的客户端。
  • (2)Consumer:消息消费者,从Kafka broker取消息的客户端。
  • (3)Consumer Group(CG):消费者组,由多个consumer组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
  • (4)Broker:一台Kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
  • (5)Topic:可以理解为一个队列,生产者和消费者面向的都是一个topic。
  • (6)Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。
  • (7)Replica:副本。一个topic的每个分区都有若干个副本,一个Leader和若干个Follower。
  • (8)Leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是Leader。
    Follower:每个分区多个副本中的“从”,实时从Leader中同步数据,保持和Leader数据的同步。Leader发生故障时,某个Follower会成为新的Leader。

生产者消息发送流程

在这里插入图片描述

生产者重要参数列表

参数名称描述
bootstrap.servers生产者连接集群所需的broker地址清单。例如hadoop102:9092,hadoop103:9092,hadoop104:9092,可以设置1个或者多个,中间用逗号隔开。注意这里并非需要所有的broker地址,因为生产者从给定的broker里查找到其他broker信息。
key.serializer和value.serializer指定发送消息的key和value的序列化类型。一定要写全类名。
buffer.memoryRecordAccumulator缓冲区总大小,默认32m。
batch.size缓冲区一批数据最大值,默认16k。适当增加该值,可以提高吞吐量,但是如果该值设置太大,会导致数据传输延迟增加。
linger.ms如果数据迟迟未达到batch.size,sender等待linger.time之后就会发送数据。单位ms,默认值是0ms,表示没有延迟。生产环境建议该值大小为5-100ms之间。
acks0:生产者发送过来的数据,不需要等数据落盘应答。1:生产者发送过来的数据,Leader收到数据后应答。-1(all):生产者发送过来的数据,Leader+和isr队列里面的所有节点收齐数据后应答。默认值是-1,-1和all是等价的。
max.in.flight.requests.per.connection允许最多没有返回ack的次数,默认为5,开启幂等性要保证该值是 1-5的数字。
retries当消息发送出现错误的时候,系统会重发消息。retries表示重试次数。默认是int最大值,2147483647。如果设置了重试,还想保证消息的有序性,需要设置MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION=1否则在重试此失败消息的时候,其他的消息可能发送成功了。
retry.backoff.ms两次重试之间的时间间隔,默认是100ms。
enable.idempotence是否开启幂等性,默认true,开启幂等性。
compression.type生产者发送的所有数据的压缩方式。默认是none,也就是不压缩。 支持压缩类型:none、gzip、snappy、lz4和zstd。

生产经验–提高吞吐量

在这里插入图片描述

生产经验–数据可靠性

ack应答
在这里插入图片描述

生产经验–数据去重

幂等性

1)幂等性原理

在这里插入图片描述

生产者事务

0.11版本的Kafka同时引入了事务的特性,为了实现跨分区跨会话的事务,需要引入一个全局唯一的Transaction ID,并将Producer获得的PID和Transaction ID绑定。这样当Producer重启后就可以通过正在进行的Transaction ID获得原来的PID。
为了管理Transaction,Kafka引入了一个新的组件Transaction Coordinator。Producer就是通过和Transaction Coordinator交互获得Transaction ID对应的任务状态。
Transaction Coordinator还负责将事务所有写入Kafka的一个内部Topic,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以得到恢复,从而继续进行。
注意:提前开启幂等性!!!

生产经验–数据有序or怎么解决乱序

  • Kafka 最多只保证单分区内的消息是有序的,所以如果要保证业务全局严格有序,就要设置 Topic 为单分区。
    在这里插入图片描述
  • 如何保证单分区内数据有序or怎么解决乱序?
    在这里插入图片描述
    其中参数134都是保证数据安全性的,2是保证顺序的
    在这里插入图片描述
    在生产者向kafka中传输数据时
    在producer中就排好序seqnum,0-5给6-11
    6-9均已传输完成,传输第10个batch时发生故障写入失败,从broker返回写入失败的消息,于是producer开始重新传输batch10
    但此时batch11已发出,到broker时,broker发现batch11的编号是5,而batch9的seqnum是3,5-3 不等于1,那么broker就不让batch11写入,保证了数据的有序性
    等到batch10重新发送的请求成功写入了之后再允许后面的batch写入

Kafka Broker工作流程

在这里插入图片描述
broker启动后在zk中注册(即在集群上启动kafka)
然后controller选举leader(leader只存在于同一分区的不同副本上),谁先注册,谁说了算(当leader)选举规则如图
由leader节点上的controller监听broker节点的变化
每台节点上的controller将节点信息上传到ZooKeeper,其他节点的controller从zk同步相关信息
假设broker1(leader)挂了,controller监听到节点变化就要获取 ISR 选举新的leader:broker0,更新leader和 ISR

broker 重要参数

参数名称描述
replica.lag.time.max.msISR中,如果Follower长时间未向Leader发送通信请求或同步数据,则该Follower将被踢出ISR。该时间阈值,默认30s。
auto.leader.rebalance.enable默认是true。 自动Leader Partition 平衡。
leader.imbalance.per.broker.percentage默认是10%。每个broker允许的不平衡的leader的比率。如果每个broker超过了这个值,控制器会触发leader的平衡。
leader.imbalance.check.interval.seconds默认值300秒。检查leader负载是否平衡的间隔时间。
log.segment.bytesKafka中log日志是分成一块块存储的,此配置是指log日志划分 成块的大小,默认值1G。
log.index.interval.bytes默认4kb,kafka里面每当写入了4kb大小的日志(.log),然后就往index文件里面记录一个索引。
log.retention.hoursKafka中数据保存的时间,默认7天。
log.retention.minutesKafka中数据保存的时间,分钟级别,默认关闭。
log.retention.msKafka中数据保存的时间,毫秒级别,默认关闭。
log.retention.check.interval.ms检查数据是否保存超时的间隔,默认是5分钟。
log.retention.bytes默认等于-1,表示无穷大。超过设置的所有日志总大小,删除最早的segment。
log.cleanup.policy默认是delete,表示所有数据启用删除策略;如果设置值为compact,表示所有数据启用压缩策略。
num.io.threads默认是8。负责写磁盘的线程数。整个参数值要占总核数的50%。
num.replica.fetchers副本拉取线程数,这个参数占总核数的50%的1/3
num.network.threads默认是3。数据传输线程数,这个参数占总核数的50%的2/3 。
log.flush.interval.messages强制页缓存刷写到磁盘的条数,默认是long的最大值,9223372036854775807。一般不建议修改,交给系统自己管理。
log.flush.interval.ms每隔多久,刷数据到磁盘,默认是null。一般不建议修改,交给系统自己管理。

Leader和Follower故障处理细节

在这里插入图片描述
在这里插入图片描述

kafka文件存储机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
index:稀疏索引
log:offset,偏移量
timeindex:时间索引

kafka-run-class.sh kafka.tools.DumpLogSegments --files ./00000000000000000000.index
kafka-run-class.sh kafka.tools.DumpLogSegments --files ./00000000000000000000.log
kafka-run-class.sh kafka.tools.DumpLogSegments --files ./00000000000000000000.index --print-data-log
//从3往下的所有数据
kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic demo --partition 0 --offset 3

高效读写数据

在这里插入图片描述

消费者

消费者初始化流程

在这里插入图片描述

消费者消费详细流程

在这里插入图片描述

生产经验——分区的分配以及再平衡

就是coordinate 选出来的Leader 是如何将分区分配给组内的各个消费者的
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值