2024年最新Golang八股文面试题_golang面试题2024,2024年最新阿里P7大牛手把手教你

img
img
img

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

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

如果你需要这些资料,可以戳这里获取

1.如果删除的元素是值类型,如int,float,
bool,string以及数组和struct,map的内
存不会自动释放
2.如果删除的元素是引用类型,如指针,slice,
map,chan等,map的内存会自动释放,但释放的
内存是子元素应用类型的内存占用
3.将map设置为nil后,内存被回收

20、怎么处理对 map 进行并发访问?有没有其他方案?

1.对整个map加上读写锁sync.RWMutex虽然
解决问题但是锁粒度大,影响性能
2.1操作会导致整个map被锁住,导致性能降低
所以提出了分片思想,将一个map分成几个片,
按片加锁。第三方包实现:
github.com/orcaman/concurrent-map
3.标准库中的sync.Map是专为append-only
场景设计的。sync.Map在读多写少性能比较好
否则并发性能很差。

21、 nil map 和空 map 有何不同?

1.初始化状态:
Nil Map:没有初始化分配内存的map,默认值为
nil `var m map[keyType]valueType` 
Empty Map:已分配内存但没有任何键值对的map
`m := make(map[keyType]valueType)`
2.写入操作:
Nil Map:不能向nil map写入键值对.否则会
导致运行时错误(panic)
Empty Map:可以向空map中安全地写入键值对.
3.读取操作:
Nil Map 和 Empty Map:都可以安全地进行
读取操作.如果键不存在,都会返回值类型的零值
4.长度:
Nil Map 和 Empty Map:两者的长度都是 0

22、map 的数据结构是什么?是怎么实现扩容?

type hmap struct {
// 元素数量
	count     int
//状态标识,比如被写,被遍历等 
	flags     uint8
//桶(bmap)数量-2^B个
	B         uint8
//溢出的bucket个数 
	noverflow uint16
//哈希种子,增加哈希函数的随机性 
	hash0     uint32
//指向数组buckets的指针
	buckets    unsafe.Pointer
//扩容时保存原buckets的指针
	oldbuckets unsafe.Pointer
//表示扩容进度-已迁移的个数
	nevacuate  uintptr
	extra \*mapextra 
}
1.触发扩容有两种情况:
第一种:负载因子超过了默认值6.5,就是正常元素
过多造成的扩容-增量扩容
负载因子=元素数量除桶数量
第二种:overflow的bucket数量过多,就是因为
元素不断的进行增删造成溢出桶很多元素很少,没
有满足负载因子的默认值,但效率很低--等量扩容
2.golang通过拉链发解决哈希冲突(开放寻址法)
3.map扩容是渐进式的,即整个扩容过程拆散在每
一次的写操作里面,这样的好处是保证每一次map
的读写操作时间复杂度都是稳定的。

23、map 取一个 key,然后修改这个值,原 map 数据的值会不会变化

在Go语言中,map为引用类型,所以在修改map内
的值时,原数据也会随之变化,因此当你通过一个
key 取出一个值并对其进行修改时,将会影响到
原map 中该key 对应的值。

24、什么是 GMP?(必问)调度过程是什么样的?

1.G - Goroutine也就是协程,是用户态
轻量级线程,一个goroutine大概需要2k
内存,在 64 位的机器上,可以轻松创建
几百万goroutine
2.M - Machine Thread,也就是操作系
统线程,go runtime 最多允许创建1万个
操作系统线程,超过了就会抛出异常
3.P - Processor逻辑处理器,默认数量
等于cpu核心数,通过环境变量GOMAXPROCS
改变其数量
4.全局队列(GlobalQueue)存放等待运行
的G,P还有个本地队列(也称为LRQ):存放等
待运行的G,但G的数量不超过256个。新建的
goroutine优先保存在P的本地队列中,如果
P的本地队列已满,则会保存到全局队列中
5.P包含了运行G所需要的资源,M想要运行
goroutine必须先获取P然后从P的本地队列
获取Goroutine,P队列为空的时候,M也会
尝试从全局队列拿一批Goroutine放到P的
本地队列,或者从其他P的本地队列偷取一半
放到自己P的本地队列,M不断通过P获取
Goroutine并执行,不断重复下去。如果M
阻塞或者不够了,会创建新的M来支持。比如
所有的M都被阻塞住了,而P中还有很多的就
绪任务,调度器就会去寻找空闲的M。找不
到的话,就会去创建新的M,总而言之一个M
阻塞P就会去创建或者切换另一个M,

