我的個(gè)人主頁:螞蟻的寶藏
傳統(tǒng)數(shù)據(jù)庫遵循ACID原則,而NOSQL遵循CAP原則。
Consistency(一致性): 所有節(jié)點(diǎn)在同一時(shí)間具有相同的數(shù)據(jù)
Availability(可用性):集群中一部分節(jié)點(diǎn)失效后,集群整體保證響應(yīng)客服端的讀寫請求
Partition tolerance(分區(qū)容災(zāi)性):系統(tǒng)中任意信息的丟失或失敗不會影響系統(tǒng)繼續(xù)運(yùn)行。
任何時(shí)候,最多滿足以上兩點(diǎn),在分布式存儲中,分區(qū)容災(zāi)性是必須的,所以在一致性和可用性上要做出權(quán)衡。redis在一致性上做出了妥協(xié),采用結(jié)果最終一致性的弱化處理數(shù)據(jù)異步復(fù)制。
redis演變
復(fù)制
redis提供復(fù)制功能,用戶可以通過復(fù)制master來創(chuàng)建多個(gè)slave。只要主從服務(wù)器之間通信正常,會保持相同的數(shù)據(jù),master會一直將自身的數(shù)據(jù)更新至slave。解決了master的讀壓力。
哨兵
redis sentinel 在分布式系統(tǒng)中,監(jiān)控主從服務(wù)器,在master下線,會自動進(jìn)行故障轉(zhuǎn)移,保證了系統(tǒng)的高可用。
集群(proxy)
通過增加proxy層來進(jìn)行數(shù)據(jù)分片,減輕redis的寫壓力。但是proxy層無法保證高可用,維護(hù)成本增加。
集群(直連型)
去除proxy層,無中心架構(gòu);通過選舉制實(shí)現(xiàn)故障轉(zhuǎn)移,完成slave到master的角色轉(zhuǎn)換;節(jié)點(diǎn)可動態(tài)擴(kuò)張;通過增加slave節(jié)點(diǎn)實(shí)現(xiàn)高可用;數(shù)據(jù)按照slot存儲,節(jié)點(diǎn)數(shù)據(jù)可共享。
redis數(shù)據(jù)結(jié)構(gòu)
redis以 key-value 鍵值對 作為存儲方式。支持多種數(shù)據(jù)結(jié)構(gòu)。
String
string是redis使用最多的數(shù)據(jù)結(jié)構(gòu)之一,value大小不能超過512M,set的時(shí)候,可以不用引號。
值可以是字符串,整數(shù),浮點(diǎn)數(shù)。
若值為數(shù)字,做運(yùn)算時(shí),redis會自動進(jìn)行轉(zhuǎn)換。
| 命令 | 說明 |
|---|---|
| SET key value | 定義key并賦值 |
| GET key | 獲取key的值 |
| DEL key | 刪除key |
| APPEND key value | 末尾追加,字符串拼接 |
| STRLEN key | 獲取字符串長度 |
| INCR key | 自增 |
| DECR key | 自減 |
| INCRBY key increment | 按指定步長增長 |
| DECRBY key increment | 按指定步長減少 |
| SETEX key seconds value | 同時(shí)設(shè)置過期時(shí)間,同EXPIRE,可使用TTL查看剩余時(shí)間 |
List
鏈表上的每個(gè)節(jié)點(diǎn)包含一個(gè)字符串。鏈表的兩端都可以進(jìn)行讀寫。
| 命令 | 說明 |
|---|---|
| LPUSH key value | 向鏈表左端添加元素value |
| RPUSH key value | 向鏈表右端添加元素value |
| LPOP key | 從鏈表左側(cè)讀取并移除元素 |
| RPOP key | 從鏈表右側(cè)讀取并移除元素 |
| LINDEX key index | 按index讀取vaule |
| LRANGE key start stop | 讀取指定范圍的元素 |
| BRPOP key[key ...] timeout | 阻塞的方式從鏈表右側(cè)彈出元素,如果元素為空,阻塞等待,直到超時(shí)或者有值返回 |
| BLPOP key[key ...] timeout | 阻塞的方式從鏈表右側(cè)彈出元素,如果元素為空,阻塞等待,直到超時(shí)或者有值返回 |
Set
無序且無重復(fù)的字符串集合
常用命令:
| 命令 | 說明 |
|---|---|
| SADD key value | 向key中添加元素value,成功返回1,失敗返回0 |
| SREM key value | 從key中移除元素value,成功1,失敗0 |
| SMEMBERS key | 列出key中所有元素 |
| SISMEMBER key value | 判斷key中是否存在元素value,沒找到0 |
zset
有序的set集合,通過浮點(diǎn)數(shù)score來實(shí)現(xiàn)。
元素a,b,若a.score>b.score,則a>b;若a.score=b.score,a>b,則a>b。
| 命令 | 說明 |
|---|---|
| ZADD key score member | 向key集合中插入memeber,設(shè)置score |
| ZRANGE key start stop | 讀取指定范圍類元素 |
| ZRANGEBYSCORE key min man | 按照score的范圍讀取元素 |
| ZREM key member | 移除元素 |
hash
包含key,value的散列表。
| 命令 | 說明 |
|---|---|
| HMSET key field value [field value ...] | 添加值 |
| HGET key field | 取值 |
| HMGET key field [field ...] | 取值 |
| HGETALL key | 獲取所有元素 |
| HDEL key field [field ...] | 刪除指定字段 |
事務(wù)
因?yàn)閞edis是單線程來處理所有client的請求,所以redis對事務(wù)的處理比較簡單,通過一個(gè)類似阻塞隊(duì)列的東西保證一個(gè)client發(fā)起的事務(wù)中的命令可以順序執(zhí)行,中間不會插入其他client的命令。
通過 EXEC 命令來開啟一個(gè)事務(wù),DISCARD取消事務(wù),EXEC結(jié)束事務(wù)
發(fā)布訂閱
發(fā)布訂閱(pub/sub)是類似觀察者模式的一種消息通信模式,發(fā)送者(pub)發(fā)送消息,訂閱者(sub)接收消息。

