Redis:相关知识点纵观
這篇文章先簡單的介紹一下redis有什么相關知識點,然后再從接下去的一些文章對一些重要的知識點進行總結。
一、Redis 是什么
Redis 是速度非常快的非關系型(NoSQL)內存鍵值數據庫,可以存儲鍵和五種不同類型的值之間的映射。
五種類型數據類型為:字符串、列表、集合、有序集合、散列表。
Redis 支持很多特性,例如將內存中的數據持久化到硬盤中,使用復制來擴展讀性能,使用分片來擴展寫性能。
?
二、五種基本類型
| 數據類型 | 可以存儲的值 | 操作 |
| STRING | 字符串、整數或者浮點數 | 對整個字符串或者字符串的其中一部分執行操作 |
| LIST | 鏈表 | 從兩端壓入或者彈出元素 |
| SET | 無序集合 | 添加、獲取、移除單個元素 |
| HASH | 包含鍵值對的無序散列表 | 添加、獲取、移除單個鍵值對 |
| ZSET | 有序集合 | 添加、獲取、刪除元素 |
?
三、鍵的過期時間
Redis 可以為每個鍵設置過期時間,當鍵過期時,會自動刪除該鍵。
對于散列表這種容器,只能為整個鍵設置過期時間(整個散列表),而不能為鍵里面的單個元素設置過期時間。
過期時間對于清理緩存數據非常有用。
四、發布與訂閱
發布與訂閱實際上是觀察者模式,訂閱者訂閱了頻道之后,發布者向頻道發送字符串消息會被所有訂閱者接收到。
發布與訂閱有一些問題,很少使用它,而是使用替代的解決方案。問題如下:
五、事務
Redis 最簡單的事務實現方式是使用 MULTI 和 EXEC 命令將事務操作包圍起來。
MULTI 和 EXEC 中的操作將會一次性發送給服務器,而不是一條一條發送,這種方式稱為流水線,它可以減少客戶端與服務器之間的網絡通信次數從而提升性能。
六、持久化
Redis 是內存型數據庫,為了保證數據在斷電后不會丟失,需要將內存中的數據持久化到硬盤上。
1. 快照持久化
將某個時間點的所有數據都存放到硬盤上。
可以將快照復制到其它服務器從而創建具有相同數據的服務器副本。
如果系統發生故障,將會丟失最后一次創建快照之后的數據。并且如果數據量很大,保存快照的時間也會很長。
2. AOF 持久化
AOF 持久化將寫命令添加到 AOF 文件(Append Only File)的末尾。
對硬盤的文件進行寫入時,寫入的內容首先會被存儲到緩沖區,然后由操作系統決定什么時候將該內容同步到硬盤,用戶可以調用file.flush() 方法請求操作系統盡快將緩沖區存儲的數據同步到硬盤。因此將寫命令添加到 AOF 文件時,要根據需求來保證何時將添加的數據同步到硬盤上,有以下同步選項:
| 選項 | 同步頻率 |
| always | 每個寫命令都同步 |
| everysec | 每秒同步一次 |
| no | 讓操作系統來決定何時同步 |
always 選項會嚴重減低服務器的性能;everysec 選項比較合適,可以保證系統奔潰時只會丟失一秒左右的數據,并且 Redis 每秒執行一次同步對服務器性能幾乎沒有任何影響;no 選項并不能給服務器性能帶來多大的提升,而且也會增加系統奔潰時數據丟失的數量。
隨著服務器寫請求的增多,AOF 文件會越來越大;Redis 提供了一種將 AOF 重寫的特性,能夠去除 AOF 文件中的冗余寫命令。
七、復制
通過使用 slaveofhost port 命令來讓一個服務器成為另一個服務器的從服務器。
一個從服務器只能有一個主服務器,并且不支持主主復制。
從服務器連接主服務器的過程
1.?????主服務器創建快照文件,發送給從服務器,并在發送期間使用緩沖區記錄執行的寫命令。快照文件發送完畢之后,開始向從服務器發送存儲在緩沖區中的寫命令;
2.?????從服務器丟棄所有舊數據,載入主服務器發來的快照文件,之后從服務器開始接受主服務器發來的寫命令;
3.?????主服務器每執行一次寫命令,就向從服務器發送相同的寫命令。
主從鏈
隨著負載不斷上升,主服務器可能無法很快地更新所有從服務器,或者重新連接和重新同步從服務器將導致系統超載。為了解決這個問題,可以創建一個中間層來分擔主服務器的復制工作。中間層的服務器是最上層服務器的從服務器,又是最下層服務器的主服務器。
八、處理故障
要用到持久化文件來恢復服務器的數據。
持久化文件可能因為服務器出錯也有錯誤,因此要先對持久化文件進行驗證和修復。對 AOF 文件就行驗證和修復很容易,修復操作將第一個出錯命令和其后的所有命令都刪除;但是只能驗證快照文件,無法對快照文件進行修復,因為快照文件進行了壓縮,出現在快照文件中間的錯誤可能會導致整個快照文件的剩余部分無法讀取。
當主服務器出現故障時,Redis 常用的做法是新開一臺服務器作為主服務器,具體步驟如下:假設 A 為主服務器,B 為從服務器,當 A 出現故障時,讓 B 生成一個快照文件,將快照文件發送給 C,并讓 C 恢復快照文件的數據。最后,讓 B 成為 C 的從服務器。
九、分片
Redis 中的分片類似于 MySQL 的分表操作,分片是將數據劃分為多個部分的方法,對數據的劃分可以基于鍵包含的 ID、基于鍵的哈希值,或者基于以上兩者的某種組合。通過對數據進行分片,用戶可以將數據存儲到多臺機器里面,也可以從多臺機器里面獲取數據,這種方法在解決某些問題時可以獲得線性級別的性能提升。
假設有 4 個 Reids 實例 R0,R1,R2,R3,還有很多表示用戶的鍵 user:1,user:2,... 等等,有不同的方式來選擇一個指定的鍵存儲在哪個實例中。最簡單的方式是范圍分片,例如用戶 id 從 0~1000 的存儲到實例 R0 中,用戶 id 從 1001~2000 的存儲到實例 R1 中,等等。但是這樣需要維護一張映射范圍表,維護操作代價很高。還有一種方式是哈希分片,使用 CRC32 哈希函數將鍵轉換為一個數字,再對實例數量求模就能知道應該存儲的實例。
1. 客戶端分片
客戶端使用一致性哈希等算法決定鍵應當分布到哪個節點。
2. 代理分片
將客戶端請求發送到代理上,由代理轉發請求到正確的節點上。
3. 服務器分片
Redis Cluster。
十、事件
事件類型
1. 文件事件
服務器有許多套接字,事件產生時會對這些套接字進行操作,服務器通過監聽套接字來處理事件。常見的文件事件有:客戶端的連接事件;客戶端的命令請求事件;服務器向客戶端返回命令結果的事件;
2. 時間事件
又分為兩類:定時事件是讓一段程序在指定的時間之內執行一次;周期性時間是讓一段程序每隔指定時間就執行一次。
事件的調度與執行
服務器需要不斷監聽文件事件的套接字才能得到待處理的文件事件,但是不能監聽太久,否則時間事件無法在規定的時間內執行,因此監聽時間應該根據距離現在最近的時間事件來決定。
事件調度與執行由aeProcessEvents 函數負責,偽代碼如下:
defaeProcessEvents(): ? ??? # 獲取到達時間離當前時間最接近的時間事件 ??? time_event = aeSearchNearestTimer() ? ??? # 計算最接近的時間事件距離到達還有多少毫秒 ??? remaind_ms = time_event.when - unix_ts_now() ? ??? # 如果事件已到達,那么 remaind_ms 的值可能為負數,將它設為 0 ??? if remaind_ms <0: ??????? remaind_ms =0 ? ??? # 根據 remaind_ms 的值,創建 timeval ??? timeval = create_timeval_with_ms(remaind_ms) ? ??? # 阻塞并等待文件事件產生,最大阻塞時間由傳入的 timeval 決定 ??? aeApiPoll(timeval) ? ??? # 處理所有已產生的文件事件 ??? procesFileEvents() ? ??? # 處理所有已到達的時間事件 ??? processTimeEvents()將aeProcessEvents 函數置于一個循環里面,加上初始化和清理函數,就構成了 Redis 服務器的主函數,偽代碼如下:
defmain(): ? ??? # 初始化服務器 ??? init_server() ? ??? # 一直處理事件,直到服務器關閉為止 ??? while server_is_not_shutdown(): ??????? aeProcessEvents() ? ??? # 服務器關閉,執行清理操作 ??? clean_server()從事件處理的角度來看,服務器運行流程如下:
?
十一、Redis 與 Memcached 的區別
兩者都是非關系型內存鍵值數據庫。有以下主要不同:
數據類型
Memcached 僅支持字符串類型,而 Redis 支持五種不同種類的數據類型,使得它可以更靈活地解決問題。
數據持久化
Redis 支持兩種持久化策略:RDB 快照和 AOF 日志,而 Memcached 不支持持久化。
分布式
Memcached 不支持分布式,只能通過在客戶端使用像一致性哈希這樣的分布式算法來實現分布式存儲,這種方式在存儲和查詢時都需要先在客戶端計算一次數據所在的節點。
Redis Cluster 實現了分布式的支持。
內存管理機制
在 Redis 中,并不是所有數據都一直存儲在內存中,可以將一些很久沒用的 value 交換到磁盤。而 Memcached 的數據則會一直在內存中。
Memcached 將內存分割成特定長度的塊來存儲數據,以完全解決內存碎片的問題,但是這種方式會使得內存的利用率不高,例如塊的大小為 128 bytes,只存儲 100 bytes 的數據,那么剩下的 28 bytes 就浪費掉了。
十二、Redis 適用場景
緩存
s使用 Redis 作為緩存,將熱點數據放到內存中。
消息隊列
Redis 的 List 類型是雙向鏈表,很適合用于消息隊列。
計數器
Redis 這種內存數據庫才能支持計數器的頻繁讀寫操作。
好友關系
使用 set 類型的交集很容易就可以知道兩個用戶的共同好友。
十三、數據淘汰策略
可以設置內存最大使用量,當內存使用量超過時施行淘汰策略,具體有 6 種淘汰策略。
| 策略 | 描述 |
| volatile-lru | 從已設置過期時間的數據集中挑選最近最少使用的數據淘汰 |
| volatile-ttl | 從已設置過期時間的數據集中挑選將要過期的數據淘汰 |
| volatile-random | 從已設置過期時間的數據集中任意選擇數據淘汰 |
| allkeys-lru | 從所有數據集中挑選最近最少使用的數據淘汰 |
| allkeys-random | 從所有數據集中任意選擇數據進行淘汰 |
| no-envicition | 禁止驅逐數據 |
如果使用 Redis 來緩存數據時,要保證所有數據都是熱點數據,可以將內存最大使用量設置為熱點數據占用的內存量,然后啟用allkeys-lru 淘汰策略,將最近最少使用的數據淘汰。
十四、一個簡單的論壇系統分析
該論壇系統功能如下:
- 可以發布文章;
- 可以對文章進行點贊;
- 在首頁可以按文章的發布時間或者文章的點贊數進行排序顯示;
文章信息
文章包括標題、作者、贊數等信息,在關系型數據庫中很容易構建一張表來存儲這些信息,在 Redis 中可以使用 HASH 來存儲每種信息以及其對應的值的映射。
Redis 沒有關系型數據庫中的表這一概念來將同類型的數據存放在一起,而是使用命名空間的方式來實現這一功能。鍵名的前面部分存儲命名空間,后面部分的內容存儲 ID,通常使用 : 來進行分隔。例如下面的 HASH 的鍵名為 article:92617,其中 article 為命名空間,ID 為 92617。
?
點贊功能
當有用戶為一篇文章點贊時,除了要對該文章的 votes 字段進行加 1 操作,還必須記錄該用戶已經對該文章進行了點贊,防止用戶點贊次數超過 1。可以建立文章的已投票用戶集合來進行記錄。
為了節約內存,規定一篇文章發布滿一周之后,就不能再對它進行投票,而文章的已投票集合也會被刪除,可以為文章的已投票集合設置一個一周的過期時間就能實現這個規定。
?
?
對文章進行排序
為了按發布時間和點贊數進行排序,可以建立一個文章發布時間的有序集合和一個文章點贊數的有序集合。(下圖中的 score 就是這里所說的點贊數;下面所示的有序集合分值并不直接是時間和點贊數,而是根據時間和點贊數間接計算出來的)
總結
以上是生活随笔為你收集整理的Redis:相关知识点纵观的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot java.util
- 下一篇: ubuntu下最简单的MySQL安装教程