redis哨兵详解

  • sentinel命令
  • 客户端连接
    • 素材代码
    • 思路
    • 实现过程
  • 哨兵的切换实现原理
    • 发布订阅基础
    • 哨兵的实现原理
    • 部署建议
    • 需要关注的问题
    • 代码流程

内容来源为六星教育,这里仅作为学习笔记

sentinel命令

sentinel是一个特殊的redis节点,它有自己专属的api;

  1. sentinel masters 显示被监控的所有master以及它们的状态.
  2. sentinel master <master name> 显示指定master的信息和状态;
  3. sentinel slaves <master name> 显示指定master的所有slave以及它们的状态;
  4. sentinel get-master-addr-by-name <master name> 返回指定master的ip和端口, 如果正在进行failover或者failover已经完成,将会显示被提升为master的slave的ip和端口。
  5. sentinel failover <master name> 强制sentinel执行failover,并且不需要得到其他sentinel的同意。 但是failover后会将最新的配置发送给其他sentinel。

sentinel masters

展示所有被监控的主节点状态以及相关的信息,如:

127.0.0.1:26379> sentinel masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "192.160.1.79"
5) "port"
6) "6379"
..............忽略...............
2) ....

sentinel master <master name>

127.0.0.1:26379> sentinel master mymaster
1) "name"
2) "mymaster
3) "ip"
4) "192.160.1.79"
5) "port"
6) "6379"
..............忽略...............

sentinel slaves <master name>

展示指定的从节点状态以及相关的统计信息,如:

127.0.0.1:26379> sentinel slaves mymaster
1) 1) "name"
2) "192.160.1.81:6379"
3) "ip"
4) "192.160.1.81"
5) "port"
6) "6379"
..............忽略...............
2) 1) "name"
2) "192.160.1.80:6379"
3) "ip"
4) "192.160.1.80"
5) "port"
6) "6379"
..............忽略...............

sentinel sentinels <master name>

展示指定 的sentinel节点集合(不包含当前sentinel节点)如:

127.0.0.1:26379> sentinel sentinels mymaster
1) 1) "name"
2) "52ca335d45d9ad67e2d58f5d436525993ea41b58"
3) "ip"
4) "192.160.1.180"
5) "port"
6) "26379"
..............忽略...............
2) 1) "name"
2) "a6636421120e8a3ffa6cf43c0741d3903cd6eb25"
3) "ip"
4) "192.160.1.179"
5) "port"
6) "26379"
..............忽略...............

sentinel get-master-addr-by-name <master name>

获取主节点信息

127.0.0.1:26379> sentinel get-master-addr-by-name mymaster
1) "192.160.1.79"
2) "6379"

sentinel failover <master name>

对<master name>进行强制故障转移

127.0.0.1:26379> sentinel failover mymaster
OK
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.160.1.80:6379,slaves=2,sentinels=3

客户端连接

素材代码

这里我对于素材封装在了composer作为组件了 如下是格式及文件内容
目录结构

redisStudy- SentinelClient- test- config.php- index.php- Input.php- RedisMs.php- MasterAndSlave- test- config.php- index.php- Input.php- RedisMs.php- vendor- composer.json

素材内容
redisStudy\composer.json

{"name": "shineyork/redis-study","authors": [{"name": "shineyork","email": "shineyork@sixstaredu.com"}],"require": {},"autoload":{"psr-4":{"Shineyork\\Redis\\":""}}
}

redisStudy\MasterAndSlave\RedisMs.php

