大问题小回答

1.null reference空引用不好又好为什么

不好:代码不够优雅、超越类型检查;好:Usually errors in production code NEED to be identified as fast as possible so they can be fixed (usually data error). The easier it is to debug, the better.

2.如何在一个不可靠的协议之上构建一个可靠的通信协议

在不可靠的协议基础上添加类似于TCP协议的超时重传,有序接收,应答确认,滑动窗口流量控制等机制。

3.存储过程有什么优缺点?在什么情况下才用存储过程?

存储过程简单点说就是一堆 SQL 的合并,中间加再加一些逻辑控制。

好处:一次编译、多次执行、速度更快;多条sql语句一个连接一次性执行,效率更高;
坏处:过程化,不方便复杂业务逻辑开发;扩展性差,数据库分库分表会导致运行出问题;加重数据库负担,本可以放在逻辑服务器处理,都放在了数据库处理

4.为什么要实行敏捷开发

敏捷开发的本质是以人为本、循序渐进、迭代优化的开发方法。核心思路是将大的项目拆分成多个子项目,每个子项目由一部分人来完成开发、测试、调试、部署、上线等完整过程。提升效率,减少不必要的跨项目跨部门沟通。

5.TCP为什么需要三次握手四次挥手

三次握手是为了建立连接用的,为什么需要三次而不是两次,如果两次就能建立连接,有这么一种情况,一个本来早已失效的请求延迟了很久才到达server端,server端会以为是新的建立连接的请求,所以同意建立连接,但是这时候client不这么认为,因为它并不是新建立连接,进而客户端不会给server发送任何新的消息,server端就一直等待客户端发送消息,浪费了server端的资源。其实,从本质上说,一来一回两次请求只能对客户端来说是建立了连接,但是对服务端来说并不能表示建立了连接,因为普通的请求响应也是这样一来一回,而多加一次client的ack,server端就知道这是建立连接了。
按照上边说的应该要两个来回,分别确认两端即:
1.A 发送SYN 报文给B,这是第一次报文交互。

  1. B发送ACK确认A的SYN报文,这是第二次报文交互,即:B确认了A
  2. B发送自己的SYN报文给A,这是第三次报文交互
  3. A需要ACK确认B的SYN报文,这是第四次报文交互,即:A确认了B
    以上的演绎没有问题,但是报文2、3为何要分开发送呢?增加了延迟不说,同时还白白浪费了网络的带宽,完全可以将报文2、3合并起来,不就是在报文2的ACK状态位的位置置“1”就结了吗?这就是三次消息交互的由来!
    四次挥手也是为了client与server端都要关闭连接,一来一回只能说明一方不再继续发送数据了,但是还是可以接收数据的,client和server都搞个一来一回就说明两方都不再发送数据了,最终关闭整个连接。
    本质上说,要在不可靠的信道上双方就某个问题达成一致,三次通信是理论上的最小值。请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了.
6.TCP拥塞控制机制

从一端到另一端的角度,推测网络传输是否发生了拥塞,如果推测出发生了,就想办法去缓解拥塞。判断产生拥塞的方法:发送端会设置一个超时重传计时器,如果发送一个报文,计时器到时间了还没有收到接收端的确认报文,则认为网络链路产生拥塞。TCP的拥塞控制算法包括了慢启动(slow start)、拥塞避免(congestion avoidance)、快速重传(fast retransmit)和快速恢复(fast recovery)四部分。慢启动是说在数据传输的开始阶段,因为不知道网络情况,试探性的慢慢放大拥塞窗口,防止一开始就造成拥塞。拥塞避免是说随着慢启动发送窗口越来越大,如果中间收到确认超时,则减半发送窗口,避免拥塞。快速重传是一种能让发送端快速知道中间某个已发送的报文段丢失了或者超时很久接收端都没有收到,知道后发送端立马能够重传丢失的报文段,而不用等到计时器超时再去重传。快速重传算法中规定如果收到某数据报文段的三个重复确认,则立即重传下一个数据报文段。快速恢复是说在收到三个重复确认时,也减半满启动的发送窗口,预防拥塞发生。

