關于Redis與Memcached的一點澄清(譯)

jopen 9年前發布 | 13K 次閱讀 Redis

By youngsterxyf

原文:Clarifications about Redis and Memcached

譯者:youngsterxyf

譯注:本文為Redis的作者所寫

如果你了解我,就會知道我并不是那種認為競品是一件壞事的人。實際上我喜歡用戶有選擇的空間,因此我很少做將Redis與其他技術做對比這類事情。

然而,為了選擇正確的方案,用戶必須獲取正確的知識,這一點也是理所應當的。

本文的起因是讀了Mike Perham寫的一篇博文,你也許知道他是Sidekiq這一流行程序庫的作者,Sidekiq又恰好使用Redis做后端。因此我毫不認為Mike是一個“反對”Redis的人。但在博文(你可以在 http://www.mikeperham.com/2015/09/24/storing-data-with-redis/ 找到這篇博文)中,他陳述到:要用緩存,“你可能應該選擇Memcached(而不是Redis)”。這樣看來,Mike確實簡單地相信Redis不適合用做緩存,在文章中他是這樣論述的:

  • 1) Memcached專為緩存而設計
  • 2) 它根本不會有磁盤I/O操作
  • 3) 它是多線程的,在多核上能線性擴展到每秒處理100,000個請求
  • </ul>

    我會一一辯駁以上陳述,之后會提供進一步的信息,這些信息在上面的句子中并沒有得到表達,但在我看來與緩存用戶及用例更加相關。

    Memcached專為緩存而設計:我會跳過這個,因為這并不是一個論點。我同樣可以說“Redis專為緩存而設計”。因此,就這一點而言,它們是一樣的,我們接著來看下一個論點。

    它根本不會有磁盤I/O操作:使用Redis時,你可以按需求禁用磁盤I/O,所有操作就是純內存的了。此外,若你確實需要,可以只在重啟Redis之時持久化數據庫,例如:使用“SHUTDOWN SAVE”命令。再怎么說,即使你根本不使用Redis持久化功能,它也是一個附加值。

    它是多線程的:確實如此。我的目標是把Redis的I/O線程化(像Memcached那樣,從根本上說數據訪問本身不是線程化的)。然而,Redis,特別是使用流水線(pipeling)模式后,每個線程每秒能處理超大量的請求(使用密集的流水線,通常能達到每秒50萬左右;不使用流水線,也能達到每秒10萬左右)。在普通的緩存場景中 - 每個Redis實例是一樣的、角色為主、禁用磁盤操作、分區由客戶端決定(像“Memcached分區模型”那樣) - 每個系統上運行多個Redis進程并不可怕。一旦你這樣做,得到的就是一套無共享多線程的設置,那么關鍵看的是單個線程能夠處理的操作量了。上一次我檢驗 Redis時,每個線程至少是和Memached一樣快的。內部實現隨著時間在改變,因此如今最新版可能有所出入,但我敢打賭兩者的性能是相近的,因為它們都竭盡所能利用了能夠使用的資源。Memcached的多線程仍然是個優勢,因為它讓一切更易于使用和管理,但我認為這不是關鍵性的部分。

    再說一點。Mike在談及每秒執行的操作時,并未說明操作的 *質量*。在Redis與Memached這類系統中,相比真正地獲取內存數據結構中的數據,命令分發和I/O的代價是主要的。因此本質上在Redis中執行一個簡單的GET、SET或一個復雜操作如ZRANK操作,其代價基本是相同的。但是從應用層的角度來看,通過復雜操作能節省很多工作。也許無需分5 次獲取緩存數據,你只要發送一個簡短的Lua腳本就能搞定。因此這兩個系統實際的“可擴展性”有許多維度,你能得到是其中之一。

    Mike關注的幾點問題,我認為唯一有根據的是多線程那個,如果我們將特殊用例下的Redis看做是Memcached的替代品,執行多個 Redis進程也能反駁“Memcached多線程更好”這個觀點,或者簡單地執行一個Redis進程也行,因為做Memcached那樣的操作要想打滿一個線程是非常非常難的。

    真正的區別

    現在是時候談論兩個系統之間的真正區別了。

    • 內存效率
    • </ul>

      這一點Memcached曾比Redis做得好。在一個被設計為用字典化字符串存儲普通字符串的系統中,更好地利用內存相對會更簡單。這一區別并不顯著,而且大約有5年我沒去檢驗這一點了,但曾經是值得注意的。

      然而,如果我們考慮一個長期運行的進程的內存效率,事情就有些不同了。具體細節請讀下一節。

      但是在真正評估內存效率時,你應該記得考慮:Redis中特殊編碼的小型聚合值內存效率非常高。例如:小整數集合在內存存儲為一個8、16、32或64位整數的數組,當需要檢查某些整數是否存在時,對數級時間就能訪問到,因為這個數組是有序的,因為可以使用二分查找。

      當你使用哈希來存儲對象而不是借助JSON時,同樣如此。因此,真正的內存效率必須基于手頭的應用案例來評估。

      • Redis LRU vs Slab內存分配器
      • </ul>

        從內存利用的角度來看,Memcached并不完美。如果你恰好有個應用隨著時間會改變緩存數據的尺寸大小,很可能會導致嚴重的內存碎片問題,而唯一的解決方法就是重啟應用。從這一視角來看,Redis對內存的利用不會變化莫測。

        此外,Redis的LRU最近優化了很多,現在非常接近真正的LRU。進一步的信息可閱讀:http://redis.io/topics/lru-cache。如果我沒理解錯的話,Memcached的LRU依舊是根據它的slab分配器來判斷數據過期的,因此有時其行為與真正的LRU相差甚遠,但我希望這方面的專家能夠針對這個問題說點什么。如果你想測試Redis的LRU,在最近幾個版本的Redis中可以使用redis-cli的LRU測試模式。

        • 智能緩存
        • </ul>

          如果你想把Redis用作緩存,并且像Memcached那樣使用,那你就真的要錯失一些東西了。在我看來,這是Mike那篇博文中的最大錯誤。越來越多的人從Memcached切換到Redis,是因為他們發現可以以更有用的方式來表現緩存數據。如何保持只緩存某個東西的最新N項數據?使用“脫帽”列表(原文為:capped list)。想獲取一個緩存的流行指數?使用一個有序集合,等等。

          • 持久化和復制
          • </ul>

            若你需要,那它們就是重要的優勢。例如:使用這一模型擴展高負載的緩存讀操作就非常簡單;基于持久化 - 按期快照緩存數據 - 重啟服務而不丟緩存數據也很簡單;諸如此類等等。但是對有些用法來說,這兩個特性確實無關緊要。這里我想表達的是存在一些“純緩存”的應用案例,其中持久化和復制也很重要。

            • 可觀測性
            • </ul>

              Redis提供了很多方式以便于觀測Redis運行時的行為狀態。它提供大量內部度量的詳細報告,你可以掃描數據集,觀察對象的有效期。可以調優LRU算法。可以為客戶端連接命名并使用CLIENT LIST來查看關于它們的報告。可以使用MONITOR命令來調試你的應用,以及其他高級事項。我相信這是一大優勢。

              • Lua腳本編程能力
              • </ul>

                我相信在很多緩存應用案例中,Lua腳本編程能力都是一大助力。例如:如果你有一個JSON緩存數據塊,使用一個Lua命令可以抽取其中某個字段并將其返回給客戶端,而不需要傳輸所有東西(從概念上來說,直接使用Redis哈希來表現對象,也可以做到)。

                結論

                Memcached是一個偉大的軟件,我多次閱讀其源碼,對于我們產業來說,它是一個革命,你應該自己查明對你來說,相比 Redis,Memcached是否是更好的選擇。然而,一切事物都必須如實評估。讀到Mike的報告或這些年來讀到的類似報告都讓我有些惱怒了,所以我決定亮一亮自己的觀點。如果你發現有些事情事實上我說得不對,請聯系我,我會以“校訂”一節來更新這篇博文。

                </div> 來自:http://blog.xiayf.cn/2015/12/01/redis-vs-memcached/

                 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
                 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
                 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!