redis內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。
可以好好利用Hash,list,sorted set,set等集合類型數據,因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。盡可能使用散列表(hashes),散列表(是說散列表里面存儲的數少)使用的內存非常小,所以你應該盡可能的將你的數據模型抽象到一個散列表里面。比如你的web系統中有一個用戶對象,不要為這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶的所有信息存儲到一張散列表里面。
使用keys指令可以掃出指定模式的key列表。
對方接著追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什么問題?
這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重復概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
Redis2.6開始redis-cli支持一種新的被稱之為pipe mode的新模式用于執行大量數據插入工作。
1.Master最好不要做任何持久化工作,包括內存快照和AOF日志文件,特別是不要啟用內存快照做持久化。
2.如果數據比較關鍵,某個Slave開啟AOF備份數據,策略為每秒同步一次。
3.為了主從復制的速度和連接的穩定性,Slave和Master最好在同一個局域網內。
4.盡量避免在壓力較大的主庫上增加從庫
5.Master調用BGREWRITEAOF重寫AOF文件,AOF在重寫的時候會占大量的CPU和內存資源,導致服務load過高,出現短暫服務暫停現象。
6.為了Master的穩定性,主從復制不要用圖狀結構,用單向鏈表結構更穩定,即主從關系為:Master<–Slave1<–Slave2<–Slave3…,這樣的結構也方便解決單點故障問題,實現Slave對Master的替換,也即,如果Master掛了,可以立馬啟用Slave1做Master,其他不變。
所謂 Redis 的并發競爭 Key 的問題也就是多個系統同時對一個 key 進行操作,但是最后執行的順序和我們期望的順序不同,這樣也就導致了結果的不同!
推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實現分布式鎖,如果不存在 Redis 的并發競爭 Key 問題,不要使用分布式鎖,這樣會影響性能)。基于zookeeper臨時有序節點可以實現的分布式鎖。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。完成業務流程后,刪除對應的子節點釋放鎖。
在實踐中,當然是從以可靠性為主。所以首推Zookeeper。
Redis為單進程單線程模式,采用隊列模式將并發訪問變成串行訪問,且多客戶端對Redis的連接并不存在競爭關系Redis中可以使用SETNX命令實現分布式鎖。
當且僅當 key 不存在,將 key 的值設為 value。若給定的 key 已經存在,則 SETNX 不做任何動作。其中SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。
返回值:設置成功,返回 1 。設置失敗,返回 0 。
從理論上說,只要我們設置了合理的鍵的過期時間,我們就能保證緩存和數據庫的數據最終是一致的。因為只要緩存數據過期了,就會被刪除。隨后讀的時候,因為緩存里沒有,就可以查數據庫的數據,然后將數據庫查出來的數據寫入到緩存中。除了設置過期時間,我們還可以通過新增、更改、刪除數據庫操作時同步更新 Redis,可以使用事物機制來保證數據的一致性。一般有如下四種方案,具體如下:
1.先更新數據庫,后更新緩存
2.先更新緩存,后更新數據庫
3.先刪除緩存,后更新數據庫
4先更新數據庫,后刪除緩存
第一種方案存在問題是:并發更新數據庫場景下,會將臟數據刷到緩存。
第二種方案存在的問題是:如果先更新緩存成功,但是數據庫更新失敗,則肯定會造成數據不一致。
目前主要用第三和第四種方案。
Redis的內存淘汰策略是指在Redis的用于緩存的內存不足時,怎么處理需要新寫入且需要申請額外空間的數據。
全局的鍵空間選擇性移除:
noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯。
allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。(這個是最常用的)
allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。
設置過期時間的鍵空間選擇性移除
volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除 近 少使用的key。
volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。
volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。
Redis的過期鍵的刪除策略是指當Redis中的緩存的key過期了,Redis要如何處理。
Redis中提供了三種刪除策略:
1.定時刪除
當放入數據后,設置一個定時器,當定時器讀秒完畢后,將對應的數據從dict中刪除。
優點: 內存友好,數據一旦過期就會被刪除
缺點: CPU不友好,定時器耗費CPU資源,并且頻繁的執行清理操作也會耗費CPU資源。用時間換空間
2.惰性刪除
當數據過期的時候,不做任何操作。當訪問數據的時候,查看數據是否過期,如果過期返回null,并且將數據從內存中清除。如果沒過期,就直接返回數據。
優點: CPU友好,數據等到過期并且被訪問的時候,才會刪除。
缺點: 內存不友好,會占用大量內存。用空間換時間
3.定期刪除
定期刪除是定時刪除和惰性刪除的折中方案。每隔一段時間對redisServer中的所有redisDb的expires依次進行隨機抽取檢查。
Redis中有一個server.hz定義了每秒鐘執行定期刪除的次數,每次執行的時間為250ms/server.hz。Redis中會維護一個current_db變量來標志當前檢查的數據庫。current_db++,當超過數據庫的數量的時候,會重新從0開始。
定期檢查就是執行一個循環,循環中的每輪操作會從current_db對應的數據庫中隨機依次取出w個key,查看其是否過期。如果過期就將其刪除, 并且記錄刪除的key的個數。如果過期的key個數大于w25%,就會繼續檢查當前數據庫,當過期的key小于w25%,會繼續檢查下一個數據庫。當執行時間超過規定的最大執行時間的時候,會退出檢查。一次檢查中可以檢查多個數據庫,但是最多檢查數量是redisServer中的數據庫個數,也就是最多只能從當前位置檢查一圈。
可以在同一個服務器部署多個 Redis 的實例,并把他們當作不同的服 務器來使用,在某些時候,無論如何一個服務器是不夠的, 所以, 如果你想使用多個 CPU,你可以考慮一下分片(shard)。
分區可以讓Redis管理更大的內存,Redis將可以使用所有機器的內存。如果沒有分區,你最多只能使用一臺機器的內存。分區使Redis的計算能力通過簡單地增加計算機得到成倍提升,Redis的網絡帶寬也會隨著計算機和網卡的增加而成倍增長。
1.客戶端分區就是在客戶端就已經決定數據會被存儲到哪個redis節點或者從哪個redis節點讀取。大多數客戶端已經實現了客戶端分區。
2.代理分區 意味著客戶端將請求發送給代理,然后代理決定去哪個節點寫數據或者讀數據。代理根據分區規則決定請求哪些Redis實例,然后根據Redis的響應結果返回給客戶端。redis和memcached的一種代理實現就是Twemproxy。
3.查詢路由(Query routing) 的意思是客戶端隨機地請求任意一個redis實例,然后由Redis將請求轉發給正確的Redis節點。Redis Cluster實現了一種混合形式的查詢路由,但并不是直接將請求從一個redis節點轉發到另一個redis節點,而是在客戶端的幫助下直接redirected到正確的redis節點。
1.涉及多個key的操作通常不會被支持。例如你不能對兩個集合求交集,因為他們可能被存儲到不同的Redis實例(實際上這種情況也有辦法,但是不能直接使用交集指令)。
2.同時操作多個key,則不能使用Redis事務。
3.分區使用的粒度是key,不能使用一個非常長的排序key存儲一個數據集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set)
4.當使用分區的時候,數據處理會非常復雜,例如為了備份你必須從不同的Redis實例和主機同時收集RDB / AOF文件。
5.分區時動態擴容或縮容可能非常復雜。Redis集群在運行時增加或者刪除Redis節點,能做到最大程度對用戶透明地數據再平衡,但其他一些客戶端分區或者代理分區方法則不支持這種特性。然而,有一種預分片的技術也可以較好的解決這個問題。