面试笔记 (ㄒoㄒ) ~~

+ [创建文件](#_363)
+ [显示指定文件或文件夹的详细信息](#_369)
+ [获取指定文件的类型](#_375)
+ [查看当前账户/其他账户 uid/gid](#_uidgid_383)
+ [查看当前文件夹下文件及文件夹所属账户](#_391)
+ [查看进程列表](#_397)
+ [创建用户](#_403)
+ [创建组](#_415)
+ [组的作用:](#_422)
+ [给账户添加组](#_434)
+ [查看组的信息](#_442)
+ [删除用户](#_449)
+ [修改用户密码](#_457)
+ [普通用户获取管理员权限](#_463)
+ [修改某一个文件或文件夹的属主/属组](#_469)
+ [修改文件属组](#_477)
+ [修改文件权限](#_486)

1.string类可以被继承吗?

String类被final修饰不可以被继承

2.String StringBuffer StringBuilder 三者的区别

都是字符串常量

String 是final修饰的字符数组,对象是不可变的,常量,线程安全(操作少量数据时使用)

StringBuffer 线程安全的,对方法加了同步锁或者对调用的方法加了同步锁 (多线程操作数据量大使用)

StringBuilder 非线程安全,没有加同步锁(单线程数据量大使用)

3.集合

3.1List和Set的区别?

List可以包含重复元素,而Set包含唯一项。
List是一个有序集合,它维护插入顺序,而Set是一个无序集合,不保留插入顺序。
List接口包含一个遗留类:Vector类,而Set接口没有任何遗留类。
List接口可以允许n个null值,而Set接口只允许一个null值。

3.2ArrayList 和LinkedList的区别

Array和LinkedList数据结构的不同。

ArrayList是基于数组实现的,查询快增删慢

LinkedList是基于双链表实现的。查询慢,增删快,线程不安全,效率高。

3.2.1 数组为什么增删慢?双链表增删快?

因为数组是有序的集合,增加或者删除都会使其他值移位(增加向后移,删除向前移)
双量表无论查询哪个数据都需要从头开始找,增删直接新增数据值和上下两个地址

3.3 HashMap和concurrentHashMap区别

1、HashMap

数据结构:数组 + 链表 + 红黑树

安全性:非线程安全,因为底层代码操作数组时未加锁。

应用场景:高并发情况下,put、remove 成员变量时可能产生线程安全问题,需加锁;

操作非成员标量时不会发生线程安全问题,可以不用加锁。

扩容:元素插入后判断数组长度是否超阈,默认阈值0.75,若超阈则进行扩容,扩容大小为原数组的2的幂次方,若原数组所在内存上没有连续的可用空间,则申请新的可用连续空间,将旧数组复制到新的地址,再将旧数组置为null,等待GC回收。

缩容:无动态缩容机制,需手动缩容。

2、concurrentHashMap

数据结构:分段数组 + 链表 + 红黑树

安全性:线程安全,因为底层代码在操作每一个segment时都会对segment加锁,保证线程安全。

应用场景:高并发情况下,线程安全,操作成员变量或局部变量都不需要单独加锁处理。

性能:读取数据时不加锁,高效,且因为map中的value值是添加volatile关键字修饰的,可保证读取到最新值,降低CPU负载。

写入数据时,会先通过hashcode算法算出要写入的segment(桶的位置),然后锁定当前segment,而不是锁定整个数组,所以读写效率比hashTable要高很多。

3.3.1分段数组

分段数组是一种数据结构,用于解决动态区间查询的问题。它将一个大的数组划分为若干个较小的块,每个块包含一定数量的元素。每个块都保存了该块内元素的一些预处理信息,例如最大值、最小值、和等。这样,在查询时,可以通过对块进行预处理和对块内元素进行操作,来快速得到查询结果。

分段数组的主要优势在于它能够在保持较小的块大小的同时,提供较快的查询操作。当需要对整个数组进行查询时,可以通过对每个块进行操作,然后将结果合并得到最终结果。这样可以减少查询的时间复杂度。

分段数组的实现方式有多种,常见的有块状链表和树状数组。块状链表将数组划分为若干个块,并使用链表将这些块连接起来。树状数组则使用二进制索引树的结构来实现。

总结来说,分段数组是一种用于解决动态区间查询问题的数据结构,通过将大数组划分为小块,并对每个块进行预处理和操作,可以提高查询效率。

4.SpringAop

1.常见的使用场景

  • 日志记录
  • 异常处理
  • 权限验证
  • 缓存处理
  • 效率检查

2.springAop用的动态代理还是反射

答:动态代理

2.1动态代理有两种能讲讲吗?

JDK动态代理只提供接口代理,不支持类代理

核心:InvocationHandler接口和Proxy类

InvocationHandler通过invok()方法反射来调用目标类中的代码,动态的将横切逻辑和业务编织在一起,Proxy类利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

CGLIB通过继承方式做的动态代理

如果代理类没有实现InvocationHandler接口,那么SpringAop会使用CGLIB来动态代理目标类。

CGLIB是一个代码生成的类库,在运行时动态的生成指定类的一个子类对象,覆盖其中特定的方法并添加增强代码,实现AOP。

通过继承的方式做的动态代理,如果某个类被标记为final,那么它是无法使用CGLIB的,

5. sleep和wait的区别

sleep不会释放当前占有的锁,需要捕获异常

wait 只有等待另外的线程通知或被中断才会返回,会释放对象的锁,一般用在同步方法或者同步代码块中,不需要捕获异常

6.notify和notifyall的区别

notify会随机从等待池中选择一个线程进行唤醒

notifyall会唤醒所有线程进行竞争锁的机会

7.传输协议

TCP传输控制协议,是一种面向连接的,可靠的,基于IP的传输层协议。

UDP无连接的传输层协议,提供面向事务的简单不可靠的传送服务。

7.1 TCP和UDP的区别

  • 基于连接 无连接
  • 数据正确性 可能丢包
  • 保证数据顺序 不保证

8.JVM的内存模型

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些数据区域都有各自的用途,以及创建和销毁的时间,并且它们可以分为两种类型:线程共享的方法区和堆线程私有的虚拟机栈、本地方法栈和程序计数器。在此基础上,我们探讨了在虚拟机中对象的创建和对象的访问定位等问题,并分析了Java虚拟机规范中异常产生的情况。

1)、程序计数器

为了线程切换后能够恢复到正确的执行位置,每条线程都需要一个独立的程序计数器去记录其正在执行的字节码指令地址。

2)、虚拟机栈

**虚拟机栈描述的是Java方法执行的内存模型,是线程私有的。**每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,而且 每个方法从调用直至完成的过程,对应一个栈帧在虚拟机栈中入栈到出栈的过程。

3)、本地方法栈

本地方法栈与Java虚拟机栈非常相似,也是线程私有的,区别是虚拟机栈为虚拟机执行 Java 方法服务,而本地方法栈为虚拟机执行 Native 方法(非Java语言)服务

2、线程共享的数据区

线程共享的数据区 具体包括 Java堆 和 方法区 两个区域,它们的内涵分别如下:

1)、Java 堆

Java 堆的唯一目的就是存放对象实例,几乎所有的对象实例(和数组)都在这里分配内存。

2)、方法区

*方法区与Java堆一样,也是线程共享的并且不需要连续的内存,其用于存储已被虚拟机加载的 *类信息*、*常量*、*静态变量*、*即时编译器编译后的代码等数据

9.元空间

  • JDK7以前

在7以及之前堆和方法区连在了一起,但这并不能说堆和方法区是一起的,它们在逻辑上依旧是分开的。但在物理上来说,它们又是连续的一块内存

在这里插入图片描述

“永久代(Permanet Generation,也称PermGen)”。对于习惯了在HotSpot虚拟机上开发、部署的程序员来说,很多人都愿意将方法区称作永久代。

HotSpot虚拟机:

Java是一种解释类型的语言,但并不意味着它一定被解释执行。早期的虚拟机确实是通过解释器( Interpreter )一条一条指令依次解释执行的,但人们发现这样效率太低, 难以满足各种要求,因此出现了许多其它虚拟机,例如 JIT 虚拟机。当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会把这些代码认定为“热点代码”为了提高热点代码的执行效率,在运行时,即时编译器(Just In Time Compiler ) 会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化。

而HotSpot也是类似一种虚拟机,自从SUN买下后,已经把它放入 JRE 1.3以及后续版本中,它顶替了JIT虚拟机,也是目前使用范围最广的Java虚拟机。

采用HotSpot的Java虚拟机,已经很难说Java是被虚拟机解释执行了,因为原来的Java是将源代码编译为字节码后运行在虚拟机上而HotSpot实际上是把Java的部分常用bytecode编译成本地代码Native code,然后运行,大大提高了Java的运行性能。

总结:由于编译器一条一条的指令依次解释执行效率低,所以当如果模块代码运行频发的时候(热点代码),编译器会把热点代码编译成与本地平台相关的机器码HotSpot应运而生

  • JDK8以后

Hotspot取消了永久代,改为了元空间

方法区存在于元空间(Metaspace),同时元空间不再与堆连续,而且是存在于本地内存(Native memory)。

元空间存在于本地内存,意味着只要本地内存足够,它不会出现像永久代中的

默认情况下元空间是可以无限使用本地内存的,但为了不让它如此膨胀,JVM同样提供了参数来限制它使用的使用。

  • -XX:MetaspaceSize,class metadata的初始空间配额,以bytes为单位,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当的降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize(如果设置了的话),适当的提高该值。
  • -XX:MaxMetaspaceSize,可以为class metadata分配的最大空间。默认是没有限制的。
  • -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为class metadata分配空间导致的垃圾收集。
  • -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为class metadata释放空间导致的垃圾收集。

9.1 为什么永久代消失了

表面上看是为了避免OOM异常。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误(内存溢出)。

当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。

更深层的原因还是要合并HotSpot和JRockit的代码,使用了元空间取代永久代,不用担心运行性能问题了,在覆盖到的测试中, 取代后程序启动和运行速度降低不超过1%,但是这点性能损失换来了更大的安全保障

10.数据库执行效率

10.1 定位执行 效率慢的sql

mysql内置的explain + sql语句

10.2索引优化

  • 最左前缀法则

​ 如果建立的复合索引,执行顺序要按照建立时的顺序执行

  • 不能使用null判断 != > < 不做列运算
  • 尽量避免在where子句中使用or来连接条件,一个字段有索引,一个没索引,会失效
  • 左%的匹配查询不写

10.3 创建索引的语句

  1. 主键索引:创建表时自动创建 { 聚集索引:一个表中只有一个聚集索引 }
  2. 唯一索引:CREATE UNIQUE INDEX unique_index_warn[索引名称] ON cas_alarm[表名] (warn_id[列名])
  3. 普通索引:CREATE INDEX index_saas_report_service_status[索引名称] ON saas_report_service_status[表名] (service_status[列名]);
  4. 组合索引:CREATE INDEX index_saas_report_service_type[索引名称] ON saas_report_service_status[表名] (service_type[列名],service_status[列名],sort_value[列名]);

10.4数据库引擎

  • mysql5.5版本之前用的MyISAM 存储引擎

不支持事务

  • 之后用的 InnoDB存储引擎

支持事务,支持行级锁

11. mybatis的缓存机制

  • 一级缓存

sqlSession级别的,默认开启无法关闭。

  • 二级缓存

默认没有开启,需要手动开启

作用域Mapper

需要实现Serializable序列化接口

11.1如何开启二级缓存

在Setting全局参数中配置开启二级缓存,conf.xml配置:

<setting>
	<setting name="cacheEnable" value="true"></setting>  默认是false,关闭二级缓存
</setting>

12.MongoDb数据模型

数据库database

集合collection(表)

文档document(行)

字段field(列)

13.ElasticSearch如何使用的

通过@configuration注解创建使用Es的对象RestHighLevelClient交给容器管理

调用RestHighLevelClient对象进行操作

14.Linux的常见常用命令

查看当前系统发行版本详细信息

LSB是Linux Standard Base的缩写,lsb_release命令用来显示LSB和特定版本的相关信息

lsb_release -a

被问到:查看当前系统内核信息

uname -a

查看当前系统版本信息

cat /proc/version

查看CPU相关信息

cat /proc/cpuinfo

查看系统位数

getconf LONG_BIT

查看本机ip地址

ip addr  

路径跳转

cd 所要跳转的路径

创建目录

mkdir 目录名称     

创建多层目录

mkdir  -p(小写的) 

显示当前工作目录

pwd -P(大写的) 

显示当前目录下隐藏文件

ls -a

删除空文件夹

rmdir 想要删除的空目录路径 

创建文件

touch  文件名.文件类型

显示指定文件或文件夹的详细信息

stat  文件路径     

获取指定文件的类型

file  文件路径  

查看当前账户/其他账户 uid/gid

id

id  账户名

查看当前文件夹下文件及文件夹所属账户

ll

查看进程列表

ps aux|less

创建用户

useradd  用户名 //会默认创建一个和用户名一样的组
useradd 用户名 -G 组名  //前提是已经创建分组了   //往主组之后添加新组
useradd 用户名 -d 文件夹路径   //给新创建的用户指定操作目录   
默认生成的uid是在现有最大id的基础上+1
useradd 用户名 -u 指定用户编号(编号只能为数字且不可重复)
useradd 用户名 -g 指定用户主组编号/名称      //直接替换主组,只保留一个组


创建组

groupadd  组名
groupadd  组名  -g  编号(gid)//创建指定编号的组

组的作用:

可以更方便的对部分用户做权限操作

例如

ss01用户  刚开始只是普通权限,由于工作需要,需要对权限进行调整

那么可以直接把ss01加入该权限的组中即可,不用再单独设置权限。

给账户添加组

gpasswd -a  yangyang01 dcc01
//yangyang01是要修改的账户名
//dcc01是要添加进的组名(只能是组名不能是gid)

查看组的信息

tail /etc/group
//新创建的组会在文件的最下面显示

删除用户

userdel  用户名

userdel  -r  用户名    //删的更彻底

修改用户密码

passwd 用户名

普通用户获取管理员权限

sudo su

修改某一个文件或文件夹的属主/属组

chown 所要修改的账户名 修改的文件/文件夹路径
//如果要同时修改属主和属组则
chown 所要修改的账户名.所修改的组名 修改的文件/文件夹路径

修改文件属组

chgrp 所修改的组名 修改的文件/文件夹路径
//若要修改该文件夹下所有文件的属组则
chgrp -R 所修改的组名 修改的文件/文件夹路径 
//-R为递归参数

修改文件权限

chmod 对象+权限 文件/文件夹路径
//删除所有对象的权限
chmod a=- 文件/文件夹路径
//同时给不同身份修改权限 不同身份操作之间用,隔开
chmod u=r,g=rx,o+w 文件/文件夹路径

15.docker的常用命令

1、Docker创建并启动容器

docker run [OPTIONS] IMAGE [COMMAND] [ARG…]

--name="容器新名字":为容器指定一个名称;
-i:以交互模式运行容器,通常与-t或者-d同时使用;
-t:为容器重新分配一个伪输入终端,通常与-i同时使用;
-d: 后台运行容器,并返回容器ID;
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口

启动普通容器: docker run --name 别名 镜像ID (不常用)
启动交互式容器: docker run -it --name 别名 镜像ID 来运行一个容器,取别名,交互模式运行,以及分配一个伪终端,并且进入伪终端;
实例:
docker run -it --name mycentos03 67fa590cfc1c

注意:

1、启动普通容器的方式基本不用,没有伪终端,没有太大价值;
2、启动交互式容器的方式,容器一创建完毕,立即进入伪终端

守护式方式创建并启动容器
docker run -di --name 别名 镜像ID
实例:
docker run -di --name mycentos02 67fa590cfc1c

2、Docker列出容器

OPTIONS说明:
-a :显示所有的容器,包括未运行的。
-f :根据条件过滤显示的内容。
--format :指定返回值的模板文件。
-l :显示最近创建的容器。
-n :列出最近创建的n个容器。
--no-trunc :不截断输出。
-q :静默模式,只显示容器编号。
-s :显示总的文件大小。

3、Docker退出容器

exit 容器停止退出
ctrl+P+Q 容器不停止退出

4、Docker进入容器

a、docker attach 容器ID or 容器名

实例:
docker attach ce6343ee288f
不能进入停止的状态的容器
You cannot attach to a stopped container, start it first

b、Docker进入容器执行命令
docker exec -it 容器名称 或者 容器ID 执行命令
实例:
docker exec -it tomcat02 ls -l /root/webapp02

直接操作容器,执行完 回到 宿主主机终端;

我们一般用于 启动容器里的应用 比如 tomcat nginx redis elasticsearch等等

5、Docker启动容器

docker start 容器ID or 容器名

实例:
docker start mycentos00

6、Docker重启容器

docker restart 容器ID or 容器名

实例:
docker restart f9cadea1a5e7

7、Docker停止容器

docker stop 容器ID or 容器名

实例:
docker stop 865b755cd0b2

暴力删除,直接杀掉进程 (不推荐)
docker kill 容器ID or 容器名

8、Docker删除容器
docker rm 容器ID

如果删除正在运行的容器,会报错,我们假如需要删除的话,需要强制删除;
强制删除docker rm -f 容器ID

删除多个容器
docker rm -f 容器ID1 容器ID2 中间空格隔开
实例:
docker rm 865b755cd0b2 ce6343ee288f

删除所有容器
docker rm -f $(docker ps -qa)

9、Docker容器日志

$ docker logs [OPTIONS] CONTAINER
  Options:
        --details        显示更多的信息
    -f, --follow         跟踪实时日志
        --since string   显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
        --tail string    从日志末尾显示多少行日志, 默认是all
    -t, --timestamps     显示时间戳
        --until string   显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)

16.redis

问:如果做秒杀功能需要使用什么数据类型

list可用于秒杀抢购场景

在商品秒杀场景最怕的就是商品超卖,为了解决超卖问题,我们经常会将库存商品缓存到类似MQ的队列中,多线程的购买请求都是从队列中取,取完了就卖完了,但是用MQ处理的化有点重,这里就可以使用redis的list数据类型来实现,在秒杀前将本场秒杀的商品放到list中因为list的pop操作是原子性的,所以即使有多个用户同时请求,也是依次pop,list空了pop抛出异常就代表商品卖完了。

问:如果做排行榜功能需要使用什么数据类型

用Zset数据类型

一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。

17.redis AOF,RDB 等持久化方式

RDB在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上。(默认的持久化方式)

AOF,将redis执行的所有指令记录下来,下次重新启动redis时,只要把这些写指令从前到后重新执行一遍,就可以实现数据恢复了。

两种方式可以同时使用,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。

18.kafka为什么吞吐量高

1.顺序读写

Kafka是将消息记录持久化到本地磁盘中的,一般人会认为磁盘读写性能差,可能会对Kafka性能如何保证提出质疑。实际上不管是内存还是磁盘,快或慢关键在于寻址的方式,磁盘分为顺序读写与随机读写,内存也一样分为顺序读写与随机读写。基于磁盘的随机读写确实很慢但磁盘的顺序读写性能却很高,一般而言要高出磁盘随机读写三个数量级,一些情况下磁盘顺序读写性能甚至要高于内存随机读写。

磁盘的顺序读写是磁盘使用模式中最有规律的,并且操作系统也对这种模式做了大量优化,Kafka就是使用了磁盘顺序读写来提升的性能。Kafka的message是不断追加到本地磁盘文件末尾的,而不是随机的写入,这使得Kafka写入吞吐量得到了显著提升 。

2.Page Cache

为了优化读写性能,Kafka利用了操作系统本身的Page Cache,就是利用操作系统自身的内存而不是JVM空间内存。这样做的好处有:

1避免Object消耗:如果是使用 Java 堆,Java对象的内存消耗比较大,通常是所存储数据的两倍甚至更多。

2避免GC问题:随着JVM中数据不断增多,垃圾回收将会变得复杂与缓慢,使用系统缓存就不会存在GC问题

相比于使用JVM或in-memory cache等数据结构,利用操作系统的Page Cache更加简单可靠。首先,操作系统层面的缓存利用率会更高,因为存储的都是紧凑的字节结构而不是独立的对象。其次,操作系统本身也对于Page Cache做了大量优化,提供了 write-behind、read-ahead以及flush等多种机制。再者,即使服务进程重启,系统缓存依然不会消失,避免了in-process cache重建缓存的过程。

通过操作系统的Page Cache,Kafka的读写操作基本上是基于内存的,读写速度得到了极大的提升。

3.零拷贝

通过这种 “零拷贝” 的机制,Page Cache 结合 sendfile 方法,Kafka消费端的性能也大幅提升。这也是为什么有时候消费端在不断消费数据时,我们并没有看到磁盘io比较高,此刻正是操作系统缓存在提供数据。

4.分区分段+索引

Kafka的message是按topic分类存储的,topic中的数据又是按照一个一个的partition即分区存储到不同broker节点。每个partition对应了操作系统上的一个文件夹,partition实际上又是按照segment分段存储的。这也非常符合分布式系统分区分桶的设计思想。

通过这种分区分段的设计,Kafka的message消息实际上是分布式存储在一个一个小的segment中的,每次文件操作也是直接操作的segment。为了进一步的查询优化,Kafka又默认为分段后的数据文件建立了索引文件,就是文件系统上的.index文件。这种分区分段+索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度。

5.批量读写

Kafka数据读写也是批量的而不是单条的。

除了利用底层的技术外,Kafka还在应用程序层面提供了一些手段来提升性能。最明显的就是使用批次。在向Kafka写入数据时,可以启用批次写入,这样可以避免在网络上频繁传输单个消息带来的延迟和带宽开销。假设网络带宽为10MB/S,一次性传输10MB的消息比传输1KB的消息10000万次显然要快得多。

6.批量压缩

在很多情况下,系统的瓶颈不是CPU或磁盘,而是网络IO,对于需要在广域网上的数据中心之间发送消息的数据流水线尤其如此。进行数据压缩会消耗少量的CPU资源,不过对于kafka而言,网络IO更应该需要考虑。

  • 如果每个消息都压缩,但是压缩率相对很低,所以Kafka使用了批量压缩,即将多个消息一起压缩而不是单个消息压缩
  • Kafka允许使用递归的消息集合,批量的消息可以通过压缩的形式传输并且在日志中也可以保持压缩格式,直到被消费者解压缩
  • Kafka支持多种压缩协议,包括Gzip和Snappy压缩协议

Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

上的.index文件。这种分区分段+索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度。

5.批量读写

Kafka数据读写也是批量的而不是单条的。

除了利用底层的技术外,Kafka还在应用程序层面提供了一些手段来提升性能。最明显的就是使用批次。在向Kafka写入数据时,可以启用批次写入,这样可以避免在网络上频繁传输单个消息带来的延迟和带宽开销。假设网络带宽为10MB/S,一次性传输10MB的消息比传输1KB的消息10000万次显然要快得多。

6.批量压缩

在很多情况下,系统的瓶颈不是CPU或磁盘,而是网络IO,对于需要在广域网上的数据中心之间发送消息的数据流水线尤其如此。进行数据压缩会消耗少量的CPU资源,不过对于kafka而言,网络IO更应该需要考虑。

  • 如果每个消息都压缩,但是压缩率相对很低,所以Kafka使用了批量压缩,即将多个消息一起压缩而不是单个消息压缩
  • Kafka允许使用递归的消息集合,批量的消息可以通过压缩的形式传输并且在日志中也可以保持压缩格式,直到被消费者解压缩
  • Kafka支持多种压缩协议,包括Gzip和Snappy压缩协议

Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。

[外链图片转存中…(img-x4iDQUCy-1714208455057)]
[外链图片转存中…(img-Hf4ooW16-1714208455058)]
[外链图片转存中…(img-cQdbGS1s-1714208455058)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值