2020重新出發,NOSQL,什麼是Redis?

@

Redis是什麼?

Redis 是一個由 Salvatore Sanfilippo 寫的 key-value 存儲系統,是當前互聯網世界最為流行的 NoSQL 資料庫。NoSQL 在互聯網系統中的作用很大,因為它可以在很大程度上提高互聯網系統的性能。

Redis 開源免費,提供了 Java,C/C++,C#,PHP 等客戶端,使用方便。主要應用於**內容快取 ** 和 處理大量數據的高訪問負載

Redis 具備一定持久層的功能,也可以作為一種快取工具。對於 NoSQL 資料庫而言,作為持久層,它存儲的數據是半結構化的,這就意味著電腦在讀入記憶體中有更少的規則,讀入速度更快。

對於那些結構化、多範式規則的資料庫系統而言,它更具性能優勢。作為快取,它可以支援大數據存入記憶體中,只要命中率高,它就能快速響應,因為在記憶體中的數據讀/寫比資料庫讀/寫磁碟的速度快幾十到上百倍,其作用如圖 1 所示。

NoSQL的作用

​ 圖 1 NoSQL 的作用

NoSQL和傳統資料庫的區別

目前 NoSQL 有很多爭議,有些人認為它可以取代資料庫,有些人卻不這麼認為。

  1. 首先,NoSQL 的數據主要存儲在記憶體中(部分可以持久化到磁碟),而資料庫主要是磁碟。其次,NoSQL 數據結構比較簡單,雖然能處理很多的問題,但是其功能畢竟是有限的,不如資料庫的 SQL 語句強大,支援更為複雜的計算。
  2. 再者,NoSQL 並不完全安全穩定,由於它基於記憶體,一旦停電或者機器故障數據就很容易丟失數據,其持久化能力也是有限的,而基於磁碟的資料庫則不會出現這樣的問題。
  3. 最後,其數據完整性、事務能力、安全性、可靠性及可擴展性都遠不及資料庫。

基於以上原因,有些人並不認為 NoSQL 會取代資料庫。

毫無疑問,Redis 作為一種 NoSQL 是十分成功的,但是它的成功主要是解決互聯網系統的一些問題,而主要的問題是性能問題。

實際上,在互聯網系統大部分的業務場景中,業務都是相對簡單的,而難以處理的問題主要是性能問題,特別是那些會員數比較多的高並發服務網站。

  • 例如,你可以常常在淘寶或者京東網站上看到一個即將被搶購的商品,有多達幾萬人的關注,可能一個時刻就發生了成千上萬筆業務,此時使用 Redis 作為快取數據,就可以明顯提升系統的性能,而且這十分有效。

因為資料庫系統有更好的規範性和數據完整性,功能更強大,作為持久層更為完善,安全性更高。而 NoSQL 結構鬆散、不完整,功能有限,目前尚不具備取代資料庫的實力,但是作為快取工具,它的高性能、高響應等功能,使它成為一個很重要的工具。

Redis的優點

當前 Redis 已經成為了主要的 NoSQL 工具,其原因如下:

  1. 響應快速(速度快):Redis 響應非常快,每秒可以執行大約 110 000 個寫入操作,或者 81 000 個讀操作,其速度遠超資料庫。如果存入一些常用的數據,就能有效提高系統的性能。
  2. 支援6種數據類型(數據類型豐富):它們是字元串、哈希結構、列表、集合、可排序集合和基數。比如對於字元串可以存入一些 Java 基礎數據類型,哈希可以存儲對象,列表可以存儲 List 對象等。這使得在應用中很容易根據自己的需要選擇存儲的數據類型,方便開發。對於 Redis 而言,雖然只有 6 種數據類型,但是有兩大好處:
    • 一方面可以滿足存儲各種數據結構體的需要;
    • 另外一方面數據類型少,使得規則就少,需要的判斷和邏輯就少,這樣讀/寫的速度就更快。
  3. 操作都是原子的(原子性):所有 Redis 的操作都是原子的,從而確保當兩個客戶同時訪問 Redis 伺服器時,得到的是更新後的值(最新值)。在需要高並發的場合可以考慮使用 Redis 的事務,處理一些需要鎖的業務。
  4. MultiUtility 工具:Redis 可以在如快取、消息傳遞隊列中使用(Redis 支援「發布+訂閱」的消息模式),在應用程式如 Web 應用程式會話、網站頁面點擊數等任何短暫的數據中使用。正是因為 Redis 具備這些優點,使得它成為了目前主流的 NoSQL 技術,在 Java 互聯網中得到了廣泛使用。
    • 一方面,使用 NoSQL 從資料庫中讀取數據進行快取,就可以從記憶體中讀取數據了,而不像資料庫一樣讀磁碟。現實是讀操作遠比寫操作要多得多,所以快取很多常用的數據,提高其命中率有助於整體性能的提高,並且能減緩資料庫的壓力,對互聯網系統架構是十分有利的。
    • 另一方面,它也能滿足互聯網高並發需要高速處理數據的場合,比如搶紅包、商品秒殺等場景,這些場合需要高速處理,並保證並發數據安全和一致性。

Redis在Java Web中的應用

一般而言 Redis 在 Java Web 應用中存在兩個主要的場景,

  • 一個是快取常用的數據,
  • 另一個是在需要高速讀/寫的場合使用它快速讀/寫,比如一些需要進行商品搶購和搶紅包的場合。

