你管這破玩意叫哨兵?
低并發(fā)編程 戰(zhàn)略上藐視技術(shù),戰(zhàn)術(shù)上重視技術(shù)


redis-cli -h 10.232.0.0 -p 6379
redis-cli -h 10.232.0.1 -p 6379
redis-cli -h 10.232.0.2 -p 6379
redis-cli -h 10.232.0.3 -p 6379然后每隔 1s 分別發(fā)送 redis 專屬的命令 PING


選擇一個從節(jié)點,將其變?yōu)橹鞴?jié)點。
10.232.0.3:6379> slaveof no one
OK10.232.0.3:6379> info
...
role:slave10.232.0.3:6379> info
...
role:master10.232.0.1:6379> slaveof 10.232.0.3 6379
OK
10.232.0.2:6379> slaveof 10.232.0.3 6379
OK10.232.0.0:6379> slaveof 10.232.0.3 6379

10.232.0.0:6379> info
...
role:master
...
slave0:ip=10.232.0.1,port=6379,state=online ...
slave0:ip=10.232.0.2,port=6379,state=online ...
slave0:ip=10.232.0.3,port=6379,state=online ...
...
節(jié)點 | 狀態(tài) | 距離上次回復(fù)的時間 | 復(fù)制偏移量 | uid |
1 | DISCONNECTED | 8 | 50 | 12345 |
2 | DOWN | 8 | 50 | 12346 |
3 | √ | 7 | 50 | 12347 |
4 | √ | 1 | 50 | 12348 |
5 | DOWN | 8 | 50 | 12349 |
6 | √ | 1 | 50 | 12350 |
節(jié)點 | 狀態(tài) | 距離上次 回復(fù)的時間 | 復(fù)制偏移量 | uid |
1 | DISCONNECTED | 8 | 50 | 12345 |
2 | DOWN | 8 | 50 | 12346 |
3 | √ | 7 | 50 | 12347 |
4 | √ | 1 | 50 | 12348 |
5 | DOWN | 8 | 50 | 12349 |
6 | √ | 1 | 50 | 12350 |
節(jié)點 | 狀態(tài) | 距離上次 回復(fù)的時間 | 復(fù)制偏移量 | uid |
1 | DISCONNECTED | 8 | 50 | 12345 |
2 | DOWN | 8 | 50 | 12346 |
3 | √ | 7 | 50 | 12347 |
4 | √ | 1 | 50 | 12348 |
5 | DOWN | 8 | 50 | 12349 |
6 | √ | 1 | 50 | 12350 |
節(jié)點 | 狀態(tài) | 距離上次 回復(fù)的時間 | 復(fù)制偏移量 | uid |
4 | √ | 1 | 50 | 12348 |
6 | √ | 1 | 50 | 12350 |
節(jié)點 | 狀態(tài) | 距離上次 回復(fù)的時間 | 復(fù)制偏移量 | uid |
4 | √ | 1 | 50 | 12348 |





后記
后記
本次選取的 redis 代碼為 redis-3.0.0。
之所以能夠通過"我"這個視角來寫哨兵,正是因為哨兵這個程序,完全可以由人不斷輸入 redis 命令來輕松完成,并不需要什么其他協(xié)議的支持。
比如判斷節(jié)點健康狀態(tài)的 ping,拿到節(jié)點信息的 info,設(shè)置主從節(jié)點的 slaveof,甚至詢問其他哨兵節(jié)點是否在線的命令 sentinel is-master-down-by addr 等等,都是 redis 支持的客戶端命令,對用戶端非常友好。
redis 的源代碼也是非常干凈,而且設(shè)計得很精妙,建議有興趣的讀者可以深入源碼進(jìn)行閱讀,不算難。
比如上面講的,如何從一堆從節(jié)點中,選取一個作為主節(jié)點。
這個知識點網(wǎng)上搜,你會搜到很多云里霧里的解釋,而如果你看源碼,你會發(fā)現(xiàn)這個過程非常清晰。
sentinelRedisInstance *sentinelSelectSlave() {
...
// 去掉一些節(jié)點
while((de = dictNext(di)) != NULL) {
...
if (slave->flags & (DOWN||DISCONNECTED)) continue;
if (mstime() - slave->last_avail_time > 5000) continue;
if (slave->slave_priority == 0) continue;
if (...) continue;
...
}
// 剩下的節(jié)點排個序
qsort(..., compareSlavesForPromotion);
// 取第一個
return instance[0];
}
// 怎么排序呢?就這么排
int compareSlavesForPromotion(const void *a, const void *b) {
// 先按優(yōu)先級排
if ((*sa)->slave_priority != (*sb)->slave_priority)
return (*sa)->slave_priority - (*sb)->slave_priority;
// 優(yōu)先級一樣按偏移量排
if ((*sa)->slave_repl_offset > (*sb)->slave_repl_offset) {
return -1;
} else if ((*sa)->slave_repl_offset < (*sb)->slave_repl_offset) {
return 1;
}
...
// 偏移量一樣按唯一標(biāo)識排
return strcasecmp(sa_runid, sb_runid);
}
我想相信如果你停下來仔細(xì)看幾秒,哪怕你對 c 語言并不熟悉,也能看懂個大概了,再結(jié)合網(wǎng)上或者書上關(guān)于這塊的描述,你就有了很直觀的印象。
關(guān)于 redis 源碼的深入學(xué)習(xí),我建議先閱讀黃健宏的《Redis 設(shè)計與實現(xiàn)》,這本書代碼量很少,但邏輯描述完全按照寫代碼的思維來講,你讀一下就知道了。
讀完這本書,直接上手 redis 源碼的閱讀,你可以選擇 redis-1.0.0 代碼,非常少,主要閱讀其整個網(wǎng)絡(luò) IO 以及命令處理的流程。
接著,從 redis-3.0.0 開始,有針對性研究其主從、集群、哨兵等特性。
這樣,redis 在你這,就不再是模模糊糊了。
