文章目錄
- 寫在前面
- 一面
- 了解過切片和數組嗎?有什麼差別?
- 那這樣初始化可以嗎?有什麼問題?
- 用過map吧?怎麼周遊map?
- 那周遊 map 是有序的嗎?
- 為什麼是無序的?
- 用過chan吧?怎麼聲明一個chan呢?
- 怎麼發消息給chan呢?
- 給一個關閉的chan發消息會怎麼樣?
- 講講 GMP 吧
- 那GC有了解過嗎?
- mysql 有用過吧?MVCC 是怎麼實作的?
- mysql 的鎖是怎麼實作的?
- 用過gin是吧?gin是怎麼處理請求的?
- 如果有一個業務給你,你怎麼寫這個請求?
- 算法:将重複的元素移到最後
- 二面
- 如果你的系統突然多了10w的通路量,你要怎麼處理?
- redis用過是吧?說說你在項目裡面的排行榜?你說說redis的底層是怎麼處理的?
寫在前面
深信服面試起來感覺有點偏向應用,沒有涉及高并發等等内容,想想也确實,深信服更多偏向B端。業務能力紮實也是應該的。深信服挺好的,但我想找toc的,就拒掉了。。
一面
了解過切片和數組嗎?有什麼差別?
切片的底層其實是數組,數組是不可變長度的,而切片是可變長度的。
那這樣初始化可以嗎?有什麼問題?
var array []int
這種其實不好,因為這樣是不能賦予位址的。是以容易報錯,我們要麼用
make去建立
,要麼用
文法糖 array:=[]int{}
去建立。
用過map吧?怎麼周遊map?
for k,v:=range map{
...
}
那周遊 map 是有序的嗎?
無序的
為什麼是無序的?
不是有序的,使用 range 多次周遊 map 時輸出的 key 和 value 的順序可能不同,map在周遊時,并不是從固定的0号bucket開始周遊的,每次周遊,都會從一個
随機值序号
的bucket,再從其中
随機的 cell
開始周遊。map 周遊時,是
按序周遊 bucket
,同時按需周遊 bucket 和其 overflow bucket 中 的 cell。
但是 map 在
擴容
後,會發生 key 的搬遷,這造成原來落在一個 bucket 中的 key,搬遷後,有可能會落到其他 bucket 中了,從這個角度看,周遊 map 的結果就不可能是按照原來的順序了。
用過chan吧?怎麼聲明一個chan呢?
chan是引用類型,一般我們應該用make去建立一個chan
ch:=make(chan int)
怎麼發消息給chan呢?
ch <- 1
給一個關閉的chan發消息會怎麼樣?
會引起panic
講講 GMP 吧
G:表示goroutine,存儲了goroutine的執行stack資訊、goroutine狀态以及goroutine的任務函數等;另外G對象是
可以重用
的。
P:表示邏輯processor,P 的數量決定了系統内最大可并行的 G 的數量(前提:系統的實體cpu核數 >= P的數量);P的最大作用還是其擁有的各種G對象隊列、連結清單、一些cache和狀态。
M:M 代表着真正的執行計算資源,實體 Processor。
G 如果想運作起來必須依賴 P,因為 P 是它的,但是 P 要想真正的運作,他也需要與 M 綁定,這樣才能真正的運作起來,
邏輯處理單元
。
P 和 M 的這種關系就相當于 Linux 系統中的使用者層面的線程和核心的線程是一樣的
那GC有了解過嗎?
Go是采用三色标記法來進行垃圾回收的,是傳統 Mark-Sweep 的一個改進,它是一個并發的 GC 算法。
on-the-fly
原理如下
- 整個程序空間裡申請每個對象占據的記憶體可以視為一個圖, 初始狀态下每個記憶體對象都是白色标記。
- 先
,将掃描任務作為多個并發的goroutine立即入隊給排程器,進而被CPU處理,第一輪先掃描所有可達的記憶體對象,标記為灰色放入隊列stop the world
- 第二輪可以恢複start the world,将第一步隊列中的對象引用的對象置為灰色加入隊列,一個對象引用的所有對象都置灰并加入隊列後,這個對象才能置為黑色并從隊列之中取出。循環往複,最後隊列為空時,整個圖剩下的白色記憶體空間即不可到達的對象,即沒有被引用的對象;
- 第三輪再次
,将第二輪過程中新增對象申請的記憶體進行标記(灰色),這裡使用了stop the world
(寫屏障)去記錄這些記憶體的身份;writebarrier
這個算法可以實作
on-the-fly
,也就是在程式執行的同時進行收集,并不需要暫停整個程式。
mysql 有用過吧?MVCC 是怎麼實作的?
MVCC 的目的就是多版本并發控制,在資料庫中的實作,就是為了解決讀寫沖突,它的實作原理主要是依賴記錄中的
3個隐式字段,undo日志 ,Read View
來實作的。是以我們先來看看這個三個 point 的概念
- 隐式字段
每行記錄除了我們自定義的字段外,還有資料庫隐式定義的 DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID 等字段
- DB_TRX_ID:6 byte,
:記錄建立這條記錄/最後一次修改該記錄的事務 ID最近修改(修改/插入)事務 ID
- DB_ROLL_PTR:7 byte,
,指向這條記錄的上一個版本(存儲于 rollback segment 裡)復原指針
- DB_ROW_ID:6 byte,
,如果資料表沒有主鍵,InnoDB 會自動以DB_ROW_ID ,産生一個聚簇索引。隐含的自增 ID(隐藏主鍵)
- undo日志
- insert undo log:代表事務在 insert 新記錄時産生的 undo log,隻在事務復原時需要,并且在事務送出後可以被立即丢棄。
- update undo log:事務在進行 update 或 delete 時産生的 undo log ,不僅在事務復原時需要,在快照讀時也需要;是以不能随便删除,隻有在快速讀或事務復原不涉及該日志時,對應的日志才會被 purge線程統一清除。
- Read View
Read View 就是事務進行 快照讀 操作的時候生産的 讀視圖 (Read View),在該事務執行的快照讀的那一刻,會生成資料庫系統目前的一個快照,
記錄并維護系統目前活躍事務的 ID
(當每個事務開啟時,都會被配置設定一個 ID , 這個 ID 是遞增的,是以最新的事務,ID 值越大)。
mysql 的鎖是怎麼實作的?
當時确實沒了解如何實作的,隻知道如何for update這些,可以看這篇部落格,很詳細了。
Mysql鎖機制及原理簡析
用過gin是吧?gin是怎麼處理請求的?
Gin其實是通過一個context來進行上下文的傳遞,将這個傳遞參數,參數傳回。
如果有一個業務給你,你怎麼寫這個請求?
首先肯定是傳統的MVC模型來進行操作。
controller層來接受請求,service層來進行請求的處理,dao層來寫sql語句。
算法:将重複的元素移到最後
二面
二面基本都是跟着項目走。
如果你的系統突然多了10w的通路量,你要怎麼處理?
- nginx來進行負載均衡。
- 使用者驗證的資訊的過期時間設定長一點,以免發生緩沖雪崩的問題。
- 設定布爾過濾器。
- 檢查sql語句,是否符合要求,是否是慢sql,如果是則解決。
redis用過是吧?說說你在項目裡面的排行榜?你說說redis的底層是怎麼處理的?
主要是用redis的zset實作的。
zset主要是跳躍表實作的。
Redis 的跳躍表由
redis.h/zskiplistNode
和
redis.h/zskiplist
兩個結構定義,其中
zskiplistNode
結構用于表示跳躍表節點,而
zskiplist
結構則用于儲存跳躍表節點的相關資訊,比如節點的數量,以及指向表頭節點和表尾節點的指針等等。
- header:指向跳躍表的表頭節點。
- tail:指向跳躍表的表尾節點。
- level:記錄目前跳躍表内,層數
。最大的那個節點的層數
- 記錄跳躍表的長度,也就是,跳躍表目前包含節點的數量。
- 層(level):節點中用L1、L2、L3等字樣标記節點的各個層,L1表示第一層,L2代表第二層,以此類推。每層都帶有兩個屬性:
。前進指針用于方位位于表尾方向的其他節點。而跨度則記錄了前進指針所指向節點和目前節點的距離。前進指針和跨度
- 後退(backward)指針:
節點中用BW字樣标記的後退指針,他指向目前節點的前一個節點。後退指針在程式從表尾向表頭周遊時使用。
- 分值(score):各個節點中的 1.0、2.0、3.0是節點所儲存的分值。在跳躍表中,節點按各個所儲存的分值從小到大排序。
- 成員對象(obj):各個節點中的o1,o2 和 o3 是節點所儲存的成員對象。