[2020-12-14] 近期面试的一些总结

近期面试中遇到的一些问题的总结

规划

近一年有1/3的时间中老家开荒种地,其他时间有用来学会和中年危机自处,虽然是失败了,还在调整中;有一部分时间用来思考和规划自己的未来,前期很盲目,后期在某音上看到某网红的3+1理论,大意是择业标准:趋势(主) + (爱好,能力,资源)的一个抉择,个人觉得很有道理。
自己选了 golang 作为后续的主要发展目标,完全摒弃了前端开发。当然,自己业余还是可以做一点的。
在网站上刷新状态,被动式找工作。
然后由于没有 golang 的实际操作经验,导致自己的面试的机会和面试的表现都很差劲。
所以今天决定静下心来学习和沉淀一些东西以认真的态度对待面试,以及面对自己的人生。
虽然前路迷茫,但是还得走一步是一步。

问题汇总

golang的垃圾回收

golang 的垃圾回收机制和我之前所了解的 as 所使用的引用技术法有根本性的不同。
golang 使用的是 标记清除法,即 mark-sweeping
他主要是分为两步:

  • 标记:三色标记法,通过将所有对象区分为白,灰,黑三色,配合以写屏障 write barrier
  • 清理:清理所有的白色对象

需要注意的是,标记清理期间需要暂停整个程序 stw:stop the world

变量逃逸

一般代指局部变量本来应当分配到栈上的,但是这个局部变量在本作用域,即本函数外需要使用到,那么这个局部变量会被存储到堆上去。

字符串拼接

这个主要考察的是否你是否会直接使用 '+' 来拼接字符串,其实跟 java 类似,java 有类似 StringBuffer 之类的东西来处理字符串拼接,golang 里面用的是 string.Buffer 来处理字符串拼接。
当然,我面试的时候回答用 '[]byte' 来处理拼接也是可以的。但是,这里是需要指定长度的。不用 '+' 进行操作也是这个运原理,一个string 其实代表的是一个 rune数组

内存分配的问题

之前被问到 slice的内存分配是什么样子的。我的回答是当前 内存x2。面试官接着问是否一直都是 x2 的申请呢?答案肯定不是。在 2048 byte 之前,内存都是 x2 的去申请,大于 2048 byte 的话每次申请 640 byte

处理channel超时

goroutine 超时可以通过 Context.withtimeouttimer.after 来处理。
goroutine 是不能杀死的。

for和range

不懂区别的最好用 for,因为无论在何种情况下for的性能永远是大于等于range的,range在循环复杂对象的时候性能会远小于 for ,当然,传入复杂对象指针除外。
想起面试过一个问题,map 的循环是引用还是值,其实,这个问题是值得商榷的,他循环是其实是值的复制。
另外,数组的基本值,不是引用类型。

读写锁和互斥锁

互斥锁就是 mutex.Lock, 读写锁就是 mutex.RWLock 。两者的区别是把读和写分开来,读写锁可以同时读,也就是只锁定写。效率在读多写少的情况下肯定是互斥锁强得多。

常用缓存失效算法

  • FIFO: first in first out
  • LFU: Least Frequenctly Used
  • LRU: Least Recently Used

分布式缓存相关

分布式缓存节点存值问题

分布式缓存并不是每个节点上存的都一样,他是根据每个key进行hash操作然后确定这个缓存会存储到哪个节点上去。
这样节省了缓存空间,也提高了缓存效率。

缓存雪崩

节点变化,例如 10 个变成了 9 个。那么h hash 取值就从 hash(key)%10 变成了 hash(key)%9。这样一来,几乎所有的缓存都失效了,节点接受到请求之后都需要重新去获取,就造成了缓存雪崩。

缓存雪崩:缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。常因为缓存服务器宕机,或缓存设置了相同的过期时间引起。

解决缓存雪崩,需要用到一致性 hash

一致性hash算法

一致性hash算法原理:

  • 一致性hash算法将key映射到2^32的空间中,这是一个首尾相连的环
  • 计算节点的hash值,将他投放到环上,hash值通常以机器码,ip,编号等来计算
  • 计算key的hash值,顺时针寻找到的第一个计算节点就是他存取的节点

这样一来,新增/删除节点只需要重新定位这个节点附近的节点就可以了。

一致性hash可能会导致的数据倾斜问题

但是这样的话,由于机器hash分布不均匀,有可能导致数据倾斜。
为了解决这个问题,引入了虚拟节点,一个真实节点对应多个虚拟节点,例如:节点1包含节点1-1,节点1-2....即诶单1-n
代价是只需要维护一个map来存放虚拟节点的映射关系。

缓存击穿和缓存穿透

缓存击穿:一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到 DB ,造成瞬时DB请求量大、压力骤增。

缓存穿透:查询一个不存在的数据,因为不存在则不会写到缓存中,所以每次都会去请求 DB,如果瞬间流量过大,穿透到 DB,导致宕机。

这两个都是出现在并发请求过高的时候,优化的手段是同时收到的请求合并处理就可以了。

Redis缓存淘汰策略

缓存设置:

  • 在 redis 中,允许用户设置最大使用内存大小maxmemory,默认为0,没有指定最大缓存,如果有新的数据添加,超过最大内存,则会使redis崩溃,所以一定要设置。
  • redis 内存数据集大小上升到一定大小的时候,就会实行数据淘汰策略。
  • redis淘汰策略配置:maxmemory-policy voltile-lru,支持热配置

缓存淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  4. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  6. no-enviction(驱逐):禁止驱逐数据

参考

posted @ 2021-08-26 09:58  Ado_On  阅读(11)  评论(0编辑  收藏  举报