天天看點

【Golang開發面經】深信服(兩輪技術面)

文章目錄

  • ​​寫在前面​​
  • ​​一面​​
  • ​​了解過切片和數組嗎?有什麼差別?​​
  • ​​那這樣初始化可以嗎?有什麼問題?​​
  • ​​用過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 系統中的使用者層面的線程和核心的線程是一樣的​

​。
【Golang開發面經】深信服(兩輪技術面)

那GC有了解過嗎?

Go是采用三色标記法來進行垃圾回收的,是傳統 Mark-Sweep 的一個改進,它是一個并發的 GC 算法。​

​on-the-fly​

原理如下

  1. 整個程序空間裡申請每個對象占據的記憶體可以視為一個圖, 初始狀态下每個記憶體對象都是白色标記。
  2. 先​

    ​stop the world​

    ​,将掃描任務作為多個并發的goroutine立即入隊給排程器,進而被CPU處理,第一輪先掃描所有可達的記憶體對象,标記為灰色放入隊列
  3. 第二輪可以恢複start the world,将第一步隊列中的對象引用的對象置為灰色加入隊列,一個對象引用的所有對象都置灰并加入隊列後,這個對象才能置為黑色并從隊列之中取出。循環往複,最後隊列為空時,整個圖剩下的白色記憶體空間即不可到達的對象,即沒有被引用的對象;
  4. 第三輪再次​

    ​stop the world​

    ​​,将第二輪過程中新增對象申請的記憶體進行标記(灰色),這裡使用了​

    ​writebarrier​

    ​(寫屏障)去記錄這些記憶體的身份;

這個算法可以實作 ​

​on-the-fly​

​,也就是在程式執行的同時進行收集,并不需要暫停整個程式。

mysql 有用過吧?MVCC 是怎麼實作的?

MVCC 的目的就是多版本并發控制,在資料庫中的實作,就是為了解決讀寫沖突,它的實作原理主要是依賴記錄中的​

​ 3個隐式字段,undo日志 ,Read View​

​ 來實作的。是以我們先來看看這個三個 point 的概念

  1. 隐式字段
每行記錄除了我們自定義的字段外,還有資料庫隐式定義的 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,​

    ​隐含的自增 ID(隐藏主鍵)​

    ​,如果資料表沒有主鍵,InnoDB 會自動以DB_ROW_ID ,産生一個聚簇索引。
  1. undo日志
  • insert undo log:代表事務在 insert 新記錄時産生的 undo log,隻在事務復原時需要,并且在事務送出後可以被立即丢棄。
  • update undo log:事務在進行 update 或 delete 時産生的 undo log ,不僅在事務復原時需要,在快照讀時也需要;是以不能随便删除,隻有在快速讀或事務復原不涉及該日志時,對應的日志才會被 purge線程統一清除。
  1. Read View

Read View 就是事務進行 快照讀 操作的時候生産的 讀視圖 (Read View),在該事務執行的快照讀的那一刻,會生成資料庫系統目前的一個快照,​

​記錄并維護系統目前活躍事務的 ID​

​ (當每個事務開啟時,都會被配置設定一個 ID , 這個 ID 是遞增的,是以最新的事務,ID 值越大)。

【Golang開發面經】深信服(兩輪技術面)

mysql 的鎖是怎麼實作的?

當時确實沒了解如何實作的,隻知道如何for update這些,可以看這篇部落格,很詳細了。

​​​Mysql鎖機制及原理簡析​​

用過gin是吧?gin是怎麼處理請求的?

Gin其實是通過一個context來進行上下文的傳遞,将這個傳遞參數,參數傳回。

如果有一個業務給你,你怎麼寫這個請求?

首先肯定是傳統的MVC模型來進行操作。

controller層來接受請求,service層來進行請求的處理,dao層來寫sql語句。

算法:将重複的元素移到最後

二面

二面基本都是跟着項目走。

如果你的系統突然多了10w的通路量,你要怎麼處理?

  1. nginx來進行負載均衡。
  2. 使用者驗證的資訊的過期時間設定長一點,以免發生緩沖雪崩的問題。
  3. 設定布爾過濾器。
  4. 檢查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 是節點所儲存的成員對象。

繼續閱讀