<?php
namespace Shineyork\Redis\MasterAndSlave;
class RedisMs
{protected $config;protected $connections;/*** 记录从节点连接的小标*/protected $connSlavesIndex;public function __construct($config = []){if ($config['is_ms']) {Input::info("主从读写分离");$this->connections['master'] = $this->getRedis($config['master']['host'], $config['master']['port']);// 创建从节点$this->createSlave($config['slaves']);// 进行节点偏移量检测 -- 判断是否延迟$this->maintain();} else {$this->connections['master'] = $this->getRedis($config['host'], $config['port']);}$this->config = $config;}/*** 进行节点偏移量检测 -- 判断是否延迟*/protected function maintain(){$redis = $this->getMaster();swoole_timer_tick(2000, function () use ($redis){$replicationInfo = $redis->info('replication');$masterOffset = $replicationInfo['master_repl_offset'];$slaves = [];for ($i=0; $i < $replicationInfo['connected_slaves']; $i++) {$match = $this->stringToArr($replicationInfo['slave'.$i]);$slaveFlag = $this->slaveFlag($match['ip'],$match['port']);if( $masterOffset - $match['offset'] < 100){if (!in_array($slaveFlag, $this->connSlavesIndex)) {$slaves[$slaveFlag] = ['host' => $match['ip'],'port' => $match['port']];Input::info($slaveFlag, "新增 从节点");}} else {Input::info($slaveFlag, "删除 从节点");unset($this->connections['slaves'][$slaveFlag]);}}$this->createSlave($slaves);});}protected function slaveFlag($ip, $port){return $ip.":".$port;}private function stringToArr($str, $flag1 = ',' , $flag2 = '='){$arr = explode($flag1,$str);$arr2 = array();foreach($arr as $k=>$v){$arr = explode($flag2 , $v);$arr2[$arr[0]] = $arr[1];}return $arr2;}/*** 创建从节点连接*/private function createSlave($slaves){foreach ($slaves as $slave => $value) {$this->connections['slaves'][$this->slaveFlag($value['host'],$value['port'])] = $this->getRedis($value['host'], $value['port']);}$this->connSlavesIndex = array_keys($this->connections['slaves']);}/*** 获取redis连接*/private function getRedis($host, $port){$redis = new \Redis();$redis->pconnect($host, $port);return $redis;}/*** 执行命令*/public function runCommand($command, $params) {try {if ($this->config['is_ms']) {$redis = $this->getByCommand($command);} else {$redis = $this->getMaster();}return $redis->{$command}(...$params);} catch (Exception $e) {throw new Exception($e->getMessage(), $e->getCode());}}/*** 根据command命令来获取服务器*/protected function getByCommand($command) {$read_command = ['smembers', 'get'];$write_command = ['sadd', 'set'];if(in_array($command, $read_command)) { //读命令,随机返回一台读服务器return $this->oneSlave();} elseif(in_array($command, $write_command)) {return $this->getMaster();} else {throw new Exception('不支持该命令:'.$command);}}/*** 随机生成一台从服务器*/public function oneSlave() {$indexs = $this->connSlavesIndex;$count = count($indexs);$i = mt_rand(0,$count - 1);// 负载均衡算法return $this->connections['slaves'][$indexs[$i]];}/*** 获取主服务器* @return mixed*/public function getMaster() {return $this->connections['master'];}/*** 获取所有的从节点*/public function getSlaves() {return $this->connections['slaves'];}
}
?>

redisStudy\MasterAndSlave\Input.php

<?php
namespace Shineyork\Redis\MasterAndSlave;
class Input
{public static function info($message, $description = null){echo "======>>> ".$description." start\n";if (\is_array($message)) {echo \var_export($message, true);} else if (\is_string($message)) {echo $message."\n";} else {var_dump($message);}echo "======>>> ".$description." end\n";}
}?>

redisStudy\MasterAndSlave\test\config.php

<?php
$config = ['host' => '','port' => '','is_ms' => true,'master' => ['host' => '192.160.1.150','port' => 6379,],'slaves' => ['slave1' => ['host' => '192.160.1.140','port' => 6379,],'slave2' => ['host' => '192.160.1.130','port' => 6379,],]
];
?>

redisStudy\MasterAndSlave\test\index.php

<?php
require __DIR__.'/../../vendor/autoload.php';
use Shineyork\Redis\MasterAndSlave\RedisMs;
$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->set(['worker_num' => 1
]);
$http->on('workerStart', function ($server) use ($config){require_once './config.php';global $redisMS;$redisMS = new RedisMs($config);
});
$http->on('request', function ($request, $response){global $redisMS;if ($request->get['type'] == 1) {// 写$response->end($redisMS->runCommand($request->get['method'], explode(',', $request->get['params'])));} else {// 读$response->end($redisMS->runCommand($request->get['method'], [$request->get['params']]));}
});
$http->start();
?>

思路

sentinel节点集合具备了监控、通知、自动故障转移、配置缇欧供着若干功能,也就是说实际上最了解主节点的就是sentinel节点集合,而各个主节点可以通过<master-name>进行标识的,所以,无论是那种编程语言的客户端,如果需要正确地连接redis sentinel

  1. 遍历sentinel节点集合获取一个可用的sentinel节点,sentinel会共享数据,所以从任意一个sentinel节点获取主节点信息都可以
  2. 通过 sentinel get-master-addr-by-name master-name 这个api来获取对应主节点的相关信息
  3. 验证当前获取的“主节点”是真正的主节点,这样做的木得是未来放置故障转移期间主节点的变化
  4. 保持和sentinel节点集合的“联系”,时刻获取关于主节点的相关“信息”

实现过程

首先需要处理一下RedisMs的对象中的方法,需要使它能够很好的支持我们接下来的操作

redisStudy- SentinelClient- test- config.php- index.php- Input.php- RedisMs.php

先对于配置文件内容的定义

<?php
namespace Shineyork\Redis;
$config = ['host' => '','port' => '','initType' => 'isSentinelInit', // isMsInit , isSentinelInit , normalInfo'master' => ['host' => '192.160.1.150','port' => 6379,],'slaves' => ['slave1' => ['host' => '192.160.1.140','port' => 6379,],'slave2' => ['host' => '192.160.1.130','port' => 6379,]]'sentinels' => ['masterName'  => 'mymaster','addr'    => [['host'=>'192.160.1.179','port'=>'26379'],['host'=>'192.160.1.180','port'=>'26379'],['host'=>'192.160.1.181','port'=>'26379'],]]
]
?>

然后对于redisMs进行完善修改

namespace Shineyork\Redis\SentinelClient;class RedisMs
{/*** 记录redis连接* [*     "master" => \Redis,*     "slaves "=> [*       '0' => \Redis*       '1' => \Redis*    ],*    'sentinel' => [],* ]*/protected $connections;/*** 记录连接下的下标*/protected $connIndexs;public function __construct($config){$this->config = $config;$this->{$this->config['initType']."Init"}();}// ---初始化操作---protected function isMsInit(){Input::info("主从读写分离");$this->connections['master'] = $this->getRedis($this->config['master']['host'], $this->config['master']['port']);// 创建从节点$this->createConn($this->config['slaves']);// 进行节点偏移量检测 -- 判断是否延迟$this->maintain();}protected function isSentinelInit(){Input::info("哨兵模式");}protected function normalInfo(){$this->connections['master'] = $this->getRedis($this->config['host'], $this->config['port']);}/*** 进行节点偏移量检测 -- 判断是否延迟*/protected function maintain(){swoole_timer_tick(2000, function (){Input::info("检测状态");if ($this->config['initType'] == "isSentinelInit") {}$this->delay();});}/*** 延迟维护* @return [type] [description]*/protected function delay(){$redis = $this->getMaster();$replicationInfo = $redis->info('replication');$masterOffset = $replicationInfo['master_repl_offset'];$slaves = [];for ($i=0; $i < $replicationInfo['connected_slaves']; $i++) {$match = $this->stringToArr($replicationInfo['slave'.$i]);$slaveFlag = $this->connFlag($match['ip'],$match['port']);if( $masterOffset - $match['offset'] < 1000){if (!in_array($slaveFlag, $this->connIndex['slaves'])) {$slaves[$slaveFlag] = ['host' => $match['ip'],'port' => $match['port']];Input::info($slaveFlag, "新增 从节点");}} else {Input::info($slaveFlag, "删除 从节点");unset($this->connections['slaves'][$slaveFlag]);}}$this->createConns($slaves);}/*** 创建从节点连接*/protected function createConns($Conns, $flags = 'slaves'){foreach ($Conns as $key => $conn) {$this->connections[$flags][$this->connFlag($conn['host'],$conn['port'])] = $this->getRedis($conn['host'], $conn['port']);}$this->connIndex[$flags] = array_keys($this->connections[$flags]);}/*** 执行命令*/public function runCommand($command, $params) {try {if ($this->config['initType']) {$redis = $this->getByCommand($command);} else {$redis = $this->getMaster();}return $redis->{$command}(...$params);} catch (Exception $e) {}}/*** 随机获取一个连接*/public function getConn($flag = 'slaves') {$indexs = $this->connIndex[$flag];$count = count($indexs);$i = mt_rand(0,$count - 1);// 负载均衡算法Input::info($indexs[$i], "选中的链接");return $this->connections[$flag][$indexs[$i]];}// ...此处代码省略...
}
?>

在之前的基础上做了一些修改
属性名
$connSlavesIndex 修改为 $connIndex
方法名
slaveFlag() 修改为 connFlag() createSlave() 修改为 createConns() oneSlave() 修改为 getConn($flag = ‘slaves’)
方法内存修改及完善
__construct($config = []) maintain() runCommand($command, $params) getConn($flag = ‘slaves’) createConns($Conns, $flags = ‘slaves’)
新增方法:
isMsInit() isSentinelInit() normalInfo() delay()

在进行调节之后,下一步就是实现sentinel,这里我们把sentinel封装为一个traits类对象然后再RedisMs中引用
redisStudy\SentinelClient\Traits\Sentinel.php

<?php
namespace Shineyork\Redis\SentinelClient\Traits;use Shineyork\Redis\SentinelClient\Input;trait Sentinel
{protected $maseterName = 'mymaster';protected $masterFlag = null;protected $sentinelFlag = 'sentinels';/*** 得到redis的详细信息,master与slave的 ip及port* @return boolean [description]*/public function sentinelInit(){// 1. 获取哨兵$sentinel = $this->getConn($this->sentinelFlag);// 2. 根据哨兵获取主节点及从节点信息$masterInfo = $sentinel->rawCommand('sentinel', 'get-master-addr-by-name', $this->config['sentinels']['masterName']);$slaveInfo = $sentinel->rawCommand('sentinel', 'slaves', $this->config['sentinels']['masterName']);// Input::info($masterInfo);// Input::info($slaveInfo);$newFlag = $this->connFlag($masterInfo[0], $masterInfo[1]);// 判断主节点是否出现问题if ($this->masterFlag == $newFlag) {Input::info("主节点没问题");return;}Input::info("切换主节点:" . $newFlag);$this->masterFlag = $newFlag;unset($this->config['master']);unset($this->config['slaves']);$this->config['master'] = ['host' => $masterInfo[0],'port' => $masterInfo[1],];foreach ($slaveInfo as $key => $slave) {$this->config['slaves']['slave' . $key] = ['host' => $slave[3],'port' => $slave[5],];}Input::info($this->config);// 3. 然后初始化主从连接$this->isMsInit($this->config);}/*** 设置哨兵*/public function setSentinels($sentinels){$this->createConns($sentinels, $this->sentinelFlag);}/*** 获取哨兵*/public function getSentinel(){$this->getConn($this->sentinelFlag);}public function setMaseterName($name){$this->maseterName = $name;}
}?>

最后再完善RedisMs类既可以
redisStudy\SentinelClient\test\config.php

<?php
namespace Shineyork\Redis\SentinelClient;use Shineyork\Redis\SentinelClient\Traits\Sentinel;/****/
class RedisMs
{use Sentinel;// ...此处代码省略...protected function isSentinelInit(){Input::info("哨兵模式");$this->setSentinels($this->config['sentinels']['addr']);$this->sentinelInit();}/*** 进行节点偏移量检测 -- 判断是否延迟*/protected function maintain(){swoole_timer_tick(2000, function () {Input::info("检测状态");if ($this->config['initType'] == "isSentinelInit") {$this->sentinelInit();}$this->delay();});}/*** 延迟维护* @return [type] [description]*/protected function delay(){try {$redis = $this->getMaster();$replicationInfo = $redis->info('replication');} catch (\Exception $e) {Input::info('主节点异常');return null;}// ...此处代码省略...}/*** 创建从节点连接*/protected function createConns($Conns, $flags = 'slaves'){foreach ($Conns as $key => $conn) {if ($redis = $this->getRedis($conn['host'], $conn['port'])) {$this->connections[$flags][$this->connFlag($conn['host'], $conn['port'])] = $redis;}}$this->connIndex[$flags] = array_keys($this->connections[$flags]);}/*** 获取redis连接*/protected function getRedis($host, $port){try {$redis = new \Redis();$redis->pconnect($host, $port);return $redis;} catch (\Exception $e) {Input::info('信息异常连接不上', $this->connFlag($host, $port));return null;}}// ...此处代码省略...
}?>

最后测试对象

<?php
require __DIR__ . '/../../vendor/autoload.php';use Shineyork\Redis\SentinelClient\RedisMs;$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->set(['worker_num' => 1
]);
$http->on('workerStart', function ($server) use ($config) {//引入配置文件require_once './config.php';global $redisMS;$redisMS = new RedisMs($config);
});
$http->on('request', function ($request, $response) {global $redisMS;if ($request->get['type'] == 1) {// 写$response->end($redisMS->runCommand($request->get['method'], explode(',', $request->get['params'])));} else {// 读$response->end($redisMS->runCommand($request->get['method'], [$request->get['params']]));}
});
$http->start();
?>

哨兵的切换实现原理

发布订阅基础

publish channel message – 发布消息
publish channel:sports “hello channel” – 向channel:sports发送消息
subscribe channel [channel …] – 订阅消息

对于redis的发布订阅来说消息是不会做保存的

哨兵的实现原理

Sentinel 的实现原理,主要分为以下三个步骤

  1. 检测问题,主要讲的是三个定时任务,这三个内部的执行任务可以保证出现问题马上让 Sentinel 知道。
  2. 发现问题,主要讲的是主观下线和客观下线。当有一台 Sentinel 机器发现问题时,它就会主观对它主观下线。但是当多个 Sentinel 都发现有问题的时候,才会出现客观下线。
  3. 找到解决问题的人,主要讲的是领导者选举,如何在 Sentinel 内部多台节点做领导者选举,选出一个领导者。
  4. 解决问题,主要讲的是故障转移,即如何进行故障转移

三个定时任务

首先要讲的是内部 Sentinel 会执行以下三个定时任务。

  • 每10秒每个 Sentinel 对 Master 和 Slave 执行一次 Info Replication 。
  • 每2秒每个 Sentinel 通过 Master 节点的 channel 交换信息(pub/sub)。
  • 每1秒每个 Sentinel 对其他 Sentinel 和 Redis 执行 ping

第一个定时任务,指的是 Redis Sentinel 可以对 Redis 节点做失败判断和故障转移,在 Redis 内部有三个定时任务作为基础,来 Info Replication 发现 Slave 节点,这个命令可以确定主从关系。

第二个定时任务,类似于发布订阅, Sentinel 会对主从关系进行判定,通过 sentinel:hello 频道交互。了解主从关系可以帮助更好的自动化操作 Redis 。然后Sentinel 会告知系统消息给其它 Sentinel 节点,最终达到共识,同时 Sentinel 节点能够互相感知到对方。

第三个定时任务,指的是对每个节点和其它 Sentinel 进行心跳检测,它是失败判定的依据

主观和客观下线

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000

那么什么是主观下线呢?

每个 Sentinel 节点对 Redis 节点失败的“偏见”。之所以是偏见,只是因为某一台机器30秒内没有得到回复

那么如何做到客观下线呢?

这个时候需要所有 Sentinel 节点都发现它30秒内无回复,才会达到共识

领导者选举

选举算法Raft:http://raft.github.io/ 或者 https://www.cnblogs.com/xybaby/p/10124083.html

  • 每个做主观下线的sentinel节点,会向其他的sentinel节点发送命令,要求将它设置成为领导者
  • 收到命令sentinel节点,如果没有同意通过其它节点发送的命令,那么就会同意请求,否则就会拒绝
  • 如果sentinel节点发现自己票数超过半数,同时也超过了 sentinel monitor mymaster 127.0.0.1 6379 2 超过2个的时候,就会成为领导者
  • 进行故障转移操作

故障转移

Redis 内部其实是有一个优先级配置的,在配置文件中 slave-priority ,这个参数是 Salve 节点的优先级配置,如果存在则返回,如果不存在则继续。

当上面这个优先级不满足的时候, Redis 还会选择复制偏移量最大的 Slave节点,如果存在则返回,如果不存在则继续。之所以选择偏移量最大,这是因为偏移 量越小,和 Master 的数据越不接近,现在 Master 挂掉了,说明这个偏移量小的机器数据也可能存在问题,这就是为什么要选偏移量最大的 Slave 的原因。

如果发现偏移量都一样,这个时候 Redis 会默认选择 runid 最小的节点

部署建议

  1. Sentinel 节点不应该部署在一台物理“机器”上。
    这里特意强调物理机是因为一台物理机做成了若干虚拟机或者现今比较流行的容器,它们虽然有不同的 IP 地址,但实际上它们都是同一台物理机,同 一台物理机意味着如果这台机器有什么硬件故障,所有的虚拟机都会受到影响,为了实现 Sentinel 节点集合真正的高可用,请勿将 Sentinel 节点部署在 同一台物理机器上。
  2. 部署至少三个且奇数个的 Sentinel 节点。
  3. 个以上是通过增加 Sentinel 节点的个数提高对于故障判定的准确性,因为领导者选举需要至少一半加1个节点。 奇数个节点可以在满足该条件的基础上节省一个节点。

需要关注的问题

配置

min-slaves-to-write 1 -- 要求至少有1个slave
min-slaves-max-lag 10 -- 数据复制和同步的延迟不能超过10秒,如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了

异步复制导致数据丢失

描述:因为master->slave的复制是异步,所以可能有部分还没来得及复制到slave就宕机了,此时这些部分数据就丢失了。 解决:在异步复制的过程当中,通过min-slaves-max-lag 这个配置,就可以确保的说,一旦 slave 复制数据和 ack 延迟时间太长,就认为可能 master 宕机 后损失的数据太多了,那么就拒绝写请求,这样就可以把master宕机时由于部分数据未同步到 slave 导致的数据丢失降低到可控范围内

集群脑裂导致数据丢失

描述: 脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其它slave机器不能连接,但是实际上master还运行着此时哨兵可能就会认为master宕机了,然后开始选举,将其它 slave 切换成 master 。这时候集群里就会有2个 master ,也就是所谓的脑裂。此时虽然某个 slave 被切换成了 master ,但是可能client 还没来得及切换成新的 master ,还继续写向旧的 master 的数据可能就丢失了。因此旧master再次恢复的时候,会被作为一个 slave 挂到新的 master 上去,自己的数据会被清空,重新从新的 master 复制数据。

解决:集群脑裂因为 client 还没来得及切换成新的 master ,还继续写向旧的 master 的数据可能就丢失了通过 min-slaves-to-write 确保必须是有多少个从 节点连接,并且延迟时间小于 min-slaves-max-lag 多少秒

对于客户端来说:就需要做些处理,比如先将数据缓存到内存当中,然后过一段时间处理,或者连接失败,接收到错误切换新的 master 处理

代码流程

首先可以根据启动来看,在之前有提过哨兵有两种启动方式分别通过redis-server,redis-sentinel这两方式启动;
可以看看server.c中的代码体现

int main(int argc, char **argv) {server.sentinel_mode = checkForSentinelMode(argc,argv);/*...省略代码....*/if (server.sentinel_mode) {initSentinelConfig(); // 讲监听端口设置为26379initSentinel(); // 更改哨兵可执行命令。哨兵中只能执行优先的几种服务端命令,如ping,sentinel等}/*...省略代码....*//* 哨兵的配置通过 sentinelHandleConfiguration 在config.c中加载*/if (!server.sentinel_mode) {} else {InitServerLast();sentinelIsRunning(); // 随机生成一个40子节点哨兵id,打印启动日志}
}

在主程序的函数中主要是对于哨兵进行初始,而实际的简历命令连接和消息连接是通过redis的时间让我severCron处理的

int serverCron(){/*...省略代码....*/if (server.sentinel_mode) sentinelTimer();/*...省略代码....*/
}

哨兵每次执行serverCron时,都会调用sentineTimer()函数。该函数会建立连接,并且定时发送心跳包并采集信息。该函数主要功能如下。

  1. 建立命令连接和消息连接。消息连接建立之后会订阅redis服务的__sentinel__:hello频道。
  2. 在命令连接上每10s发送info命令进行信息采集;每1s在命令连接上发送ping命令探测存活性

如下是哨兵的命令

struct redisCommand sentinelcmds[] = {{"ping",pingCommand,1,"",0,NULL,0,0,0,0,0},{"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0},{"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0},{"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},{"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0},{"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},{"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0},{"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0},{"role",sentinelRoleCommand,1,"l",0,NULL,0,0,0,0,0},{"client",clientCommand,-2,"rs",0,NULL,0,0,0,0,0},{"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0},{"auth",authCommand,2,"sltF",0,NULL,0,0,0,0,0}
};

redis学习笔记(7)之redis哨兵详解相关推荐

  1. JDBC学习笔记02【ResultSet类详解、JDBC登录案例练习、PreparedStatement类详解】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  2. 小猫爪:i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解

    i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解 1 前言 2 FlexCAN简介 2.1 MB(邮箱)系统 2.1.1 正常模式下 2.1.2 激活了CAN FD情况下 2. ...

  3. IP地址和子网划分学习笔记之《IP地址详解》

    在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. IP地址和子网划分学习笔记相关篇章: 1.I ...

  4. 我的学习笔记——CSS背景渐变(Gradients)详解

    我的学习笔记--CSS背景渐变(Gradients)详解 一.线性渐变(Linear Gradients) 1.语法 background-image: linear-gradient(directi ...

  5. IP地址和子网划分学习笔记之《子网划分详解》

    一,子网划分概述 IP地址和子网划分学习笔记相关篇章: 1.IP地址和子网划分学习笔记之<预备知识:进制计数> 2.IP地址和子网划分学习笔记之<IP地址详解> 3.IP地址和 ...

  6. redis学习笔记(2)之redis主从详解

    redis主从详解 主从详解 主从配置 拓扑 原理 数据同步 概念 复制偏移量 复制积压缓冲区 主节点运行ID Psync命令 全量复制流程 部分复制流程 心跳 缓冲大小调节 读写分离 内容来源为六星 ...

  7. redis学习笔记(6)之redis哨兵

    redis哨兵 redis哨兵初识 基础概念 主从复制的问题 redis 哨兵的高可用性 redis哨兵安装和部署 部署结构 内容来源为六星教育,这里仅作为学习笔记 redis哨兵初识 redis的主 ...

  8. redis学习笔记(5)之redis内存优化

    redis内存优化 配置优化 Linux 配置优化 Redis配置优化 缩减键值对象 命令处理 缓存淘汰优化 动态改配置命令 设置最大内存 设置淘汰策略 内存淘汰策略 如何选择淘汰策略 内容来源为六星 ...

  9. linux和redis笔记,Redis学习笔记一(Redis的详细安装及Linux环境变量配置和启动)...

    Redis Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 我使用的是下面这个版本: 一.接下来打开你的Li ...

最新文章

  1. 关于学习Python的一点学习总结(6->元组)
  2. 阿里内部禁用Executors创建线程池,为什么?
  3. centos安装anaconda_每天三分钟之TensorFlow学习03:Win下安装TF2
  4. strstr,strrchr,strpos,strrpos的区别http://blog.qit...
  5. 谷歌A/B实验——重叠实验基础设施解读
  6. 电子商务网站常用源码介绍
  7. 程序员的幽默--火车
  8. arcgis 删除图形重复折点_【干货】ArcGIS中画环状图斑、挑子区及消除图斑重复区域...
  9. 问题十五:C++中抽象类,虚函数是什么鬼?怎么测试
  10. 东方财富单独下单软件_炒股理财,就选东方财富证券!
  11. 教你成为质量管理高手GJB
  12. 通过duet软件实现ipad作为mac的副屏并修改分辨率
  13. 梦三花重金修改服务器,2021年3月31日维护公告:新门派花果山
  14. python之爬虫(十一) 实例爬取上海高级人民法院网开庭公告数据
  15. 北京家庭摇号积分计算方式
  16. mysql 1556_mysqldump: Got error: 1556: You can't use locks with log tables.
  17. PMP是什么考试,有什么作用?(含资料)
  18. Android 的四大组件
  19. word计算机桌面加密,word文档加密,怎么让word自动加密 -电脑资料
  20. Spring-boot mvn 打包之后Java -jar找不到启动类的问题

热门文章

  1. 华为机试:服务器广播
  2. 服务器芯片 128核心,无惧 X86,Ampere 公布 128核ARM 处理器
  3. 论文阅读【用监督对比学习建模域外检测(OOD Detection) 的 鉴别表示】
  4. 树形结构(1)(Java语言)——树的基本概念
  5. 【JSON教科书】什么是JSON,JSON字符串有什么作用?(JSON学习总结)
  6. 电子书领取入口|独家数据深入探索GameFi热潮
  7. 记一次API 接口定义 添加 @ApiOperation 注解触发中间件 bug 问题分析
  8. 浅谈物联网发展的几大趋势
  9. 经验教训 软件开发_软件可靠性的教训
  10. nginx配置文件实用干货