25、进程、线程、协程有什么区别?(必问)

1.进程:是应用程序的启动实例,每个进程
都有独立的内存空间,不同的进程通过管道,
信号量,共享内存等方式来通信。
2.线程:从属于进程,每个进程至少包含一
个线程,线程是CPU调度的基本单位,多线程
之间可以共享进程的资源,并通过共享内存
等方式来通信。
3.协程:轻量级线程,与线程相比,协程不受
操作系统的调度,协程的调度器由用户程序
提供,协程调度器按照调度策略把协程调度
到线程中运行

26、抢占式调度是如何抢占的?

操作系统负责线程的调度,Go的runtime负
责goroutine的调度.现代操作系统调度线
程都是抢占式,不依赖代码主动让出CPU,或
者因为IO,锁等待而让出,这样会造成调度的
不公平.基于经典时间片算法,当线程的时间
片用完之后,会被时钟中断,调度器会将当前
线程的执行上下文进行保存,然后恢复下一
个线程的上下文,分配新的时间片令其开始
执行.这种抢占对于线程本身是无感知的,系
统底层支持,不需要开发人员特殊处理.基于
时间片的抢占式调度有个明显的优点,能够
避免CPU资源持续被少数线程占用,从而使其
他线程长时间处于饥饿状态.goroutine的
调度器也用到了时间片算法.只是整个Go程序
都是运行在用户态的,所以不能像操作系统那
样利用时钟中断来打断运行中的goroutine.
也得益于完全在用户态实现,goroutine的调
度切换更加轻量。

27、怎么控制并发数?如何优雅的实现一个 goroutine 池

1.信号量(Semaphore),通道(Channel),
上下文(Context)
2.协程池的实现:
1>定义池结构:需要定义一个结构体来表示
goroutine池,该结构体通常会包含一个任
务队列(用于存储待执行的任务)和一个信号
量(用于控制同时运行的goroutine数量).
2>定义任务类型:通常是一个函数签名,例如
 type Task func().
3>创建池:实现一个函数来创建新的
goroutine池,包括初始化任务队列和启动
一定数量的goroutine来处理任务.
4>任务分发:编写逻辑来接收新任务并将它
们加入任务队列.
5>执行任务:goroutine从队列中获取任
务并执行.
6>优雅关闭:提供一种方式来优雅地关闭
goroutine池,等待所有正在执行的任务
完成后再退出.
3.go-playground/pool, ants(推荐)

29、Go 如何实现原子操作?

1.原子操作就是不可中断的操作.原子操作执行时,
CPU绝对不会再去执行其他针对该值的操作
2.包sync/atomic提供了原子操作(Load读取
Store写入)
原子操作与互斥锁的区别
1)互斥锁是一种数据结构,用来让一个线程执行
程序的关键部分,完成互斥的多个操作。
2)原子操作是针对某个值的单个互斥操作。

30、悲观锁、乐观锁是什么?

1.悲观锁:当要对数据库中的一条数据进行修改
时,为了避免同时被其他人修改,直接对该数据进
行加锁以防止并发.行锁,表锁等,读锁,写锁等,
都是在做操作之前先上锁.适合多写场景.Mutex
2.乐观锁:认为更新数据不会造成冲突,但更新的
时候会检测数据是否被修改,可以使用版本号机制
和CAS算法实现.乐观锁适用于读多写少的场景,
可以提高程序的吞吐量

31、Mutex 有几种模式?

