竹云科技一二三面:
讲项目(看到我安全开发较多,延伸到)企业或者服务的安全隐患有哪些?(我答外部黑客攻击,漏洞及社工泄密;总结到内部隐患更大)-》安全防护措施有什么?-〉(面试官指出预防工作更重要,引出)零信任体系(我面的岗就是做IAM)
Go:channel;GPM;切片扩容;sync包还用过什么?(map,waitgroup,mutex等)
Go channel 实现原理分析 - 简书
深入理解Go的slice及其扩容规则 | QXQZX's Blog
GoLang GPM模型 - Go语言中文网 - Golang中文社区
Go语言sync包的应用详解 - 知乎
mysql:SQL优化
建表过程中:尽量使用vchar代替char,对经常查询和排序的字段建立索引,尽量使用组合索引
查询过程中:尽量避免索引失效情况,避免全表查询,避免select * ,组合索引中符合最左原则
Redis:数据类型,如何保证高可用?(集群,主从读写分离+同步,哨兵,内存淘汰)
https 具体过程(ca,证书链校验过程,非对称加密交换随机KEY,对称加密数据),ssl算法
全网最透彻HTTPS(面试常问)
写一个生产者消费者模型,生产者每次产生一百条数据,消费者每次读十条:
package main
import (
"fmt"
"sync"
)
func main(){
var mychan =make(chan int,100)
var mymutex = sync.Mutex{}
var wg sync.WaitGroup
wg.Add(10)
var p Producer
var w Worker
go p.Produce(&mychan,&mymutex)
var res []int
for i:=0;i<10;i++{
go w.Consume(&mychan,&wg,&res)
}
wg.Wait()
close(mychan)
}
type Producer struct {
}
type Worker struct{
}
func (p *Producer)Produce(mychan *chan int,mymutex *sync.Mutex){
mymutex.Lock()
for i:=0;i<100;i++{
*mychan <-i
}
mymutex.Unlock()
}
func (w *Worker)Consume(mychan *chan int,wg *sync.WaitGroup,res *[]int){
for i:=0;i<10;i++{
data := <-*mychan
fmt.Println(data)
*res = append(*res,data)
}
wg.Done()
}
敏于行一面:
go :GPM模型,new与make区别,锁,
mysql:锁 ,事务
项目中遇到的问题,周期
职业规划。。(我估计就是这里说漏嘴了,面试官最后问有没有回西安的打算,我说过几年,然后就截止一面了)
泰尔英福一面:
go:make与new 区别;内存泄漏(现象是内存正在被某个进程消耗完毕,c中经常遇到,用到malloc申请的内存要用free释放,否则会发生内存泄漏,go中使用垃圾回收);init执行顺序(在main函数之前,模块包中的先执行,package main中的后执行);channel有无缓冲的区别(一句话,有缓冲的是channel读写操作是异步的,无缓冲的读写操作是同步的)
问时针分针一天相遇多少次
redis:持久化,数据丢失后如何恢复
工具:git如何回退;docker如何编译(具体到dockerfile中的命令)
mysql:索引;最左前缀
python: cls装饰器;并发
二面:
redis 如果内存满了怎么办(应该回答内存淘汰的策略)
rmq消费者都挂了怎么办,如何保证的只有一个消费者拿到任务
(场景题答的不好,没有过这种高并发的经验,面的岗也是做区块链的,聊不投机)
三面:
哈哈哈哈竟然让我说七层模型,太久没看没记住气死我了,TCP/IP协议在哪一层?应用层有什么协议?太厉害了,终于有人能把TCP/IP协议讲的明明白白了!-51CTO.COM
docker的安全如何保证?我举例docker中经常需要copy配置文件,明文存储会有泄漏数据的风险,对敏感数据加密,在程序中解密,可以防止数据泄露
滴滴面试:
自我介绍-》安全研发中遇到什么困难?
讲项目-》sso单点登录过程?
什么是单点登录(SSO)
mysql:索引,非聚簇和聚簇?(主键索引是聚簇,其余是非聚簇)具体什么场景用什么锁?如何保证主从一致?如何回滚?
MySql主从复制,从原理到实践!
red is:string的数据结构是?(sds) 内存淘汰机制?(定时删除,惰性删除)
go:channel详细,map slice 是并发安全吗 为啥,mutex,wait group
网络IO: epoll
做了一道题:使用滑动窗口算法(要注意边界情况)
package main
import "fmt"
/*
正整数nums求和》=target的连续子数组 最小的长度
*/
func minSubArrayLen(target int, nums []int) int {
var length = len(nums)
if length ==0{
return 0
}
var minlength = length
var sum = 0
for start,end:=0,0;end<=length && start <= end;{
if sum >= target{
tempMinLen := end-start
if tempMinLen < minlength{
minlength = tempMinLen
}
sum -= nums[start]
start++
}else{
if end < length{
sum += nums[end]
}
end ++
}
}
return minlength
}
func testMinSunArr(){
res := minSubArrayLen(7,[]int{2,3,1,2,4,3})
fmt.Println(res)
res1 := minSubArrayLen(4,[]int{1,4,4})
fmt.Println(res1)
}
func main(){
testMinSunArr()
}
Mysql索引面试题 - 割肉机 - 博客园s
深信服一面:(面的是蓝军攻防岗 )
go:GPM
mysql:请求量过大,如何调优?(1分库分表 2 使用集群,并说了主从同步 3 使用redis缓存热键)
redis:是否是单线程?(网络IO和kv读写是单线程)雪崩了怎么办?
网络IO: 邮件协议,epoll模型,是否抓过包,Linux抓包命令
会爬虫吗
讲钓鱼项目,遇到什么难题
深信服二面:
Go:channel底层。如何读写数据
网络IO模型,select epoll
项目,sso
平时学习来源,是否封装过底层数据结构,了解漏洞和挖掘技术吗?
深信服三面:
为什么离职啦。 职业规划啦。加班态度啦。
诚迈科技一面:
讲项目,为什么选择Rocket MQ
redis中有序集合底层的数据结构 (跳表加hash)
Mysql 写SQL语句,查学生表中各个年级的男女学生个数;分布式同步如何做?(问如果一个事物需要多个应用服务完成写操作,其中一个失败了,之前的事务需要回滚,还顺便说了回滚的原理)
Go:GPM ;slice与数组的区别,slice如何扩容;如果给已关闭的channel读写数据,分别有什么影响?(写的话回Panic,读的话,返回零值);异常如何捕获(defer 和recover)
算法:跳台阶问题,多个协程并发执行,如何保证顺序打印?
package main
import (
"fmt"
"sync"
)
func main(){
var (
Awg sync.WaitGroup
Bwg sync.WaitGroup
Cwg sync.WaitGroup
)
for i:=0;i<10;i++{
Awg.Add(1)
Bwg.Add(1)
Cwg.Add(1)
go func() {
fmt.Print("A")
Awg.Done()
}()
go func() {
Awg.Wait()
fmt.Print("B")
Bwg.Done()
}()
go func() {
Bwg.Wait()
fmt.Print("C")
Cwg.Done()
}()
Cwg.Wait()
fmt.Println()
}
}
抖音一面:
讲项目,职责,难点
redis set zset 底层数据结构
mysql 事务,隔离级别,mvcc,具体如何实现的读可提交和可重复读
TCP如何保证可靠,拥塞控制具体流程
go的垃圾回收
做了一道题(没写出来,脑子固住了
package main
import "fmt"
func main() {
var matrix = [][]int{[]int{1,2,3,10},[]int{4,5,6,11},[]int{7,8,9,12}}
fmt.Println(matrixPrint(matrix))
}
//顺时针转圈打印多维数组
func matrixPrint(matrix [][]int)[]int{
if len(matrix) == 0 || len(matrix[0]) == 0{
return []int{}
}
row, col := len(matrix),len(matrix[0])
var res []int
var rowStart,rowEnd,colStart,colEnd = 0,row-1,0,col-1
var times = row * col
for index, i,j:=0,rowStart-1,colStart-1;index < times;{
for i,j=i+1,j+1;index <times && j <= colEnd;j++{
res = append(res,matrix[i][j])
index++
}
rowStart++
for i,j=i+1,j-1;index<times && i <= rowEnd;i++{
res = append(res,matrix[i][j])
index++
}
colEnd--
for i,j=i-1,j-1;index <times && j >= colStart;j--{
res = append(res,matrix[i][j])
index++
}
rowEnd--
for i,j=i-1,j+1;index <times && i >= rowStart;i--{
res = append(res,matrix[i][j])
index++
}
colStart++
}
return res
}
知乎一面:
关于锁:不释放的情况;不是自己释放的情况;
mysql:事务及四种特性靠什么实现?四种隔离状态及MVCC如何实现可重复读和读可提交;联合索引具体查询过程,B+树存的是什么?
Redis: 缓存失效的情况;击穿和雪崩情况如何处理?
RocketMQ: 如何保证消息不丢失?消费者如何消费?
做一道题:合并多个有序的子数组(知乎的面试官好酷啊,说面试先到这,留一道课后题,让我在云文档上做,可以查资料)
/*
有若干有序子数组, 合并为一个有序数组,M个子数组, 子数组的平均长度是 N
如:
A: 1, 3, 5, 7, 9
B: 2, 3, 5, 6, 8
C: 4, 6, 8, 9
D: ...
...
目标: 1, 2,3,3,4,5,5,6,6,7,8, 8 ,9,9 ...
要求:时间复杂度,空间复杂度最优。
*/
package main
import "fmt"
func main(){
TestMergeArrays()
}
func TestMergeArrays(){
var arrays = [][]int{{1, 3, 5, 7, 9},{2, 3, 5, 6, 8},{4, 6, 8, 9}}
res := MergeArraysByQuickSort(arrays) // 思路1:讲子数组所有元素添加到一个数组中,对数组使用快排
fmt.Println(res)
res = MergeArraysByMergeSort(arrays) // 思路2:对相邻的子数组使用归并,逐渐合并成大的有序子数组
fmt.Println(res)
}
func MergeArraysByQuickSort(arrays [][]int)[]int{
if len(arrays) == 0{
return []int{}
}
var mergeArrRes []int
for _, arr := range arrays{
mergeArrRes = append(mergeArrRes,arr...)
}
QuickSort(&mergeArrRes)
return mergeArrRes
}
func QuickSort(arr *[]int){
if len(*arr) == 0{
return
}
quick(arr,0,len(*arr)-1)
}
//挖坑填数法,选择一个基数(一般是第一个),两个指针指向头尾,
//比基数小的放在基数的左边,比基数大的放在基数的右边,
func quick(arr *[]int,left,right int){
low,high := left,right
pivot := (*arr)[low]
for low < high{
for low<high && (*arr)[high] > pivot{
high --
}
if low < high{
(*arr)[low] = (*arr)[high]
low++
}
for low<high && (*arr)[low] < pivot{
low ++
}
if low < high{
(*arr)[high] = (*arr)[low]
high --
}
}
(*arr)[low] = pivot
if low - left > 1{
quick(arr,left,low-1)
}
if right-low > 1{
quick(arr,low+1,right)
}
}
func MergeArraysByMergeSort(arrays [][]int)[]int{
if len(arrays) == 0{
return []int{}
}
var res []int
for _,array := range arrays{
res = merge(res,array)
}
return res
}
func merge(arr1,arr2 []int)[]int{
var brr []int
var (
i = 0
j = 0
len1 = len(arr1)
len2 = len(arr2)
)
for i<len1 && j <len2{
if arr1[i] < arr2[j]{
brr = append(brr,arr1[i])
i++
}else{
brr = append(brr,arr2[j])
j++
}
}
if i<len1{
brr = append(brr,arr1[i:]...)
}
if j<len2{
brr = append(brr,arr2[j:]...)
}
return brr
}
知乎二面
从项目出发,为什么用redis的set集合,set底层数据结构,插入查找的时间效率,设置过期时间的命令,定期删除的策略;为什么使用beanstalk,遇到过消息丢失吗?如何保证的?丢失了怎么办?mysql如何保证消息不丢失?redolog,undolog写在哪里?写一个SQL查询某字段中包含A B C?
知乎一面(再投!)
算法:做一道二分查找的题,用循环和递归两种方法
package main
import (
"fmt"
)
/*
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:
你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。
*/
func FindTargetByArray(nums []int, target int)int{
if len(nums) == 0 || target < nums[0] || target > nums[len(nums)-1]{
return - 1
}
var start, mid, end = 0, 0, len(nums)-1
for start <= end {
mid = (start + end) / 2
if nums[mid] == target{
return mid
}
if nums[mid] > target{
end = mid - 1
}
if nums[mid] < target{
start = mid + 1
}
}
return -1
}
func FindTarget(nums []int, target int)int{
if len(nums) == 0 || target < nums[0] || target > nums[len(nums)-1]{
return - 1
}
var FindTargetByDigui func(int, int)int
FindTargetByDigui = func(start int,end int)int{
var mid int
var res = -1
if start <= end{
mid = (start + end) / 2
if nums[mid] == target{
return mid
}
if nums[mid] > target{
res = FindTargetByDigui(start,mid-1)
}
if res == -1 && nums[mid] < target{
res = FindTargetByDigui(mid+1,end)
}
}
return res
}
res := FindTargetByDigui(0,len(nums)-1)
return res
}
func TestFindTarget(){
var nums = []int{-1,0,3,5,9,12}
target := 9
fmt.Println(FindTarget(nums,target))
target = 2
fmt.Println(FindTargetByArray(nums,target))
}
func main(){
TestFindTarget()
}
go: 如果slice作为形参是值拷贝还是引用拷贝,(会对slice对象拷贝,但是slice结构体内部数组指针仍然指向原地址,没有拷贝数组本身) map的底层和扩容,sync.map和map的区别,做了什么优化,channel的底层,具体的读写过程,net包与gin的区别
redis的持久化,RMQ持久化,与Kafka的区别
mysql 深翻页,这条sql的执行过程
select * from table_a where a = 1 and b = 2 limit 100000, 10
旷视科技一面:
Go: GC具体回收哪里的对象(堆);堆和栈的区别?内存逃逸?说一说slice,底层?说一说map;struct{}占多大内存?(0)怎么使用?(当占位符用,管道中不存储实际数据,只用作信号使用时)用过pprof吗?平时用过什么库?以下代码有什么问题,如何修改?
func main() {
var slice = []int{100, 200, 300, 400, 500}
wg := sync.WaitGroup{}
for i, s := range slice {
go func() {
wg.Add(1)
defer wg.Done()
fmt.Println("[", i, "]", ":", s)
}()
}
wg.Wait()
}
//不会打印任何东西主进程直接结束,修改:
func main() {
var slice = []int{100, 200, 300, 400, 500}
wg := sync.WaitGroup{}
wg.Add(len(slice))
for i, s := range slice {
go func(i,s int) {
defer wg.Done()
fmt.Println("[", i, "]", ":", s)
}(i,s)
}
wg.Wait()
}
解释rocket MQ工作机制?如何解决Redis内存满的情况?Redis的持久化?
mysql:说一说索引及B+树,什么时候建索引?怎么调优?用过expire吗?
场景题:现在有100000个Goruntine,同一时间如何保证最多只有100个Goruntine在运行?(使用一个长度为100的channel,携程内部往里写数据,协程退出前读数据,由于读写channel是原子性,可以保证只有100个协程正在运行,其余会被阻塞住)
Linux上运行的服务器挂了,一般会怎么排查?查看日志的命令?(tail -f 实时查看,cat |grep过滤查看)
请用面向对象的编程方式找出数组中和=target的两个数字
package main
import (
"errors"
"fmt"
"sync"
)
func main() {
Test()
}
type ArrayInter interface {
FindTwoNums()(int,int,error)
}
type ArraySum struct {
Array []int
Target int
}
func(as *ArraySum)FindTwoNums()(int,int,error){
if len(as.Array) == 0{
return -1,-1,errors.New("数组中没有值!")
}
var myMap = make(map[int]int) // 差值:index
for index,num := range as.Array{
if anaIndex,exist:=myMap[num];exist{
return anaIndex,index,nil
}
myMap[as.Target-num] = index
}
return -1,-1,errors.New("没有符合要求的数!")
}
func Test(){
var myStruct = ArraySum{[]int{1,3,5,2,4,6},11}
var myInter ArrayInter = &myStruct
index1,index2,err := myInter.FindTwoNums()
if err != nil{
fmt.Println(index1,index2,err.Error())
}else{
fmt.Println(index1,index2,nil)
}
var myStruct2 = ArraySum{[]int{1,3,7,2,5,15},11}
var myInter2 ArrayInter = &myStruct2
index1,index2,err = myInter2.FindTwoNums()
if err != nil{
fmt.Println(index1,index2,err.Error())
}else{
fmt.Println(index1,index2,nil)
}
var myStruct3 ArraySum = ArraySum{[]int{},11}
var myInter3 ArrayInter = &myStruct3
index1,index2,err = myInter3.FindTwoNums()
if err != nil{
fmt.Println(index1,index2,err.Error())
}else{
fmt.Println(index1,index2,nil)
}
}
旷视二面&三面:
场景题,API中需要调用其他微服务,并五分钟超时返回,如何设计?
项目中遇到什么情况需要用到什么数据结构?
TCP 长连接和短链接区别?
你觉得gorm 有哪些地方设计不合理? (0值问题)
shopee一面:
讲项目:详细讲mysql查询过程的耗时,以及为什么用了redis就快?
做了两道题:找两个节点的最近公共父节点;将二叉搜索树转换成二叉累加树;
(这个公司我不理解啊,两道算法题都写出来了,为什么一面后就没消息了?!)
地平线一面:
项目:使用的是master-worker模式,是否遇到过数据过多,消费者来不及消费的情况?(manager根据一定负载均衡策略增加或减少worker)使用beanstalk作为分布式消息队列,为什么这样选型?那如何使用redis完成分布式消息队列?(我说list),如果想在10000个数据中查找出100个数据呢?(zset) zset的底层数据结构(hash+跳跃表)
sso机制,(什么是单点登录(SSO), jwt与cookie的区别?http请求方法,响应码,
Go:slice的扩容,底层,内存泄漏的情况,(未等待协程执行完毕)如何预防?(wait group)如何检测(pprof)进程线程协程的区别,GMP模型
进程:进程是系统进行资源分配的基本单位,有独立的内存空间。
线程:线程是 CPU 调度和分派的基本单位,线程依附于进程存在,每个线程会共享父进程的资源。
协程:协程是一种用户态的轻量级线程,协程的调度完全由用户控制,协程间切换只需要保存任务的上下文,没有内核的开销。
docker: build,push,run,load,save,如何减小镜像的大小?(使用&符号将多个RUN命令连接在一起?)
mysql:InnoDB什么锁? 对于商品表的库存字段现在有高并发的读写请求问我怎么办?(将库存拆成多行,减少对一个行锁的并发量)
口述快排;
请用工厂模式设计一个能返回不同类型的方法?
package main
import (
"encoding/json"
"encoding/xml"
)
type ReturnSt interface {
output ()interface{}
}
type JsonOutPut struct {
Data string `json:"data"`
}
type XmlOutPut struct {
Data string
}
func (jt *JsonOutPut)output()interface{}{
res, err := json.Marshal(jt)
if err != nil{
return nil
}
return res
}
func (xt *XmlOutPut)output()interface{}{
res, err := xml.Marshal(xt)
if err != nil{
return nil
}
return res
}
func ReturnApi(DataType string)interface{}{
var res interface{}
var myInterface ReturnSt
switch DataType {
case "json":{
var jt = JsonOutPut{"hello world"}
myInterface = &jt
}
case "xml":{
var xt = XmlOutPut{"hello world"}
myInterface = &xt
}
}
myInterface.output()
return res
}
地平线二面:
说了一系列场景问我怎么从日志中定位出请求,想让我回答链路监控
redis内存满的情况,我回答LRU和横向扩容
集群如何保证高可用? 我回答AOF RDB 哨兵
Mysql 可以不设主键创建表吗?主键的目的?什么情况会死锁?
写代码:大文件读,文件中每一行是用户ID,一个已知的RPC接口是根据ID获取Mail,输出ID文件对应的Mail文件
package main
import (
"bufio"
"errors"
"os"
"sync"
)
func GetMailById(id string)string{
return ""
}
func readDoc(p int64, wg *sync.WaitGroup, myChan *chan string)error{
defer wg.Done()
file, err := os.Open("./userid")
file.Seek(p,1)
//mailfile ,err := os.Open("./mail"+string(p)+".txt")
if err != nil{
return errors.New("open file error")
}
defer file.Close()
buf := bufio.NewReader(file)
for{
id ,_, err := buf.ReadLine() ///
if err != nil{
return errors.New("open file error")
}
//mail := GetMailById(string(id))
//mailfile.Write([]byte(mail))
*myChan <- string(id)
}
}
func GetMail(){
var wg sync.WaitGroup
wg.Add(10)
var myChan = make(chan string)
for i:=0;i<100000;i+=10000{
go readDoc(int64(i),&wg,&myChan)
}
wg.Wait()
}
百度一面:
Go:讲一下map,是并发安全的吗?那如何做到并发安全?(我答使用sync.map或者加锁控制)常用什么锁?读写锁的工作机制?一种情况:大量协程对一个对象加读锁,导致写锁加不上的情况如何处理?协程线程的区别?创建的开销都包括什么?defer关键字的特性?一种情况:在一个函数内部创建了协程,协程中引发Panic,外层函数能否捕获?(捕获不到啊!)map和slice是值传递吗?slice扩容机制?go run命令执行时都发生什么了?
package main
import "fmt"
func expe (){
var myChan chan int
close(myChan)
myChan <- 1
}
func main(){
defer fmt.Print("主函数退出前")
defer func() {
if r := recover(); r != nil {
fmt.Printf("捕获到的错误:%s\n", r)
}
}()
go expe()
}
redis: 说一下数据结构,zset底层?跳表的插入,查找时间复杂度?zset的插入,查找时间复杂度?redis雪崩,击穿,穿透的情况和预防方法?(穿透:在接口中对参数进行校验)那ID很大这种非法参数如何校验?(用一个计数器存放ID的最大值,计数器存在redis当中)
Redis命令时间复杂度查询表 - liuxinyu123 - 博客园
聊聊Mysql索引和redis跳表 ---redis的有序集合zset数据结构底层采用了跳表原理 时间复杂度O(logn)(阿里) - aspirant - 博客园
https说一下,具体的证书验签过程?能说一下CSRF攻击吗?
Linux:awk命令用过吗?如何查找日志中某个IP的PV?
Linux服务器问题排查思路及常用命令 - 晓呆 - 博客园
代码实现:一个生产者,每次从【-50,50】中获取一个随机数,两个消费者并发去读,一个只消费正数,一个只消费负数。(这题写的稀碎)
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func CreateRandom()int{
res := rand.Int31n(50)
zf := rand.Int31n(2)
switch zf {
case 0: res = 0 - res
}
return int(res)
}
type Producer struct{}
type Consumer struct {
}
func (p *Producer)Produce(zhengChan *chan int,fuChan *chan int){
data := CreateRandom()
if data >= 0 {
*zhengChan <- data
}else{
*fuChan <- data
}
}
func (c *Consumer)ConsumeZheng(zhengChan * chan int,wg *sync.WaitGroup){
for data := range *zhengChan{
fmt.Println("consumer zheng:", data)
wg.Done()
}
}
func (c *Consumer)ConsumeFu(fuChan * chan int,wg *sync.WaitGroup){
for data := range *fuChan{
fmt.Println("consumer fu:", data)
wg.Done()
}
}
func main(){
var p Producer
var zhengChan = make(chan int,100)
var fuChan = make(chan int,100)
var wg sync.WaitGroup
wg.Add(100)
var c Consumer
go c.ConsumeZheng(&zhengChan,&wg)
go c.ConsumeFu(&fuChan,&wg)
rand.Seed(time.Now().Unix())
for i:=0;i<100;i++{
//time.Sleep(time.Second*1)
p.Produce(&zhengChan,&fuChan)
}
wg.Wait()
close(zhengChan)
close(fuChan)
}