ps.網(wǎng)上找的圖
SUBSCRIBE 訂閱主題,開啟通道,獲取消息
PUBLISH 推送消息
UNSUBSCRIBE 取消主題
持久化
為了防止服務(wù)宕機(jī)內(nèi)存數(shù)據(jù)丟失,redis提供了三種持久化方式:RDB(deafult),AOF,RDB和AOF同時(shí)使用。
RDB:
定時(shí)調(diào)用 rdbSave 函數(shù),將內(nèi)存數(shù)據(jù)寫入一個(gè)dump.rdb,如果文件存在,替換。
操作 rdbSave 函數(shù)有兩種命令,SAVE和BGSAVE
SAVE命令會直接調(diào)用rdbSave函數(shù),在RDB文件保存期間,主進(jìn)程會被阻塞,服務(wù)端無法處理客戶端請求,保存完成,喚醒主線程。
BGSAVE命令會先fork一個(gè)子進(jìn)程,由子進(jìn)程調(diào)用 rdbSave 函數(shù),不會阻塞主進(jìn)程,服務(wù)端仍可服務(wù)客戶端,保存完成,子進(jìn)程會向主進(jìn)程發(fā)送通知。
在redis服務(wù)啟動或重啟時(shí),會調(diào)用 rdbLoad 函數(shù),加載磁盤中的RDB文件到內(nèi)存中。
+-------+-------------+-----------+-----------------+-----+-----------+
| REDIS | RDB-VERSION | SELECT-DB | KEY-VALUE-PAIRS | EOF | CHECK-SUM |
+-------+-------------+-----------+-----------------+-----+-----------+
|<-------- DB-DATA ---------->|