1.正常模式:sync.Mutex的默认模式.等待获
取锁的goroutines会形成一个队列.当锁释放
时,队列中的第一个goroutine不一定获得锁,
其他新到的goroutines也有可能先获得锁.
这种情况可能导致某些goroutines长时间得
不到锁产生"饥饿"现象
2.饥饿模式
在饥饿模式下Mutex的拥有者将直接把锁交给队
列第一个goroutine,新来的goroutine不会参
与获取锁,它会加入到等待队列的尾部.
3.下面情况,会把这个Mutex转换成正常模式:
(1)当一个goroutine等待锁时间小于1毫秒.
(2)当前队列只剩下一个goroutine的时候.

32、goroutine 的自旋

在这里插入图片描述

协程加锁时,如果当前mutex的state字段的
locked位为1,说明已有其他协程持有该锁,尝
试加锁的协程并不是马上转入阻塞,而是持续探
测locked位是否变为0,
即为自旋.自旋的条件如下:
1)还没自旋超过 4 次,
2)多核处理器,
3)GOMAXPROCS > 1,
4)p 上本地 goroutine 队列为空。
mutex会让当前的goroutine去空转CPU,在空转
完后再次调用CAS方法去尝试性的占有锁资源,直
到不满足自旋条件,则最终会加入到等待队列里。

33、go三色标记法(必问)

1.起初所有的对象都是白色的;
2.从根对象出发扫描所有可达对象,标记为灰色,
放入待处理队列;
3.从待处理队列中取出灰色对象,将其引用的对
象标记为灰色并放入待处理队列中,自身标记为
黑色;
4.重复步骤(3),直到待处理队列为空,此时
白色对象即为不可达的“垃圾”,回收白色对象;
5.屏障机制-STW垃圾回收过程中为了保证准确
性防止无止境的内存增长等问题,需要停止赋值
器进一步操作对象图以完成垃圾回收。STW时间
越长,对用户代码造成的影响越大

34、知道哪些 sync 同步原语?各有什么作用?

1.sync.Mutex
它允许在共享资源上互斥访问(不能同时访问)
2.sync.RWMutex
是一个读写互斥锁
3.sync.WaitGroup
sync.WaitGroup拥有一个内部计数器.当计数
器等于0时,则Wait()方法会立即返回.否则它
将阻塞执行Wait()方法的goroutine直到计数
器等于0时为止.要增加计数器,使用Add().使
用Done()减少,也可以传递负数给Add方法把计
数器减少指定大小,Done()方法底层就是通过
Add(-1)实现的.
4.sync.Map
是并发的map.Store-添加元素.Load-检索元素
Delete-删除元素.LoadOrStore检索或添加之
前不存在的元素.如果键之前在map中存在,则返
回的布尔值为true.使用Range遍历元素.
5.sync.Pool
是一个并发池,负责安全地保存一组对象.Get()
用来从并发池中取出元素.Put将一个对象加入并
发池。
6.sync.Once
可确保一个函数仅执行一次
7.sync.Cond
它用于发出信号(一对一)或广播信号(一对多)到
goroutine

35、介绍golang的内存, 什么情况下会发生内存逃逸?

1)本该分配到栈上的变量,跑到了堆上,这就导
致了内存逃逸。
2)栈上的变量,函数结束后会被回收掉,不会有
额外性能的开销.堆上变量的回收,需要进行gc,
gc存在性能开销.变量逃逸会导致性能开销变大.
内存逃逸的情况如下:
1)方法内返回局部变量指针。
2)在闭包中引用包外的值
3)向 channel 发送指针数据。
4)在 slice 或 map 中存储指针。
5)切片(扩容后)长度太大。

36、K8s 含有哪些重要组成部分

1.Master节点:
API Server(API服务器):提供了Kubernetes 
	API,用于与Kubernetes集群进行通信,
	接受和处理各种命令。
Controller Manager(控制器管理器):负责运
	行控制器(如ReplicaSet Controller、
	DeploymentController),监控集群状态
	并根据所需状态进行调整。
Scheduler(调度器):负责将新创建的Pod调度
	到集群中的Node上,考虑资源需求,约束条
	件等因素。

2.Node节点:
Kubelet:负责在Node上管理容器,包括启动、
	停止、重启容器等。
Container Runtime(容器运行时):实际运行
	容器的软件,如Docker,containerd等。
Kube Proxy:负责维护网络规则并将网络流量
	转发到正确的容器服务。

