2013-08-28 55 views
13

我正在編寫一些Go web服務(也使用http.ListenAndServe在Go中實現web服務器)。 我有一個結構圖,我想保留在內存中(大約100Kb的數據大小)以供不同的http請求使用。Golang:在下面的http請求中存儲/緩存要提供的值

哪種方法在Go中實現這一點最好? 根據您的經驗,使用全局包變量或緩存系統(如memcache/groupcache)會更好嗎?

回答

2

不要沉迷於不成熟的優化。定義Go封裝API來封裝數據,然後您可以隨時更改實現。例如,只是塗鴉,

package data 

type Key struct { 
    // . . . 
} 

type Data struct { 
    // . . . 
} 

var dataMap map[Key]Data 

func init() { 
    dataMap = make(map[Key]Data) 
} 

func GetData(key Key) (*Data, error) { 
    data := dataMap[key] 
    return &data, nil 
} 
+0

peterSO,你親自使用哪種實現? –

+1

過早優化和過早泛化都是不好的。 :) –

+0

我可能是錯的,但由於數據將被持久保存在併發的請求中,所以任何對擁有它的全局變量的訪問都應該被互斥鎖保護。 – kostix

3

仍然解決問題的簡單解決方案通常是正確的方法。在服務器本地緩存數據既簡單又有效,即使使用更豐富的系統,也可以在許多情況下完成。

舉個例子,上個月我放了一個快速入門(http://ubuntu-edge.info),由於圍繞衆籌活動傳播的消息花了一些負擔,而且Go進程大部分時間負載很低,在一臺小型EC2機器上。數據很簡單,只是緩存在內存中,從外部進程正在更新的數據庫每分鐘刷新一次。

當我自己做這件事時,我通常會看memcache(現在是groupcache),這意味着它將複製更多的功能。例如,當內存中保存的數據過多時,或者當丟失服務器時可能會影響整個系統的性能,因爲緩存的數據全部消失,或者因爲性能受到爭用的影響。

請注意,groupcache實際上是一個庫,所以您可以將它嵌入到服務器中,而不是將其作爲實際的外部系統。

12

除了您已收到的答案之外,還可以考慮使用接收方兼容method valueshttp.HandlerFunc

如果你的數據是在過程開始之前被加載的數據,你可以像這樣的東西去:

type Common struct { 
    Data map[string]*Data 
} 

func NewCommon() (*Common, error) { 
    // load data 
    return c, err 
} 

func (c *Common) Root(w http.ResponseWriter, r *http.Request) { 
    // handler 
} 

func (c *Common) Page(w http.ResponseWriter, r *http.Request) { 
    // handler 
} 

func main() { 
    common, err := NewCommon() 
    if err != nil { ... } 

    http.HandleFunc("/", common.Root) 
    http.HandleFunc("/page", common.Page) 

    http.ListenAndServe(...) 
} 

如果所有Common數據是隻讀這工作得很好。如果Common數據讀/寫,那麼你會希望有更多的東西一樣:

type Common struct { 
    lock sync.RWMutex 
    data map[string]Data // Data should probably not have any reference fields 
} 

func (c *Common) Get(key string) (*Data, bool) { 
    c.lock.RLock() 
    defer c.lock.RUnlock() 
    d, ok := c.data[key] 
    return &d, ok 
} 

func (c *Common) Set(key string, d *Data) { 
    c.lock.Lock() 
    defer c.lock.Unlock() 
    c.data[key] = *d 
} 

,其餘基本上是一樣的,只不過不是通過接收器的領域直接訪問數據,你會訪問他們通過獲得者和制定者。在讀取大部分數據的網絡服務器中,您可能需要一個RWMutex,以便讀取可以同時執行。第二種方法的另一個優點是你已經封裝了數據,所以你可以添加透明的寫入和/或從memcache或groupcache中讀取,或者在將來如果你的應用程序增長了這樣的需求,就可以添加這種性質的東西。

我真的很喜歡將我的處理程序定義爲對象上的方法的一件事情,它可以使單元測試變得更容易:您可以輕鬆定義一個包含所需值和輸出的table driven test,而無需用全局變量來解決問題。

+0

這種解決方案不適合垃圾收集器,也不適合加載 - 平衡HTTP服務器,因爲每個客戶端都會響應不同的客戶端請求上的不同數據。 –