Redis 大全
Published: 2020-08-25 11:01:54


概述
什麼是Redis
Redis(Remote Dictionary Server) 是一個使用C 語言編寫的，開源的（BSD許可）高性能非關係型（NoSQL）的鍵值對數據庫。
Redis 可以存儲鍵和五種不同類型的值之間的映射。鍵的類型只能為字符串，值支持五種數據類型：字符串、列表、集合、散列表、有序集合。
與傳統數據庫不同的是Redis 的數據是存在內存中的，所以讀寫速度非常快，因此redis 被廣泛應用於緩存方向，每秒可以處理超過10萬次讀寫操作，是已知性能最快的Key-Value DB。另外，Redis 也經常用來做分佈式鎖。除此之外，Redis 支持事務、持久化、LUA腳本、LRU驅動事件、多種集群方案。
Redis有哪些優缺點
優點
讀寫性能優異， Redis能讀的速度是110000次/s，寫的速度是81000次/s。
支持數據持久化，支持AOF和RDB兩種持久化方式。
支持事務，Redis的所有操作都是原子性的，同時Redis還支持對幾個操作合併後的原子性執行。
數據結構豐富，除了支持string類型的value外還支持hash、set、zset、list等數據結構。
支持主從復制，主機會自動將數據同步到從機，可以進行讀寫分離。
缺點
數據庫容量受到物理內存的限制，不能用作海量數據的高性能讀寫，因此Redis適合的場景主要局限在較小數據量的高性能操作和運算上。
Redis 不具備自動容錯和恢復功能，主機從機的宕機都會導致前端部分讀寫請求失敗，需要等待機器重啟或者手動切換前端的IP才能恢復。
主機宕機，宕機前有部分數據未能及時同步到從機，切換IP後還會引入數據不一致的問題，降低了系統的可用性。
Redis 較難支持在線擴容，在集群容量達到上限時在線擴容會變得很複雜。為避免這一問題，運維人員在系統上線時必須確保有足夠的空間，這對資源造成了很大的浪費。
為什麼要用Redis /為什麼要用緩存
主要從“高性能”和“高並發”這兩點來看待這個問題。
高性能：
假如用戶第一次訪問數據庫中的某些數據。這個過程會比較慢，因為是從硬盤上讀取的。將該用戶訪問的數據存在數緩存中，這樣下一次再訪問這些數據的時候就可以直接從緩存中獲取了。操作緩存就是直接操作內存，所以速度相當快。如果數據庫中的對應數據改變的之後，同步改變緩存中相應的數據即可！
高並發：
直接操作緩存能夠承受的請求是遠遠大於直接訪問數據庫的，所以我們可以考慮把數據庫中的部分數據轉移到緩存中去，這樣用戶的一部分請求會直接到緩存這里而不用經過數據庫。
為什麼要用Redis 而不用map/guava 做緩存?
緩存分為本地緩存和分佈式緩存。以Java 為例，使用自帶的map 或者guava 實現的是本地緩存，最主要的特點是輕量以及快速，生命週期隨著jvm 的銷毀而結束，並且在多實例的情況下，每個實例都需要各自保存一份緩存，緩存不具有一致性。
使用redis 或memcached 之類的稱為分佈式緩存，在多實例的情況下，各實例共用一份緩存數據，緩存具有一致性。缺點是需要保持redis 或memcached服務的高可用，整個程序架構上較為複雜。
Redis為什麼這麼快
1、完全基於內存，絕大部分請求是純粹的內存操作，非常快速。數據存在內存中，類似於HashMap，HashMap 的優勢就是查找和操作的時間複雜度都是O(1)；
2、數據結構簡單，對數據操作也簡單，Redis 中的數據結構是專門進行設計的；
3、採用單線程，避免了不必要的上下文切換和競爭條件，也不存在多進程或者多線程導致的切換而消耗CPU，不用去考慮各種鎖的問題，不存在加鎖釋放鎖操作，沒有因為可能出現死鎖而導致的性能消耗；
4、使用多路I/O 復用模型，非阻塞IO；
5、使用底層模型不同，它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣，Redis 直接自己構建了VM 機制，因為一般的系統調用系統函數的話，會浪費一定的時間去移動和請求；
數據類型
Redis有哪些數據類型
Redis主要有5種數據類型，包括String，List，Set，Zset，Hash，滿足大部分的使用要求
Redis的應用場景
總結一
計數器
可以對String 進行自增自減運算，從而實現計數器功能。Redis 這種內存型數據庫的讀寫性能非常高，很適合存儲頻繁讀寫的計數量。
緩存
將熱點數據放到內存中，設置內存的最大使用量以及淘汰策略來保證緩存的命中率。
會話緩存
可以使用Redis 來統一存儲多台應用服務器的會話信息。當應用服務器不再存儲用戶的會話信息，也就不再具有狀態，一個用戶可以請求任意一個應用服務器，從而更容易實現高可用性以及可伸縮性。
全頁緩存（FPC）
除基本的會話token之外，Redis還提供很簡便的FPC平台。以Magento為例，Magento提供一個插件來使用Redis作為全頁緩存後端。此外，對WordPress的用戶來說，Pantheon有一個非常好的插件wp-redis，這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
查找表
例如DNS 記錄就很適合使用Redis 進行存儲。查找表和緩存類似，也是利用了Redis 快速的查找特性。但是查找表的內容不能失效，而緩存的內容可以失效，因為緩存不作為可靠的數據來源。
消息隊列(發布/訂閱功能)
List 是一個雙向鍊錶，可以通過lpush 和rpop 寫入和讀取消息。不過最好使用Kafka、RabbitMQ 等消息中間件。
分佈式鎖實現
在分佈式場景下，無法使用單機環境下的鎖來對多個節點上的進程進行同步。可以使用Redis 自帶的SETNX 命令實現分佈式鎖，除此之外，還可以使用官方提供的RedLock 分佈式鎖實現。
其它
Set 可以實現交集、並集等操作，從而實現共同好友等功能。ZSet 可以實現有序性操作，從而實現排行榜等功能。
總結二
Redis相比其他緩存，有一個非常大的優勢，就是支持多種數據類型。
數據類型說明string字符串，最簡單的kv存儲hashhash格式，value為field和value，適合ID-Detail這樣的場景。list簡單的list，順序列表，支持首位或者末尾插入數據set無序list，查找速度快，適合交集、並集、差集處理sorted set有序的set
其實，通過上面的數據類型的特性，基本就能想到合適的應用場景了。
string——適合最簡單的kv存儲，類似於memcached的存儲結構，短信驗證碼，配置信息等，就用這種類型來存儲。
hash——一般key為ID或者唯一標示，value對應的就是詳情了。如商品詳情，個人信息詳情，新聞詳情等。
list——因為list是有序的，比較適合存儲一些有序且數據相對固定的數據。如省市區表、字典表等。因為list是有序的，適合根據寫入的時間來排序，如：最新的***，消息隊列等。
持久化
什麼是Redis持久化？
持久化就是把內存的數據寫到磁盤中去，防止服務宕機了內存數據丟失。
Redis 的持久化機制是什麼？各自的優缺點？
Redis 提供兩種持久化機制RDB（默認） 和AOF 機制:
RDB：是Redis DataBase縮寫快照
RDB是Redis默認的持久化方式。按照一定的時間將內存的數據以快照的形式保存到硬盤中，對應產生的數據文件為dump.rdb。通過配置文件中的save參數來定義快照的周期。
set——可以簡單的理解為ID-List的模式，如微博中一個人有哪些好友，set最牛的地方在於，可以對兩個set提供交集、並集、差集操作。例如：查找兩個人共同的好友等。
Sorted Set——是set的增強版本，增加了一個score參數，自動會根據score的值進行排序。比較適合類似於top 10等不根據插入的時間來排序的數據。
如上所述，雖然Redis不像關係數據庫那麼複雜的數據結構，但是，也能適合很多場景，比一般的緩存數據結構要多。了解每種數據結構適合的業務場景，不僅有利於提升開發效率，也能有效利用Redis的性能。
優點：
1、只有一個文件dump.rdb，方便持久化。
2、容災性好，一個文件可以保存到安全的磁盤。
3、性能最大化，fork 子進程來完成寫操作，讓主進程繼續處理命令，所以是IO 最大化。使用單獨子進程來進行持久化，主進程不會進行任何IO 操作，保證了redis 的高性能
4.相對於數據集大時，比AOF 的啟動效率更高。
缺點：
1、數據安全性低。RDB 是間隔一段時間進行持久化，如果持久化之間redis 發生故障，會發生數據丟失。所以這種方式更適合數據要求不嚴謹的時候)
2、AOF（Append-only file)持久化方式：是指所有的命令行記錄以redis 命令請求協議的格式完全持久化存儲)保存為aof 文件。
AOF：持久化
AOF持久化(即Append Only File持久化)，則是將Redis執行的每次寫命令記錄到單獨的日誌文件中，當重啟Redis會重新將持久化的日誌中文件恢復數據。
當兩種方式同時開啟時，數據恢復Redis會優先選擇AOF恢復。
優點：
1、數據安全，aof 持久化可以配置appendfsync 屬性，有always，每進行一次命令操作就記錄到aof 文件中一次。
2、通過append 模式寫文件，即使中途服務器宕機，可以通過redis-check-aof 工具解決數據一致性問題。
3、AOF 機制的rewrite 模式。AOF 文件沒被rewrite 之前（文件過大時會對命令進行合併重寫），可以刪除其中的某些命令（比如誤操作的flushall）)
缺點：
1、AOF 文件比RDB 文件大，且恢復速度慢。
2、數據集大的時候，比rdb 啟動效率低。
優缺點是什麼？
AOF文件比RDB更新頻率高，優先使用AOF還原數據。
AOF比RDB更安全也更大
RDB性能比AOF好
如果兩個都配了優先加載AOF
如何選擇合適的持久化方式
一般來說， 如果想達到足以媲美PostgreSQL的數據安全性，你應該同時使用兩種持久化功能。在這種情況下，當Redis 重啟的時候會優先載入AOF文件來恢復原始的數據，因為在通常情況下AOF文件保存的數據集要比RDB文件保存的數據集要完整。
如果你非常關心你的數據， 但仍然可以承受數分鐘以內的數據丟失，那麼你可以只使用RDB持久化。
有很多用戶都只使用AOF持久化，但並不推薦這種方式，因為定時生成RDB快照（snapshot）非常便於進行數據庫備份， 並且RDB 恢復數據集的速度也要比AOF恢復的速度要快，除此之外，使用RDB還可以避免AOF程序的bug。
如果你只希望你的數據在服務器運行的時候存在，你也可以不使用任何持久化方式。
Redis持久化數據和緩存怎麼做擴容？
如果Redis被當做緩存使用，使用一致性哈希實現動態擴容縮容。
如果Redis被當做一個持久化存儲使用，必須使用固定的keys-to-nodes映射關係，節點的數量一旦確定不能變化。否則的話(即Redis節點需要動態變化的情況），必須使用可以在運行時進行數據再平衡的一套系統，而當前只有Redis集群可以做到這樣。
過期鍵的刪除策略
Redis的過期鍵的刪除策略
我們都知道，Redis是key-value數據庫，我們可以設置Redis中緩存的key的過期時間。Redis的過期策略就是指當Redis中緩存的key過期了，Redis如何處理。
過期策略通常有以下三種：
定時過期：每個設置過期時間的key都需要創建一個定時器，到過期時間就會立即清除。該策略可以立即清除過期的數據，對內存很友好；但是會佔用大量的CPU資源去處理過期的數據，從而影響緩存的響應時間和吞吐量。
惰性過期：只有當訪問一個key時，才會判斷該key是否已過期，過期則清除。該策略可以最大化地節省CPU資源，卻對內存非常不友好。極端情況可能出現大量的過期key沒有再次被訪問，從而不會被清除，佔用大量內存。
定期過期：每隔一定的時間，會掃描一定數量的數據庫的expires字典中一定數量的key，並清除其中已過期的key。該策略是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時，可以在不同情況下使得CPU和內存資源達到最優的平衡效果。
(expires字典會保存所有設置了過期時間的key的過期時間數據，其中，key是指向鍵空間中的某個鍵的指針，value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis集群中保存的所有鍵。)
Redis中同時使用了惰性過期和定期過期兩種過期策略。
Redis key的過期時間和永久有效分別怎麼設置？
EXPIRE和PERSIST命令。
我們知道通過expire來設置key 的過期時間，那麼對過期的數據怎麼處理呢?
除了緩存服務器自帶的緩存失效策略之外（Redis默認的有6中策略可供選擇），我們還可以根據具體的業務需求進行自定義的緩存淘汰，常見的策略有兩種：
定時去清理過期的緩存；
當有用戶請求過來時，再判斷這個請求所用到的緩存是否過期，過期的話就去底層系統得到新數據並更新緩存。
兩者各有優劣，第一種的缺點是維護大量緩存的key是比較麻煩的，第二種的缺點就是每次用戶請求過來都要判斷緩存失效，邏輯相對比較複雜！具體用哪種方案，大家可以根據自己的應用場景來權衡。
內存相關
MySQL裡有2000w數據，redis中只存20w的數據，如何保證redis中的數據都是熱點數據
redis內存數據集大小上升到一定大小的時候，就會施行數據淘汰策略。
Redis的內存淘汰策略有哪些
Redis的內存淘汰策略是指在Redis的用於緩存的內存不足時，怎麼處理需要新寫入且需要申請額外空間的數據。
全局的鍵空間選擇性移除
noeviction：當內存不足以容納新寫入數據時，新寫入操作會報錯。
allkeys-lru：當內存不足以容納新寫入數據時，在鍵空間中，移除最近最少使用的key。（這個是最常用的）
allkeys-random：當內存不足以容納新寫入數據時，在鍵空間中，隨機移除某個key。
設置過期時間的鍵空間選擇性移除
volatile-lru：當內存不足以容納新寫入數據時，在設置了過期時間的鍵空間中，移除最近最少使用的key。
volatile-random：當內存不足以容納新寫入數據時，在設置了過期時間的鍵空間中，隨機移除某個key。
volatile-ttl：當內存不足以容納新寫入數據時，在設置了過期時間的鍵空間中，有更早過期時間的key優先移除。
總結
Redis的內存淘汰策略的選取並不會影響過期的key的處理。內存淘汰策略用於處理內存不足時的需要申請額外空間的數據；過期策略用於處理過期的緩存數據。
Redis主要消耗什麼物理資源？
內存。
Redis的內存用完了會發生什麼？
如果達到設置的上限，Redis的寫命令會返回錯誤信息（但是讀命令還可以正常返回。）或者你可以配置內存淘汰機制，當Redis達到內存上限時會沖刷掉舊的內容。
Redis如何做內存優化？
可以好好利用Hash,list,sorted set,set等集合類型數據，因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。盡可能使用散列表（hashes），散列表（是說散列表裡面存儲的數少）使用的內存非常小，所以你應該盡可能的將你的數據模型抽像到一個散列表裡面。比如你的web系統中有一個用戶對象，不要為這個用戶的名稱，姓氏，郵箱，密碼設置單獨的key，而是應該把這個用戶的所有信息存儲到一張散列表裡面
線程模型
Redis線程模型
Redis基於Reactor模式開發了網絡事件處理器，這個處理器被稱為文件事件處理器（file event handler）。它的組成結構為4部分：多個套接字、IO多路復用程序、文件事件分派器、事件處理器。因為文件事件分派器隊列的消費是單線程的，所以Redis才叫單線程模型。
文件事件處理器使用I/O 多路復用（multiplexing）程序來同時監聽多個套接字， 並根據套接字目前執行的任務來為套接字關聯不同的事件處理器。
當被監聽的套接字準備好執行連接應答（accept）、讀取（read）、寫入（write）、關閉（close）等操作時， 與操作相對應的文件事件就會產生， 這時文件事件處理器就會調用套接字之前關聯好的事件處理器來處理這些事件。
雖然文件事件處理器以單線程方式運行， 但通過使用I/O 多路復用程序來監聽多個套接字， 文件事件處理器既實現了高性能的網絡通信模型， 又可以很好地與redis 服務器中其他同樣以單線程方式運行的模塊進行對接， 這保持了Redis 內部單線程設計的簡單性。
事務
什麼是事務？
事務是一個單獨的隔離操作：事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中，不會被其他客戶端發送來的命令請求所打斷。
事務是一個原子操作：事務中的命令要么全部被執行，要么全部都不執行。
Redis事務的概念
Redis 事務的本質是通過MULTI、EXEC、WATCH等一組命令的集合。事務支持一次執行多個命令，一個事務中所有命令都會被序列化。在事務執行過程，會按照順序串行化執行隊列中的命令，其他客戶端提交的命令請求不會插入到事務執行命令序列中。
總結說：redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令。
Redis事務的三個階段
事務開始MULTI
命令入隊
事務執行EXEC
事務執行過程中，如果服務端收到有EXEC、DISCARD、WATCH、MULTI之外的請求，將會把請求放入隊列中排隊
Redis事務相關命令
Redis事務功能是通過MULTI、EXEC、DISCARD和WATCH 四個原語實現的
Redis會將一個事務中的所有命令序列化，然後按順序執行。
redis不支持回滾，“Redis在事務失敗時不進行回滾，而是繼續執行餘下的命令”，所以Redis的內部可以保持簡單且快速。
如果在一個事務中的命令出現錯誤，那麼所有的命令都不會執行；
如果在一個事務中出現運行錯誤，那麼正確的命令會被執行
WATCH 命令是一個樂觀鎖，可以為Redis 事務提供check-and-set （CAS）行為。可以監控一個或多個鍵，一旦其中有一個鍵被修改（或刪除），之後的事務就不會執行，監控一直持續到EXEC命令。
MULTI命令用於開啟一個事務，它總是返回OK。MULTI執行之後，客戶端可以繼續向服務器發送任意多條命令，這些命令不會立即被執行，而是被放到一個隊列中，當EXEC命令被調用時，所有隊列中的命令才會被執行。
EXEC：執行所有事務塊內的命令。返回事務塊內所有命令的返回值，按命令執行的先後順序排列。當操作被打斷時，返回空值nil 。
通過調用DISCARD，客戶端可以清空事務隊列，並放棄執行事務， 並且客戶端會從事務狀態中退出。
UNWATCH命令可以取消watch對所有key的監控。
事務管理（ACID）概述
原子性（Atomicity）
原子性是指事務是一個不可分割的工作單位，事務中的操作要么都發生，要么都不發生。
一致性（Consistency）
事務前後數據的完整性必須保持一致。
隔離性（Isolation）
多個事務並發執行時，一個事務的執行不應影響其他事務的執行
持久性（Durability）
持久性是指一個事務一旦被提交，它對數據庫中數據的改變就是永久性的，接下來即使數據庫發生故障也不應該對其有任何影響
Redis的事務總是具有ACID中的一致性和隔離性，其他特性是不支持的。當服務器運行在AOF持久化模式下，並且appendfsync選項的值為always時，事務也具有耐久性。
Redis事務支持隔離性嗎
Redis是單進程程序，並且它保證在執行事務時，不會對事務進行中斷，事務可以運行直到執行完所有事務隊列中的命令為止。因此，Redis的事務是總是帶有隔離性的。
Redis事務保證原子性嗎，支持回滾嗎
Redis中，單條命令是原子性執行的，但事務不保證原子性，且沒有回滾。事務中任意命令執行失敗，其餘的命令仍會被執行
Redis事務其他實現
基於Lua腳本，Redis可以保證腳本內的命令一次性、按順序地執行，
其同時也不提供事務運行錯誤的回滾，執行過程中如果部分命令運行錯誤，剩下的命令還是會繼續運行完
基於中間標記變量，通過另外的標記變量來標識事務是否執行完成，讀取數據時先讀取該標記變量判斷是否事務執行完成。但這樣會需要額外寫代碼實現，比較繁瑣
集群方案
哨兵模式
哨兵的介紹
sentinel，中文名是哨兵。哨兵是redis 集群機構中非常重要的一個組件，主要有以下功能：
集群監控：負責監控redis master 和slave 進程是否正常工作。
消息通知：如果某個redis 實例有故障，那麼哨兵負責發送消息作為報警通知給管理員。
故障轉移：如果master node 掛掉了，會自動轉移到slave node 上。
配置中心：如果故障轉移發生了，通知client 客戶端新的master 地址。
哨兵用於實現redis 集群的高可用，本身也是分佈式的，作為一個哨兵集群去運行，互相協同工作。
故障轉移時，判斷一個master node 是否宕機了，需要大部分的哨兵都同意才行，涉及到了分佈式選舉的問題。
即使部分哨兵節點掛掉了，哨兵集群還是能正常工作的，因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的，那就很坑爹了。
哨兵的核心知識
哨兵至少需要3 個實例，來保證自己的健壯性。
哨兵+ redis主從的部署架構，是不保證數據零丟失的，只能保證redis集群的高可用性。
對於哨兵+ redis 主從這種複雜的部署架構，盡量在測試環境和生產環境，都進行充足的測試和演練。
哨兵的介紹
sentinel，中文名是哨兵。哨兵是redis 集群機構中非常重要的一個組件，主要有以下功能：
集群監控：負責監控redis master 和slave 進程是否正常工作。
消息通知：如果某個redis 實例有故障，那麼哨兵負責發送消息作為報警通知給管理員。
故障轉移：如果master node 掛掉了，會自動轉移到slave node 上。
配置中心：如果故障轉移發生了，通知client 客戶端新的master 地址。
哨兵用於實現redis 集群的高可用，本身也是分佈式的，作為一個哨兵集群去運行，互相協同工作。
故障轉移時，判斷一個master node 是否宕機了，需要大部分的哨兵都同意才行，涉及到了分佈式選舉的問題。
即使部分哨兵節點掛掉了，哨兵集群還是能正常工作的，因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的，那就很坑爹了。
哨兵的核心知識
哨兵至少需要3 個實例，來保證自己的健壯性。
哨兵+ redis主從的部署架構，是不保證數據零丟失的，只能保證redis集群的高可用性。
對於哨兵+ redis 主從這種複雜的部署架構，盡量在測試環境和生產環境，都進行充足的測試和演練。
在redis cluster 架構下，每個redis 要放開兩個端口號，比如一個是6379，另外一個就是加1w 的端口號，比如16379。
16379 端口號是用來進行節點間通信的，也就是cluster bus 的東西，cluster bus 的通信，用來進行故障檢測、配置更新、故障轉移授權。cluster bus 用了另外一種二進制的協議，gossip 協議，用於節點間進行高效的數據交換，佔用更少的網絡帶寬和處理時間。
節點間的內部通信機制
基本通信原理
集群元數據的維護有兩種方式：集中式、Gossip 協議。redis cluster 節點間採用gossip 協議進行通信。
分佈式尋址算法
hash 算法（大量緩存重建）
一致性hash 算法（自動緩存遷移）+ 虛擬節點（自動負載均衡）
redis cluster 的hash slot 算法
優點
無中心架構，支持動態擴容，對業務透明
具備Sentinel的監控和自動Failover(故障轉移)能力
客戶端不需要連接集群所有節點，連接集群中任何一個可用節點即可
高性能，客戶端直連redis服務，免去了proxy代理的損耗
缺點
運維也很複雜，數據遷移需要人工干預
只能使用0號數據庫
不支持批量操作(pipeline管道操作)
分佈式邏輯和存儲模塊耦合等
Redis Sharding是Redis Cluster出來之前，業界普遍使用的多Redis實例集群方法。其主要思想是採用哈希算法將Redis數據的key進行散列，通過hash函數，特定的key會映射到特定的Redis節點上。Java redis客戶端驅動jedis，支持Redis Sharding功能，即ShardedJedis以及結合緩存池的ShardedJedisPool
優點
優勢在於非常簡單，服務端的Redis實例彼此獨立，相互無關聯，每個Redis實例像單服務器一樣運行，非常容易線性擴展，系統的靈活性很強
缺點
由於sharding處理放到客戶端，規模進一步擴大時給運維帶來挑戰。
客戶端sharding不支持動態增刪節點。服務端Redis實例群拓撲結構有變化時，每個客戶端都需要更新調整。連接不能共享，當應用規模增大時，資源浪費制約優化
基於代理服務器分片
簡介
客戶端發送請求到一個代理組件，代理解析客戶端的數據，並將請求轉發至正確的節點，最後將結果回复給客戶端
特徵
透明接入，業務程序不用關心後端Redis實例，切換成本低
Proxy 的邏輯和存儲的邏輯是隔離的
代理層多了一次轉發，性能有所損耗
Redis 主從架構
單機的redis，能夠承載的QPS 大概就在上萬到幾萬不等。對於緩存來說，一般都是用來支撐讀高並發的。因此架構做成主從(master-slave)架構，一主多從，主負責寫，並且將數據複製到其它的slave 節點，從節點負責讀。所有的讀請求全部走從節點。這樣也可以很輕鬆實現水平擴容，支撐讀高並發。
redis replication 的核心機制
redis 採用異步方式複制數據到slave 節點，不過redis2.8 開始，slave node 會周期性地確認自己每次復制的數據量；
一個master node 是可以配置多個slave node 的；
slave node 也可以連接其他的slave node；
slave node 做複製的時候，不會block master node 的正常工作；
slave node 在做複製的時候，也不會block 對自己的查詢操作，它會用舊的數據集來提供服務；但是複製完成的時候，需要刪除舊數據集，加載新數據集，這個時候就會暫停對外服務了；
slave node 主要用來進行橫向擴容，做讀寫分離，擴容的slave node 可以提高讀的吞吐量。
注意，如果採用了主從架構，那麼建議必須開啟master node 的持久化，不建議用slave node 作為master node 的數據熱備，因為那樣的話，如果你關掉master 的持久化，可能在master 宕機重啟的時候數據是空的，然後可能一經過複製， slave node 的數據也丟了。
另外，master 的各種備份方案，也需要做。萬一本地的所有文件丟失了，從備份中挑選一份rdb 去恢復master，這樣才能確保啟動的時候，是有數據的，即使採用了後續講解的高可用機制，slave node 可以自動接管master node，但也可能sentinel 還沒檢測到master failure，master node 就自動重啟了，還是可能導致上面所有的slave node 數據被清空。
redis 主從復制的核心原理
當啟動一個slave node 的時候，它會發送一個PSYNC 命令給master node。
如果這是slave node 初次連接到master node，那麼會觸發一次full resynchronization 全量複製。此時master 會啟動一個後台線程，開始生成一份RDB 快照文件，
同時還會將從客戶端client 新收到的所有寫命令緩存在內存中。RDB 文件生成完畢後， master 會將這個RDB 發送給slave，slave 會先寫入本地磁盤，然後再從本地磁盤加載到內存中，
接著master 會將內存中緩存的寫命令發送到slave，slave 也會同步這些數據。
slave node 如果跟master node 有網絡故障，斷開了連接，會自動重連，連接之後master node 僅會復制給slave 部分缺少的數據。
過程原理
當從庫和主庫建立MS關係後，會向主數據庫發送SYNC命令
主庫接收到SYNC命令後會開始在後台保存快照(RDB持久化過程)，並將期間接收到的寫命令緩存起來
當快照完成後，主Redis會將快照文件和所有緩存的寫命令發送給從Redis
從Redis接收到後，會載入快照文件並且執行收到的緩存的命令
之後，主Redis每當接收到寫命令時就會將命令發送從Redis，從而保證數據的一致
缺點
所有的slave節點數據的複制和同步都由master節點來處理，會照成master節點壓力太大，使用主從從結構來解決
Redis集群的主從復制模型是怎樣的？
為了使在部分節點失敗或者大部分節點無法通信的情況下集群仍然可用，所以集群使用了主從復制模型，每個節點都會有N-1個複製品
分區
Redis是單線程的，如何提高多核CPU的利用率？
可以在同一個服務器部署多個Redis的實例，並把他們當作不同的服務器來使用，在某些時候，無論如何一個服務器是不夠的， 所以，如果你想使用多個CPU，你可以考慮一下分片（shard）。
為什麼要做Redis分區？
分區可以讓Redis管理更大的內存，Redis將可以使用所有機器的內存。如果沒有分區，你最多只能使用一台機器的內存。分區使Redis的計算能力通過簡單地增加計算機得到成倍提升，Redis的網絡帶寬也會隨著計算機和網卡的增加而成倍增長。
Redis實現分佈式鎖
Redis為單進程單線程模式，採用隊列模式將並發訪問變成串行訪問，且多客戶端對Redis的連接並不存在競爭關係Redis中可以使用SETNX命令實現分佈式鎖。
當且僅當key 不存在，將key 的值設為value。若給定的key 已經存在，則SETNX 不做任何動作
SETNX 是『SET if Not eXists』(如果不存在，則SET)的簡寫。
返回值：設置成功，返回1 。設置失敗，返回0 。
使用SETNX完成同步鎖的流程及事項如下：
使用SETNX命令獲取鎖，若返回0（key已存在，鎖已存在）則獲取失敗，反之獲取成功
為了防止獲取鎖後程序出現異常，導致其他線程/進程調用SETNX命令總是返回0而進入死鎖狀態，需要為該key設置一個“合理”的過期時間
釋放鎖，使用DEL命令將鎖數據刪除
緩存異常
緩存雪崩
緩存雪崩是指緩存同一時間大面積的失效，所以，後面的請求都會落到數據庫上，造成數據庫短時間內承受大量請求而崩掉。
解決方案
緩存數據的過期時間設置隨機，防止同一時間大量數據過期現象發生。
一般並發量不是特別多的時候，使用最多的解決方案是加鎖排隊。
給每一個緩存數據增加相應的緩存標記，記錄緩存的是否失效，如果緩存標記失效，則更新數據緩存。
緩存穿透
緩存穿透是指緩存和數據庫中都沒有的數據，導致所有的請求都落到數據庫上，造成數據庫短時間內承受大量請求而崩掉。
解決方案
接口層增加校驗，如用戶鑑權校驗，id做基礎校驗，id<=0的直接攔截；
從緩存取不到的數據，在數據庫中也沒有取到，這時也可以將key-value對寫為key-null，緩存有效時間可以設置短點，如30秒（設置太長會導致正常情況也沒法使用）。這樣可以防止攻擊用戶反復用同一個id暴力攻擊
採用布隆過濾器，將所有可能存在的數據哈希到一個足夠大的bitmap 中，一個一定不存在的數據會被這個bitmap 攔截掉，從而避免了對底層存儲系統的查詢壓力
緩存擊穿
緩存擊穿是指緩存中沒有但數據庫中有的數據（一般是緩存時間到期），這時由於並髮用戶特別多，同時讀緩存沒讀到數據，又同時去數據庫去取數據，引起數據庫壓力瞬間增大，造成過大壓力。和緩存雪崩不同的是，緩存擊穿指並發查同一條數據，緩存雪崩是不同數據都過期了，很多數據都查不到從而查數據庫。
解決方案
設置熱點數據永遠不過期。
加互斥鎖，互斥鎖