Redis是單進程單線程的,Redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷。程序員
多線程處理會涉及到鎖,並且多線程處理會設計到線程切換而消耗CPU。由於CPU不會Redis的瓶頸,Redis的瓶頸最有多是機器內存或者網絡帶寬。單線程沒法發揮多核CPU性能,不過能夠經過在單機開啓Redis實例來解決。web
EXPIRE
和PERSIST
命令。redis
內存。算法
Redis爲了達到最快的讀寫速度將數據都讀到內存中,並經過異步的方式將數據寫入磁盤。數據庫
因此redis具備快速和數據持久化的特徵。若是不將數據放在內存中,磁盤I/O速度爲嚴重影響redis的性能。後端
在內存愈來愈便宜的今天,redis將會愈來愈受歡迎。 若是設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值。緩存
Redis集羣沒有使用一致性hash,而是引入了哈希槽的概念,Redis集羣有16384個哈希槽,每一個key經過CRC16校驗後對16384取模來決定放置哪一個槽,集羣的每一個節點負責一部分hash槽。安全
一次請求/響應服務器能實現處理新的請求即便舊的請求還未被響應。這樣就能夠將多個命令發送到服務器,而不用等待回覆,最後在一個步驟中讀取該答覆。性能優化
這就是管道(pipelining),是一種幾十年來普遍使用的技術。例如許多POP3協議已經實現支持這個功能,大大加快了從服務器下載新郵件的過程。服務器
事務是一個單獨的隔離操做:事務中的全部命令都會序列化、按順序地執行。事務在執行的過程當中,不會被其餘客戶端發送來的命令請求所打斷。
事務是一個原子操做:事務中的命令要麼所有被執行,要麼所有都不執行。
MULTI
、EXEC
、DISCARD
、WATCH
Redis的內存回收主要圍繞如下兩個方面:
Redis過時策略一般有如下三種:
定時過時 每一個設置過時時間的key都須要建立一個定時器,到過時時間就會當即清除。該策略能夠當即清除過時的數據,對內存很友好;可是會佔用大量的CPU資源去處理過時的數據,從而影響緩存的響應時間和吞吐量。
惰性過時 只有當訪問一個key時,纔會判斷該key是否已過時,過時則清除。該策略能夠最大化地節省CPU資源,卻對內存很是不友好。極端狀況可能出現大量的過時key沒有再次被訪問,從而不會被清除,佔用大量內存。
按期過時 每隔必定的時間,會掃描必定數量的數據庫的expires字典中必定數量的key,並清除其中已過時的key。該策略是前二者的一個折中方案。經過調整定時掃描的時間間隔和每次掃描的限定耗時,能夠在不一樣狀況下使得CPU和內存資源達到最優的平衡效果。
Redis中同時使用了惰性過時和按期過時兩種過時策略。
在Redis中,容許用戶設置最大使用內存大小server.maxmemory
,當Redis內存數據集大小上升到必定大小的時候,就會執行數據淘汰策略
RDB持久化 原理是將Redis在內存中的數據記錄定時dump到磁盤上的RDB文件。 指定的時間間隔內將內存中的數據集快照寫入磁盤,實際操做過程是fork一個子進程,先將數據集寫入臨時文件,寫入成功後,再替換以前的文件,用二進制壓縮存儲。
AOF(append only file)持久化 原理是將Redis的操做日誌以追加的方式寫入文件。 以日誌的形式記錄服務器所處理的每個寫、刪除操做,查詢操做不會記錄,以文本的方式記錄,能夠打開文件看到詳細的操做記錄。當服務器重啓的時候會從新執行這些命令來恢復原始的數據。AOF命令以Reids協議追加保存每次寫的操做到文件末尾。Redis還能對AOF文件進行後臺重寫,使得AOF文件的體積不至於過大。
RDB持久化
AOF持久化 與RDB持久化相對應,AOF的優勢在於支持秒級持久化、兼容性好,缺點是文件大,恢復速度慢,對性能影響大
在介紹持久化策略以前,首先要明白不管是RDB仍是AOF,持久化的開啓都是要付出性能方面的代價的。對比RDB持久化,一方面是bdsave在進行fork操做時Redis主進程會阻塞,另外一方面,子進程向硬盤寫數據也會帶來IO壓力;對於AOF持久化,向硬盤寫數據的頻率大大提升(everysec策略下爲秒級),IO壓力更大,設置可能形成AOF追加阻塞文件。此外,AOF文件的重寫與RDB的basave相似,會有fork時的阻塞和子進程的IO壓力問題。相對來講,因爲AOF向硬盤中寫數據的頻率更高,所以對Redis主進程性能的影響會更大。
在實際生產環境中,根據數據量、應用對數據的安全要求、預算限制等不一樣狀況,會有各類各樣的持久化策略;如徹底不使用任何持久化,使用RDB或AOF一種,或同事開啓RDB和AOF持久化等。此外,持久化的選擇必須與Redis的主從策略一塊兒考慮,由於主從複製與持久化一樣具備數據備份的功能,並且主機master和從機slave能夠獨立的選擇持久化方案。
分區可讓Redis管理更大的內存,Redis將可使用全部機器的內存。若是沒有分區,你最多隻能使用一臺機器的內存。分區使Redis的計算能力經過簡單地增長計算機獲得成倍提高,Redis的網絡帶寬也會隨着計算機和網卡的增長而成倍增加。
爲了是在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣是用了主從複製模型,每一個節點都會有N-1個複製品
Redis並不能保證數據強一致性,這意味着在實際中集羣在特定的條件下可能會丟失寫操做
異步複製。
儘量使用散列表(hashes),散列表(是說列表裏面存儲的數少)使用的內存很是小,因此你應該儘量的將你的數據模型抽象到一個散列表裏面,好比你的web系統中有一個用戶對象,不要爲這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶全部信息存儲到一張散列表中。
單機版
特色:簡單
存在問題:
主從複製
Redis的複製(replication)功能容許用戶根據一個Redis服務器來建立任意多個該服務器的複製品,其中被複制的服務器爲主服務器(master),而經過複製建立出來的服務器複製品則爲從服務器(slave)。主要主從服務器之間的網絡鏈接正常,主從服務器二者會具備相同的數據,主服務器就會一直將發生在本身身上的數據更新同步給從服務器,從而一直保證主從服務器的數據相同。
問題:
哨兵
Redis sentinel 是一個分佈式系統中監控 redis 主從服務器,並在主服務器下線時自動進行故障轉移。其中三個特性:
監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。
提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。
自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做。
特色:
缺點:
集羣(proxy型)
Twemproxy 是一個 Twitter 開源的一個 redis 和 memcache 快速/輕量級代理服務器; Twemproxy 是一個快速的單線程代理程序,支持 Memcached ASCII 協議和 redis 協議。
特色:
缺點:
集羣(直連型)
從redis 3.0以後版本支持redis-cluster集羣,Redis-Cluster採用無中心結構,每一個節點保存數據和整個集羣狀態,每一個節點都和其餘全部節點鏈接。
特色:
缺點:
先拿setnx來爭搶鎖,搶到以後,再用expire給鎖加一個過時時間防止鎖忘記了釋放。 若是在setnx以後執行expire以前進程意外crash或者要重啓維護了,那會怎麼樣? set指令有很是複雜的參數,這個應該是能夠同時把setnx和expire合成一條指令來用的!
般使用 list 結構做爲隊列,rpush 生產消息,lpop 消費消息。當 lpop 沒有消息的時候,要適當 sleep一會再重試。
缺點:
緩存穿透
通常的緩存系統,都是按照key去緩存查詢,若是不存在對應的value,就應該去後端系統查找(好比DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對後端系統形成很大的壓力。這就叫作緩存穿透。
如何避免?
對查詢結果爲空的狀況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了以後清理緩存。
對必定不存在的key進行過濾。能夠把全部的可能存在的key放到一個大的Bitmap中,查詢時經過該bitmap過濾。
緩存雪崩 當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給後端系統帶來很大壓力,致使系統崩潰。
如何避免?
這裏的併發指的是多個redis的client同時set key引發的併發問題。其實redis自身就是單線程操做,多個client併發操做,按照先到先執行的原則,先到的先執行,其他的阻塞。固然,另外的解決方案是把redis.set操做放在隊列中使其串行化,必須的一個一個執行。
緩存預熱就是系統上線後,將相關的緩存數據直接加載到緩存系統。
這樣就能夠避免在用戶請求的時候,先查詢數據庫,而後再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!
解決思路:
目的就是在系統上線前,將數據加載到緩存中。
能夠在同一個服務器部署多個Redis的實例,並把他們看成不一樣的服務器來使用,在某些時候,不管如何一個服務器是不夠的, 因此,若是你想使用多個CPU,你能夠考慮一下分片(shard)。
針對運行實例,有許多配置選項能夠經過 CONFIG SET 命令進行修改,而無需執行任何形式的重啓。 從 Redis 2.2 開始,能夠從 AOF 切換到 RDB 的快照持久性或其餘方式而不須要重啓 Redis。檢索 CONFIG GET *
命令獲取更多信息。 但偶爾從新啓動是必須的,如爲升級 Redis 程序到新的版本,或者當你須要修改某些目前 CONFIG 命令還不支持的配置參數的時候。
若是達到設置的上限,Redis的寫命令會返回錯誤信息(可是讀命令還能夠正常返回。)或者你能夠將Redis當緩存來使用配置淘汰機制,當Redis達到內存上限時會沖刷掉舊的內容。
既然Redis是如此的輕量(單實例只使用1M內存),爲防止之後的擴容,最好的辦法就是一開始就啓動較多實例。即使你只有一臺服務器,你也能夠一開始就讓Redis以分佈式的方式運行,使用分區,在同一臺服務器上啓動多個實例。一開始就多設置幾個Redis實例,例如32或者64個實例,對大多數用戶來講這操做起來可能比較麻煩,可是從長久來看作這點犧牲是值得的。這樣的話,當你的數據不斷增加,須要更多的Redis服務器時,你須要作的就是僅僅將Redis實例從一臺服務遷移到另一臺服務器而已(而不用考慮從新分區的問題)。一旦你添加了另外一臺服務器,你須要將你一半的Redis實例從第一臺機器遷移到第二臺機器。
Redis有着更爲複雜的數據結構而且提供對他們的原子性操做,這是一個不一樣於其餘數據庫的進化路徑。Redis的數據類型都是基於基本數據結構的同時對程序員透明,無需進行額外的抽象。Redis運行在內存中可是能夠持久化到磁盤,因此在對不一樣數據集進行高速讀寫時須要權衡內存,應爲數據量不能大於硬件內存。在內存數據庫方面的另外一個優勢是, 相比在磁盤上相同的複雜的數據結構,在內存中操做起來很是簡單,這樣Redis能夠作不少內部複雜性很強的事情。 同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,由於他們並不須要進行隨機訪問。
好文推薦: