某大公司两次面试技术总结 - Go语言中文社区

某大公司两次面试技术总结


一面:
1.B+树的时间复杂度:O(logn),当时说成nlogn是讲话时没思考,B树也说成B减树,汗颜。
2.聚簇索引在存储方式上的特点,跟主键id是否自增有没有关联:只要聚簇索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。如果主键不是自增id,那么可以想象它会不断地调整数据的物理地址、分页。比如,使用UUID作为聚簇索引会很糟糕:它使得聚簇索引的插入变得完全随机。
3.mysql的乐观锁、悲观锁区别:乐观锁用版本号方式来解决,悲观锁用阻塞其他select操作的方式解决问题。
4.tcp/ip分层当时讲的模糊,现在重讲:
比特流一层
arp协议等,以及物理地址寻址、数据的成帧、流量控制、数据的检错、重发一层
ip协议一层
tcp udp等协议一层
http,ftp等协议一层
5.线程,进程,协程的区分:
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程也由操作系统调度。
协程和线程一样共享堆,不共享栈,协程由程序员在代码里调度。(援引网络博文)

当运行一个程序时,OS会为这个程序启动一个进程,可以将进程看做一个包含了程序在运行中需要用到和维护的各种资源的容器。
一个线程是一个执行空间,这个空间会被OS来运行函数中所写的代码。每个进程至少包含一个线程,每个进程的初始线程被称作主线程。(援引自GO语言实战)
6.用grep从百万行数据里面匹配出对应模式的数据前10条:
grep -e "pattern" -m 10 filepath
7.redis pub/sub如何保证消息可靠性?
redis的pub/sub不能直接支持消息可靠,建议用rabbitmq等功能更强的消息队列。
8.php浮点型应注意什么?(当时没有讲很细,没有讲出浮点型保存的小数为什么精度会失准。)
二进制保存十进制的小数,比如5.2 在十进制5.2是有限小数,改成二进制确实无限小数,所以保存起来,精度肯定会有一些缺失。
详解可以参考卢钧轶博客http://cenalulu.github.io/linux/about-denormalized-float-number/
可以知道需要用到bcmath这样的数学函数库来操作浮点数的运算,来保证精度。
参考鸟哥博客,http://www.laruence.com/2011/12/19/2399.html http://www.laruence.com/2013/03/26/2884.html

二面
1.积分排行榜解决方案:利用redis的zset数据结构的 zrank key member实现,原理类似二分搜索。
2.go高并发的原理:我的回答是利用了协程,占用cpu和内存的资源比进程和线程少。理由显然单薄。补充如下:
内存方面:
执行协程只需要极少的栈内存(大概是4~5KB),默认情况下,线程栈的大小为1MB-8MB
goroutine 的创建初始内存成本很低廉,并且会根据需要动态增长和缩减占用的资源。这使得 goroutine 会从 4096 字节的初始栈内存占用开始按需增长或缩减内存占用,而无需担心资源的耗尽。(援引自网络博文)
模型优势方面:GO语言自带一个可以调度线程和协程运行的调度处理器,这个调度处理器实现了一些高级的算法,并发模型具有优势。

进程I/O访问,阻塞了后面所有的计算,OS就直接把CPU切换到其他进程,让人家先用着。当然除了IO阻塞,还有时钟阻塞等等。然后就出现了一个问题,就是太慢了,一切换进程得反复进入内核,置换掉一大堆状态。进程数一多,大部分系统资源就被进程切换给吃掉了。后来也有用线程来改善的,大致意思就是,这个地方阻塞了,但我还有其他地方的逻辑流可以计算,这些逻辑流是共享一个地址空间的,不用特别麻烦的切换页表、刷新TLB等,只要把寄存器刷新一遍就行,能比切换进程开销少点。而协程是在进程里写一个逻辑处理器调度,利用到了并发优势,又可以避免反复系统调用,也没有进程切换造成的开销。这种用户态线程就叫协程。
协程主要解决了两个必须的问题:一是碰着阻塞式IO会导致整个进程被挂起;二是由于缺乏时钟阻塞,进程需要自己拥有调度线程的能力。如果一种实现使得每个线程需要自己通过调用某个方法,主动交出控制权。那么我们就成这种用户态线程是协作式的,就是协程。(引用自知乎~阿猫)

3.分库分表技术方面考虑,什么时候该分库分表,怎么操作?
垂直分表,把不常用的字段拆分到另外一张表。
垂直分库,把不同业务的数据放在不同的库。服务化的拆分利于解耦和提高性能,也利于系统扩展。
水平分表,表中的数据(比如user表)按照一定规律(比如对id进行hash和取模后拆分)。可以一定程度缓解查询性能瓶颈。但还会有库级别IO瓶颈,因为数据在同一个库中。
水平分库分表,于水平分表类似,唯一不同是将这些拆分出来的表保存在不同的数据库中。在冷热数据分离的场景很适用。能有效缓解单机和单裤性能瓶颈压力,突破IO、连接数、硬件资源的瓶颈。(援引Infoq作者 丁浪)

4.mysql读写分离或负载均衡靠什么机制调度?
应该是问mysql数据库访问层主流方案,这个我没接触过,以后再补充。

5.mysql跨库事务怎么做
第一,用mysql5.7的XA特性。第二,或者用队列(需要设计一下这个队列,我后面补充下)来确保两个任务执行成功(限不需要回滚的场景)

6.redis集群增加或减少一个节点应注意什么?
参考codis的redis集群方案的增加和减少节点的方法。http://www.jianshu.com/p/ec6a04eb66c3
7.swoole worker 的运行方式,我回答是以多线程方式运行的,其实是以多进程方式运行。
关于Reactor Worker Task的关系,我后期再补充下。

14.memcache 一致性哈希原理?
简单的讲,就是利用hash环和虚拟节点的思路,把请求分发到分布得很细密的虚拟节点上。增加或删除节点的时候,该节点的缓存会被分发到下一虚拟节点,而不会影响其他节点的已有缓存的命中率。
参考,朱双印博客
http://www.zsythink.net/archives/1182
php对memcache/memcached的一致性实操,可以通过三种方式实现:
第一,修改php.ini memcache扩展的配置:

[Memcache] 
Memcache.allow_failover = 1 
Memcache.hash_strategy =consistent 
Memcache.hash_function =crc32

第二,使用memcachd扩展时,可以通过setOption方法配置。

$mem = new Memcached();
$mem->setOption(Memcached::OPT_HASH, Memcached::HASH_CRC);
$mem->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$servers = array(
  array('192.168.20.193', 11211, 33),
  array('192.168.20.194', 11211, 67)
);
$mem->addServers($servers);

print_r($mem->get('str_key'));

第三,可以通过php代码实现,比如flexihash.php类库
援引http://www.itnose.net/detail/6619318.html

版权声明:本文来源简书,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.jianshu.com/p/8b4658f83ddc
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-01-12 12:58:22
  • 阅读 ( 969 )
  • 分类:面试题

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