當前位置:
首頁 > 知識 > Python + Memcached: 在分散式應用程序中實現高效緩存

Python + Memcached: 在分散式應用程序中實現高效緩存


Python部落(python.freelycode.com)組織翻譯,禁止轉載,歡迎轉發。




在開發Python程序時,實現緩存是重要的一環。緩存技術能夠在很大程度上提升性能,從而避免數據的重複計算,或是資料庫訪問過慢的問題。



Python內置了實現緩存的技術,包括簡單的字典和諸如functools.lru_cache之類更加完整的數據結構。後者可以利用「最近最少使用」演算法限制緩存的大小,做到任意緩存。




然而,依照定義,這些數據結構僅限於Python進程內部使用。這可能對大規模分散式應用導致問題,因為當你的程序的多個副本在大規模平台上運行時,使用這種本地內存中的數據結構將不允許對所緩存的內容進行共享。



因此,如果你的系統是基於分散式網路的,就需要緩存也基於分散式網路。現如今大量的網路伺服器提供了緩存能力--我們在how to use Redis for caching with Django (如何使用Redis實現Django緩存)一文中已經提到過。




在這篇教程中你將看到,memcached是實現分散式緩存的一個很好的選擇。首先是對基本的memcached使用方法的簡介,然後你會學習到一些高級方法,比如檢查和設置(cache and set),以及使用後備緩存以避免傳統的緩存性能問題。




安裝memcached





