- 高性能,指的是查詢快
redis是c語言實現,與其他語言相比,在實現語言層面性能高;redis是內存數據庫,而傳統的關系型數據庫是磁盤文件讀寫,所以redis讀寫快;單線程,無上下文切換損耗,也不需要線程間同步,在單核cpu上,性能高,如果服務器是多核cpu,可以開啟多個進程的單線程redis實例;基於以上原因,才達到了官網所說的,即使pc都支持QPS>10w/s的查詢。
- 高可用(High Availability),高可用指的是在節點故障時,服務仍然能正常運行或者進行降級后提供部分服務
單點redis:redis是內存數據庫,在遇到斷電或者重啟時,數據能恢復嗎?當然能。redis提供了兩種持久化方式AOF/RDB,AOF是Append Of File,redis的修改命令(hset、set)會寫入文件中,在恢復數據時,從頭執行一遍命令就恢復了數據了,這種數據最全,但是恢復時間長。RDB是Redis DataBase,redis會定時備份數據,這是默認的持久化方式,但是因為是定時備份所有數據會有部分缺失。
master-slave(主從.復制):如果單點redis遇到故障怎么辦?redis提供master-slave/sentinel/cluster高可用方案,master-slave是常見的復制(Replication) 方案,一個master,多個slave,就是俗稱的主從復制,master用來接收請求,slave備份master數據,冗余了數據,但master-slave有個缺點,master 故障后,slave不會自動切換為master,必須人為干預,sentinel就是用來解決這個問題的
sentinel(哨兵):這種方案在master-slave的基礎上,多了sentinel[ˈsentɪnl],sentinel漢語意思是哨兵,哨兵監測master及所有的slave狀態(心跳),如果master故障,sentinel會組織slave選舉新的master,並通知客戶端,從而實現可用性,但是單master畢竟能力有限(查詢最大10w/s),如果超過這個極限,怎么辦?我們會想,如果有多個master就好了,這就是集群
- 高並發(redis cluster.集群)
redis集群有2個TCP 端口,一個用來伺服客戶端,比如常見的6379,另外一個對6379+10000=16379,作為“high”端口,high端口用來節點間通信、失敗監測、故障轉移授權、配置更新,high端口與數據端口差值必須是固定的10000。redis集群對數據做了分片,redis數據分片沒有采用一致性哈希(consistent hash),而是使用了hash slot,redis集群一共有16384(2的14次方)個槽,key對16384取模分配,比如A、B、C三個節點,
節點A 哈希槽( 0 ~ 5500)
節點 B 哈希槽(5501 ~ 11000)
節點 C哈希槽( 11001 ~ 16383)
增加節點D,那么就要將A、B、C的部分數據遷移到D上;如果刪除A,那就要將A的數據遷移到B、C上,然后才能完全刪除A。為了增加可用性,每個節點使用主從復制,比如A1、B1、C1,當B節點故障時,集群會將B1設置為新master,當B1也故障時,集群就真down了
replication(主從.復制)
如果業務要承載的QPS在幾十萬,單機是不可能做到的,此時就可以用到復制。做一個主從架構,一主多從,master節點負責寫,slave節點負責讀,假如說一個節點可以承載的5w讀QPS,那么兩個節點就可以承載10w的讀QPS,水平擴容非常方便。
master節點掛太多slave節點會有性能問題,此時就可以在slave節點上掛slave節點
redis replication(主從復制)的核心機制有如下幾點:
- redis采用異步方式復制數據到slave node,不會block master node的正常工作
- 一個master node可以配置多個slave node,slave node也可以連接其他的slave node
- slave node主要用來進行橫向擴容,做讀寫分離,擴容的slave node可以提高讀的吞吐量
主從復制原理:
- slave連接master,發送SYNC命令;
- master接收到SYNC命名后,開始執行BGSAVE命令生成RDB文件並使用緩沖區記錄此后執行的所有寫命令;
- master BGSAVE執行完后,向slave發送快照文件,並在發送期間繼續記錄被執行的寫命令;
- slave收到快照文件后丟棄所有舊數據,載入收到的快照;
- master快照發送完畢后開始向salve發送緩沖區中的寫命令;
- slave完成對快照的載入,開始接收命令請求,並執行來自主服務器緩沖區的寫命令(從服務器初始化完成)
- master每執行一個寫命令就會向slave發送相同的寫命令,slave接收並執行收到的寫命令(從服務器初始化完成后的操作)
主從復制優缺點:
優點:
- 支持主從復制,主機會自動將數據同步到從機,可以進行讀寫分離
- 為了分載Master的讀操作壓力,Slave服務器可以為客戶端提供只讀操作的服務,寫服務仍然必須由Master來完成
- Slave同樣可以接受其它Slaves的連接和同步請求,這樣可以有效的分載Master的同步壓力。
- Master Server是以非阻塞的方式為Slaves提供服務。所以在Master-Slave同步期間,客戶端仍然可以提交查詢或修改請求。
- Slave Server同樣是以非阻塞的方式完成數據同步。在同步期間,如果有客戶端提交查詢請求,Redis則返回同步之前的數據
缺點:
- Redis不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或者手動切換前端的IP才能恢復。
- 主機宕機,宕機前有部分數據未能及時同步到從機,切換IP后還會引入數據不一致的問題,降低了系統的可用性。
- Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。
sentinel(哨兵)
主從架構有一個缺點就是如果master節點掛了,那么寫服務是不可用的,因為slave節點默認是只讀的,這時就重啟master節點或者重新配置主從,有沒有更好的方案呢?類似zookeeper的組件,能自動完成主從切換。在Redis中還真有,就是sentinel節點,當master節點發生故障能自動完成主從切換。
當master節點掛掉時,sentinel將一個slave節點變成maste節點,當原先的master節點可用時,以slave的角色加入集群。
一個高可用的系統是很忌諱有單點問題的。看到沒,sentinel就是一個單點,如果sentinel掛了,主從切換也就沒人做了。所以應該將sentinel也做成一個集群,其部署架構主要包括兩部分:Redis Sentinel 集群和 Redis 數據集群。
其中 Redis Sentinel 集群是由若干 Sentinel 節點組成的分布式集群,可以實現故障發現、故障自動轉移、配置中心和客戶端通知。Redis Sentinel 的節點數量要滿足 2n+1(n>=1)的奇數個。
哨兵的作用有如下幾點
- 集群監控,負責監控redis master和slave進程是否正常工作
- 消息通知,如果某個redis實例有故障,那么哨兵負責發送消息作為報警通知給管理員
- 故障轉移,如果master node掛掉了,會自動轉移到slave node上
- 配置中心,客戶端初始化時,通過哨兵獲得master地址,如果故障轉移發生了,通知客戶端新的master地址
哨兵的工作方式:
- 每個Sentinel(哨兵)進程以每秒鍾一次的頻率向整個集群中的Master主服務器,Slave從服務器以及其他Sentinel(哨兵)進程發送一個 PING 命令。
- 如果一個實例(instance)距離最后一次有效回復 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel(哨兵)進程標記為主觀下線(SDOWN)
- 如果一個Master主服務器被標記為主觀下線(SDOWN),則正在監視這個Master主服務器的所有 Sentinel(哨兵)進程要以每秒一次的頻率確認Master主服務器的確進入了主觀下線狀態
- 當有足夠數量的 Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間范圍內確認Master主服務器進入了主觀下線狀態(SDOWN), 則Master主服務器會被標記為客觀下線(ODOWN)
- 在一般情況下, 每個 Sentinel(哨兵)進程會以每 10 秒一次的頻率向集群中的所有Master主服務器、Slave從服務器發送 INFO 命令。
- 當Master主服務器被 Sentinel(哨兵)進程標記為客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的 Master主服務器的所有 Slave從服務器發送 INFO 命令的頻率會從 10 秒一次改為每秒一次。
- 若沒有足夠數量的 Sentinel(哨兵)進程同意 Master主服務器下線, Master主服務器的客觀下線狀態就會被移除。若 Master主服務器重新向 Sentinel(哨兵)進程發送 PING 命令返回有效回復,Master主服務器的主觀下線狀態就會被移除。
哨兵模式的優缺點
優點:
- 哨兵模式是基於主從模式的,所有主從的優點,哨兵模式都具有。
- 主從可以自動切換,系統更健壯,可用性更高。
缺點:
- Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜
redis cluster(集群)
redis的哨兵模式基本已經可以實現高可用,讀寫分離 ,但是在這種模式下每台redis服務器都存儲相同的數據,很浪費內存,因為一個master節點並不能放海量數據,而且單個Redis的實例過大時,會導致rdb文件過大,當執行主從同步時時間過長,所以在redis3.0上加入了cluster模式,實現的redis的分布式存儲,也就是說每台redis節點上存儲不同的內容。
Redis-Cluster采用無中心結構,它的特點如下:
-
所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬。
-
節點的fail是通過集群中超過半數的節點檢測失效時才生效。
-
客戶端與redis節點直連,不需要中間代理層.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可。
工作方式:
在redis的每一個節點上,都有這么兩個東西,一個是插槽(slot),它的的取值范圍是:0-16383。還有一個就是cluster,可以理解為是一個集群管理的插件。當我們的存取的key到達的時候,redis會根據crc16的算法得出一個結果,然后把結果對 16384 求余數,這樣每個 key 都會對應一個編號在 0-16383 之間的哈希槽,通過這個值,去找到對應的插槽所對應的節點,然后直接自動跳轉到這個對應的節點上進行存取操作。
為了保證高可用,redis-cluster集群引入了主從模式,一個主節點對應一個或者多個從節點,當主節點宕機的時候,就會啟用從節點。當其它主節點ping一個主節點A時,如果半數以上的主節點與A通信超時,那么認為主節點A宕機了。如果主節點A和它的從節點A1都宕機了,那么該集群就無法再提供服務了。
優點:
- 無中心架構;
- 數據按照 slot 存儲分布在多個節點,節點間數據共享,可動態調整數據分布;
- 可擴展性:可線性擴展到 1000 多個節點,節點可動態添加或刪除;
- 高可用性:部分節點不可用時,集群仍可用。通過增加 Slave 做 standby 數據副本,能夠實現故障自動 failover,節點之間通過 gossip 協議交換狀態信息,用投票機制完成 Slave 到 Master 的角色提升;
- 降低運維成本,提高系統的擴展性和可用性。
缺點:
- Client 實現復雜,驅動要求實現 Smart Client,緩存 slots mapping 信息並及時更新,提高了開發難度,客戶端的不成熟影響業務的穩定性。目前僅 JedisCluster 相對成熟,異常處理部分還不完善,比如常見的“max redirect exception”。
- 節點會因為某些原因發生阻塞(阻塞時間大於 clutser-node-timeout),被判斷下線,這種 failover 是沒有必要的。
- 數據通過異步復制,不保證數據的強一致性。
- 多個業務使用同一套集群時,無法根據統計區分冷熱數據,資源隔離性較差,容易出現相互影響的情況。
- Slave 在集群中充當“冷備”,不能緩解讀壓力,當然可以通過 SDK 的合理設計來提高 Slave 資源的利用率。
- Key 批量操作限制,如使用 mset、mget 目前只支持具有相同 slot 值的 Key 執行批量操作。對於映射為不同 slot 值的 Key 由於 Keys 不支持跨 slot 查詢,所以執行 mset、mget、sunion 等操作支持不友好。
- Key 事務操作支持有限,只支持多 key 在同一節點上的事務操作,當多個 Key 分布於不同的節點上時無法使用事務功能。
- Key 作為數據分區的最小粒度,不能將一個很大的鍵值對象如 hash、list 等映射到不同的節點。
- 不支持多數據庫空間,單機下的 redis 可以支持到 16 個數據庫,集群模式下只能使用 1 個數據庫空間,即 db 0。
- 復制結構只支持一層,從節點只能復制主節點,不支持嵌套樹狀復制結構。
- 避免產生 hot-key,導致主庫節點成為系統的短板。
- 避免產生 big-key,導致網卡撐爆、慢查詢等。
- 重試時間應該大於 cluster-node-time 時間。
- Redis Cluster 不建議使用 pipeline 和 multi-keys 操作,減少 max redirect 產生的場景。
1、客戶端分片:這種方案將分片工作放在業務程序端,程序代碼根據預先設置的路由規則,直接對多個Redis實例進行分布式訪問。這樣的好處是,不依賴於第三方分布式中間件,實現方法和代碼都自己掌控,可隨時調整,不用擔心踩到坑。這實際上是一種靜態分片技術。Redis實例的增減,都得手工調整分片程序。基於此分片機制的開源產品,現在仍不多見。這種分片機制的性能比代理式更好(少了一個中間分發環節)。但缺點是升級麻煩,對研發人員的個人依賴性強——需要有較強的程序開發能力做后盾。如果主力程序員離職,可能新的負責人,會選擇重寫一遍。所以,這種方式下,可運維性較差。出現故障,定位和解決都得研發和運維配合着解決,故障時間變長。因此這種方案,難以進行標准化運維,不太適合中小公司(除非有足夠的DevOPS)。
Twemproxy是一種代理分片機制,由Twitter開源。Twemproxy作為代理,可接受來自多個程序的訪問,按照路由規則,轉發給后台的各個Redis服務器,再原路返回。這個方案順理成章地解決了單個Redis實例承載能力的問題。當然,Twemproxy本身也是單點,需要用Keepalived做高可用方案。這么些年來,Twemproxy是應用范圍最廣、穩定性最高、最久經考驗的分布式中間件。只是,他還有諸多不方便之處。Twemproxy最大的痛點在於,無法平滑地擴容/縮容。這樣增加了運維難度:業務量突增,需增加Redis服務器;業務量萎縮,需要減少Redis服務器。但對Twemproxy而言,基本上都很難操作。或者說,Twemproxy更加像服務器端靜態sharding。有時為了規避業務量突增導致的擴容需求,甚至被迫新開一個基於Twemproxy的Redis集群。Twemproxy另一個痛點是,運維不友好,甚至沒有控制面板。
Codis由豌豆莢於2014年11月開源,基於Go和C開發,是近期涌現的、國人開發的優秀開源軟件之一。現已廣泛用於豌豆莢的各種Redis業務場景,從各種壓力測試來看,穩定性符合高效運維的要求。性能更是改善很多,最初比Twemproxy慢20%;現在比Twemproxy快近100%(條件:多實例,一般Value長度)。Codis具有可視化運維管理界面。Codis無疑是為解決Twemproxy缺點而出的新解決方案。因此綜合方面會由於Twemproxy很多。目前也越來越多公司選擇Codis。Codis引入了Group的概念,每個Group包括1個Redis Master及至少1個Redis Slave,這是和Twemproxy的區別之一。這樣做的好處是,如果當前Master有問題,則運維人員可通過Dashboard“自助式”切換到Slave,而不需要小心翼翼地修改程序配置文件。為支持數據熱遷移(Auto Rebalance),出品方修改了Redis Server源碼,並稱之為Codis Server。Codis采用預先分片(Pre-Sharding)機制,事先規定好了,分成1024個slots(也就是說,最多能支持后端1024個Codis Server),這些路由信息保存在ZooKeeper中。
Redis-cluster:
reids-cluster在redis3.0中推出,支持Redis分布式集群部署模式。采用無中心分布式架構。所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.節點的fail是通過集群中超過半數的節點檢測失效時才生效.客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可,減少了代理層,大大提高了性能。redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->key之間的關系。目前Jedis已經支持Redis-cluster。從計算架構或者性能方面無疑Redis-cluster是最佳的選擇方案。