3.Etcd:
分布式键值存储,用于保存集群的配置信息,状
态信息等,被Master和Node节点共同使用。

4.Pod:
最小部署单元,包含一个或多个容器.Pod中的容
器共享网络和存储,通常是紧密耦合的应用组件

5.Service:
提供了一种抽象,用于定义一组Pod的访问方式.
Service可以保证一组Pod的稳定网络访问。

6.Volume:
用于在Pod中持久化数据.Volume可以连接到
Node上的物理存储、网络存储等。

7.Namespace:
用于将Kubernetes集群划分为多个虚拟集群,
以便在同一集群中运行多个不同的应用,环境等

8.ConfigMap 和 Secret:
用于保存配置信息和敏感数据,可以在Pod中被
挂载为文件或环境变量。

9.Ingress:
提供HTTP和HTTPS路由到服务的规则,允许外部
流量访问Kubernetes集群中的服务。

10.StatefulSet:
用于部署有状态应用,确保Pod有唯一的标识和
稳定的网络标识标题

37、



38、内存泄露和解决方法

内存泄漏是由于程序中的数据结构不再需要时未
能被垃圾回收器(GC)回收造成的
1.全局变量的过度使用:
 全局变量会一直占用内存除非显式地将它们设
 置为nil
 解决方法:避免不必要的全局变量或在不再需要
 时将其设置为 nil
2.协程泄漏:
 未正确结束的协程可能导致内存泄漏,特别是那
 些无限循环或阻塞等待的协程.
 解决方法:确保协程能正确退出,使用context
 来管理和取消协程.
3.未关闭的通道和其他资源:
  未关闭的通道,文件句柄,数据库连接等资源
  可能导致内存泄漏.
  解决方法:使用defer关键字确保资源被释放
4.循环引用:
  特别是在使用指针和接口时,循环引用可能导
  致GC无法回收相关对象.
  解决方法:避免创建循环引用,如果必须使用,
  考虑使用弱引用。
5.大量未释放的临时对象:
  频繁创建且长时间不释放的临时对象可能导
  致内存泄漏.
  解决方法:优化代码逻辑,避免不必要的临时
  对象创建,或及时释放不再需要的对象.
6.内部数据结构过大:
  巨大的map或slice在使用后未被缩减或清理。
  解决方法:在不再需要大量数据时,及时清理或
  重新分配这些数据结构.
7.缓存未及时清理:
  长期运行的缓存如果没有适当的过期策略,可
  能会不断增长.
  解决方法:实现缓存清理策略,例如使用过期
  时间或大小限制.

解决内存泄漏的通用步骤包括:
1.性能监控:定期监控应用程序的内存使用情况。
分析和调试:使用pprof工具进行内存分析,找出
内存占用异常的部分.
2.代码审查:定期审查代码,找出潜在的内存泄漏

39、CAS算法

CAS(Compare-And-Swap)算法:是重要的并发
编程算法,用于实现无锁编程和原子操作.是实现
多线程同步的关键技术之一,尤其是在构建锁和其
他并发控制结构时.CAS操作包含三个主要参数:
1.内存位置(Memory Location):需要更新的
变量的内存地址.
2.预期原值(Expected Value):变量预期的值
3.新值(New Value):希望设置的新值。
CAS 的基本工作原理如下:
它首先检查目标内存位置的当前值是否与预期原
值相同.若相同,CAS会自动将该位置的值更新为
新值若不同,说明在检查和操作之间有其他线程
修改了该变量,CAS操作失败.CAS操作是原子性
的,意味着在执行过程中不会被其他线程中断。

CAS的优点是避免了使用传统锁所带来的开销和
潜在的死锁问题,因为它不会阻塞线程.但是CAS
可能出现活锁问题和ABA问题:
1.活锁:线程不断尝试更新操作,但总是因为其他
线程的干扰而失败,导致无限循环.
2.ABA问题:一个值原先是A,被另一个线程改为B,
然后又改回A,CAS会错误地认为该值没有被更改过

40、协程池

1.在文生图项目中,处理从redis中循环出来的数据,使用了字节开源的
协程池库
1.资源复用,控制并发数量,避免内存泄漏,任务调度和均衡

