天天看點

如何讓你的記憶體中的 NoSQL 資料存儲适合企業級應用

非常幸運的是,現代程式設計語言(例如ruby、node.js、python等)和開發平台(例如rails、sinatra、django等)已經内置了很多工具和開發庫(libraries)。這些工具和開發庫能夠有效利用記憶體資料庫的高性能和各種操作指令,能夠實作目前流行的多種應用項目。

這些開源的示例項目包括作業管理、論壇、實時分析、twitter克隆、地理位置搜尋以及進階緩存等等。

資料庫系統的可用性(availability)、可擴充性(scalability)和性能(performance)對于這些項目的成功至關重要。

本文粗略的介紹如何建構企業真正可用的基于記憶體的nosql資料庫,包括一些技巧和建議;這些技巧和建議能夠解決雲端nosql資料庫管理面臨的七大挑戰。 

<a target="_blank"></a>

無論你做什麼,對于你的應用來說資料必須是時刻可用的。這對于記憶體資料庫尤為重要;因為,如果沒有得當的措施,當下面的情形發生時你的資料将會部分或全部丢失:

節點失敗(在雲(cloud)中經常發生);

程序重新開機(你可能需要不時的進行重新開機);

需要擴充(我們假設你可能需要這個)。

對于情形1和情形2有兩種方式來解決;情形3将在稍後讨論。

複制:你要確定将你的資料儲存一份到叢集的另一節點,如果是另一資料中心則更為可靠,以便應付資料中心發生故障(亞馬遜aws在2012年至少發生了4次故障)。不幸的是事情并非如此簡單。随便就能舉一個複制非常困難的例子:

一旦程式寫的頻率增加,你會發現應用伺服器寫入速度遠大于複制的速度,尤其是在主節點和複制節 點存在網絡擁堵的情形下。一旦這種情況發生,如果資料集大到一定程度,複制節點很有可能永不再 與主節點同步。 

自動切換:為什麼需要這個?記憶體資料庫每秒處理的請求比一般資料庫通常多100倍,這就意味着每增加一秒當機時間就會延遲更多的請求處理并給使用者帶來不好的使用者體驗。在實作自動切換時一定要遵循下面的原則:

1.確定主存儲節點一旦失敗就立馬切換到備用複制節點。這一般基于成熟健壯的看門狗技術 (watchdog),看門狗持續的監控節點,一旦失敗就切換到健康的複制節點。

2.對于你的應用程式而言切換過程要盡量透明;最理想的情況是不需要更改任何配置。更進階的解決方案是僅僅修改dns中存儲節點的ip位址,確定修複過程在幾秒鐘之内完成。

3.自動切換應當基于quorum并且是完全一緻(fully consistent)或最終一緻(eventually consistent)的。讨論下面繼續:

網絡分裂(network splits)在雲中頻繁發生,對地球上的分布式存儲系統而言也是最複雜的問題。一旦發生分裂,應用程式可能隻會發現記憶體資料庫的部分節點;同時,每個記憶體nosql資料庫節點也很有可能隻能發現一部分的其他節點。

為什麼說這是一個非常嚴重的問題呢?如果你的資料庫包含一些隐蔽的設計缺陷,當網絡分裂發生時,應用程式很可能會寫入錯誤的節點。這意味着,當情況恢複時,應用程式發起的寫入就會丢失。這對基于記憶體的nosql資料庫來說這是一個非常有意義的話題,因為基于記憶體的nosql資料庫每秒的寫操作遠大于其他的nosql資料庫系統。

一個設計得當的基于記憶體的nosql是什麼樣子的呢?很不幸,你隻能從下面兩個非常糟糕的候選中選擇一個:

如果基于記憶體的nosql資料庫是完全一緻(fully consistent)的,在某些情況下你是不允許寫入任何内容的,除非網絡分裂恢複。

如果基于記憶體的nosql資料庫是最終一緻(eventually consistent)的,應用程式可以對“讀”請求采用quorum方法——傳回一個值或者阻塞。 

注意——在今天的市場上并不存在最終一緻(eventually consistent)的基于記憶體的nosql資料庫,是以隻有選項1是可以實際應用的方案。

盡管基于記憶體的nosql解決方案提供多種複制選擇,你仍需要着重考慮資料持久化和備份,原因如下:

或許你不希望為記憶體複制提供額外支出,但是仍希望将資料儲存在某個地方并且在遇到節點故障時能夠将資料恢複(即使恢複速度很慢)。

你一定希望在遇到任何故障時都能将資料恢複并且希望保留另外一個選擇——将資料儲存在另外一個安全的地方,即使資料不能與最新的的修改同步。

