2020-08-20 晚上面试
- 自我介绍
- 你最近做过哪些项目。
- 为什么要离职。
更公平的竞争环境和脱离舒适圈。
- 你的项目里有对redis的多次操作,怎么提高效率。
利用redis的pipe,将多次redis操作合并一起,降低网络延迟。
- 刚刚你说到sortedset,sort是怎么实现的。
利用了跳表实现了排序。
- sortedset的查询一个数据的时间复杂度是怎么样子的?
一开始答的logn,面试官说你确定吗?我就不确定了,查了一下,确实是logn。
- 跳表是怎么实现的?
仍然是链表的结构,但是多了几个指针指向更加后面的值,实现快速跳跃。
- redis的集群有几种?
三种,主从,哨兵,集群。
- 分别说一下这几种。
主从是指有两个redis节点,其中从节点保持跟主节点同步。
- 同步方式是怎么样子的?
就是当redis有写操作的时候,给从节点也发一个,但是从节点不会过期key,所以主节点有key删除的时候,也会跟从节点说删除某个key。(其实这个只是增量复制,还有全量复制忘记了。。)
哨兵模式是利用一个哨兵,定时地去ping redis的节点,当redis节点不可达之后,会通过修改配置文件,让从redis代替主节点,维持可用。
redis集群是通过redis key hash分区之后落在哪个hash槽中,而每个redis节点都负责一部分hash槽,从而找到该key应该被哪个节点所处理。
- redis集群是怎么实现高可用的?
答了通过gossip协议来同步配置。。。
事实上错了。。我忘记redis集群也有从节点了,当多个节点发现有节点不通,就判定该节点不可达,然后对他故障转移,然后从他的从节点中选中一个替换他,保证高可用。
- redis至少有多少个才能成为集群?(因为我上题答错了)
3个。
- 你确定是三个吗?
不确定。。但是我记得是要3个节点。(事实上还有从节点啊!!!)洗澡的时候才想起来。
- mysql用的多吗?
挺多挺熟的。
- mysql有多少种存储引擎。
mysql存储引擎有很多种,因为它支持自己开发,但是常用的只有innodb和 MyISAM 。
- 说说他们之前的差别。
innodb支持事务,myisam不支持。
innodb用的行表,myisam用的表锁。
- 四个隔离级别。
我忘记四个隔离级别叫什么名字了,只记得具体表现,跟面试官说了每种隔离级别的具体表现。
应该是未提交读,提交读,可重复读,串行化。
- innodb是第几个级别。
第三种(可重复读)
- 那可重读和可串行化的差距在哪里?
记得跟区间有关,具体忘记了。(答案是范围读的时候,如果其他事务在该范围插入数据的时候,会被读到)
- 主键索引和唯一索引的区别。
主键的话是聚簇索引,数据的内容会存在索引的叶子节点之上,而唯一索引的叶子节点只保存主键数据。
- 唯一索引查询的时候就要回表咯?
不是的,要看查询的内容,要是select的数据就是索引内容的话,就不用回表。
- 怎么看一条语句的性能。
explain。
- 有哪些数据需要注意的?
索引类型和行数。。
- 哪种索引类型最好。
答了index(事实上不对,最好应该是NULL,就是不用查直接算出来的那种)
- golang熟不熟啊?
熟啊,就用了很久。
- map是线程安全的吗?
不是。
- 怎么解决这个问题呢?
用读写锁和sync.map。
- 读写锁的表现形式是怎么样的。
当其中一个协程拥有写锁的时候,其他协程不管是要读锁还是写锁,都会被阻塞。
其中一个协程拥有读锁时,其他协程只能申请读锁,而申请写锁会被阻塞住。
- chan怎么实现的。
用的环形链表。有个头尾指针,还有个结构存储被chann阻塞的goroutine。
- 有缓存和没缓存的chan表现形式有什么不同?
有缓存当缓存未满时,往里面塞数据不会被阻塞,但是没缓存的会被阻塞。
- 这样一个场景,如果我要往一个缓存chan里面塞东西,塞不进去就丢掉怎么办?
我一直都是用select拿数据,忘记他还可以用来看缓存是否满了,一开始答的对比len和cap后面才答了select,试了一下,果然可以。
func main() {
testChan := make(chan int, 1)
testChan <- 1
select {
case testChan <- 2:
println("aaa")
default:
println("bbb")
}
}
//output:bbb
- 数组和切片的区别。
数组创建的时候,内存是固定的,只能放那么多元素,没有放的元素都初始化了。切片存储了是数组的指针和len和cap,可拓展
- 切片的append操作时怎么样子的?
会在切片的后面增加一个元素,如果切片满了要扩容,那么返回的值将和原来的切片不是一个指针。
- 说说切片的扩容。
就插入的时候发现切片内存不够了,就会触发扩容,会申请一个原容量两倍的数据切片,但是在到了一定程度(猜的1000,应该是1024)就不是两倍了,会是25%。
- 讲讲go的协程调度?
(内容太多了,自己查一下吧。)
- 如果协程发生阻塞会怎么样?
p会脱离m,让m绑定g,p去找其他m继续执行任务。
- 网络阻塞呢?
会有一个net list,有事件的epoll会到这个net list中,调度器会定时把这里面的数据拿到全局g队列里面(其实m在自旋的时候也会拿,忘记答了)
- 你们的etcd有做服务负载吗?
我们的负载均衡是靠自己实现的,etcd的表现更像是一个数据库的存在。
- 你有用prometheus吧?那你监控里的句柄数,cpu使用时怎么算的?
go的prometheus包自带的,用查询语句就能查出来。
- 有用过pprof吗?
有的。
- 主要用来干嘛?
看协程泄露,因为他记录了每个协程的堆栈,特别容易看。
- 那如果发现自己的go程序cpu很高怎么办?
利用pprof可以分析go程序,看到所有函数的cpu使用率。
- linux有用吗?
有的。
- centos还是Ubuntu。
都有,服务器用的centos,自己是用wsl,是Ubuntu。
- 你们服务器用的docker吗?k8s呢?
都没有,最原始的虚拟机。
- 怎么看连接?
netstat指定一个进程。
- 具体是什么命令。
忘记了。( netstat –ano|findstr )
- timewait是什么状态?
四次挥手之后,为了防止数据误传端口,端口需要保持这个状态一段时间。
- 怎么看句柄。
lsof。
- 看cpu占用。
top,可以看到每个进程,如果要详细,可以用vmstat。
- 最后问一道算法题,实现一个lru。
一开始没有要求,我就随便说了用数组,最简单的那种。
- 时间复杂度要求1呢?
用map+list+加记录头尾两节点实现时间复杂度为1的lru。
网友评论