2011-07-29 52 views
19

在Django文檔,它說的:django如何處理多個memcached服務器?

...

的Memcached的一個極好的特性是它在 多個服務器共享緩存的能力。這意味着您可以在多臺 機器上運行Memcached守護進程,並且該程序會將該組機器視爲單個的 緩存,而無需在每臺機器上覆制緩存值。至 利用此功能,包括位於 LOCATION中的所有服務器地址,以分號或列表分隔。

...

Django's cache framework - Memcached

究竟是如何工作的呢?我在這個網站上讀到了一些答案,表明這是通過基於密鑰哈希的服務器進行分片來完成的。

Multiple memcached servers question

How does the MemCacheStore really work with multiple servers?

這很好,但我需要一個更具體的,詳細的解答比。使用django與pylibmc或python-memcached如何實際執行分片?配置設置中的IP地址順序是否重要?如果運行同一個django應用程序的兩個不同的web服務器有兩個不同的設置文件,其中memcached服務器的IP地址以不同的順序排列?這會導致每臺機器使用不同的分片策略,導致重複密鑰和其他低效率?

如果一個特定的機器出現兩次,該怎麼辦?例如,如果我要這樣做127.0.0.1實際上與172.19.26.240相同的機器,那該怎麼辦?

CACHES = { 
    'default': { 
     'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 
     'LOCATION': [ 
      '127.0.0.1:11211', 
      '172.19.26.240:11211', 
      '172.19.26.242:11211', 
     ] 
    } 
} 

如果其中一個memcached服務器的容量比其他容量更大,該怎麼辦?如果機器有64MB memcached,機器2有128MB,那麼sharding算法是否會考慮到這一點,併爲機器2提供更大比例的密鑰?

我也讀過,如果一個memcached服務器丟失,那麼這些密鑰丟失。涉及分片時,這很明顯。更重要的是,如果memcached服務器出現故障,我將其IP地址保留在設置文件中會發生什麼情況? django/memcached會不會得到任何已經分解到失敗服務器的密鑰,還是會意識到服務器已經失敗並提出了新的分片策略?如果存在新的分片策略,它是否智能地將最初用於故障服務器的密鑰分開並將它們分配到剩餘的服務器中,或者是否提出了一個全新的策略,就好像第一個服務器不存在一樣,導致密鑰被複制?

我嘗試閱讀python-memcached的源代碼,但根本找不到這個。我打算嘗試閱讀libmemcached和pylibmc的代碼,但我想如果有人已經知道,在這裏問問會更容易。

回答

13

這是執行分片的實際memcached客戶端。 Django只將settings.CACHES的配置傳遞給客戶端。

服務器的順序並不重要*,但(至少上python-memcached的),你可以爲每個服務器指定一個「權重」:

CACHES = { 
    'default': { 
     'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 
     'LOCATION': [ 
       ('cache1.example.org:11211', 1), 
       ('cache2.example.org:11211', 10), 
      ], 
} 

我覺得快看在memcache.py(從上python-memcached的),尤其是memcached.Client._get_server應該回答你的問題的其餘部分:

def _get_server(self, key): 
    if isinstance(key, tuple): 
     serverhash, key = key 
    else: 
     serverhash = serverHashFunction(key) 

    for i in range(Client._SERVER_RETRIES): 
     server = self.buckets[serverhash % len(self.buckets)] 
     if server.connect(): 
      #print "(using server %s)" % server, 
      return server, key 
     serverhash = serverHashFunction(str(serverhash) + str(i)) 
    return None, None 

我希望,其他的memcached客戶端以類似的方式來實現。


澄清@Apreche:服務器的順序會在一個案例中的問題。如果您有多個Web服務器,你希望它們都放在同一個memcached的服務器上相同的鍵,你需要用相同的服務器列表與

+0

謝謝!這並沒有完全回答我所有的問題,但它指出了我自己正確回答問題的方向。唯一的錯誤是服務器的順序在一個案例中很重要。如果您有多個Web服務器,並且您希望它們都將相同的密鑰放在相同的Memcached服務器上,則需要使用相同的權重以相同的順序將它們配置爲具有相同的服務器列表。 – Apreche

5

我測試的這部分相同的權重配置它們以相同的順序發現使用Django 1.1和python-memcached的1.44一些有趣的東西。使用2個內存緩存服務器

cache.set('a', 1, 1000)

cache.get('a') # returned 1

在Django上仰視其內存緩存服務器「A」是分片使用2個以外的django設置每個都指向在內存緩存服務器中的一個。我內放原Django的實例和 'A' 被存儲在內存緩存服務器之間的防火牆模擬了一個連接中斷。

cache.get('a') # paused for a few seconds and then returned None

cache.set('a', 2, 1000)

cache.get('a') # returned 2 right away

內存緩存客戶端如果服務器出現故障,庫會更新其分片策略。

然後我刪除了防火牆。

cache.get('a') # returned 2 for a bit until it detected the server back up then returned 1!

當內存緩存服務器下降,回來可以讀取陳舊的數據! Memcache沒有做任何聰明的事情來試圖阻止這一點。

如果您使用緩存策略,將某些內容放入memcache中很長一段時間,並且依賴於緩存失效來處理更新,那麼這真的可能會搞砸了。一箇舊值可以寫入到該鍵,如果你鬆散連接和無效的是,窗口期間提出的「正常」的緩存服務器,當服務器再次訪問,你會讀到陳舊的數據,你不應該能夠至。

還要說明一點:我一直在閱讀有關某個對象/查詢緩存庫,我想約翰尼緩存應該不會這個問題。它沒有明確地使條目失效;相反,它改變了表在更改時緩存查詢的鍵。所以它永遠不會意外讀取舊值。

編輯:我覺得我的筆記約翰尼緩存工作確定是胡扯。 http://jmoiron.net/blog/is-johnny-cache-for-you/表示「每個加載當代的請求都有額外的緩存讀取」。如果世代存儲在緩存本身中,則上述方案可能導致讀取陳舊代。

+0

哇,這很迷人,而且我從未想過。我想你只需要清除掉落的任何memcache服務器。非常有幫助,謝謝! – Apreche

+1

Sean指出[1]逆向問題也是可能的:您也可以從memcached服務器讀取沒有關閉的陳舊數據。似乎唯一安全的解決方案是在重新連接到一個時刷新它們。 [1] https://bugs.launchpad.net/python-memcached/+bug/887765/comments/9 –

2

想到這個問題兩年後加入這個答案有人問,因爲它在搜索排名非常高。由於我們沒有找到Django在何處是說只有分佈式緩存服務器中的一個的情況。

在django 1.4.3上運行的站點,python-memcached 1.51與四個memcached實例通話時,我們發現數據庫查詢的頻率比預期的要高得多。挖futher,我們發現cache.get()爲那個被知道是存在於memcached的實例中的至少一個鍵返回None。當memcached使用-vv選項啓動時,它表明只有一臺服務器提出問題!

很多頭髮被拔掉後,我們切換後端django.core.cache.backends.memcached.PyLibMCCache(pylibmc)和問題走了。