41、 MySQL 中的 B 树和 B+ 树区别

1.存储方式: B树和B+树的存储方式不同.在B
树中,每个节点存储键和对应的值,而在B+树中,
只有叶子节点存储键和指向数据的指针,非叶子
节点只存储键.这意味着B+树的内部节点可以容
纳更多的键,减少了树的高度,从而减少了磁盘访
问次数,提高了查询性能

2.叶子节点结构:B树和B+树的叶子节点结构也
不同.在B树中,叶子节点包含了数据的实际值,
而在B+树中,叶子节点只包含键和指向数据的
指针.这使得B+树的叶子节点可以形成一个有
序链表,通过在链表上进行顺序遍历,可以高效
地获取范围内的数据.而B树则需要在不同的层
级进行跳跃,性能相对较低

4.适用场景:B树适用于需要随机访问的场景,
例如数据库索引.而B+树更适合范围查询和顺
序访问的场景,例如文件系统索引

42、Mysql 常见sql优化

1、在where及order by涉及的列上建立索引。 
2、不要在where子句中进行的操作:
1>使用!=或<>操作符,
2>对字段进行null值判断
3>使用or来连接条件
4>使用参数
5>对字段进行表达式操作,函数操作
6>对“=”左边进行函数、算术运算或其他表达式运算
7>in和not in的使用,用between或exists代替in
导致索引失效,扫描全表
3、like '%abc%' 导致索引失效 
4、不要使用 select * from t
6、不要在有大量数据重复的列上建立索引 
7、一个表的索引数不要超过6个,索引提高
select 的效率,同时也降低了insert 及
update 的效率,因为可能会重建索引
8、使用varchar代替char,因为变长字段存
储空间小,可以节省存储空间,其次对于查询
来说,在一个相对较小的字段内搜索效率
显然要高些。 
9、在使用索引字段作为条件时,如果该索引是
复合索引,那么必须使用到该索引中的第一个字
段作为条件时才能保证系统使用该索引,否则该
索引将不会被使用,并且应尽可能的让字段顺序
与索引顺序相一致。 
10、尽量使用数字型字段,若只含数值信息的
字段尽量不要设计为字符型 
11、尽量使用表变量来代替临时表。如果表变量
包含大量数据,请注意索引非常有限(只有主键索引)。 
12、避免频繁创建和删除临时表,以减少系统
表资源的消耗。 
13、临时表并不是不可使用,适当地使用它们
可以使某些例程更有效,例如,当需要重复引
用大型表或常用表中的某个数据集时。但是,
对于一次性事件,最好使用导出表。 
14、在新建临时表时,如果一次性插入数据量
很大,那么可以使用 select into 代替 
create table,避免造成大量 log ,以
提高速度;如果数据量不大,为了缓和系统表
的资源,应先create table,然后insert。 
15、如果使用到了临时表,在存储过程的最后
务必将所有的临时表显式删除,先 truncate 
table ,然后 drop table ,这样可以避免
系统表的较长时间锁定。 
16、尽量避免使用游标,因为游标的效率较差,
如果游标操作的数据超过1万行,那么就应该考
虑改写。 

43、mysql 事务实现原理

通过日志的记录和重做、回滚日志的使用、锁的
管理和控制,并发控制机制的应用实现。这些机
制共同确保了事务的原子性、一致性、隔离性和
持久性,保证了数据库的数据完整性和并发操作
的正确性
1. 日志(Log):
重做日志(Redo Log)**: 在事务进行修改操
作时,MySQL 将修改的内容记录到重做日志中,
以确保事务的修改可以持久化到磁盘。重做日志
是顺序写入的,因此具有较高的写入性能。
回滚日志(Undo Log)**: 在事务进行修改操
作之前,MySQL 将当前数据的副本记录到回滚日
志中。如果事务需要回滚,MySQL 可以使用回滚
日志将数据恢复到事务开始之前的状态。
2. 锁(Lock):
行级锁(Row-Level Locking)**: MySQL 
支持行级锁,允许在事务中对数据行进行加锁。
这样可以控制并发事务对同一数据的访问,确保
数据的一致性和隔离性。
锁粒度(Lock Granularity)**: MySQL 
的锁粒度可以根据具体情况调整,包括表级锁、
页级锁和行级锁。较小的锁粒度可以提高并发
性能,但也会增加锁管理的开销。
3. 隔离级别(Isolation Level)**: 
MySQL 支持多个隔离级别,例如:
读未提交(Read Uncommitted)、
读已提交(Read Committed)、
可重复读(Repeatable Read)
串行化(Serializable)。
隔离级别定义了事务之间的隔离程度,
决定了事务读取数据的一致性和并发性。
4. 并发控制(Concurrency Control)**: 
MySQL 使用并发控制机制来处理多个并发
事务对数据库的访问。这包括锁的获取与释
放、冲突检测和解决,以及事务的调度和执行。