7.TIME_WAIT状态的作用

TCP不允许针对同一目的ip端口有处于TIME_WAIT状态的连接而又去创建新连接,因为TIME_WAIT状态持续2MSL(报文段最大生命周期的2倍),所以创建新连接的时候保证老的连接的数据包不会再传递到新的连接上了。

8.golang new与make的区别

new分配基本的结构空间并返回一个指针而make分配的是结构空间以及附属的其他底层数据空间,返回的是结构本身而不是指针。

一个简单案例:
new: p := new([]int)
以上分配了一个slice结构,但是结构中的应该指向底层数组的ptr指针为空,
故实际不能往这个slice里面存取数据,同时分配了一个指针p,
也即(在32位系统中)占4个字节并存放slice结构的地址

make: v := make([]int, 0)
以上分配了一个slice结构,且结构中的应该指向底层数组的ptr指针已经指向了某个底层数组,
这个底层数组应该已经分配了,故这个slice已经可以使用了。
v就是这个slice结构,而不是一个指向slice的指针。
9.CAP理论中的P到底指的是什么?

摘自知乎里的一个回答,我觉得很好理解

C:集群中所有机器状态是一致的。A:客户端访问集群中任意一个节点,总能得到"处理成功"的结果。
假设有五个节点:n1~n5 ,出现网络分区被分成两组:[n1~n2]和[n3~n5],
那么当n1出来客户端请求时(为了处理这种情况,也就是说"容忍网络分区",即支持 P)
1:如果要保证C(一致性),那么它需要把消息复制到所有节点,但是网络分区导致无法成功复制到n3~n5,
所以它只能返回"处理失败"的结果给客户端。(这时系统就处于不可用状态,即丧失了A)
2:如果要保证可用性A,那么n1就只能把消息复制到n2,而不用复制到n3~n5(或者无视复制失败/超时),
但n3同时也可能在处理客户端请求(譬如对同一个值进行修改),n3也为了保证A而做了同样的处理。 
那么 [n1~n2]和[n3~n5]的状态就不一致了,于是就丧失了 C。
那么如果不支持P(也就是不容忍网络分区),也就是说(很乐观的认为)假设系统不会出现网络分区~

链接:https://www.zhihu.com/question/54105974/answer/138030946
10.架构的本质是什么

架构的本质:抽象、拆分、拓展。即:重复性业务逻辑的抽象(从低到高:函数、类、模块、服务)、复杂场景逻辑的拆分(大而全到小而专)、对未来的不确定性保留很好的拓展(快速支撑新的业务需求)。

11.索引失效的场景

索引列上有函数或数学运算;!=以及not in;or 运算;不符合复合索引最左前缀原则;索引列包含有null值;like双百分号

12.为什么mongodb存储用B树而Mysql存储用B+树?

mysql采用B+树的原因是因为B+树很适合磁盘数据存储,B+树只有叶子节点保存数据,而非叶子节点中不保存数据仅充当索引,这样索引的数据就比较少方便从磁盘加载到内存快速查找,另外叶子节点间通过指针相连还能快速进行关系数据库的范围查找;而mogodb不是关系数据库,被设计用于数据模型简单性能高的场景,非叶子节点保存有数据能够更加快速的查询到数据,能够加快查找。

13.为什么要选gRPC?

I.grpc是由google主导开发的rpc框架,传输协议基于HTTP/2,序列化协议基于Protobuf。不仅仅支持普通的一来一回式请求,还支持双向流请求,头部压缩、单tcp多路复用,更适合移动设备,能够省电省流量;强大的IDL描述接口详情,生成跨语言的客户端,方便多人多团队开发。
II.grpc基于http2另外的优势:因为添加了头信息,可以方便在框架层面对调用做拦截和控制(比如说限流,调用链分析,安全认证等)。
III.强制要求写proto文件,流式传输带来一定开发复杂性,基于http2会带一些额外的东西导致性能的下降。

14.为什么说TCP无界,UDP有界

