Golang校招簡歷專案-簡單的分散式快取
阿新 • • 發佈:2020-04-03
## 前言
前段時間,校招投了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