groupcache 架構(gòu)設(shè)計

groupcache 是一個分布式緩存 go 語言庫,支持多節(jié)點互備熱數(shù)據(jù)滞造,有良好的穩(wěn)定性和較高的并發(fā)性。

這里有個簡單的應(yīng)用場景:

groupcache.png

當(dāng) GET foo 打到 groupcache-1 后:

  1. groupcache-1 先看看自己的 cache 里有沒有 foo,有的話直接返回
  2. 要是沒有露筒,看看這個請求歸不歸自己管,若是敌卓,去 DataSever 獲取慎式,否則問 group-2(假設(shè) foo 歸 -2管) 要數(shù)據(jù),成功返回后 groupcache-1 本地也緩存一份
  3. 在 2 過程中,所有后來打到 groupcache-1 的 GET foo 都會阻塞瘪吏,直到第一個請求返回

問題來了癣防,如何判斷 foo 由誰來處理?

consistenthash.png

如上圖掌眠,利用hash將所有節(jié)點平均打散到全集蕾盯,然后當(dāng) foo 進來后用相同hash算法就會得到一個唯值,落在那個區(qū)間就屬于那個節(jié)點蓝丙,要保證一致性级遭。

因為 foo 和某資源一一對應(yīng),這就要求 groupcache 只有 get 沒有 update渺尘。

一個簡單的HTTP groupcache Server:

package main

import "github.com/golang/groupcache"

import "github.com/gin-gonic/gin"
import "net/http"
import "time"
import "bytes"

// 虛擬文件生成方法
func generateThumbnail(fileName string) []byte {
    return []byte("fake file")
}

func main() {
    // 本機 ip
    me := "http://10.0.0.1"
    peers := groupcache.NewHTTPPool(me)
    // 設(shè)置互備的 node
    peers.Set("http://10.0.0.1", "http://10.0.0.2", "http://10.0.0.3")
    // 創(chuàng)建一個 cache group挫鸽,最大緩存為64M
    var thumbNails = groupcache.NewGroup("thumbnail", 64<<20, groupcache.GetterFunc(
        func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
            fileName := key
            dest.SetBytes(generateThumbnail(fileName))
            return nil
        }))

    // 設(shè)置 thumbnail 的 peers
    groupcache.RegisterPeerPicker(func() groupcache.PeerPicker {
        return peers
    })

    // 起一個 HTTP server
    server := gin.Default()
    server.GET("/files/:name", gin.HandlerFunc(
        func(ctx *gin.Context) {
            var data []byte
            name := ctx.Param("name")
            // 獲取緩存
            err := thumbNails.Get(ctx, name, groupcache.AllocatingByteSliceSink(&data))
            if err != nil {
                ctx.JSON(http.StatusBadRequest, gin.H{"mesage": "file not found"})
                return
            }
            // 返回給客戶端
            http.ServeContent(ctx.Writer, ctx.Request, name, time.Now(), bytes.NewReader(data))
        }))
    server.Run("10.0.0.1:80")
}

Group

groupcache.NewGroup(addr string)
Group 代表一個 cache資源庫

type Group struct {
    name       string
    getter     Getter // cache 沒有命中,從數(shù)據(jù)庫獲取
    peersOnce  sync.Once 
    peers      PeerPicker // peer 節(jié)點調(diào)度器
    cacheBytes int64 // 最大cache字節(jié)數(shù)
    mainCache cache // 此節(jié)點緩存
    hotCache cache // 其他節(jié)點緩存
    loadGroup flightGroup // 請求并發(fā)控制器
    Stats Stats // 統(tǒng)計數(shù)據(jù)
}

對于一個 Group 來說鸥跟,會緩存自己節(jié)點的數(shù)據(jù)和訪問比較頻繁的 peer節(jié)點 的數(shù)據(jù)丢郊,用LRU算法控制緩存。

當(dāng) cache 沒有命中的時候医咨,首先看看這個請求歸不歸該節(jié)點管枫匾,若是就是調(diào)用 getter:

Getter

type Getter interface {
    Get(ctx Context, key string, dest Sink) error
}

對于一個 cache 來說,他不知道如何拉取需要緩存的數(shù)據(jù)拟淮,所以他說啊干茉,你要是想緩存新的東西,就得有個 type 實現(xiàn) Getter 接口很泊,然后給我一個 Getter 對象角虫,這樣cache沒有命中的時候我能靠這個對象拉取數(shù)據(jù)。

這個 Getter 類似于 http.Handler撑蚌,抽象拉取要緩存的數(shù)據(jù)這個行為上遥,Context(interface{}) 是操作的附帶信息,key 請求的 id争涌,Sink 類似于 http.ResponseWriter粉楚,抽象了數(shù)據(jù)載體的行為:

