摘抄並用於自查筆記
1. Redis簡介
我們日常Java Web開發,一般使用數據庫進行存儲,在數據量較大的情況下,單一使用數據庫保存數據的系統會因為面向磁盤,磁盤讀寫速度比較慢而存在嚴重的性能弊端,一瞬間成千上萬的請求到來,需要系統在極短時間內完成千萬次的讀寫操作,這個時候數據庫承受不了,易造成數據庫癱瘓。為克服此類問題,Java Web項目通常引入Nosql技術,這是一種基於內存的數據庫,並且提供一定的持久化功能。
Redis是一個key-value存儲系統,可支持五種數據類型:字符串、哈希、鏈表、集合和有序集合。其性能十分優越,可支持每秒十幾萬次的讀寫操作,性能遠超數據庫,且支持集群,分布式,主從同步等配置,原則上可以無限擴展,讓更多人數據存儲在內存中,支持一定的事務能力,保證高並發下數據的安全和一致性。
2. Redis在Java Web中的應用
Redis在Java Web主要有兩個應用場景:
1)存儲緩存用的數據
2)需要高速讀寫的場合使用他快速讀寫
緩存
根據業務需求,在Redis中存儲一些常用和主要的數據,一般從以下幾個方面考慮:
業務數據常用嗎?如果是命中率低,沒有必要寫入緩存。
命中率如何?如果命中率低,就沒有必要寫入緩存。
讀操作多還是寫操作多?如果寫操作多,頻繁寫入數據庫,也沒有必要使用緩存。
業務數據大小如何?如果要存儲幾百M字節的文件,會給緩存帶來很大壓力,這樣也沒必要。
高速讀寫的場合
在高並發的情況下,例如搶演唱會門票,僅用數據庫會比較慢或數據庫癱瘓,所以需要使用Redis來應對這樣的高並發需求的場合。
i)當一個請求到達服務器時,只是把業務數據在Redis上進行讀寫,而沒有對數據進行任何的操作,這樣就能大大提高讀寫速度,從而滿足高速響應的需求
ii)但是這些緩存的數據仍需要持久化,也就是存入數據庫之中,所以在一個請求操作完Redis的讀寫后,會去判斷該高速讀寫的業務是否結束,這個判斷如果是成功了,則觸發事件將Redis緩存的數據以批量的形式一次性寫入數據庫,從而完成持久化的工作。
3. Redis常用數據類型操作和其他操作
1)String
String是redis最基本的數據類型。String類型是二進制安全的,意思是,redis的String可以包含任何數據,比如,jpg或者序列化的對象,其最大能存儲512MB
2)Hash(哈希)
Redis Hash是一個鍵值對集合。hash特別適合用於存儲對象。
HMSET runoob field1 "Hello" field2 "World"
HGET runoob field1
HGET runoob field2
3) List(列表)
Redis列表是簡單的字符串列表,按照插入順序排序。可以添加一個元素到列表的頭部或者尾部。
4)Set(集合)
Redis的Set是String類型的無需集合,集合是通過哈希表實現的,所以添加、刪除、查找的復雜度都是o(1)
5)zset(sorted set:有序集合)
zset和set一樣是String類型元素的集合,且不允許出現重復的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序,zset的成員是唯一的,但分數卻是可以重復的。
6)Redis HyperLogLog
Redis HyperLogLog是用來做基數統計的算法,HyperLogLog的優點是在輸入元素的數量或者體積非常非常大時,計算基數所需的空間總是固定的,且是很小。
7)Redis 發布訂閱
Redis發布訂閱是一種消息通信模式。
8)Redis事務
MULTI, EXEC, DISCARD和WATCH命令是Redis事務操作的基礎。他們可以讓Redis在一個步驟里面執行一組命令,且能做到如下2個保證:
i)事務中所有的命令都是序列化且都是按順序執行的,在一個客戶端執行Redis事務的過程中,不會接收其他任何客戶端對他發出的請求。這保證了這些命令是作為一個單獨的獨立操作執行的。
ii)所有的命令要么都被一起處理,要么全部都沒有被處理,所以Redis事務是原子的。EXEC會命令觸發事務中所有命令的執行。
使用MULTI命令進入事務模式,這個命令只會返回OK,這個時候,用戶發出多個要執行的命令,Redis暫時不會執行這些命令,二十把他們放進隊列,當EXEC被調用時,所有的命令才會被一次性執行。
在其中可能會有2種錯誤:
i)命令可能排隊失敗。如,命令的語法可能錯誤,或者重要的環境問題,內存不足。
ii)EXEC調用后,一些命令可能執行失敗,如,在一個字符串上進行列表命令的操作。
第一種錯誤,發生在EXEC命令前,可以通過檢查命令的返回值,QUEUED,redis對於在排隊期間發生的錯誤,會拒絕執行EXEC,並放棄這個事務。
執行EXEC后,所有的命令都會被執行,甚至是錯誤的命令。就算其中有失敗的命令,隊列中的其他命令也會被執行。
為什么Redis不支持回滾
EXEC命令調用后的錯誤(這個問題在命令隊列時無法檢測到),Redis命令執行失敗,都是程序性錯誤,這類錯誤在開發過程中就能夠發現並解決,幾乎不會出現在生產環境。
由於不需要回滾,這使得redis內部更加簡單,而且運行速度更快
樂觀鎖(check-and-set)
WATCH命令為事務提供一個check-and-set(CAS)行為。
WATCH命令可以用來監聽事務中的隊列的命令,在EXEC之前,一旦發現有參數是被修改了的,那么整個事務就會終止,EXEC返回一個NULL,提示用戶事務失敗了。這種形式的鎖稱為樂觀鎖,是一種非常強大的鎖。
WATCH命令使得EXEC命令的執行必須滿足一個條件:如果被WATCH的keys沒有一個被更改,則執行事務;不然就不執行這個事務。
WATCH可以被多次調用,所有的WATCH調用都會在EXEC調用之前起作用,WATCH可以接收任意多的key。
當EXEC被調用后,所有的keys都將UNWATCH,不管這個事務會不會終止。同樣,當一個客戶端鏈接關閉后,一切都將UNWATCH。
可以用UNWATCH命令來刷新所有被WATCH的keys。
這個常用於高並發的情況,例如,搶紅包或者商品。
9)Redis持久化
Redis支持RDB和AOF兩種持久化機制。持久化能有效避免因進程退出造成的數據丟失問題,下一次重啟時,利用之前持久化的文件,即可實現數據恢復。
1. RDB:這種是把當前進程數據生成快照保存到硬盤的過程,觸發RDB持久化過程分為手動觸發和自動觸發。
手動觸發:save和bgsave。save命令阻塞當前Redis服務(主進程),bgsave命令Redis進程執行fork操作創建子進程,RDB持久化過程由子進程負責,完成后自動結束,阻塞只發生在fork階段,時間短。(fork解釋 : 一個進程,包括代碼、數據和分配給進程的資源。fork()函數通過系統調用創建一個與原來進程幾乎完全相同的進程,也就是兩個進程可以做完全相同的事,但如果初始參數或者傳入的變量不同,兩個進程也可以做不同的事。 一個進程調用fork()函數后,系統先給新的進程分配資源,例如存儲數據和代碼的空間。然后把原來的進程的所有值都復制到新的新進程中,只有少數值與原來的進程的值不同。相當於克隆了一個自己。)
自動觸發:有以下幾種場景會觸發
a)使用save相關配置,如 save m n , 表示m秒內數據集存在n次修改時,自動觸發bgsave
b)如果從節點執行全量復制操作,主節點自動執行bgsave生成RDB文件並發送給從節點。
c)執行debug reload命令重新加載Redis時,也會自動觸發save操作。
d)默認情況下執行shutdown命令時,如果沒有開啟AOF持久化功能則自動執行bgsave
保存:RDB文件保存在dir配置指定的目錄下,文件名通過dbfilename配置指定。
優點:非常適用備份,全量賦值等場景,恢復數據遠快於AOF方法。
缺點:沒有辦法做到實時持久化/秒級持久化。其文件格式存在多版本格式不兼容情況。
2. AOF
開啟AOF功能需要設置配置:appendonly yes。默認不開啟。文件名通過appendfilename配置,默認appendonly.aof。
a)所有寫入命令會追加到aof_buf(緩沖區)中。
b)AOF緩沖區根據對應的策略向硬盤做同步操作
c)隨着AOF文件越來越大,需要定去對AOF文件進行重寫,達到壓縮目的
d)當Redis服務器重啟時,可以加載AOF文件進行數據恢復
10)管道技術
Redis是一種基於客戶端-服務端模型以及請求/響應協議的TCP服務。這意味着通常情況下一個請求會遵循以下步驟:
客戶端向服務端發送一個查詢請求,並監聽Socket返回,通常是以阻塞模式,等待服務器端響應,服務端處理命令,並將結果返回客戶單。
但是Redis管道技術可以在服務端未響應時,客戶端可以繼續向服務端發送請求,並最終一次讀取所有服務端的響應。
管道技術最顯著的優勢是提高了redis服務的性能。開啟管道操作后,往返延時被改善的相當低。