写在前面

滴滴面试感觉还行吧,挺注重基础的,很多时间都花在了挖项目上面,所以大家一定要很熟悉自己的项目!面试官水平也很高。不过也感叹这个曾经的大厂现在变成这个样子,唉。。

笔试

一面

进程间通信方式

管道、消息队列、信号量、共享内存

栈上分配内存快还是堆上,为什么?

显然从栈上分配内存更快,因为从栈上分配内存仅仅就是栈指针的移动而已
寄存器存放栈的地址专门的指令执行

channel 底层

type hchan struct {
 qcount   uint   
 // channel 里的元素计数
 dataqsiz uint   
 // 可以缓冲的数量,如 ch := make(chan int, 10)。 此处的 10 即 dataqsiz
 elemsize uint16 
 // 要发送或接收的数据类型大小
 buf      unsafe.Pointer 
 // 当 channel 设置了缓冲数量时,该 buf 指向一个存储缓冲数据的区域,该区域是一个循环队列的数据结构
 closed   uint32 
 // 关闭状态
 sendx    uint  
 // 当 channel 设置了缓冲数量时,数据区域即循环队列此时已发送数据的索引位置
 recvx    uint  
 // 当 channel 设置了缓冲数量时,数据区域即循环队列此时已接收数据的索引位置
 recvq    waitq 
 // 想读取数据但又被阻塞住的 goroutine 队列
 sendq    waitq 
 // 想发送数据但又被阻塞住的 goroutine 队列
 
 lock mutex
 ...
}

在这里插入图片描述

七层模型

从上而下分别是 应用层,表示层,会话层,传输层,网络层,数据链路层,物理层等等…

tcp、udp

TCP 是可靠传输,面向连接,基于流,占用资源多,效率低。

UDP是尽最大努力交付,基于无连接,基于报文,UDP 占用系统资源较少,效率高。

redis持久化的方式以及使用场景

持久化机制数据恢复
当前进程的数据生成快照存入到磁盘手动触发与自动触发AOF 持久化持久化的实时性

如何实现线程池?

线程池有两部分组成:同步队列和线程池。

同步队列Put() thread 类型Start()numThreadsRunThread()Stop()

在这里插入图片描述

算法:二叉树俯视图

二面

怎么判断给定ip是否在给定ip区间内?

IP地址可以转换成整数,可以将IP返回化整为整数范围进行排查。

package main

import (
    "fmt"
    "strconv"
    "strings"
)

func main() {
    ipVerifyList := "192.168.1.0-192.172.3.255"
    ip := "192.170.223.1"
    ipSlice := strings.Split(ipVerifyList, `-`)
    if len(ipSlice) < 0 {
        return
    }
    if ip2Int(ip) >= ip2Int(ipSlice[0]) && ip2Int(ip) <= ip2Int(ipSlice[1]) {
        fmt.Println("ip in iplist")
        return
    }
    fmt.Println("ip not in iplist")
}

func ip2Int(ip string) int64 {
    if len(ip) == 0 {
        return 0
    }
    bits := strings.Split(ip, ".")
    if len(bits) < 4 {
        return 0
    }
    b0 := string2Int(bits[0])
    b1 := string2Int(bits[1])
    b2 := string2Int(bits[2])
    b3 := string2Int(bits[3])

    var sum int64
    sum += int64(b0) << 24
    sum += int64(b1) << 16
    sum += int64(b2) << 8
    sum += int64(b3)

    return sum
}

func string2Int(in string) (out int) {
    out, _ = strconv.Atoi(in)
    return
}

如何优化慢SQL?

  1. 查看是否使用到了索引。
  2. 查看 SQL语句 是否符合最左匹配原则。
  3. 对查询进行优化,尽可能避免全表扫描
  4. 字段冗余,减少跨库查询或多表连接操作
  5. 将一些常用的数据结构放在缓冲中(部门名字,组织架构之类的),就不需要查数据库了。

什么情况不建议使用索引

  1. 在where条件中(包括group by以及order by)里用不到的字段不需要创建索引,索引的价值是快速定位,如果起不到定位的字段通常是不需要创建索引的。
  2. 数据量小的表最好不要使用索引,少于1000个
  3. 字段中如果有大量重复数据(性别),也不用创建索引
  4. 避免对经常更新的表创建过多的索引。
  5. 不建议使用无序的值作为索引。

线程池的几种拒绝策略及其应用场景

当时都不知道这是个啥…
具体看这篇博客吧 线程池拒绝策略应用场景

http与tcp区别

http 就是基于传输层的 tcp 实现的一个应用层协议。

长连接与短连接

长连接意味着进行一次数据传输后,不关闭连接,长期保持连通状态。

短连接意味着每一次的数据传输都需要建立一个新的连接,用完再马上关闭它。下次再用的时候重新建立一个新的连接,如此反复。

讲讲tcp的挥手?

ESTABLISHED
FIN1seq=u1FIN-WAIT-1(终止等待1)

注意:TCP规定,FIN报文段即使不携带数据,他也消耗掉一个序号!!

ack = u + 1v最后一个字节的序号加1CLOSE-WAIT(关闭等待)FIN-WAIT-2(终止等待2)FIN = 1wack = u + 1LAST-ACK(最后确认)ACK置1ack=w+1seq=u+1TIME-WAIT还没有还没有释放掉2MSL

时间MSL叫做最长报文段寿命,RFC793建议设在两分钟。但是在现在工程来看两分钟太长了,所以TCP允许不同的实现可以根据具体情况使用更小的MSL值。

在这里插入图片描述

time wait,过多怎么办

  1. 修改TIME_WAIT连接状态的上限值
  2. 启动快速回收机制
  3. 开启复用机制
  4. 修改短连接为长连接方式
  5. 由客户端来主动断开连接

算法:忘了…

三面

聊人生…