Redis-sentinel是Redis实例的监控管理、通知和实例失效备援服务,是Redis集群的管理工具。在一般的分布式中心节点数据库中,Redis-sentinel的作用是中心节点的工作,监控各个其他节点的工作情况并且进行故障恢复,来提高集群的高可用性。(简介来自链接:http://www.searchdatabase.com.cn/showcontent_71572.htm)
下面是我对Redis 2.9.11-非稳定版作的测试总结,更新的版本可能没有下面的问题。
1.使用Redis-sentinel,redis实例必须在非集群模式下运行
2.如果默认主从关系的主挂了,这时启动failover,在failover过程中,有n个slave还活着,那么新master就有n个slave,旧master重启还可以加入集群,但其他在failover之前或过程中挂掉的slave重启是不能加入集群的,除非修改它们的配置文件,将master指向新master.
3.如果默认主从关系变了,其中一个slave挂了重启,它的master还是指向配置文件指定的,但它也是新master的slave,这是由于旧master已变为新master的slave,所以旧master的slave也是新master的slave,新master的slave数不变,这可从命令:sentinel slaves mymaster看出。
ps:从这里可以看出,slave重启不会重定向master,主从关系是sentinel发info请求获取的
4.如果默认主从关系的主挂了且failover正常结束,旧master重启还可以加入集群,但旧master第二次重启就不能加入集群了。
5.只要有slave of master命令调用,即主从关系建立, 就会触发主和该从采用save方式持久化数据,不论你是否禁止save.
6.在集群中,如果默认主从关系的主挂了并立即重启,如果主没有做持久化,数据会完全丢失,从而从的数据也被清空。
配置:redis config
==配置文件全解===分布时效+效率安全分布和时效:基本 + 主从 + 限制kv
效率和安全:日志 + 慢查询 +服务端 + 配置信息 +连接测试 + 安全
==基本配置
daemonize no 是否以后台进程启动
databases 16 创建database的数量(默认选中的是database 0)
save 900 1 #刷新快照到硬盘中,必须满足两者要求才会触发,即900秒之后至少1个关键字发生变化。
save 300 10 #必须是300秒之后至少10个关键字发生变化。
save 60 10000 #必须是60秒之后至少10000个关键字发生变化。
stop-writes-on-bgsave-error yes #后台存储错误停止写。
rdbcompression yes #使用LZF压缩rdb文件。
rdbchecksum yes #存储和加载rdb文件时校验。
dbfilename dump.rdb #设置rdb文件名。
dir ./ #设置工作目录,rdb文件会写入该目录。
==主从配置
slaveof <masterip> <masterport> 设为某台机器的从服务器
masterauth <master-password> 连接主服务器的密码
slave-serve-stale-data yes # 当主从断开或正在复制中,从服务器是否应答
slave-read-only yes #从服务器只读
repl-ping-slave-period 10 #从ping主的时间间隔,秒为单位
repl-timeout 60 #主从超时时间(超时认为断线了),要比period大
slave-priority 100 #如果master不能再正常工作,那么会在多个slave中,选择优先值最小的一个slave提升为master,优先值为0表示不能提升为master。
repl-disable-tcp-nodelay no #主端是否合并数据,大块发送给slave
slave-priority 100 从服务器的优先级,当主服挂了,会自动挑slave priority最小的为主服
===安全
requirepass foobared # 需要密码
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 #如果公共环境,可以重命名部分敏感命令 如config
===限制
maxclients 10000 #最大连接数
maxmemory <bytes> #最大使用内存
maxmemory-policy volatile-lru #内存到极限后的处理
volatile-lru -> LRU算法删除过期key
allkeys-lru -> LRU算法删除key(不区分过不过期)
volatile-random -> 随机删除过期key
allkeys-random -> 随机删除key(不区分过不过期)
volatile-ttl -> 删除快过期的key
noeviction -> 不删除,返回错误信息
#解释 LRU ttl都是近似算法,可以选N个,再比较最适宜T踢出的数据
maxmemory-samples 3
====日志模式
appendonly no #是否仅要日志
appendfsync no # 系统缓冲,统一写,速度快
appendfsync always # 系统不缓冲,直接写,慢,丢失数据少
appendfsync everysec #折衷,每秒写1次
no-appendfsync-on-rewrite no #为yes,则其他线程的数据放内存里,合并写入(速度快,容易丢失的多)
auto-AOF-rewrite-percentage 100 当前aof文件是上次重写是大N%时重写
auto-AOF-rewrite-min-size 64mb aof重写至少要达到的大小
====慢查询
slowlog-log-slower-than 10000 #记录响应时间大于10000微秒的慢查询
slowlog-max-len 128 # 最多记录128条
====服务端命令
time 返回时间戳+微秒
dbsize 返回key的数量
bgrewriteaof 重写aof
bgsave 后台开启子进程dump数据
save 阻塞进程dump数据
lastsave
slaveof host port 做host port的从服务器(数据清空,复制新主内容)
slaveof no one 变成主服务器(原数据不丢失,一般用于主服失败后)
flushdb 清空当前数据库的所有数据
flushall 清空所有数据库的所有数据(误用了怎么办?)
shutdown [save/nosave] 关闭服务器,保存数据,修改AOF(如果设置)
slowlog get 获取慢查询日志
slowlog len 获取慢查询日志条数
slowlog reset 清空慢查询
info []
config get 选项(支持*通配)
config set 选项 值
config rewrite 把值写到配置文件
config restart 更新info命令的信息
debug object key #调试选项,看一个key的情况
debug segfault #模拟段错误,让服务器崩溃
object key (refcount|encoding|idletime)
monitor #打开控制台,观察命令(调试用)
client list #列出所有连接
client kill #杀死某个连接 CLIENT KILL 127.0.0.1:43501
client getname #获取连接的名称 默认nil
client setname "名称" #设置连接名称,便于调试
====连接命令===
auth 密码 #密码登陆(如果有密码)
ping #测试服务器是否可用
echo "some content" #测试服务器是否正常交互
select 0/1/2... #选择数据库
quit #退出连接
语法:
<?php
/*
创建 连接=>curd+存在性+批量+数据增减+排序+生存时效+配置=>持久化+主从+事务
string 静态数据:存取
hash 属性数据:关系
set:去重数据:集合
list:列表数据:头尾
sort set 排序数据:先后
*/
//存取 时效 加减1 键名操作 事务 持久化
//get set setex setex delete mset getMultiple flushdb flushall| ttl persist setTimeout expireAt|
//incr incrby decr decrby | multi exec discard watch unwatch
//save bgsave lastsave bgrewriteaof slaveof info auth
//keys randomKey type dbsize rename renameNx move exists
//set s +add rem move pop sort + inter/store union/store diff-前面的差集/store +randMember members contains size
//zset z+ add rem |rev/range rem/rangebyscore score rank |count incrby size |union/inter
//list:l r + push/x pop+set get | l+range/trim/rem/insert lsize |rpoplpush
//string:getSet get/setRange append strlen
//hash h +m/set m/get del +keys vals getall +len exists incrby
//ttl -2 是过期了,-1是持久有效
//sort
/*
'by' => 'some_pattern_*',
'limit' => array(0, 1),
'get' => 'some_other_pattern_*' or an array of patterns,
'sort' => 'asc' or 'desc',
'alpha' => TRUE,
'store' => 'external-key'
*/
$r = new Redis;
$r->connect('127.0.0.1',6379);
$r->auth('password');
$option = $r->ping();
$r->set('key','val');
$val = $r->get('key');
// echo $val;
$r->setnx('key','val');
$nx = $r->get('key');
$r->setex('keys',3,'vals');
$time = $r->ttl('keys');
//echo $time;
$num = $r->delete('key');
//echo $num;
$r->persist('keys');
$val = $r->get('keys');
//echo $val;
$r->mset(array('key1'=>'val1','key2'=>'val2','key3'=>'val3','key4'=>'val4','key5'=>'val5'));
$val = $r->get('key3');
// echo $val;
$vals = $r->getMultiple(array('key1','key2','key3','key4','key5'));
// echo '<pre>';
// print_r($vals);
$have = $r->exists('key2');
// echo($have);
//$number = $r->set('num',1);
$numNow = $r->incr('num');
$numNow = $r->incrby('num',10);
// echo $numNow;
//事务失败后不能回滚,造成部分执行完毕,事务只能保证操作的原子性,但不能保证数据原子性,因此采用乐观锁,watch/unwatch
$r->watch('num');
$r->multi()->incrby('num',100)->exec(); //or $r->multi()->incrby('num',100)->discard();
$num = $r->get('num');
// echo $num;
// $r->flushDB();
// $r->flushAll();
$keyss = $r->randomKey();
echo $keyss;
$r->select(0);
$r->set('x',42);
$r->move('x',1);
$r->select(1);
$val = $r->get('x');
// echo $val;
$r->set('name1','zy');
$r->set('name2','zy');
$r->set('name3','zy');
$r->set('name4','zy');
$r->set('name','zy');
$r->rename('name','myname');
$r->get('myname');
$r->renameNx('myname','myname2');
$r->setTimeout('x',30);
$time = $r->ttl('x');
// echo $time;
$r->expireAt('x',time()+301);
$time = $r->ttl('x');
//echo $time;
$key = $r->keys('*');
// print_r($key);
$db = $r->dbSize();
// var_dump($db);
echo '<pre>';
$r->bgrewriteaof();
// $r->slaveof('127.0.0.1',6380);
$r->save();;
$r->bgsave();
$unix = $r->lastSave();
$date = date('Y-m-d H:i:s',$unix);
// echo $date;
// print_r($operate);
$info = $r->info());
var_dump($r->type('myname'));
//string
$r->set('string','str');
$len = $r->strlen('string');
$r->set('insert','insertVals');
$r->append('string','insert');
// $val = $r->get('string');
// echo $val;
$r->set('abc','def');
$vals = $r->getSet('string','abc');
echo $vals;
$change = $r->get('string');
echo $change;
//hash
$r->hmset('student',array('wangming'=>80,'xiaohong'=>85,'ligang'=>90));
$r->hdel('student','ligang');
$vals = $r->hmget('student',array('xiaohong','wangming'));
var_dump($vals);
$val = $r->hget('student','xiaohong');
echo $val;
$exists = $r->hexists('student','wangming');
var_dump($exists);
$len = $r->hlen('student');
echo $len;
$r->hincrBy('student','xiaohong',10);
$score=$r->hget('student','xiaohong');
var_dump($score);
$keys = $r->hkeys('student');
$vals = $r->hvals('student');
$all = $r->hgetall('student');
echo '<pre>';
var_dump($keys);
var_dump($vals);
var_dump($all);
//zset
$r->zadd('set',0,'123');
$r->zadd('set',1,'456');
$r->zadd('set',2,'789');
$r->zadd('set',3,'1231');
$r->zrem('set','789');
$r->zadd('set',42,'1232');
$count = $r->zcount('set',0,42);
$size = $r->zsize('set');
$r->zincrby('set',2000,'123');
$rangeScore = $r->zremrangeByScore('set',0,1);
$scores = $r->zscore('set','123');
var_dump($scores);
$rank = $r->zrank('set','789');
var_dump($rank);
echo $size;
var_dump($count);
echo '<pre>';
$range = $r->zRevrange('set',0,-1);
var_dump($range);