一. redis
1.1 redis的哈希槽
在redis集羣中,怎麼確定新增的數據添加到哪個實例中去呢?
這個時候就涉及到哈希槽的概念。
1.1.1 集羣中的哈希槽分配
redis默認初始化了16384(2的14次方)個哈希槽。在新增一個key-value的時候,redis會計算key的哈希值(crc16),然後對16384取餘數,得到這個key所對應的哈希槽,然後按照範圍分配到相應的redis實例中。
1.1.2 集羣的增刪節點
因爲哈希槽的存在,所以增刪節點,只需要遷移部分數據就可以,如果分配規則是按照實例個數進行取模的話,增刪節點都會導致實例個數變化,也就是所有數據的映射關係變化。
1.2 一致性哈希
在分佈式系統做負載均衡,或者集羣處理請求,一般是通過哈希求餘數的算法來確定將請求交給哪個節點處理。
1.2.1 爲什麼要用一致性哈希
也就是 hash(key)% 實例個數
,但是這個算法伸縮性和拓展性很差。如果想要增加節點或刪除節點,都會導致公式的實例個數變化,也就導致映射關係失效。
1.2.2 一致性哈希算法的原理
其實一致性哈希算法,重點就是一個均勻佈滿了槽位的哈希環。
- 有一個哈希環,有2的32次方的槽位均勻分佈在環上
- 將集羣(或者分佈式系統)中的機器的名稱(或者ip地址)進行hash函數得到一個值,然後對2的32次方取模後,就會落在環上的槽位上
- 這樣來了一個請求時,將請求的某個屬性也進行hash函數,並對2的32次方取模,同樣會對應一個槽位。
- 將這個請求分配給按順時針尋找到的第一個節點處理
如果刪除一個節點
刪除節點,此時原本應該分配到該節點的請求,根據哈希環順延到下一個節點。其他位置的不受影響,不會造成所有的映射關係失效的問題
如果新增一個節點
在新增一個節點後,哈希算法得出的新節點的哈希槽,則從這個節點位置開始,逆時針遇到的第一個節點的位置爲止,這段原本應該由順時針後面的一個節點處理,現在由新節點處理
受影響的數據僅僅是新服務器到其環空間中前一臺服務器(即沿着逆時針方向行走遇到的第一臺服務器)之間數據,其它數據也不會受到影響
1.2.3 數據分佈不均
當節點比較少的時候,可能會出現兩個節點的哈希槽位置相近,這就導致兩個節點接受的請求和數據不均
虛擬節點
爲了解決這個問題,可以給每個節點計算多個哈希,比如在IP地址或者服務器名後面加序號,得到多個虛擬的哈希槽位
1.3 redis持久化
redis的持久化有兩種,RDB(redisDatabase,默認),和AOF(Append Only File)
1.3.1 RDB方式
RDB是默認的redis持久化的方式。在指定的間隔時間內,如果達到了指定的修改數量,則會把內存中的數據存到硬盤中
save <seconds> <changes>
# save ""
save 900 1
save 300 10
save 60 10000
滿足下面的條件就觸發:
- 900秒內有1次修改
- 300秒內有10次修改
- 60秒內有10000次修改
觸發持久化的方式:
- 上面描述的,指定間隔時間內,達到了指定的修改數量
- 手動調用命令
save
阻塞的,和bgsave
(backgroundSave)子進程處理,不阻塞 shutdown
關閉的時候
1.3.2 AOF的方式
AOF是爲了彌補RDB的不足而產生的,因爲RDB不能保證數據的強一致性,AOF會採用日誌的形式記錄寫操作,恢復數據的時候會重新執行一遍所有的寫命令
# appendfsync always
appendfsync everysec
# appendfsync no
AOF可以設置屬性ppendfsync
,always是實時同步,everysec是每秒同步。always實時同步會因爲頻繁的io導致效率降低,默認是everysec每秒同步
當AOF文件達到一定大小的時候,會觸發**重寫(rewrite)**的操作。
重寫:
將當前內存中的最新數據,轉成set命令寫入新的aof臨時文件。然後改名替換原文件
因爲重寫是最新的數據,所以比原來的aof文件,少了過期的數據,少了刪除命令,同時對同類型操作的數據合併成一條命令,有效的減小了文件大小。
觸發機制
當aof文件達到上一次rewrite文件的一倍大,且文件大於64M的時候
1.4 兩者的對比
RDB | AOF |
---|---|
數據一致性比較弱,實時性比較差,可能因爲實例宕機丟失數據 | 數據一致性強,同步記錄頻繁 |
存儲的是二進制文件 | 存儲的是基於命令的文本文件 |
適合大量數據的備份和恢復,redis加載RDB文件速度快 | 數據量大的話,因爲是一條條命令執行,會影響數據恢復的效率 |
可以進行壓縮,文件相對原數據小 | 文件大 |