1. 程式人生 > >Golang校招簡歷專案-簡單的分散式快取

Golang校招簡歷專案-簡單的分散式快取

## 前言 前段時間,校招投了golang崗位,但是沒什麼好的專案往簡歷上寫,於是參考了許多網上資料,做了一個簡單的分散式快取專案。 現在閒下來了,打算整理下。 github專案地址:https://github.com/Jun10ng/Gache 裡面還有我整理的一些面試問題,給顆星吧。 --- typora-root-url: ./ --- # Golang校招面試專案-類redis分散式快取 實現一個分散式快取,功能有:LRU淘汰策略,http呼叫,併發快取,一致性雜湊,分散式節點,防止快取擊穿 ## 實現LRU淘汰策略 LRU的資料結構大致如下,上層是一個`map`,key是資料物件的key值,而value值則是指向 下層雙向連結串列的節點,在雙向連結串列中,每個節點儲存的元素是完整的資料物件,包含key值和value。 - get:存在->將元素所在節點提到最前面,不存在->返回失敗 - add:存在->更新,不存在->增加;將元素所在節點提到最前面,判斷是否大於`maxSize` - removeOldest:刪除連結串列最後方的節點 ![](https://img2020.cnblogs.com/blog/1948421/202004/1948421-20200403180308747-1043307662.jpg) ### 程式碼實現 具體程式碼實現看:https://github.com/Jun10ng/Gache/tree/master/lru 定義了三個資料結構 `Value`是golang中的介面型別,可以理解為java中的Object類,是一個能“兜底”所有資料結構的資料型別。 `entry`是一個雙向連結串列儲存的資料結構 `Cache`則是lru核心資料結構,包含一個雜湊表和一個雙向連結串列 ``` type Value interface { //返回佔用的記憶體大小 Len() int } type entry struct { key string value Value } type Cache struct { //允許使用的最大記憶體 maxBytes int64 //當前已使用的記憶體 nbytes int64 ll *list.List cache map[string] *list.Element //某條記錄被移除時的回撥函式,可以是nil OnEvicted func(key string, value Value) } ``` 這裡說一下`OnEvicted`成員,這是一個函式物件,他的作用是,在快取中沒有需要的資料物件時,我們需要去原始資料來源獲取,(redis中沒有,就需要去資料庫中獲取),但是資料來源不唯一,有時候是資料庫,有時候是磁碟,有時候是表格,他們的獲取方式都不相同,所以`OnEvicted`成員傳入的函式,就是自定義的獲取方法。 ## 實現單機併發 具體程式碼實現:https://github.com/Jun10ng/Gache/blob/master/cache.go 上文實現的LRU資料結構並不支援併發,需要加鎖來實現併發,所以使用`sync.Mutex`,在LRU資料結構上封裝,使之實現併發功能。 ``` type cache struct { mu sync.Mutex lru *lru.Cache cacheBytes int64 } ``` cache並沒有new方法,因為採用的是延遲初始化 在add方法中,判斷c.lru是否為nil,如果等於nil再建立 這種方法稱為延遲初始化,一個物件的延遲初始化意味著該物件的 建立將會延遲至第一次使用該物件時。 這個方法在redis中很常見,因為能一定程度上提高效能 ``` func (c *cache) add(key string, value ByteView){ c.mu.Lock() defer c.mu.Unlock() if c.lru == nil{ c.lru = lru.New(c.cacheBytes,nil) } c.lru.Add(key,value) } ``` ## 主體結構 具體程式碼實現:https://github.com/Jun10ng/Gache/blob/master/gache.go 本質上是再進行一次封裝 難道一臺機器就只有一個快取表嗎?你開啟redis的視覺化工具,能看到redis還有16個池呢,所以我們要實現多個快取表。怎麼做?再加一層。試想一下: ``` //groups 例項集合表 groups = make(map[string]*Group) ``` ![](https://img2020.cnblogs.com/blog/1948421/202004/1948421-20200403180322506-988023268.jpg) 我們要實現的資料結構大致是這樣的,是一個儲存`併發cache`的表,這是本專案的核心結構 ``` //這裡的group是例項 type Group struct { name string getter Getter mainCache cache } ``` ## http服務呼叫 具體程式碼實現:https://github.com/Jun10ng/Gache/blob/master/http.go 當請求URL具有字首`/_Gache/`時,則認為該請求為快取呼叫。 約定的請求URL為:`http://XXX.com/_Gache//` `groupname`欄位為主體結構中`groups`中的某個元素的`name`值,由此呼叫。`key`欄位為元素中的元素的`key`值,所以最後邏輯為 ``` groups[groupname][key] ``` ## TODo 一致性雜湊 分散式節點 主要參考資料:https://geektutu.com/post/geecache.html