44、mysql中 explain工具的使用

type 字段可能的值
ALL < index < range ~ index_merge < ref < eq_ref < const < system

在这里插入图片描述

45、Go 的 select 特性

1.select提供了多路IO复用机制,用于检测
是否有读写事件ready.select结构组成是
case语句和default语句和对应的执行函数
2.case中的表达式必须是Channel收发操作
3.多个case同时被触发,会随机执行其中一个
4.select同时监听多个case的channel是
否可执行,如果都不能执行,则运行default
5.要判断一个channel是否写满数据或为空,
可以使用select语句结合default分支.当
channel满或者为空时,执行default分支,
否则执行对应的case分支

46、单引号,双引号,反引号的区别?

1.单引号:表示rune类型,对应int32类型

2.双引号:是字符串,实际上是字符数组。

3.反引号:表示字符串字面量,但不支持任何转义
序列

47、redis 常见的数据类型

1、string(字符串);
2、hash(哈希);
3、list(列表);
4、set(集合);
5、sort set (有序集合)

48、Redis 的pipeline

管道(pipeline)可以一次性发送多条命令给
服务端,处理完毕后,再通过一条响应一次性将
结果返回,pipeline通过减少客户端与服务端
的通信次数来降低网络往返时延,减少read和
write的系统调用以及进程上下文切换次数,以
提升程序的执行效率与性能,Pipeline实现的
原理是队列,而队列原理是先进先出,这样就保
证数据的顺序性

49、 Redis 的雪崩,击穿,穿透

1.缓存雪崩:大量缓存数据在同一时间过期或者
Redis故障宕机时,如果此时有大量的用户请求,
都无法在Redis中处理,于是全部请求都直接访
问数据库,从而导致数据库的压力骤增,严重的会
造成数据库宕机,从而形成一系列连锁反应,造成
整个系统崩溃
2.缓存击穿:如果缓存中的某个热点数据过期了,
此时大量的请求访问了该热点数据,就无法从缓
存中读取,直接访问数据库,数据库很容易就被高
并发的请求冲垮
3.缓存穿透:当用户访问的数据,既不在缓存中,
也不在数据库中,导致请求在访问缓存时,发现
缓存缺失,再去访问数据库时,发现数据库中也
没有要访问的数据,没办法构建缓存数据,来服
务后续的请求.那么当有大量这样的请求到来时,
数据库的压力骤增

在这里插入图片描述

50、基于Redis实现分布式锁

SET lock_key unique_value NX PX 10000 
1.lock_key 就是 key 键;
2.unique_value 是客户端生成的唯一的标识,
区分来自不同客户端的锁操作;
3.NX 代表lock_key不存在时,对lock_key设置
才能成功(返回1,失败返回0)
4.PX 10000表示设置lock_key过期时间为10s
避免客户端发生异常而无法释放锁。

51、Redis 获取指定前缀

1.keys feng*该命令会阻塞redis执行其他
命令,禁止生产使用,因为它采用的是遍历的形
式,而且redis是单线程的,顺序执行指令,当
查找的key的量特别多的时候,会一直在查找,
其他的命令就无法执行,导致阻塞或者超时报
错等
2.scan 0 match feng* count 10 
游标从0开始扫描,匹配以feng开头的key,
遍历槽位10个.返回下一次遍历的游标开始
值,如果最后结果返回0,表示遍历完了

