GO面试
2025-11-04 15:28:53 145 举报
AI智能生成
GO面试
作者其他创作
大纲/内容
GO
基础
iota
iota在const关键字出现时被重置为0
const声明快中每新增一行iota值自增1
或者:iota代表了const声明快的行索引
return
若为命名返回值,return将后面的表达式的值赋给返回值,然后执行defer,最后返回结果
若为匿名返回值,return将后面表达式的值赋值给一个临时变量,执行完defer后再将临时变量返回
defer
执行顺序:压栈:后进先出
return->defer->返回
panic后依然会执行defer,主动os.Exit不会执行defer
defer后的函数参数会被先执行
局部变量分配在堆还是栈
编译器会自动决定,编译器会做逃逸分析,当变量逃逸则分配在堆上
make与new的区别
make会进行初始化,new返回一个零值的指针
栈的特点
并发与并行
数据结构
channel<br>
主要用于goroutine间通信
map
用哈希表实现,每个bucket存储一组键值对<br>
GO用链地址法解决哈希冲突
interface
互斥锁
包含一个state状态和sema信号量<br>
state为32位整型,1位表示是否被锁定,1位表示是否有协程已被唤醒,1位表示是否处于饥饿状态,29位表示阻塞的协程数<br>
解锁时若有被阻塞协程,则释放信号量<br>
normal模式<br>
获取锁失败不会立即阻塞,会有短时间的自旋,尝试抢锁<br>
starvation模式<br>
饥饿模式不会自旋
被唤醒的协程再次阻塞超过1ms,锁将会被标记为饥饿<br>
一旦有协程释放锁,那么一定会唤醒协程,被唤醒的协程也会成功获取到锁<br>
读写锁
进行写锁定时先将读计数器减去2^30,此时读锁定来检测到读计数器为负数则阻塞等待<br>
互斥锁、读/写信号量,读计数器、写阻塞计数器
垃圾回收
标记清扫
三色标记
混合写屏障
内存分配<br>
go调度
GMP
调度器设计策略
复用线程
避免频繁创建、销毁线程,而是进入睡眠复用线程
M休眠队列
利用并行
最多有GOMAXPROCS个线程分布在CPU上同时运行
抢占
一个goroutine最多占用CPU10ms,防止其他goroutine被饿死
context
writgroup
广播
继承
多态
消息中间件
kafka
消费者组
相同的数据会被不同的消费者组消费多次
同一组内一个消费者只能消费一个分区,消费者大于分区数将会空闲
ack机制
0:kafka不会等待broker的ack,延迟低,但当server挂掉可能会丢数据
1:等待leader确认收到发送ack消息,如果leader挂掉,不保证新leader上存在次数据
-1:等待所有follower收到数据才发送ack
消费者
消费者会记录消费的物理偏移量
一个分片对应一个消费者成员,如果消费者组中成员太多会有空闲成员
顺序
kafka每个partition中的消息在写入时都是有序的,消费时,每个partition只能被每一个group中的一个消费者消费,保证了消费时也是顺序的
整个topic不保证有序,如果保证topic整个有序,那么将partition调整为1
网络
http
http1
给定的TCP连接,一次允许一个请求未完成
文本传输效率低
http2
多路复用,同一域名只需要一个TCP连接
二进制数据传输效率更高
通过流实现多路复用,每个帧会标识出属于哪个流
数据库
mysql
隔离级别<br>
读未提交
脏读
读已提交
不可重复读
可重复读
写数据情况幻读
快照读
select
当前读
update、insert、delete
串行化
对所有读取的行都加锁<br>
并发控制<br>
读写锁<br>
共享锁,排它锁
锁粒度
InnoDB存储引擎实现了行级锁<br>
表锁
MVCC
添加两个版本号,创建事务ID,删除事务ID
乐观锁
给数据行加上版本号
索引
最左前缀原则
查询必须从索引最左边开始,且不能跳过
不能使用范围条件右边的列<br>
索引设计
数据结构尽量简单
主要是数据之间的比较
尽量不为空
索引不会包含有空值的列<br>
前缀索引,指定长度
在列上进行运算,不会使用索引<br>
like以通配符开头,不会使用索引
避免or条件
如果or前面条件使用索引后面没使用,则会放弃所有索引
索引排序
filesort
内存中排序,快排
内存装载不下,外部排序(使用临时表)
索引排序
索引顺序与order by顺序相同,且为同方向(同为正序或同为倒序)
与查询型子句一样,需要满足最左前缀原则,where条件也可以加入评估
连表查询时,仅当order by所有列都是第一个表的字段时才使用索引
索引数据结构
平衡二叉树
基于二分法策略,提高数据查询速度的数据结构
任何节点两个子树高度差不超过1
B树(B-Tree)
B-Tree为多叉树,又名平衡多路查找树
排序方式:递增,左小右大
所有叶子节点均在同一层
非叶子节点保存关键字记录指针
B+Tree
B+Tree的非叶子节点,不保存关键字记录的指针,能保存更多的关键字
叶子节点保存了父节点所有关键字记录的指针
关键字在叶子节点从小到大依次排序,左边结尾数据保存一个右边开始数据的指针<br>
每一个叶子节点包含指向下一个叶子节点的指针,方便范围遍历
优点
层级更少
能保存更多的关键字所以层级更少
查询速度稳定
所有关键字数据地址都存储在叶子节点<br>
系统从磁盘读取数据到内存是以磁盘块为基本单位,位于同一磁盘块的数据会被一次性读出来
InnoDB
聚簇索引(主键索引)
Innodb对主键建立聚簇索引,如果没有主键则选择一个唯一非空字段,在没有就定义一个隐藏主键(一个表只有一个聚簇索引)<br>
节点页只包含索引,叶子页包含了全部行数据(聚簇索引就是”表“)
非聚簇索引(二级索引)
叶子节点存储的是索引key和主键值
MyISAM
非聚簇索引
叶子节点存储指向数据的指针
redis
redis持久化
RDB(存储快照)
将redis存储的数据生成快照并存储到磁盘等介质上
适合于对数据完整性不敏感
AOF(记录指令)
将redis执行过的所有指令记录下来,在下次redis重新启动时,只要把这些指令执行一遍就可以实现数据恢复了
每秒将指令刷入硬盘
缓存
缓存穿透
查询缓存中不存在的数据时会造成缓存穿透
解决方案一:缓存空对象
当redis和mysql都没有对象时,缓存一个空对象到redis
缺点
缓存过多空值,可能导致有效数据被淘汰策略淘汰掉
设置了过期时间,可能导致数据库和redis在某一时间数据不一致
解决方案二:布隆过滤器
存在哈希碰撞,布隆过滤器说这条数据存在,其实不一定存在,但布隆过滤器说这条数据不存在,则一定不存在
将数据哈希到bit数组,增加bit数组长度或使用多个哈希函数避免哈希冲突<br>
缓存击穿
热点数据失效,大量请求到达mysql
解决方案一:分布式锁
缓存雪崩
多个热点数据同时失效,或redis挂了
解决方案一:使用随机的过期时间<br>
解决方案二:使用集群
高可用(HA)
主从
主从复制
从数据库向主数据库发送sync请求
主数据库生产RDB文件并记录此后执行的命令到缓冲区
向所有从数据库发送快照文件,并继续记录被执行的命令
从数据库载入快照,执行主数据库缓冲区记录的命令
主数据库每执行一个命令就向从数据库发送相同的命令
优点
主从复制、读写分离<br>
哨兵
基于主从模式,添加哨兵监控,实现master宕机,自动选举新master并将其他从节点指向master
集群
实现redis的分布式存储,对数据进行分片,每台redis节点存储不同的内容
数据结构
zset
ziplist
元素数量小于128,所有元素长度小于64字节
使用压缩列表来保存,member与score紧挨着
skiplist
dict保存元素与score的字典
skiplist保存元素有序列表
红黑树
黑色完美平衡
淘汰策略
redis用作缓存时,如果内存空间满了,就会自动驱逐老数据
LRU:最近最少使用
记录每个数据最近一次访问的时间戳
随机选出n个数据进行LRU
LFU:最少频率使用
记录每个数据的最近访问时间和访问次数
根据频率、时间顺序进行淘汰
0 条评论
下一页