Memcached提供了[很多平台的版本](https://github.com/memcached/memcached/wiki/Install) :




  • 如果你運行的是

    Linux

    ,安裝命令是 apt-get install memcached 或 yum install memcached 你既可以通過預構造的安裝包安裝,也可以從源文件安裝



  • 對於

    macOS

    ,使用Homebrew安裝是最簡單的。只要有Homebrew包管理器,直接運行 brew install memcached 



  • 對於

    Windows

    , 你需要自行編譯memcached,或者尋找預編譯的版本




安裝完畢後,運行memecached命令即可啟動它:



$ memcached


在正式使用memcached的功能之前,你還需要安裝一個memcached的客戶端庫。下面介紹安裝的方法,以及基本的緩存訪問操作。




使用Python存儲和檢索緩存值




即便你從未使用過memcached,也很容易理解。基本來說,memcached提供了一個超大的網路字典。這個字典的幾個屬性不同於經典的Python字典:




  • 鍵和值都必須是bytes(位元組)



  • 到了過期時間後,鍵和值將被自動刪除




因此,與memcached交互的兩個基本操作是:set和get。正如你可能猜到了,他們分別表示給某個鍵賦值,和從某個鍵取值。




我個人偏愛的與memcached交互的Python庫是 pymemcache,推薦使用。它用pip就可以安裝:



$ pip install pymemcache




以下代碼顯示了如何連接memcached和如何在你的Python程序中將它用作網路分散式緩存:



memcached網路協議十分簡單,其實現運行起來也非常快,使得它在數據存儲上很管用。換作其他技術,這些數據要麼訪問起來很慢,要麼需要重新計算。




這個例子簡單明了,卻演示了鍵值的跨網路存儲,以及程序的多個分散式副本如何來訪問鍵值。很簡單,卻很強大。這是很棒的邁向程序優化的第一步。




緩存數據的自動過期





在memcached中存儲數據時,你可以設置過期時間,即mecached保存鍵和值的最長時間,單位是秒。到期以後,memcached會自動從緩存中刪除他們。




過期時間應該設多長呢?沒有一個直接的答案,過期時間完全取決於你處理的數據和程序的類型。可能是幾秒鐘,也可能是幾個小時。




「緩存失效」定義了當緩存中的數據與當前數據不一致時,什麼時候刪除緩存數據,這也是你的程序必須處理的問題,尤其是在不得不呈現已經過時或過於陳舊的數據的情況下。




重申一下,沒有直接的答案;過期時間取決於你構造的程序類型。不過,有幾類外圍情況需要處理,我在上面的例子中尚未涉及。



緩存伺服器不能無限增長--內存是有限資源。因此,伺服器一旦需要更多的空間來存儲其他東西,就會立即清空已有的鍵。




有些鍵由於到了過期時間(有時叫做生存周期,或TTL),會變無效。在這些情況下,數據會丟失,並且必須再次重新從標準數據源查詢。




聽上去比實際情況更加複雜。通常來說,你在Python中使用memcached可以遵循以下方式:




註:由於存在清理操作,處理丟失的鍵是一定要做的。此外,像memcached剛剛啟動這種冷緩存的情況也必須進行處理。在這種情況下,緩存是全空狀態,需要一次載入一個請求,直至充分填滿。




這意味著說,任何緩存的數據都應視作是臨時性的。而且,千萬不要期望緩存中包含你先前寫入的值。




冷緩存的預熱





有些冷緩存的情況是無法避免的,比如memcached發生了崩潰。而有些冷緩存情況,比如遷移到一個新的memcached伺服器,是可以避免的。




當你預見會發生冷緩存的情況時,最好避開它。一個需要重新填滿的緩存。意味著突然之間,所有缺少緩存數據的用戶會大量地訪問標準數據源。這種現象也稱作「驚群效應」。



pymemcache庫提供了一個名為FallbackClient的類來實現這種場景,如下所述:



FallbackClient類能夠依照順序,查詢傳遞給構造函數的老的緩存。這種情況下,總是優先查詢新的緩存伺服器。如果未命中,則查詢老的緩存,從而避免來回查詢主數據源的可能。




鍵會被設置到新的緩存中。一段時間後,可以淘汰老的緩存,然後用new_cache客戶端直接替換FallbackClient




檢查和設置




在與緩存進行遠程通信時,可能發生常見的並發性問題,即有多個客戶端嘗試同時訪問同一個鍵。Memcached提供了一個叫做檢查和設置(check and set)的操作,縮寫CAS,來解決這一問題。




最簡單的例子比如,有個程序希望統計它的用戶數。每當有用戶連接時,計數器加一。用memcached,簡單實現起來是這樣子的:



然而,如果這個程序的兩個實例嘗試同時更新這個計數器,情況會怎樣呢?




第一個client.get("visitors")調用會返回相同的用戶數,比方說是42。兩個實例同時加一,結果是43,但是43是錯的,正確的結果應該是42+1+1 = 44。




通過CAS操作解決並發問題,就很方便。以下的片段實現了一個正確的方案。



類似於get方法,gets方法既返回鍵值,又返回CAS值。




值的內容是無關的,但在下一次cas方法的調用中會用得著。除了值的內容自gets操作後發生了變化就會導致運行失敗,這個方法等同於set操作。運行成功時,循環是中斷的,否則操作會從頭開始。




當程序的兩個實例嘗試同時更新計數器時,只有一個實例可以成功地將計數器從42加到43。另一個實例會由client.cas調用返回一個「假」值,只能再次走一遍循環。這次它會得到43,加1得到44,且cas調用會成功完成,從而解決了我們的問題




增加計數器這個例子的有趣之處在於,簡單地解釋了CAS的工作原理。其實,memcached其實提供了incr和decr方法,可以在單個請求中遞增或遞減,而無需多次調用gets / cas 。 現實中的程序中使用gets/cas來實現更加複雜的數據類型或者操作。




大多數的遠程緩存伺服器和數據存儲都提供了類似的方法,以防止出現並發性問題。了解和合理的使用這些方法至關重要。




更多緩存知識




這篇教程演示了使用memcached來提高Python程序的性能是多麼的容易。


只要執行兩個基本的"set"和"get"操作,你就可以加速數據檢索,或者避免反覆的計算結果。有了memcache,你可以在大量的分散式節點間實現緩存的共享。




另外,類似CAS操作更高級的方法允許你跨多個Python線程/進程並發地更新緩存中的數據,同時不破壞這些數據。




如果你有興趣學習更多的高級技巧,寫出更快、擴展性更好的Python程序,可以訪問Scaling Python。它包含了許多高級主題,比如網路分布,排隊系統,分散式哈希演算法,和代碼性能分析。






英文原文:https://realpython.com/blog/python/python-memcache-efficient-caching/


譯者:泰然



喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python程序員 的精彩文章:

用AlphaGo背後的人工智慧做金融投資
【限量閃購】《決戰618》僅售55元包郵,只有兩本

TAG:Python程序員 |