原文地址:Go面试看这里了~(十七)
1、time-wait?
TIME_WAIT是TCP协议中断开连接所经历的一种状态,状态图如下:
上图中作为主动关闭的一方(Client)出现了TIME_WAIT状态,目的是告诉Server端,己方没有需发送的数据,但是仍然保持了接收对方数据的能力。
常见关闭连接过程如下:
-
当客户端无待发送数据时,会向服务端发送FIN消息,发送消息后进入FIN_WAIT_1状态。
-
服务端接收到客户端的FIN消息后,进入CLOSE_WAIT状态并向客户端发送ACK消息,客户端接收到ACK消息时进入FIN_WAIT_2状态。
-
当服务端无待发送数据时,服务端会向客户端发送FIN消息。
-
客户端接收到FIN消息后,进入TIME_WAIT状态并向服务端发送ACK消息,服务端收到后进入CLOSED状态。
-
客户端等待两个最大数据段生命周期(Maximum segment lifetime,MSL)的时间后也进入CLOSED状态。
TIME_WAIT一定是发生在主动关闭一方,被动关闭一方会直接进入CLOSED状态,主动关闭一方需要等待2*MSL时间才会最终关闭,客户端和服务端之间的连接此时就会正常关闭,新创建的TCP连接收到影响的概率也微乎其微,保证了数据传输的可靠性。
TIME_WAIT主要为防止被动关闭方的延迟数据被窃取,及未收到最后的ACK报文。
Redis在并发量突增时很容易出现TCP连接失败(无可用端口),原因在于TIME_WAIT数量过大(会占用端口),每次连接断开后都会产生TIME_WAIT,跟三次握手四次挥手有关,其实本质上TIME_WAIT是用于优化网络通信的,如关闭此优化方案,虽然可行,但不建议这样处理,关闭之后可能会产生其它网络异常,虽然可能是小概率的,这里提供几条优化建议:
-
对于Redis缓存,使用redisgo自带的连接池,需配置MaxIdle值。
-
对于数据库,自带连接池(默认可能未启用),直接调用SetMaxIdleConns设置MaxIdle值。
-
对于http请求,默认没有连接池,可使用通用的go-commons-pool,通过borrow和return机制使用连接池,如有资源申请要记得释放。
-
通过nginx转发,需在nginx.conf配置文件中增加keep-alive配置。
2、for循环遍历slice的问题?
-
子切片和父切片用的是同一个底层数组,改变子切片的值,也会改动到父切片。
-
for range遍历的是副本,对副本的改动不会体现在原有切片。
-
for循环中直接出来的值永远是遍历的最后一位,需定义局部变量。
3、现有100枚硬币,其中有一枚硬币重量不一样,用天平秤怎么快速找到这一枚硬币?
第一次:将100枚硬币分两份,每份50,选择重量较轻的一组继续称。
第二次:将50枚硬币分两份,每份25,选择重量较轻的一组继续称。
第三次:取出1枚硬币,将剩下的24枚硬币分两份,每份12枚硬币,如重量一致,则取出的那1枚硬币就是假币,反之选择重量较轻的一组继续称。
第四次:将12枚硬币分两份,每份6,选择重量较轻的一组继续称。
第五次:将6枚硬币分两份,每份3,选择重量较轻的一组继续称。
第六次:取出1枚硬币,将剩下的2枚硬币分两份,每份1枚硬币,如重量一致,则取出的那1枚硬币就是假币,反之较轻的那枚硬币为假币。
至此,本次分享就结束了,后期会慢慢补充。
以上仅为个人观点,不一定准确,能帮到各位那是最好的。
好啦,到这里本文就结束了,喜欢的话就来个三连击吧。
扫码关注公众号,获取更多优质内容。