由於在高並發的情況下,需要對數據進行高速讀/寫的場景,一個最為核心的問題是數據一致性和訪問控制。

快取

在對資料庫的讀/寫操作中,現實的情況是讀操作的次數遠超寫操作,一般是 1:9 到 3:7 的比例,所以需要讀的可能性是比寫的可能性多得多。

當發送 SQL 去資料庫進行讀取時,資料庫就會去磁碟把對應的數據索引回來,而索引磁碟是一個相對緩慢的過程。如果把數據直接放在運行在記憶體中的 Redis 伺服器上,那麼不需要去讀/寫磁碟了,而是直接讀取記憶體,顯然速度會快得多,並且會極大減輕資料庫的壓力。

而使用記憶體進行存儲數據開銷也是比較大的,因為磁碟可以是 TGB 級別,而且十分廉價,記憶體一般是幾百個 GB 就相當了不起了,所以記憶體雖然高效但空間有限,價格也比磁碟高許多,因此使用記憶體代價較高,並不是想存什麼就存什麼,因此我們應該考慮有條件的存儲數據。

一般而言,存儲一些常用的數據,比如用戶登錄的資訊;一些主要的業務資訊,比如銀行會存儲一些客戶基礎資訊、銀行卡資訊、最近交易資訊等。一般而言在使用 Redis 存儲的時候,需要從 3 個方面進行考慮。

  1. 業務數據常用嗎?命中率如何?如果命中率很低,就沒有必要寫入快取。
  2. 該業務數據是讀操作多,還是寫操作多,如果寫操作多,頻繁需要寫入資料庫,也沒有必要使用快取。
  3. 業務數據大小如何?如果要存儲幾百兆位元組的文件,會給快取帶來很大的壓力,有沒有必要?

在考慮過這些問題後,如果覺得有必要使用快取,那麼就使用它。使用 Redis 作為快取的讀取邏輯如圖 1 所示。

Redis的快取應用

​ 圖 1 Redis 的快取應用

從圖 1 中可以知道以下兩點。

  • 當第一次讀取數據的時候,讀取 Redis 的數據就會失敗,此時會觸發程式讀取資料庫,把數據讀取出來,並且寫入 Redis。
  • 當第二次及以後讀取數據時,就直接讀取 Redis,讀到數據後就結束了流程,這樣速度就大大提高了。

從上面的分析可知,大部分的操作是讀操作,使用 Redis 應對讀操作,速度就會十分迅速,同時也降低了對資料庫的依賴,大大降低了資料庫的負擔。

分析了讀操作的邏輯後,下面再來分析寫操作的流程,如圖 2 所示。

寫操作的流程

​ 圖 2 寫操作的流程

從流程可以看出,更新或者寫入的操作,需要多個 Redis 的操作。如果業務數據寫次數遠大於讀次數沒有必要使用 Redis。如果是讀次數遠大於寫次數,則使用 Redis 就有其價值了,因為寫入 Redis 雖然要消耗一定的代價,但是其性能良好,相對資料庫而言,幾乎可以忽略不計。

高速讀/寫場合

在互聯網的應用中,往往存在一些需要高速讀/寫的場合,比如商品的秒殺,搶紅包,淘寶、京東的雙十一活動或者春運搶票等。

以上這類場合在一個瞬間成千上萬的請求就會達到伺服器,如果使用的是資料庫,一個瞬間資料庫就需要執行成千上萬的 SQL,很容易造成資料庫的瓶頸,嚴重的會導致資料庫癱瘓,造成 Java Web 系統服務崩潰。

在這樣的場合的應對辦法往往是考慮非同步寫入資料庫,而在高速讀/寫的場合中單單使用 Redis 去應對,把這些需要高速讀/寫的數據,快取到 Redis 中,而在滿足一定的條件下,觸發這些快取的數據寫入資料庫中。先看看一次請求操作的流程圖,如圖 3 所示。

Redis在高速讀/寫場合的應用

​ 圖 3 Redis 在高速讀/寫場合的應用

進一步論述這個過程:

  • 當一個請求達到伺服器,只是把業務數據先在 Redis 讀/寫,而沒有進行任何對資料庫的操作,換句話說系統僅僅是操作 Redis 快取,而沒有操作資料庫,這個速度就比操作資料庫要快得多,從而達到需要高速響應的效果。
  • 但是一般快取不能持久化,或者所持久化的數據不太規範,因此需要把這些數據存入資料庫,所以在一個請求操作完 Redis 的讀/寫後,會去判斷該高速讀/寫的業務是否結束。
  • 這個判斷的條件往往就是秒殺商品剩餘個數為 0,搶紅包金額為 0,如果不成立,則不會操作資料庫;如果成立,則觸發事件將 Redis 快取的數據以批量的形式一次性寫入資料庫,從而完成持久化的工作。
  • 假設面對的是一個商品秒殺的場景,從上面的流程看,一個用戶搶購商品,絕大部分的場合都是在操作記憶體資料庫 Redis,而不是磁碟資料庫,所以其性能更為優越。只有在商品被搶購一空後才會觸發系統把 Redis 快取的數據寫入資料庫磁碟中,這樣系統大部分的操作基於記憶體,就能夠在秒殺的場合高速響應用戶的請求,達到快速應答。
  • 而現實中這種需要高速響應的系統會比上面的分析更複雜,因為這裡沒有討論高並發下的數據安全和一致性問題,沒有討論有效請求和無效請求、事務一致性等諸多問題。