52、Redis对于多数据库的支持

Redis支持多数据库,在Redis中数据库的概念
是通过数据库索引(Database Index)来实现
的.默认情况下,Redis有16个数据库,索引从0
到15.通过SELECT命令来切换当前使用的数据库

53、Innodb与Myisam引擎的区别

1.InnoDB 支持事务,外键 MyISAM 不支持
2.innodb使用聚簇索引存储数据,表数据和索引
数据就存储在一个索引树结构中.查询数据时直接
通过索引就可以找到数据行。
myisam采用非聚簇索引存储数据,表数据和索引
数据分离存储.索引中保存的是数据在磁盘上的位
置,即指针.聚簇索引的叶子节点就是数据节点,而
非聚簇索引的叶子节点是指向对应数据块的指针
3.InnoDB 不保存表的具体行数,MyISAM保存了
整个表的行数
4.InnoDB 最小的锁粒度是行锁,
  MyISAM是表锁

54、什么时候触发行级锁,表级锁

1.执行DDL语句去修改表结构时,会使用表级锁。
alter table,drop table,trunchte table
或者对应的SQL就没有使用索引,没指定查询列
2.当需要修改或读取表中某一行数据,当增删改查
匹配到索引时,Innodb会使用行级锁

55、mysql 中JOIN操作类型

1.INNER JOIN:它返回两个表中匹配的行.如
果在一个表中没有匹配的行,那么这些行就不会
出现在结果集中
2.LEFT JOIN:返回左表中的所有行,以及右表
中与左表中匹配的行.如果在右表中没有匹配的
行,结果集中将包含NULL值
3.RIGHT JOIN:返回右表中的所有行,以及左
表中与右表中匹配的行.如果在左表中没有匹配
的行,结果集中将包含NULL值
4.FULL JOIN:返回两个表中所有的行,无论是
否有匹配.如果在一个表中没有匹配的行,结果集
中将包含NULL值

56、Golang中连接字符串的方式有哪些

1.使用`+`操作符,或者`strings.Join()函数`
循环中连接大量字符串,使用`strings.Join()`
通常更有效率,因为它会预分配足够的空间来避免
多次分配
result := str1 + str2
strs := []string{"Hello", "World!"}
result := strings.Join(strs, " ")

57、Gin框架限流-令牌桶

1.基于官方库实现
golang.org/x/time/rate
r := gin.Default()
l := rate.NewLimiter(rate.Every(time.Second), 200)
r.Use(func(c \*gin.Context) {
	// 尝试获取一个令牌
	if l.Allow() {
		...
		c.Next() // 继续处理请求
	} else {
		c.JSON(http.StatusTooManyRequests,
		gin.H{"error": "请求过于频繁,请稍后重试"})
		c.Abort() // 终止请求处理
	}
})	

58、TCP可靠传输依靠

TCP实现可靠传输依靠的有序列号,自动重传,滑动窗口,确认应答等机制
在这里插入图片描述

59、http三次握手-建立Tcp连接和四次挥手-释放tcp链接

0.ISN(Initial Sequence Number):存入
	seq字段的值名称:初始化序列号
1.序号(sequence number):seq序号,占32
	位,表示这个tcp包的序列号.tcp协议拼
	凑接收到的数据包时,根据seq来确定顺序,
	且能确定是否有数据包丢失
2.确认序号(acknowledgement number):
	ack序号,占32位,只有ACK标志位为1时,
	确认序号字段才有效,ack=seq+1.
3.标志位(Flags):共6个,如下:
	URG:紧急指针(urgent pointer)有效.
	ACK:确认序号有效(为了与确认号ack区
	分开,用大写表示)
	PSH:接收方应尽快将该报文交给应用层.
	RST:重置连接.
	SYN:发起一个新连接.
	FIN:释放一个连接.
seq序号,ack序号:用于确认数据是否准确,是
	否正常通信.
标志位:用于确认/更改连接状态.

第一次握手:客户端-服务端(SYN=1,seq=x)

第二次握手:(SYN=1,ACK=1,seq=y,ACKnum=
x+1),服务器端进入SYN_RCVD状态。

第三次握手:(ACK=1,ACKnum=y+1)

在这里插入图片描述

第一次挥手:(FIN=1,seq=x),客户端状态为
FIN_WAIT_1

第二次挥手:(ACK=1,ACKnum=x+1),服务器
状态为CLOSE_WAIT,客户端状态为
FIN_WAIT_2

第三次挥手:(FIN=1,seq=y):服务器端进入
LAST_ACK状态,等待客户端的最后一个ACK。

第四次挥手:(ACK=1,ACKnum=y+1),客户端进
入TIME_WAIT状态.服务器端进入CLOSED状态.
客户端等待一段时间之后,没有收到服务器端的
ACK,认为服务器端已经正常关闭连接,于是自己
也关闭连接,进入CLOSED状态.

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

60、tcp 和 http 的区别

HTTP 是无状态的短连接,是应用层协议
定义传输数据的内容规范
TCP是有状态的长连接,是传输层协议
定义数据传输和连接方式的规范

在这里插入图片描述

61、TCP粘包

1.粘包:指发送方发送的若干数据包到达接收方
时粘成了一个包,导致接收方无法正常解析数据,
因数据包的边界不明确
2.TCP粘包的原因:
(1)TCP传输协议默认使用Nagle算法(主要为减
少网络中TCP段的数量,每个TCP段中至少装载了
40个字节的标记和首部),Nagle算法主要做了:
上一个分组得到确认,才发送下一个分组;收集多
个小分组,在收到确认时将其一起发送.Nagle算
法可能造成发送方出现粘包问题
(2)TCP接收到数据包时,应用层并不会立即处理.
而是将其保存到接收缓存里,然后应用程序主动从
缓存读取收到的数据.如果TCP接收数据包到缓存
的速度大于应用程序从缓存中读取数据包的速度,
多个包就会被缓存堆积,应用程序可能读取到首尾
粘到一起的包.
3.解决粘包方法:
(1)对于发送方造成的粘包问题,可以通过关闭
Nagle算法来解决,用TCP_NODELAY关闭算法
(2)应用层处理.
格式化数据:每条数据有固定的格式(开始符,结
束符).选择开始符和结束符时一定要确保每条数
据的内部不包含开始符和结束符;
发送长度:发送每条数据时,将数据的长度一并
发送,应用层在处理时可以根据长度来判断每个
分组的开始和结束位置


![img](https://img-blog.csdnimg.cn/img_convert/d328a4dfcf883087c8fe9231c648e2e4.png)
![img](https://img-blog.csdnimg.cn/img_convert/40717fc4dd3d053fe3555be000deffb7.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

据传输和连接方式的规范

在这里插入图片描述

61、TCP粘包

1.粘包:指发送方发送的若干数据包到达接收方
时粘成了一个包,导致接收方无法正常解析数据,
因数据包的边界不明确
2.TCP粘包的原因:
(1)TCP传输协议默认使用Nagle算法(主要为减
少网络中TCP段的数量,每个TCP段中至少装载了
40个字节的标记和首部),Nagle算法主要做了:
上一个分组得到确认,才发送下一个分组;收集多
个小分组,在收到确认时将其一起发送.Nagle算
法可能造成发送方出现粘包问题
(2)TCP接收到数据包时,应用层并不会立即处理.
而是将其保存到接收缓存里,然后应用程序主动从
缓存读取收到的数据.如果TCP接收数据包到缓存
的速度大于应用程序从缓存中读取数据包的速度,
多个包就会被缓存堆积,应用程序可能读取到首尾
粘到一起的包.
3.解决粘包方法:
(1)对于发送方造成的粘包问题,可以通过关闭
Nagle算法来解决,用TCP_NODELAY关闭算法
(2)应用层处理.
格式化数据:每条数据有固定的格式(开始符,结
束符).选择开始符和结束符时一定要确保每条数
据的内部不包含开始符和结束符;
发送长度:发送每条数据时,将数据的长度一并
发送,应用层在处理时可以根据长度来判断每个
分组的开始和结束位置


[外链图片转存中...(img-aoqcrelQ-1715738563315)]
[外链图片转存中...(img-bsoma82Z-1715738563315)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值