TCP通过字节流传输,即TCP将应用程序看成是一连串的无结构的字节流。每个TCP套接口有一个发送缓冲区,如果字节流太长时,TCP会将其拆分进行发送。当字节流太短时,TCP会等待缓冲区中的字节流达到一定程度时再构成报文发送出去,TCP发给对方的数据,对方在收到数据时必须给矛确认,只有在收到对方的确认时,本方TCP才会把TCP发送缓冲区中的数据删除。
而UDP传输报文的方式是由应用程序控制的,应用层交给UDP多长的报文,UDP照样发送,既不拆分,也不合并,而是保留这些报文的边界,即一次发送一个报文。
有界与无界之分是根据接收报文来划分的,对于TCP协议,客户端连续发送数据,只要服务端的这个函数的缓冲区足够大,会一次性接收过来,即客户端是分好几次发过来,是有边界的,而服务端却一次性接收过来,所以证明是无边界的;
而对于UDP协议,客户端连续发送数据,即使服务端的这个函数的缓冲区足够大,也只会一次一次的接收,发送多少次接收多少次,即客户端分几次发送过来,服务端就必须按几次接收,从而证明,这种UDP的通讯模式是有边界的。

15.UDP数据包的发送和接收问题 (https://zhuanlan.zhihu.com/p/25622691)

(1) UDP的通信有界性
在阻塞模式下,UDP的通信是以数据包作为界限的,即使server端的缓冲区再大也要按照client发包的次数来多次接收数据包,server只能一次一次的接收,client发送多少次,server就需接收多少次,即客户端分几次发送过来,服务端就必须按几次接收。
(2) UDP数据包的无序性和非可靠性
client依次发送1、2、3三个UDP数据包,server端先后调用3次接收函数,可能会依次收到3、2、1次序的数据包,收包可能是1、2、3的任意排列组合,也可能丢失一个或多个数据包。
(3) UDP数据包的接收
client发送两次UDP数据,第一次 500字节,第二次300字节,server端阻塞模式下接包,第一次recvfrom( 1000 ),收到是 1000,还是500,还是300,还是其他?
由于UDP通信的有界性,接收到只能是500或300,又由于UDP的无序性和非可靠性,接收到可能是300,也可能是500,也可能一直阻塞在recvfrom调用上,直到超时返回(也就是什么也收不到)。
在假定数据包是不丢失并且是按照发送顺序按序到达的情况下,server端阻塞模式下接包,先后三次调用:recvfrom( 200),recvfrom( 1000),recvfrom( 1000),接收情况如何呢?
由于UDP通信的有界性,第一次recvfrom( 200)将接收第一个500字节的数据包,但是因为用户空间buf只有200字节,于是只会返回前面200字节,剩下300字节将丢弃。第二次recvfrom( 1000)将返回300字节,第三次recvfrom( 1000)将会阻塞。
(4) UDP包分片问题
如果MTU是1500,Client发送一个8000字节大小的UDP包,那么Server端阻塞模式下接包,在不丢包的情况下,recvfrom(9000)是收到1500,还是8000。如果某个IP分片丢失了,recvfrom(9000),又返回什么呢?
根据UDP通信的有界性,在buf足够大的情况下,接收到的一定是一个完整的数据包,UDP数据在下层的分片和组片问题由IP层来处理,提交到UDP传输层一定是一个完整的UDP包,那么recvfrom(9000)将返回8000。如果某个IP分片丢失,udp里有个CRC检验,如果包不完整就会丢弃,也不会通知是否接收成功,所以UDP是不可靠的传输协议,那么recvfrom(9000)将阻塞。

16.通常情况下,UDP的使用范围是较小的,在以下的场景下,使用UDP才是明智的

[1] 实时性要求很高,并且几乎不能容忍重传
例子:NTP协议,实时音视频通信,多人动作类游戏中人物动作、位置
[2] TCP实在不方便实现多点传输的情况
[3] 需要进行NAT穿越
[4] 对网络状态很熟悉,确保udp网络中没有氓流行为,疯狂抢带宽
[5] 熟悉UDP编程

17. 码代码2-8 原则

一般只用 20% 的代码就可以解决 80% 的问题。但要想解决剩下 20% 的问题的话,则需要额外 80% 的代码。

你可能感兴趣的:(大问题小回答)