redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷php
單進程單線程模式,採用隊列模式將併發訪問變爲串行訪問。Redis自己沒有鎖的概念,Redis對於多個客戶端鏈接並不存在競爭,利用setnx實現鎖。前端
./redis-serverjava
java、C、C#、C++、php、Node.js、Go等。git
Rdb 和 Aofgithub
持久化保證了即便redis服務重啓也不會丟失數據,由於redis服務重啓後會將硬盤上持久化的數據恢復到內存中,可是當redis服務器的硬盤損壞了可能會致使數據丟失,若是經過redis的主從複製機制就能夠避免這種單點故障,redis
一、徹底基於內存,絕大部分請求是純粹的內存操做,很是快速。數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1);算法
二、數據結構簡單,對數據操做也簡單,Redis中的數據結構是專門進行設計的;數據庫
三、採用單線程,避免了沒必要要的上下文切換和競爭條件,也不存在多進程或者多線程致使的切換而消耗 CPU,不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗;數組
四、使用多路I/O複用模型,非阻塞IO;這裏「多路」指的是多個網絡鏈接,「複用」指的是複用同一個線程緩存
五、使用底層模型不一樣,它們之間底層實現方式以及與客戶端之間通訊的應用協議不同,Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求;
Redis是基於內存的操做,CPU不是Redis的瓶頸,Redis的瓶頸最有多是機器內存的大小或者網絡帶寬。既然單線程容易實現,並且CPU不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了(畢竟採用多線程會有不少麻煩!)。
used_memory:Redis分配器分配的內存總量(單位是字節),包括使用的虛擬內存(即swap);Redis分配器後面會介紹。used_memory_human只是顯示更友好。
used_memory_rss:Redis進程佔據操做系統的內存(單位是字節),與top及ps命令看到的值是一致的;除了分配器分配的內存以外,used_memory_rss還包括進程運行自己須要的內存、內存碎片等,可是不包括虛擬內存。
mem_fragmentation_ratio:內存碎片比率,該值是used_memory_rss used_memory的比值。
mem_allocator:Redis使用的內存分配器,在編譯時指定;能夠是 libc 、jemalloc或者tcmalloc,默認是jemalloc;截圖中使用的即是默認的jemalloc。
做爲數據庫,數據是最主要的部分;這部分佔用的內存會統計在used_memory中。
Redis主進程自己運行確定須要佔用內存,如代碼、常量池等等;這部份內存大約幾兆,在大多數生產環境中與Redis數據佔用的內存相比能夠忽略。這部份內存不是由jemalloc分配,所以不會統計在used_memory中。
緩衝內存包括客戶端緩衝區、複製積壓緩衝區、AOF緩衝區等;其中,客戶端緩衝存儲客戶端鏈接的輸入輸出緩衝;複製積壓緩衝用於部分複製功能;AOF緩衝區用於在進行AOF重寫時,保存最近的寫入命令。在瞭解相應功能以前,不須要知道這些緩衝的細節;這部份內存由jemalloc分配,所以會統計在used_memory中。
內存碎片是Redis在分配、回收物理內存過程當中產生的。例如,若是對數據的更改頻繁,並且數據之間的大小相差很大,可能致使redis釋放的空間在物理內存中並無釋放,但redis又沒法有效利用,這就造成了內存碎片。內存碎片不會統計在used_memory中。
不管是哪一種類型,Redis都不會直接存儲,而是經過redisObject對象進行存儲。
(即以空字符’\0’結尾的字符數組)做爲默認的字符串表示,而是使用了SDS。SDS是簡單動態字符串(Simple Dynamic String)的縮寫。
複製是高可用Redis的基礎,哨兵和集羣都是在複製基礎上實現高可用的。複製主要實現了數據的多機備份,以及對於讀操做的負載均衡和簡單的故障恢復。缺陷:故障恢復沒法自動化;寫操做沒法負載均衡;存儲能力受到單機的限制。
在複製的基礎上,哨兵實現了自動化的故障恢復。缺陷:寫操做沒法負載均衡;存儲能力受到單機的限制。
RDB持久化的觸發分爲手動觸發和自動觸發兩種。
Redis服務器默認開啓RDB,關閉AOF;要開啓AOF,須要在配置文件中配置:
appendonly yes
下面是AOF經常使用的配置項,以及默認值;前面介紹過的這裏再也不詳細介紹。
RDB持久化
優勢:RDB文件緊湊,體積小,網絡傳輸快,適合全量複製;恢復速度比AOF快不少。固然,與AOF相比,RDB最重要的優勢之一是對性能的影響相對較小。
缺點:RDB文件的致命缺點在於其數據快照的持久化方式決定了必然作不到實時持久化,而在數據愈來愈重要的今天,數據的大量丟失不少時候是沒法接受的,所以AOF持久化成爲主流。此外,RDB文件須要知足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。
AOF持久化
與RDB持久化相對應,AOF的優勢在於支持秒級持久化、兼容性好,缺點是文件大、恢復速度慢、對性能影響大。
(1)若是Redis中的數據徹底丟棄也沒有關係(如Redis徹底用做DB層數據的cache),那麼不管是單機,仍是主從架構,均可以不進行任何持久化。
(2)在單機環境下(對於我的開發者,這種狀況可能比較常見),若是能夠接受十幾分鍾或更多的數據丟失,選擇RDB對Redis的性能更加有利;若是隻能接受秒級別的數據丟失,應該選擇AOF。
(3)但在多數狀況下,咱們都會配置主從環境,slave的存在既能夠實現數據的熱備,也能夠進行讀寫分離分擔Redis讀請求,以及在master宕掉後繼續提供服務。
使用mutex。簡單地來講,就是在緩存失效的時候(判斷拿出來的值爲空),不是當即去load db,而是先使用緩存工具的某些帶成功操做返回值的操做(好比Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操做返回成功時,再進行load db的操做並回設緩存;不然,就重試整個get緩存的方法
像慢查詢分析、性能測試、Pipeline、事務、Lua自定義命令、Bitmaps、HyperLogLog、發佈/訂閱、Geo等個性化功能。
# dbsize 返回當前數據庫 key 的數量。 # info 返回當前 redis 服務器狀態和一些統計信息。 # monitor 實時監聽並返回redis服務器接收到的全部請求信息。 # shutdown 把數據同步保存到磁盤上,並關閉redis服務。 # config get parameter 獲取一個 redis 配置參數信息。(個別參數可能沒法獲取) # config set parameter value 設置一個 redis 配置參數信息。(個別參數可能沒法獲取) # config resetstat 重置 info 命令的統計信息。(重置包括:keyspace 命中數、 # keyspace 錯誤數、 處理命令數,接收鏈接數、過時 key 數) # debug object key 獲取一個 key 的調試信息。 # debug segfault 製造一次服務器當機。 # flushdb 刪除當前數據庫中全部 key,此方法不會失敗。當心慎用 # flushall 刪除所有數據庫中全部 key,此方法不會失敗。當心慎用
# redis-server:Redis 服務器的 daemon 啓動程序 # redis-cli:Redis 命令行操做工具。固然,你也能夠用 telnet 根據其純文本協議來操做 # redis-benchmark:Redis 性能測試工具,測試 Redis 在你的系統及你的配置下的讀寫性能 $ redis-benchmark -n 100000 –c 50 模擬同時由 50 個客戶端發送 100000 個 SETs/GETs 查詢 # redis-check-aof:更新日誌檢查 # redis-check-dump:本地數據庫檢查
因爲Redis是一種內存型數據庫,即服務器在運行時,系統爲其分配了一部份內存存儲數據,一旦服務器掛了,或者忽然宕機了,那麼數據庫裏面的數據將會丟失,爲了使服務器即便忽然關機也能保存數據,必須經過持久化的方式將數據從內存保存到磁盤中。
exists key +key名字
del key1 key2 ...
分佈式環境下(單機就不用說了)很是容易出現緩存和數據庫間的數據一致性問題,針對這一點的話,只能說,若是你的項目對緩存的要求是強一致性的,那麼請不要使用緩存。咱們只能採起合適的策略來下降緩存和數據庫間數據不一致的機率,而沒法保證二者間的強一致性。合適的策略包括 合適的緩存更新策略,更新數據庫後要及時更新緩存、緩存失敗時增長重試機制,例如MQ模式的消息隊列。
bloomfilter就相似於一個hash set,用於快速判某個元素是否存在於集合中,其典型的應用場景就是快速判斷一個key是否存在於某容器,不存在就直接返回。布隆過濾器的關鍵就在於hash算法和容器大小
存在同一時間內大量鍵過時(失效),接着來的一大波請求瞬間都落在了數據庫中致使鏈接異常。
解決方案:
一、也是像解決緩存穿透同樣加鎖排隊。
二、創建備份緩存,緩存A和緩存B,A設置超時時間,B不設值超時時間,先從A讀緩存,A沒有讀B,而且更新A緩存和B緩存;
這裏的併發指的是多個redis的client同時set key引發的併發問題。比較有效的解決方案就是把redis.set操做放在隊列中使其串行化,必須的一個一個執行,具體的代碼就不上了,固然加鎖也是能夠的,至於爲何不用redis中的事務,留給各位看官本身思考探究。
redis支持主從的模式。原則:Master會將數據同步到slave,而slave不會將數據同步到master。Slave啓動時會鏈接master來同步數據。
這是一個典型的分佈式讀寫分離模型。咱們能夠利用master來插入數據,slave提供檢索服務。這樣能夠有效減小單個機器的併發訪問數量
經過增長Slave DB的數量,讀的性能能夠線性增加。爲了不Master DB的單點故障,集羣通常都會採用兩臺Master DB作雙機熱備,因此整個集羣的讀和寫的可用性都很是高。讀寫分離架構的缺陷在於,無論是Master仍是Slave,每一個節點都必須保存完整的數據,若是在數據量很大的狀況下,集羣的擴展能力仍是受限於單個節點的存儲能力,並且對於Write-intensive類型的應用,讀寫分離架構並不適合。
爲了解決讀寫分離模型的缺陷,能夠將數據分片模型應用進來。
能夠將每一個節點當作都是獨立的master,而後經過業務實現數據分片。
結合上面兩種模型,能夠將每一個master設計成由一個master和多個slave組成的模型。
Master最好不要作任何持久化工做,如RDB內存快照和AOF日誌文件
若是數據比較重要,某個Slave開啓AOF備份數據,策略設置爲每秒同步一次
爲了主從複製的速度和鏈接的穩定性,Master和Slave最好在同一個局域網內
儘可能避免在壓力很大的主庫上增長從庫
RESP 是redis客戶端和服務端以前使用的一種通信協議;RESP 的特色:實現簡單、快速解析、可讀性好
先拿setnx來爭搶鎖,搶到以後,再用expire給鎖加一個過時時間防止鎖忘記了釋放。**若是在setnx以後執行expire以前進程意外crash或者要重啓維護了,那會怎麼樣?**set指令有很是複雜的參數,這個應該是能夠同時把setnx和expire合成一條指令來用的!
通常使用list結構做爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。缺點:在消費者下線的狀況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。**能不能生產一次消費屢次呢?**使用pub/sub主題訂閱者模式,能夠實現1:N的消息隊列。
利用SCAN系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成數據迭代。
在某些場景下咱們在一次操做中可能須要執行多個命令,而若是咱們只是一個命令一個命令去執行則會浪費不少網絡消耗時間,若是將命令一次性傳輸到 Redis
中去再執行,則會減小不少開銷時間。可是須要注意的是 pipeline
中的命令並非原子性執行的,也就是說管道中的命令到達 Redis
服務器的時候可能會被其餘的命令穿插
class LRUCache<K, V\> extends LinkedHashMap<K, V\> { private final int CACHE\_SIZE; /\*\* \* 傳遞進來最多能緩存多少數據 \* \* @param cacheSize 緩存大小 \*/ public LRUCache(int cacheSize) { // true 表示讓 linkedHashMap 按照訪問順序來進行排序,最近訪問的放在頭部,最老訪問的放在尾部。 super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); CACHE\_SIZE \= cacheSize; } @Override protected boolean removeEldestEntry(Map.Entry<K, V\> eldest) { // 當 map中的數據量大於指定的緩存個數的時候,就自動刪除最老的數據。 return size() \> CACHE\_SIZE; } }
獲取當前時間(start)。
依次向 N 個 Redis
節點請求鎖。請求鎖的方式與從單節點 Redis
獲取鎖的方式一致。爲了保證在某個 Redis
節點不可用時該算法可以繼續運行,獲取鎖的操做都須要設置超時時間,須要保證該超時時間遠小於鎖的有效時間。這樣才能保證客戶端在向某個 Redis
節點獲取鎖失敗以後,能夠馬上嘗試下一個節點。
計算獲取鎖的過程總共消耗多長時間(consumeTime = end - start)。若是客戶端從大多數 Redis
節點(>= N/2 + 1) 成功獲取鎖,而且獲取鎖總時長沒有超過鎖的有效時間,這種狀況下,客戶端會認爲獲取鎖成功,不然,獲取鎖失敗。
若是最終獲取鎖成功,鎖的有效時間應該從新設置爲鎖最初的有效時間減去 consumeTime
。
若是最終獲取鎖失敗,客戶端應該馬上向全部 Redis
節點發起釋放鎖的請求。
定時刪除:在設置鍵的過時時間的同時,建立一個定時任務,當鍵達到過時時間時,當即執行對鍵的刪除操做
惰性刪除:聽任鍵過時無論,但在每次從鍵空間獲取鍵時,都檢查取得的鍵是否過時,若是過時的話,就刪除該鍵,若是沒有過時,就返回該鍵
按期刪除:每隔一點時間,程序就對數據庫進行一次檢查,刪除裏面的過時鍵,至於要刪除多少過時鍵,以及要檢查多少個數據庫,則由算法決定。
因爲定時刪除會佔用太多cpu時間,影響服務器的響應時間和吞吐量以及惰性刪除浪費太多內存,有內存泄露的危險,因此出現一種整合和折中這兩種策略的按期刪除策略。
github地址
Redis module 是Redis 4.0 之後支持的新的特性,這裏不少國外牛逼的大學和機構提供了不少牛逼的Module 只要編譯引入到Redis 中就能輕鬆的實現咱們某些需求的功能。在Redis 官方Module 中有一些咱們常見的一些模塊,咱們在這裏就作一個簡單的使用。
GEOADD key longitude latitude member \[longitude latitude member ...\]
將給定的位置對象(緯度、經度、名字)添加到指定的key。其中,key爲集合名稱,member爲該經緯度所對應的對象。在實際運用中,當所需存儲的對象數量過多時,可經過設置多key(如一個省一個key)的方式對對象集合變相作sharding,避免單集合數量過多。
成功插入後的返回值:
(integer) N
其中N爲成功插入的個數。