golang后端面试复习
网络
-
TCP/IP的三次握手四次挥手
-
键入一个网址到完全呈现的流程
-
1.当浏览器发起请求的时候,并不会先做查询,而是查看浏览器的 DNS 缓存和操作系统的 DNS 缓存有没有相应网址的映射,如果有,则调用,如果都没有,就会发起一个 DNS 查询,浏览器通过 IP 地址与 Web 服务器通信
-
2.获取到ip地址后,浏览器就可以调用 socket 函数,发起TCP请求,通过三次握手建立连接
-
3.客户端通过 TCP 套接字向 Web 服务器发送 HTTP 请求。
-
一个请求报文由请求行、请求头、空行和请求数据 4 部分组成
-
HTTP请求一开始并没有先打到 web 应用上,而是先打到反向代理 Nginx(Nginx 是一个高性能的静态服务器, 很多访问量比较高的网站都会使用 Nginx 来负载均衡,可以把请求通过 Nginx 转换到动态服务器上,增大吞吐量)
-
Nginx 再将请求转发到 WSGI 服务器上(WSGI是 Web Server Gateway Interface 的缩写, 它是 web 框架与 Web 服务器之间的一种接口, 常用的 web 服务器软件有 uWSGI,Gunicorn等), WSGI 服务器接受并解析请求,再将请求发送给后端 web 应用。
-
-
4.Web 服务器接受请求并返回 HTTP 响应,服务器将资源复本写到 TCP 套接字,由客户端读取。
- 一个HTTP响应由状态行(包含版本号、状态代码、描述)、响应头部、空行和响应数据 4 部分组成。
-
5.若没有其他数据传输,则通过 TCP 四次挥手释放连接
-
6.客户端读取响应数据 HTML,根据 HTML 的语法对其进行格式化,并在浏览器窗口中显示。
-
- 端口不通,两个服务器怎么排查?
- 进程、协程、线程
数据库
- Mysql的索引有哪些(按类型分),隔离四个性,b+树和b树的区别
- sql注入和常见的网络攻击
- 缓存击穿、雪崩、穿透及其解决方案
`缓存穿透`定义:缓存穿透是指用户请求的数据既不在缓存中,也不存在于数据库中。每次请求都会直接访问数据库,导致缓存失效,数据库压力骤增。
解决方案:布隆过滤器:使用布隆过滤器存储所有可能存在的键,快速判断请求是否有效,避免无效请求直接访问数据库。缓存空值:当数据库查询结果为空时,将空值缓存起来,并设置较短的过期时间,减少重复查询。参数校验:对请求参数进行合法性校验,过滤掉明显无效的请求。`缓存击穿`
定义:缓存击穿发生在热点数据过期时,大量并发请求同时访问数据库,导致数据库负载过高。
解决方案:
加锁机制:使用分布式锁(如Redis锁)限制同一时刻只有一个请求访问数据库,其余请求等待锁释放。自动续期:在缓存即将过期时,通过定时任务刷新缓存,确保热点数据始终有效。缓存预热:在系统启动或高峰期前,将热点数据提前加载到缓存中,避免缓存失效。`缓存雪崩`定义:缓存雪崩是指大量缓存数据在同一时间失效,或缓存服务器宕机,导致所有请求直接涌向数据库,可能引发系统崩溃。
解决方案:随机过期时间:为缓存数据设置随机过期时间,避免大量缓存同时失效。高可用架构:使用Redis集群或哨兵模式,确保缓存服务的高可用性,避免单点故障。
- redis的批量操作(mget、lua脚本)
- redis的物种基本类型和应用场景
- mysql的慢查询优化检查
- 索引覆盖
消息中间件
kafka
1.kafka的消息顺序(partition)
2.
Go语言
- slice底层,go的类型分类和具体类型(引用和值类型):
type slice struct {array unsafe.Pointer // 指向底层数组的指针len int // 长度cap int // 容量
}`切片是对数组的抽象,底层包含了三个部分数组的指针,长度,容量。`
`go分为类型分为引用类型和值类型,切片就是引用类型,但他本身是一个结构体是一个值类型,只是包含了一个指向数组的指针。`
`这意味着函数间传递切片时,是传递了这个结构体的副本,在函数内部对这个切片的元素进行修改时,会影响到底层数组,而对切片进行扩容则不会影响原切片(因为容量和长度是值类型)`
- channel,有缓冲和无缓冲有什么特征,说一下并发控制和关闭,channel是否是线程安全
`channel创建无缓冲是同步通信,有缓冲是异步通信。即无缓冲时,发送端将会阻塞直到有接收端开始接收。而有缓冲时,发送端发送的数据将会存到缓冲区,而不会阻塞。`
`channel的并发控制一般使用select进行多路复用,同时可以监听多个select。
也可以使用for……range循环会在channel关闭后自动退出。
done(channel)则代表这个channel被关闭
close函数用于关闭一个channel。关闭channel表明不再有值会被发送到该channel上。关闭channel后,接收操作仍然可以继续,直到已经发送的数据都被接收完毕,之后接收操作会立即返回零值和一个表示channel已关闭的标志,监听到关闭标志则可以停止接收。` // select会阻塞直到某个case可以执行select {case msg1 := <-ch1:fmt.Println(msg1)case msg2 := <-ch2:fmt.Println(msg2)case <-time.After(3 * time.Second):fmt.Println("timeout")}
`channel是线程安全的,多个协程可以通过channel进行通信而不会发生数据竞争`
`1.在使用channel时需要注意:由发送者关闭channel而不是在接受者关闭。
2.不可以重复关闭channel会导致panic
3.可以利用waitGroup协调多个goroutine,保证协程关闭`
- map的key可以有哪些类型
布尔、字符串、数字、指针、通道都可以作为key值。以下类型不能作为map的key:切片(slice)、包含切片或函数的结构体或数组其他的map。如果使用接口类型作为key,那么实际存储的接口值必须是非nil且其动态类型是可比较的,否则会导致运行时panic。
- GC垃圾回收机制
Go 的 GC 是一个并发、三色标记清除(concurrent, tri-color mark-and-sweep)的收集器。
Go 的 GC 使用三色标记算法来追踪对象:白色对象:尚未被 GC 访问的对象(可能为垃圾)灰色对象:已被 GC 访问,但其引用的对象还未被检查黑色对象:已被 GC 访问,且其引用的对象也已被检查。GC的阶段:1.Mark准备(Mark Setup):STW阶段,开启写屏障,准备根对象。2.Marking:并发标记阶段,遍历所有可达对象。3.Mark终止:STW阶段,关闭写屏障,清理标记状态。4.Sweeping:并发清除阶段,回收不可达对象的内存Go 的 GC 会在以下情况下触发(Go 的 GC 是并发的,意味着它可以在程序运行的同时执行大部分工作,只有极短的 STW(Stop-The-World)暂停。):1.自动触发:当堆内存增长到一定比例时(由 GOGC 环境变量控制)2.手动触发:调用 runtime.GC() 函数3.定时触发:如果长时间没有 GC,会强制触发
- defer的执行顺序
在函数执行完成之后再执行,可以用来关闭连接,多个defer会根据先定义后执行的顺序执行(类似栈的顺序)
- 协程调度 GMP模型:
GMP 分别代表:G:Goroutine,Go 语言中的轻量级线程,由 Go 运行时管理。M:Machine(或 Worker Thread),代表着操作系统线程,由操作系统调度。P:Processor,是一个逻辑处理器,它包含了运行 Goroutine 所需的资源,比如本地队列。调度过程
每个 M 都需要绑定一个 P 来执行 G。每个 P 维护一个本地 Goroutine 队列(Local Run Queue),同时还有一个全局 Goroutine 队列(Global Run Queue)用于平衡负载。当一个新的 G 被创建时,它会被优先放入当前 P 的本地队列。如果本地队列已满,则把本地队列的一半 G 移动到全局队列。当 M 执行完当前 G 后,它会尝试从绑定的 P 的本地队列获取 G。如果本地队列为空,则从全局队列获取,如果全局队列也为空,则从其他 P 的本地队列偷取一半(工作窃取,Work Stealing)。阻塞处理
如果 G 执行了阻塞操作(如系统调用),则 M 会被阻塞,此时 P 会和 M 解绑,并寻找空闲的 M 来执行其他 G。如果没有空闲 M,则会创建新的 M。当阻塞操作完成,G 会被重新放入全局队列,M 会尝试绑定一个 P 继续执行,如果没有可用的 P,则 M 会进入休眠状态。
- select和switch的区别,执行机制:
switch当做if……else来使用,而select一般用于channel的监听相关的IO操作,如果 select 的多个分支都满足条件,则会随机的选取其中一个满足条件的分支执行
- 读写锁和mutex的区别
读写锁可以多读1写,mutex锁是互斥锁,锁住了就不可以再使用资源了必须等锁释放
- map是线程安全吗?如何让map安全:
不安全,可以使用sync包中map或map使用加读写锁,不然会读写冲突会导致panic,高并发场景下,可以使用map分片加锁的方式,有对应的开发引用项目可以使用
- sync.waitgroup是怎么用的
配合addgroup使用,用来控制协程的并发
- 结构体可以比较吗?反射考点
Go 结构体有时候并不能直接比较,当其基本类型包含:slice、map、function 时,是不能比较的。若强行比较,就会导致出现例子中的直接报错的情况。反射比较方法 reflect.DeepEqual 常用于判定两个值是否深度一致,其规则如下:相同类型的值是深度相等的,不同类型的值永远不会深度相等。
当数组值(array)的对应元素深度相等时,数组值是深度相等的。
当结构体(struct)值如果其对应的字段(包括导出和未导出的字段)都是深度相等的,则该值是深度相等的。
当函数(func)值如果都是零,则是深度相等;否则就不是深度相等。
当接口(interface)值如果持有深度相等的具体值,则深度相等。
...
框架
- gin框架的优缺点
LINUX
- 查看服务满了的命令(查看进程和端口)
- 如何查看内存,查看磁盘余量
- 查看文件权限
数据结构
1.二叉树和红黑树的区别
2.