標籤:
Redis是一個遠程記憶體資料庫,它不僅效能強勁,而且還具有複製特性以及為解決問題而生的獨一無二的資料模型。Redis提供了5種不同類型的資料結構,各式各樣的問題都可以很自然地映射到這些資料結構上:Redis的資料結構致力於協助使用者解決問題,而不會像其他資料庫那樣,要求使用者扭曲問題來適應資料庫。除此之外,通過複製、持久化(persistence)和用戶端分區(client-side sharding)等特性,使用者可以很方便地將Redis擴充成一個能夠包含數百GB資料、每秒處理上百萬次請求的系統。
筆者第一次使用Redis是在一家公司裡面,這家公司需要對一個儲存了6萬個客戶連絡方式的關聯式資料庫進行搜尋,搜尋可以根據名字、郵件地址、所在地和電話號碼來進行,每次搜尋需要花費10~15秒的時間。在花了一周時間學習Redis的基礎知識之後,我使用Redis重寫了一個新的搜尋引擎,然後又花費了數周時間來仔細測試這個新系統,使它達到生產層級,最終這個新的搜尋系統不僅可以根據名字、郵件地址、所在地和電話號碼等資訊來過濾和排序客戶連絡方式,並且每次操作都可以在50毫秒之內完成,這比原來的搜尋系統足足快了 200 倍。
1、Redis簡介
前面對於Redis資料庫的描述只說出了一部分真相。Redis是一個速度非常快的非關聯式資料庫(non-relational database),它可以儲存鍵(key)與5種不同類型的值(value)之間的映射(mapping),可以將儲存在記憶體的索引值對資料持久化到硬碟,可以使用複製特性來擴充讀效能,還可以使用用戶端分區1來擴充寫效能。
2、使用Redis的理由
有memcached使用經驗的讀者可能知道,使用者只能用APPEND命令將資料添加到已有字串的末尾。memcached的文檔中聲明,可以用APPEND命令來管理元素列表。這很好!使用者可以將元素追加到一個字串的末尾,並將那個字串當作列表來使用。但隨後如何刪除這些元素呢?memcached採用的辦法是通過黑名單(blacklist)來隱藏列表裡面的元素,從而避免對元素執行讀取、更新、寫入(包括在一次資料庫查詢之後執行的memcached寫入)等操作。相反地,Redis的LIST和SET允許使用者直接添加或者刪除元素。
使用Redis而不是memcached來解決問題,不僅可以讓代碼變得更簡短、更易懂、更易維護,而且還可以使代碼的運行速度更快(因為使用者不需要通過讀取資料庫來更新資料)。除此之外,在其他許多情況下,Redis的效率和易用性也比關聯式資料庫要好得多。
資料庫的一個常見用法是儲存長期的報告資料,並將這些報告資料用作固定時間範圍內的彙總資料(aggregates)。收集彙總資料的常見做法是:先將各個行插入一個報告表裡面,之後再通過掃描這些行來收集彙總資料,並根據收集到的彙總資料來更新彙總表中已有的那些行。之所以使用插入行的方式來儲存,是因為對於大部分資料庫來說,插入行操作的執行速度非常快(插入行只會在硬碟檔案末尾進行寫入)。不過,對錶裡面的行進行更新卻是一個速度相當慢的操作,因為這種更新除了會引起一次隨機讀(random read)之外,還可能會引起一次隨機寫(random write)。而在Redis裡面,使用者可以直接使用原子的(atomic)INCR命令及其變種來計算彙總資料,並且因為Redis將資料存放區在記憶體裡面2,而且發送給Redis的命令請求並不需要經過典型的查詢分析器(parser)或者查詢最佳化工具(optimizer)進行處理,所以對Redis儲存的資料執行隨機寫的速度總是非常迅速的。
使用 Redis 而不是關聯式資料庫或者其他硬碟儲存資料庫,可以避免寫入不必要的臨時資料,也免去了對臨時資料進行掃描或者刪除的麻煩,並最終改善程式的效能。雖然上面列舉的都是一些簡單的例子,但它們很好地證明了“工具會極大地改變人們解決問題的方式”這一點。
3、Redis與其他資料庫和軟體的對比
如果你熟悉關聯式資料庫,那麼你肯定寫過用來關聯兩個表的資料的SQL查詢。而Redis則屬於人們常說的NoSQL資料庫或者非關聯式資料庫:Redis不使用表,它的資料庫也不會預定義或者強制去要求使用者對Redis儲存的不同資料進行關聯。
高效能索引值快取服務器memcached也經常被拿來與Redis進行比較:這兩者都可用於儲存索引值映射,彼此的效能也相差無幾,但是Redis能夠自動以兩種不同的方式將資料寫入硬碟,並且Redis除了能儲存普通的字串鍵之外,還可以儲存其他4種資料結構,而memcached只能儲存普通的字串鍵。這些不同之處使得Redis可以用於解決更為廣泛的問題,並且既可以用作主要資料庫(primary database)使用,又可以作為其他儲存系統的次要資料庫(auxiliary database)使用。
本書的後續章節會分別介紹將Redis用作主儲存(primary storage)和二級儲存(secondary storage)時的用法和查詢模式。一般來說,許多使用者只會在Redis的效能或者功能是必要的情況下,才會將資料存放區到Redis裡面:如果程式對效能的要求不高,又或者因為費用原因而沒辦法將大量資料存放區到記憶體裡面,那麼使用者可能會選擇使用關聯式資料庫,或者其他非關聯式資料庫。在實際中,讀者應該根據自己的需求來決定是否使用Redis,並考慮是將Redis用作主儲存還是輔助儲存,以及如何通過複製、持久化和事務等手段保證資料的完整性。展示了一部分在功能上與Redis有重疊的資料庫伺服器和快取服務器,從以下表中可以看出Redis與這些資料庫及軟體之間的區別。
一些資料庫和快取服務器的特性與功能
名稱 |
類型 |
資料存放區選項 |
查詢類型 |
附加功能 |
Redis |
使用記憶體儲存(in-memory)的非關聯式資料庫 |
字串、列表、集合、散列表、有序集合 |
每種資料類型都有自己的專屬命令,另外還有大量操作(bulk operation)和不完全(partial)的事務支援 |
發布與訂閱,主從複製(master/slave replication),持久化,指令碼(預存程序,stored procedure) |
memcached |
使用記憶體儲存的索引值緩衝 |
索引值之間的映射 |
建立命令、讀取命令、更新命令、刪除命令以及其他幾個命令 |
為提升效能而設的多線程伺服器 |
MySQL |
關聯式資料庫 |
每個資料庫可以包含多個表,每個表可以包含多個行;可以處理多個表的視圖(view);支援空間(spatial)和第三方擴充 |
SELECT、INSERT、UPDATE、DELETE、函數、預存程序 |
支援ACID性質(需要使用InnoDB),主從複製和主主複製 (master/master replication) |
PostgreSQL |
關聯式資料庫 |
每個資料庫可以包含多個表,每個表可以包含多個行;可以處理多個表的視圖;支援空間和第三方擴充;支援可定製類型 |
SELECT、INSERT、UPDATE、DELETE、內建函數、自訂的預存程序 |
支援ACID性質,主從複製,由第三方支援的多主複製(multi-master replication) |
MongoDB |
使用硬碟儲存(on-disk)的非關係文檔儲存 |
每個資料庫可以包含多個表,每個表可以包含多個無schema(schema-less)的BSON文檔 |
建立命令、讀取命令、更新命令、刪除命令、條件查詢命令等 |
支援map-reduce操作,主從複製,分區,空間索引(spatial index) |
4、Redis附加特性
在使用類似Redis這樣的記憶體資料庫時,一個首先要考慮的問題就是“當伺服器被關閉時,伺服器儲存的資料將何去何從呢?”Redis擁有兩種不同形式的持久化方法,它們都可以用小而緊湊的格式將儲存在記憶體中的資料寫入硬碟:第一種持久化方法為時間點轉儲(point-in-time dump),轉儲操作既可以在“指定時間段內有指定數量的寫操作執行”這一條件被滿足時執行,又可以通過調用兩條轉儲到硬碟(dump-to-disk)命令中的任何一條來執行;第二種持久化方法將所有修改了資料庫的命令都寫入一個只追加(append-only)檔案裡面,使用者可以根據資料的重要程度,將只追加寫入設定為從不同步(sync)、每秒同步一次或者每寫入一個命令就同步一次。我們將在第4章中更加深入地討論這些持久化選項。
另外,儘管Redis的效能很好,但受限於Redis的記憶體儲存設計,有時候只使用一台Redis伺服器可能沒有辦法處理所有請求。因此,為了擴充Redis的讀效能,並為Redis提供容錯移轉(failover)支援,Redis實現了主從複製特性:執行複製的從伺服器會串連上主伺服器,接收主伺服器發送的整個資料庫的初始副本(copy);之後主伺服器執行的寫命令,都會被發送給所有串連著的從伺服器去執行,從而即時地更新從伺服器的資料集。因為從伺服器包含的資料會不斷地進行更新,所以用戶端可以向任意一個從伺服器發送讀請求,以此來避免對主伺服器進行集中式的訪問。我們將在第4章中更加深入地討論Redis從伺服器。
連結:http://www.epubit.com.cn/article/200
使用Redis的理由