Sink

type Sink interface {
    // SetString 寫入 string
    SetString(s string) error

    // SetBytes 寫入字節(jié)數(shù)組,調(diào)用者會保留 v 引用
    SetBytes(v []byte) error

    // SetProto 寫入proto.Message亮垫,調(diào)用者會保留 m 應(yīng)用
    SetProto(m proto.Message) error

    // ...
}

groupcache 提供了一些常用的 Sink 如 StringSink模软,BytesSliceSink 和 ProtoSink,這個 proto 是github.com/golang/protobuf/proto饮潦,groupcache 規(guī)定內(nèi)部 peer 節(jié)點之間數(shù)據(jù)通信格式使用 google/protobuf燃异,為了抽象 peer 節(jié)點,定義了 ProtoGetter:

ProtoGetter

type ProtoGetter interface {
    Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error
}

pb.GetRequestpb.GetResponse 定義了請求和響應(yīng) struct继蜡,這個抽象可以分離底層傳輸方式回俐。

當(dāng)然還需要對節(jié)點調(diào)度器抽象逛腿,PeerPicker:

PeerPicker

type PeerPicker interface {
    // PickPeer 根據(jù) key 返回應(yīng)該處理這個 key 的節(jié)點
    // ok 為 true 代表找到了節(jié)點
    // nil, false 代表當(dāng)前節(jié)點就是 key 的處理器
    PickPeer(key string) (peer ProtoGetter, ok bool)
}

調(diào)度器主要負(fù)責(zé)根據(jù)管理 key 和節(jié)點的一致性映射。

groupcache 實現(xiàn)了一個 HTTP 的 PeerPicker仅颇,HTTPPool单默。

至此,groupcache 通過 Getter忘瓦,PeerPicker搁廓,ProtoGetter 三個 interface 定義了cache,節(jié)點和調(diào)度器之間的連接方式耕皮,可以有效地控制耦合度境蜕,也提供了比較大的靈活性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凌停,一起剝皮案震驚了整個濱河市粱年,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苦锨,老刑警劉巖逼泣,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趴泌,死亡現(xiàn)場離奇詭異舟舒,居然都是意外死亡,警方通過查閱死者的電腦和手機嗜憔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門秃励,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吉捶,你說我怎么就攤上這事夺鲜。” “怎么了呐舔?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵币励,是天一觀的道長。 經(jīng)常有香客問我珊拼,道長食呻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任澎现,我火速辦了婚禮仅胞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剑辫。我一直安慰自己干旧,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布妹蔽。 她就那樣靜靜地躺著椎眯,像睡著了一般挠将。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上编整,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天捐名,我揣著相機與錄音,去河邊找鬼闹击。 笑死镶蹋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赏半。 我是一名探鬼主播贺归,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼断箫!你這毒婦竟也來了拂酣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤仲义,失蹤者是張志新(化名)和其女友劉穎婶熬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體埃撵,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡赵颅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了暂刘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饺谬。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖谣拣,靈堂內(nèi)的尸體忽然破棺而出募寨,到底是詐尸還是另有隱情,我是刑警寧澤森缠,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布拔鹰,位于F島的核電站,受9級特大地震影響贵涵,放射性物質(zhì)發(fā)生泄漏列肢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一独悴、第九天 我趴在偏房一處隱蔽的房頂上張望例书。 院中可真熱鬧,春花似錦刻炒、人聲如沸决采。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽树瞭。三九已至拇厢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晒喷,已是汗流浹背孝偎。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凉敲,地道東北人衣盾。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像爷抓,于是被迫代替她去往敵國和親势决。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蓝撇,服務(wù)發(fā)現(xiàn)果复,斷路器,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • 原文出處: 楊步濤的博客 一渤昌、 設(shè)計理念 1. 空間換時間1) 多級緩存虽抄,靜態(tài)化客戶端頁面緩存(http head...
    CookieziSui閱讀 2,503評論 0 48
  • 問題導(dǎo)讀: 1.如何構(gòu)建高并發(fā)電商平臺架構(gòu) 2.哈希、B樹独柑、倒排迈窟、bitmap的作用是什么? 3.作為軟件工程師群嗤,...
    MaLiang閱讀 5,112評論 1 70
  • 高并發(fā)平臺架構(gòu) 設(shè)計理念 1. 空間換時間 多級緩存菠隆,靜態(tài)化前端頁面緩存(HTTP Header中包含Expire...
    AkaTBS閱讀 3,017評論 0 13
  • 一直以來兵琳,甲班之夜都是有人來分享狂秘,然后其他小伙伴默默的聽,然后提問偶爾冒冒泡躯肌,于是今天者春,我換了一種方式,讓大家做主...
    雜草袁閱讀 345評論 2 0