redis详解

reids使用场景:

1.一般的数据缓存

2.队列应用:非实时业务如发放积分或需要削峰降流的秒杀等场景都会用到队列

3.发布订阅

4.计数器

5.排行榜:微博的热榜就是很好的例子

6.资源锁:这个秒杀的时候往往也会用到,防止超卖等现象发生,当然还有很多其他防并发的用途。

 

redis的五种常用数据类型:string,hash,set,zset.list

 

 

redis淘汰策略:

      noevication:不删除策略,达到maxmemory,直接返回错信息

     allkeys-lru: 优先删除最近最少使用的key

     volatile-lru: 优先删除设置过expire的最近最少使用的key.

     allkeys-random: 随机删除部分key

     volatile-random:随机删除设置过过期时间的key

     volitile-ttl : 删除设置过期时间中的剩余时间最少的key

 

一般来说:

如果分为热数据与冷数据, 推荐使用 allkeys-lru 策略。 也就是, 其中一部分key经常被读写. 如果不确定具体的业务特征, 那么 allkeys-lru 是一个很好的选择。
如果需要循环读写所有的key, 或者各个key的访问频率差不多, 可以使用 allkeys-random 策略, 即读写所有元素的概率差不多。
假如要让 Redis 根据 TTL 来筛选需要删除的key, 请使用 volatile-ttl 策略。

 

 

Redis为了保证高可用性,采用Master-slave形式部署,采用AOF或RDB进行持久化,采用集群culster机制来分布式存储。

 

redis哨兵:
很显然,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群,这样有几个好处:
即使有一些sentinel进程宕掉了,依然可以进行 集群的主备切换;
如果只有一个sentinel进程,如果这个进程运行出错,或者是网络堵塞,那么将无法实现redis集群的主备切换(单点问题);
如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息

 

对象序列化:serialize 方便存储redis(strig)
1.hash

是一个string类型的field 和 value的映射表,适合存储对象;

常用命令:hget,hset,hgetall 等;

hset myhash name cyh

hset user:001 name cyh
hget user:001 name --返回cyh 把user:001当作一个表 name为字段名 cyh为字段值

hsetnx user:002 name ss --如果存在则返回0不保存进去

hmset user:003 name ss age 20 sex women -- 批量设置
hmget user:003 name age sex -- 批量返回(ss ,0 ,women)
hget user:003 age --20

hincrby user:003 age 5 --自增5
hexists user:003 age --判断hash表里面的字段是否存在的方法
hlen user:003 --返回字段的数量

hdel user:003 age --删除age字段的值

hkeys user:003 --返回所以字段名(array_keys)
hvals user:003 --返回所有的值(array_vales)

hgetall user:003 --返回所有键值

expire age 10 --给age设置过期时间十秒钟

ttl age --返回-1查看是否过过期

 

2.list(有序非去重集合)

常用命令:lpush,rpush(存数到队列),lpop(取数),rpop,lrange等。

使用场景:做消息队列系统

下面这个程序模拟了20w人一瞬间涌入这个页面进行秒杀,能够秒杀成功的只有500人,我们把先进来的用户放入redis队列中,当队列中的用户达到500时,后来用户就转到秒杀结束页面。这里用随机数来表示不同的用户。

$redis = new redis();

$redis->connect('localhost','6379');

$redis->select(1);

$redis_name = 'miaosha';

$num = 500;   抢购名额

$i = 20000;    抢购人数

$n = 0;        验证执行数量是否正确

while($i--){

   $n++;

  $uid = mt_rand(100000,99999)

   if( $redis->llen($redis_name) <  $num){

             $redis->rpush($reids_name,$uid);

            echo  $uid. '秒杀成功';

 }else{

            echo $uid . "秒杀失败"

}   

$redis->close();

 

}

 


3.string:最简单的数据类型(k-v)
set name cyh
get name

setnx name cyh (防止覆盖,如果存在这个key则返回0存不进去)

setex color 10 red 设置键值并设置有效值

setrange name 6 qq.com 替换字符串,从下标为6(下表从0开始)的开始替换,后面的参数为替换的内容

mset key1 val1 key2 val2 批量设置

getrange name 0 5 获取字符串(0到5)

incr id3 自增操作
decr 自减
incrby id 5 自增五个
decrby id 5

