Redis进阶篇

目录

一.高级特性

1.发布订阅模式

2.redis事务

3.lua

4.redis为什么这么快

二.过期策略

惰性过期

定期过期

三.淘汰策略

LRU

LFU

四.持久化机制

RDB Redis DataBase

AOF Append Only File

五.缓存穿透、缓存击穿、缓存雪崩

1.缓存穿透

2.缓存雪崩

3.缓存击穿

4.什么是缓存数据一致性问题?怎么解决的?

六.集群 


一.高级特性

1.发布订阅模式

publish 发布

subscribe 订阅

unsubscribe 取消订阅

2.redis事务

redis的单个命令是原子性的,但是多个命令我们该怎么保证原子性呢

事务命令

  • multi 开启一个事务  会把后续的操作命令放进队列
  • exec 执行事务
  • discard 取消事务
  • watch 相当于cas乐观锁机制

发生异常情况

  • 编译异常:在exec前出现编译异常,事务会discarded也就是会取消这个事务。
  • 运行异常:异常前的可以执行成功,异常的无法执行。(我们会发现这跟我们想的原子性不同)

那么如何保证原子性呢? 引入lua脚本

3.lua

为什么使用lua脚本

  • 一次发送多个命令,减少网络开销
  • 保证原子性
  • lua file 可以实现命令的复用

redis中执行lua脚本

redis> eval lua-script key-num [key1 key2 key3.....] [value1value2 value3 ....]

  • eval代表执行Lua语言的命令。
  • lua-script代表Lua语言脚本内容。
  • key-num表示参数中有多少个key,需要注意的是Redis中key是从1开始的,如果没有key的参数,那么写0。
  • [key1 key2 key3...]是key作为参数传递给Lua语言,也可以不填,但是需要和key-num的个数对应起来。
  • [value1 value2 value3...…]这些参数传递给Lua语言,它们是可填可不填的。

在lua中执行redis命令

redis.call(command, key [param1,param2...])

  • command是命令,包括set、get、del等。
  • key是被操作的键。
  • param1,param2...代表给key的参数。

命令 set zs 500 用lua脚本执行的话是

192.168.115.132:6379> eval "return redis.call('set',KEYS[1],ARGV[1])" 1 zs 500
OK
192.168.115.132:6379> get zs
"500"

4.redis为什么这么快

  • 与内存交互,没有磁盘IO
  • IO多路复用
  • 单线程
  • 底层数据结构巧妙设计 比如跳表

二.过期策略

        因为我们的redis是一个内存型数据库,我们的数据都是放在内存里面的!但是内存是有大小的! redis,里有个很重要的配置文件,redis.conf里面有 个配置,

# maxmemory <bytes> redis占用的最大内存

如果我们不淘汰,那么它的数据就会满,满了肯定就不能再放数据,发挥不了redis的作用!

过期策略就是把之前设置的expired的key,把已经过期了的淘汰掉。

如果把redis比作冰箱,数据比作菜,那么过期策略就是要把过期了的菜扔掉。

惰性过期

惰性过期是一种被动过期,就是只有当我们访问或者操作key的时候才会判断它是否过期。如果过期了就淘汰。

该策略就可以最大化地节省CPU资源,因为它平时不会去判断,所以也没有啥cpu损耗,因为只有访问的时候我才去判断一下!

但是却对内存非常不友好。因为你不实时过期了,该过期删除的就可能一直堆积在内存里面!极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

特点:对cpu比较优化 但是对内存不友好。

源码expireIfNeeded db.c文件下1302行)

int expireIfNeeded(redisDb *db, robj *key) { 
    if (!keyIsExpired(db,key)) return 0;  
    if (server.masterhost != NULL) return 1; /* Delete the key */                     
    server.stat_expiredkeys++; 
    propagateExpire(db,key,server.lazyfree_lazy_expire);
    notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired",key,db->id); 
    int retval = server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) : dbSyncDelete(db,key); 
    if (retval) signalModifiedKey(NULL,db,key); 
    return retval;

定期过期

        惰性这种又会可能导致大量无效数据堆积在内存里面,我们总得有个办法来解决吧!不能让他一直堆在内存里面啊!

        所以我们就有了一个定期过期策略,虽然实时性比不上定时的,但是也足够解决垃圾数据大量堆积在内存的这种情况!

先了解一下数据结构  源码 dict.h

redishash默认使用的是ht[0]ht[1]不会初始化和分配空间。

哈希表dictht是用链地址法来解决碰撞问题的。如果节点数量比哈希表的大小要大很多的话,那么哈希表就会退化成多个链表,哈希表本身的性能优势就不再存在,在这种情况下需要扩容。 Redis里面的这种操作叫做rehash

那么它怎么做rehash的? ht[0]ht[1]

定期策略是定时去扫描一下key有没有过期。

定多久扫描一次由谁来决定? 

redis 时间事件 ServerCron 隔多久去执行一次,hz(配置文件可配)每秒会执行多少次。hz10(默认的)代表100ms执行一次ServerCron。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w7486

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值