redis (一)

来源:互联网 发布:考勤系统源码 编辑:程序博客网 时间:2024/06/01 07:13
array(php)-->cache(mem)-->nosql(主从 事务 持久化)

使用:返回值  场景  字段
设计:字段  mysql冷数据 写入  测试
weibo:推拉  关注/被关注  用户注册登录


主从(含义、迁移和切换) +  运维(命令和参数) + Redis-sentinel(集群管理工具) |  语法+配置+区别
主(-rdb +aof)--从(+rdb slaveof passwd  slave-read-only)备份—>读写分离—>任务分离(分担备份、计算)

主从:
主1—>从1(可快速切换为主)切换时主需要全部dump出来,再aof,不要多台slave同时启动,以防io剧增
      —>从2(从1 从2 互为主从,主1宕机可快速切换)

--redis 主从同步


redis和memcache比较像的,memcache可以实现服务器的集群,redis肯定也是可以的。下面在一台机,实现redis主从复制。

1,copy一下redis.conf,生成一个从机的配置

cp /usr/local/redis/redis.conf /usr/local/redis/redis_slave.conf

2,修改主服务器的配置redis.conf

bind 127.0.0.1

3,修改从服务器的配置redis_slave.conf

pidfile /usr/local/redis/var/redis_slave.pid

port 10002

bind 127.0.0.1

logfile /usr/local/redis/var/redis_slave.log

dbfilename dump_slave.rdb

slaveof 127.0.0.1 6379

4,启动主服务器,从服务器

redis-server /usr/local/redis/redis.conf

redis-server /usr/local/redis/redis_slave.conf



迁移:
1. 在新服务器上启动一个redis实例slave不仅读取,还要写入   slave-read-only no
2. 使新的redis服务成为slave    redis127.0.0.1:6379> SLAVEOF 192.168.1.100 6379
3. 完成迁移,原有master关闭了  redis127.0.0.1:6379> SLAVEOF no one

运维:


1.命令:

TIME查看时间戳与微秒数

DBSIZE查看当前库中的key数量

BGREWRITEAOF后台进程重写AOF

BGSAVE      后台保存rdb快照

SAVE        保存rdb快照

LASTSAVE    上次保存时间

SLAVEOF     设为slave服务器

FLUSHALL    清空所有db

FLUSHDB     清空当前db

SHUTDOWN[""|save|nosave]    断开连接,关闭服务器

SLOWLOG  显示慢查询

INFO     显示服务器信息

CONFIG GET获取配置信息

CONFIG SET设置配置信息

MONITOR   打开控制台

SYNC      主从同步

CLIENT LIST客户端列表

CLIENT KILL关闭某个客户端

CLIENT SETNAME为客户端设置名字


CLIENT GETNAME获取客户端名字


2.观察:内存 主从 持久化  fork耗时 慢日志

--内存# Memory

used_memory:859192数据结构的空间

used_memory_rss:7634944实占空间

mem_fragmentation_ratio:8.892者的比例,1.N为佳


--主从复制# Replication

role:slave

master_host:192.168.1.128

master_port:6379

master_link_status:up


--持久化# Persistence

rdb_changes_since_last_save:0

rdb_last_save_time:1375224063


--fork耗时#Status

latest_fork_usec:936 上次持久化花费微秒


--慢日志

config get/set slowlog-log-slower-than

CONFIG get/SET slowlog-max-len

slow log get获取慢日志


补充:Redis-sentinel:
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.在集群中,如果默认主从关系的主挂了并立即重启,如果主没有做持久化,数据会完全丢失,从而从的数据也被清空。

7.在集群中,如果非默认主从关系的主挂了并立即重启,主从关系变乱,集群不可用。


区别:

Redis--分库快速写 与 Memcached--搜索纯读取

区别:          redis       memcache

网络IO         单线程      多线程

内存            申请         预先申请

客户端         操作少,快      操作多,慢

数据类型      多            少

持久化         支持swap  不支持

数据一致性   支持         不支持

分布式           Twemproxy  consistent_hash  

有效性       LRU--惰性失效 | expire--惰性+随机+暴力

内容            字符串       字符串 图片、视频




配置:
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);

0 0
原创粉丝点击