append name.ss 给name的value追加字符串

strlen name 求键的长度


4.set(去重无序集合)

常用命令:sadd,spop,smembers,sunion 等。

 


5.zest

使用场景:排行榜应用,取TOP N操作

 

redis事务特性:不具有事务的原子性(加入队列中的某个事务没有执行成功,但是整个事务不会全部回滚),会导致数据不具有一致性
$redis->muilti --开始事务上下文
ok
$redis->set age 10 --先将事务放入队列中
queued
$redis->set age 20
queued
$redis->exec --执行事务
1ok
2ok
$redis->get age
20
$redis->discard --取消事务(事务回滚:清空队列并退出事务上下文)


redis 乐观锁:类似版本控制器(更新后版本号加1,如果提交版本号大于当前版本号则更新当前版本号,否则则认为是过期数据)
watch age --监控age

$redis->set age 30

$redis->muilti
$redis->set age 20
queued
$redis->exec --事务将执行失败 、
(当watch监控age时,发现从监视起这个key发生过变化,则整个事务将失败,(打开watch就相当于对当前key增加了一个乐观锁)
也可以调用watch多次监视多个key,这样就可以对指定的key加乐观锁,watch的key是对整个事务都有效的,事务也一样
unwatch ,discard,exec都会清除连接中的所有监视
当前事务的age不是最新的age,属于过期数据不允许执行)

 

redis 持久化机制:
redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到硬盘来保证持久化。

redis持久化的方式:
1.快照模式(snapshoting 文件dump.rdb 二进制) 也是默认方式: 相当于把数据做一个备份(将数据存到文件里)
ans:
这种方式是将内存中的数据以快照的方式写到二进制文件中,默认的文件名为dump.rdb。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照
save 300 10 #300秒内如果有10个key被修改过,则发起快照保存

2.append_only_file(aof 文件appendonly.aof 某种协议) 增量型持久化: 将写和更改的操作存到一个文件里面(insert.update)extend:所有被写入 AOF 的命令都是以 redis 的协议('RESP')格式来保存的。
ans:
由于快照方式在一定时间间隔内做一次的,如果redis意外宕机,就会丢失掉最后一次快照后的所有修改。
aof比快照有更好的持久化,由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到文件中。
当redis重启时,会重新执行文件中保存的写命令来在内存中重建整个数据库的内容。

appendonly yes --启用aof持久化
appendfsync always --收到写命令就立即写入磁盘,最慢,但是数据最完整
appendfsync everysec --每秒写入磁盘一次 性能折中
appendfsync no --完全依赖os,性能最好,持久化没保障


发布与订阅:
是一种消息通信模式,主要是解决消息订阅者和发布者之间的耦合性,redis作为一个pub/sub的server,在订阅者和发布者之间起到路由的功能
订阅者可以通过subscribe和psubscribe向redis service订阅自己感兴趣的消息类型,redis将信息类型称为通道,当发布者通过publish命令向
redis service发送特定的消息类型的信息时,订阅改信息的全部client都会收到此消息

可以做一个web聊天系统

subscribe tv1 tv2
cyh


publish tv1 cyh


虚拟内存:
把不经常使用的数据交换到磁盘上

 

常规使用:
$redis = new redis();
redis->connect();


-- 添加
$redis->hset()

--批量添加
$uid = $redis->incr("userid");
$redis->hMset('user:' . uid,array('uid'=>$uid,name'=>'cyh','age'=>'20'))
$redis->hMset('header:rows1',array('name'=>'cyh','age'=>'20'))

-- 批量获取
require("redis.php");
foreach($i = 1 ; $i <= ($redis->get("userid")) ; $i++){
$data[] = $redis->hgetall("user:" . $i);
}

-- 删除
$redis->del("user" . $uid)


-- 分页
总数
$count = $redis->lsize("uid");

页大小
$page_size = 10;

当前页码
$page_num = $GET_['page'];

页总数
$page_count = ceil($count/$page_size)

$ids = $redis->lrange('uid',($page_num-1)*$page_size,(($page_num-1)*$page_size+($page_size-11))
foreach($ids as $v){
$data[] = $redis->hgetall('user:'.$v);
}

 

posted @ 2018-12-16 22:49  你脑子有bug  阅读(940)  评论(0编辑  收藏  举报