還有一些采用資料持久化的其他理由,例如為了測試将資料從生産環境導入到過渡環境等

現在你已經确信資料持久化是必要的,在大多數雲環境中你應當使用附屬在雲主機上的儲存設備(像aws的ebs、azure的cloud derive等)。如果你将資料儲存在本地硬碟,當遇到節點故障時你就會丢失資料。

一旦資料得到持久化儲存,你最大的挑戰将變成:在将改變實時寫入到持久化存儲的同時保證記憶體nosql資料庫的速度。

基于記憶體的nosql資料庫(例如redis和memcached)的設計目标是:在毫秒延遲内,每秒鐘能夠處理超過10萬個請求。但是,這個數字在雲環境下是很難達到的,除非你遵循以下的原則:

避免i/o瓶頸,盡量使用功能強大的儲存設備,最好配置了raid。其次,要確定在“突然爆發”的情況下也不能阻塞你的應用。例如,使用開源的redis,你可以配置slave節點進行寫操作;master節點專心處理使用者請求,這樣就能盡量避免“突然爆發”情況下的逾時現象。

如果記憶體資料庫基于單線程架構(例如redis),千萬不要在同一個線程中運作多個資料庫。不然,一個資料庫在執行指令的過程中非常有可能阻塞另外一個資料庫。

大多數雲主機都配置了一塊1gbps網卡。在基于記憶體的nosql資料庫中,該網卡需要完成以下操作:

處理應用請求

叢集内部的互動

複制

存儲通路

這很容易成為運作的瓶頸,是以,這裡提供一些解決該問題的建議:

為每一台雲主機配置10gbps的網卡(要有心理準備,這非常昂貴)

選擇能夠為一些特殊應用配置多塊1gbps網卡的雲提供商,例如aws的vpc

采用能夠在記憶體nosql節點之間高效配置設定資源的解決方案以減小網絡擁塞。

對于簡單的kv(key/value)緩存(例如memcached或者redis的簡單應用),擴充很少被認為是一個很嚴重的問題;因為在大多數情況下,這隻需要在在伺服器清單中增加或删除節點并修改哈希方法。但是,實際經曆過該問題的人就會意識到這是一個非常令人痛苦的問題。對于該話題我們有一些建議:

采用一緻性哈希(hashing)。如果采用簡單的哈希函數(例如求模),在擴充的時候就意味着丢失所有的資料。另一方面,很多人不知道的是:即使采用一緻性哈希函數,在擴充的時候你仍然會丢失部分資料。例如,在擴充的時候你會丢失1/n的資料,n是你擴充後節點的數目。是以,如果n比較小,這仍然是一個非常痛苦的過程(如果對于2個節點的叢集采用一緻性哈希就意味着丢失1/3的資料)。

建構一種方法将擴充操作通知到每一個nosql的用戶端,以便阻止在擴充過程中不同的應用伺服器寫入不同節點。

另一方面,很多人聲稱新一代的超高性能ram能夠解決節點擴充中遇到的大多數問題。但現實與他們的聲稱有所不同,在25gb-30gb資料規模上,對于像redis一樣的記憶體資料庫,還有一些其他方面的問題會阻止擴充的真正實施。這些問題與本文前面提到的挑戰密切相關,像複制、i/o、每核一個線程的架構、網絡開銷等。

基于記憶體的nosql資料庫的運維會産生巨大的額外開銷。它需要對這些技術進行深入了解,以便在緊要關頭做出正确決策。同時,因為這些技術變化頻率很快(可能是非常快),你還要時刻關注這些系統的趨勢和最新修改。

正如我們上面所說的一樣,為了更好的利用redis、memcached等開源技術帶給我們的優勢,我們需要對這些技術進行深入了解和掌握。對于企業的it團隊來說,為了能夠在企業環境中使用基于記憶體的nosql資料庫,了解如何更好的應對這些挑戰就顯得更為重要。不是我持有偏見,我強烈建議尋找一些能夠克服可擴充性和高可用性限制而不損害功能和性能的商業解決方案;因為運作維護基于記憶體的nosql資料庫需要該領域的進階專家,這是非常稀少的。

在市場上有一些關于redis和memcached的nosql服務(nosql-as-a-service);我建議你對每一個可用的服務進行深入的比對(就像diy),以便挑選一個最好的解決方案。能夠實際體驗一下這些服務就更好了,很多服務商為這個目的都提供了免費體驗。

 原文釋出時間為:2013-10-04

本文來自雲栖社群合作夥伴“linux中國”