保存策略:
save 900 10 #900s內(nèi)超過10個(gè)key被修改,發(fā)起快照保存。
AOF:
append-only-file,以協(xié)議(RESP)文本的方式,把數(shù)據(jù)庫的命令操作參數(shù)追加到aof文件中。
這個(gè)過程分為三步:
1.命令傳播:Redis 將執(zhí)行完的命令、命令的參數(shù)、命令的參數(shù)個(gè)數(shù)等信息發(fā)送到 AOF 程序中。
2.緩存追加:AOF 程序根據(jù)接收到的命令數(shù)據(jù),將命令轉(zhuǎn)換為網(wǎng)絡(luò)通訊協(xié)議的格式,然后將協(xié)議內(nèi)容追加到服務(wù)器的 AOF 緩存中。
3.文件寫入和保存:AOF 緩存中的內(nèi)容被寫入到 AOF 文件末尾,如果設(shè)定的 AOF 保存條件被滿足的話, fsync 函數(shù)或者 fdatasync 函數(shù)會被調(diào)用,將寫入的內(nèi)容真正地保存到磁盤中。
AOF支持三種保存模式:
1.AOF_FSYNC_NO :不保存。
2.AOF_FSYNC_EVERYSEC :每一秒鐘保存一次。(不阻塞主進(jìn)程)
3.AOF_FSYNC_ALWAYS :每執(zhí)行一個(gè)命令保存一次。(阻塞主進(jìn)程)
參考文獻(xiàn) -- 《Redis設(shè)計(jì)與實(shí)現(xiàn)》

可以看到 rdb文件中存儲的數(shù)據(jù),aof文件中存儲的是命令+數(shù)據(jù),而且aof的文件可讀性更高。
除此之外,AOF的更新頻率高于RDB,優(yōu)先加載aof。
復(fù)制
redis的復(fù)制方式有兩種,一種是主(master)-從(slave),一種是從(slave)-從(slave)。

配置方式:
# 復(fù)制一份配置文件 cp redis.conf slave.conf
# 修改slave的配置 slaveof ip port
# 修改master的配置 bind 0.0.0.0
# 啟動slave ./redis-server ../slave.conf &
集群
在redis集群中,引入了hash槽-slot的概念。
集群中的節(jié)點(diǎn)node,共同分配16384個(gè)slot,所以集群中節(jié)點(diǎn)最多只能有16384個(gè),所有的key都對映射到對應(yīng)的slot中。
redisCluster通過CRC16(key)/16384 來計(jì)算key屬于哪個(gè)槽。
通過為每個(gè)node分片不同數(shù)量的slot,按照槽來分片,可以控制不同節(jié)點(diǎn)的數(shù)據(jù)量和請求數(shù)。
redisCluster的特點(diǎn):
1.節(jié)點(diǎn)自動發(fā)現(xiàn)
2.slave->master 選舉,集群容錯(cuò)
3.支持rehsard在線分片
4.節(jié)點(diǎn)直連型,不需要proxy層
5.所有節(jié)點(diǎn)彼此互連(ping-pong)
數(shù)據(jù)遷移
當(dāng)我們需要新增節(jié)點(diǎn)時(shí),只需要從以往節(jié)點(diǎn)中分配部分slot到新節(jié)點(diǎn);需要?jiǎng)h除節(jié)點(diǎn)時(shí),先把該節(jié)點(diǎn)的slot轉(zhuǎn)移到其他節(jié)點(diǎn),然后刪除即可。這個(gè)功能極大方便了集群的線性擴(kuò)展或縮容,并不會造成集群不可用的狀態(tài)。

在slot遷移過程中,masterA狀態(tài)為MIGRATING,masterB狀態(tài)為IMPORTING。
真正改變node映射的是鍵空間遷移。
src目錄下的集群管理命令redis-trib.rb支持reshard的手動在線遷移方式。
| 命令 | 說明 |
|---|---|
| call | 在集群全部節(jié)點(diǎn)上執(zhí)行命令 |
| set-timeout | 設(shè)置集群節(jié)點(diǎn)間心跳連接的超時(shí)時(shí)間 |
| del-node | 從集群中刪除節(jié)點(diǎn) |
| reshard | 在線遷移slot |
| check | 檢查集群 |
| import | 將外部redis數(shù)據(jù)導(dǎo)入集群 |
| add-node | 將新節(jié)點(diǎn)加入集群 |
| create | 創(chuàng)建集群 |
| info | 查看集群信息 |
| fix | 修復(fù)集群 |
| rebalance | 自動平分集群節(jié)點(diǎn)slot數(shù)量 |