美文网首页
Redis基础复习

Redis基础复习

作者: 笔记本一号 | 来源:发表于2020-05-15 03:08 被阅读0次
其他命令

info:查看redis系统信息,包括库的信息 Keyspace
select:Keyspace中选择db

image.png
flushdb:删除当前的db
flushall:删除所有的db
quit:退出cli
以下k代表key值,v代表value值,n代表name值
键命令

exists:exitsts k 查看是否存在在这个key
ttl:ttl k 查看key的剩余生存时间,-1代表不存过期时间,-2不存在或已到期
type:type k 查看key的类型
randomkey: randomkey 随机随机返回一个key
rename:rename k newk 改变key的名字,如果修改的名称已经存在则直接覆盖存在同名的key
renamenx:renamenx k newk 改变key的名字,如果修改的名称已经存在则会返回0代表修改失败

5种数据结构
string

set:set k v
get:get k
del:del k
setex: setex k 100 v ex是expired的缩写,设置key值的过期时间是100秒
psetex: setex k 100 v ex是expired的缩写,设置key值的过期时间是100毫秒
getrange:getrange k 0 3 截取key值对应的value,例如value是redis,截取0到3返回就是redi
getset: getset k v 先get key的value值并返回,然后set key 的value值
mset: mset k1 v1 k2 v2 k3 v3 设置多个key的value
mget: mget k1 k2 k3 获取多个key的value
setnx: setnx k v 判断是否已经存在k值,存在则设置失败返回0,成功则是设置成功返回1
msetnx: mset k1 v1 k2 v2 k3 v3 设置多个key的value,先判断这些key是否存在,只要有一个不存在就命令就会整个失败,具有原子性
strlen: strlen k 获取key对应value的长度
incr: incr k 使k对应的value值加1,并返回结果
incrby: incrby k 100 使k对应的value值加100,并返回结果
decr: decr k 使k对应的value值减1,并返回结果
decrby: decrby k 100 使k对应的value值减100,并返回结果
append: append k av 在key对应的value值后边最近字符串

hash

hset:hset n k v 设置一个哈希的名字及这个哈希的key和value
hexists:hexists n k 查询一个哈希中的key是否是存在的,返回0不存在,1存在
hget:hget n k 获取一个哈希中的key对应的value值,没有值存在就返回nil(null)
hgetall:hgetall n 获取一个哈希中所有的key value值
hkeys:hkeys n 获取一个哈希中所有的key值
hvals:hvals n 获取一个哈希中所有的value值
hlen:hlen n 获取一个哈希中的 key的数量
hmset: hmset n k1 v1 k2 v2 k3 v3 设置一个哈希中多个key-value键值对
hmget:hmget n k1 k2 k3 获取一个哈希中指定数量的key1 key2 key2对应的value值
hdel:hdel n k1 k2 删除一个哈希中指定数量和名称的key
hsetnx: hsetnx n k newv 设置一个哈希中对应的key,并且会判断key值是否存在,存在则操作失败

list

lpush: lpush n v1 v2 v3 v4 v5 将多个v值按顺序排列成list列表
llen:llen n获取list的长度
lrange:lrange n 0 3 在一个list中获取list中0到3的元素 设置为0到-1时就是获取所有的元素
lset: lset n 0 nv0 在一个list中设置第0个元素的值为nv0
lindex:lindex n 5 在一个通过index索引list中 获取到
lpop:lpop n 在一个list中移除list最前面的元素。并返回移除元素的值
rpop:rpop n 在一个list中移除list最后面的元素。并返回移除元素的值

set

set是一个不存在重复值并且无序的数据类型,和java的特点一样
sadd:sadd n v1 v2 v3 v4 设置一个set的元素,这里的元素是不允许重复的
scard:scard n 获取set中的元素个数
smembers:smembers n 查看set中的元素
sdiff:sdiff n1 n2 获取set1和set2的差集,返回set1的元素在set2中不存在的
sinter:sinter n1 n2 获取set1和set2的交集,返回set1的元素在set2中存在的
sunion:sunion n1 n2 获取set1和set2的并集,返回set1的元素在set2元素的合并然后去重的结果
srandom:srandmember n 2 获取一个set集合的x个随机数
sismember:sismemeber n v 查询一个元素是否是属于一个set集合中的元素
srem:srem n v1 v2 v3 移除一个set集合的v1 v2 v3元素
spop:spop n 移除一个set集合中的某个元素,并将其返回

sorted set

sorted set是一个有序,不可重复的集合,查询效率和set一样,通过分数保证集合的顺序
zadd:zadd n 100 v1 200 v2 300 v3 设置一个zset的元素,并设置元素的分数用于排名,按照分数从小到大排序
zcard:zcard n 查询zset的元素个数
zscore:zscore n v 查询元素在一个zset中的分数
zcount:zcount n 100 300 查询一个zset中在100到300分的分数区间的元素个数
zrank:zrank n v 查询一个元素在一个zset中的索引值
zincrby:zincrby n 1000 v 给一个zset中的v元素增加分数1000
zrange:zrange n 0 100 取出前0到100的元素 0到-1表示取出所有元素
zrange ....withscores:zrange n 0 100 withscores 取出前0到100的元素 0到-1表示取出所有元素,并且带上分数

Redis的过期策略和内存淘汰机制

过期删除

删除过期的键,这种策略对cpu的性能影响比较大

在Redis中使用的是定期删除和惰性删除
定期删除+惰性删除

定期删除

所谓定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意,这里可不是每隔100ms就遍历所有的设置过期时间的key,那样就是一场性能上的灾难。实际上redis是每隔100ms随机抽取一些key来检查和删除的。

惰性删除

但是,定期删除可能会导致很多过期key到了时间并没有被删除掉,所以就得靠惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。并不是key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下

通过上述两种手段结合起来,保证过期的key一定会被干掉。
但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了,怎么办?
答案是:走内存淘汰机制。

内存淘汰机制

redis.conf中配置:

 maxmemory-policy allkeys-lru 

noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

Redis为什么这么快

1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1);
2、数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
4、使用多路 I/O 复用模型,非阻塞 IO;
5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

缓存雪崩,击穿,穿透

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决方案:

1.在服务器端,接收参数时业务接口中过滤不合法的值,null,负值,和空值进行检测和空值。

2.布隆过滤器:类似于哈希表的一种算法,用所有可能的查询条件生成一个bitmap,在进行数据库查询之前会使用这个bitmap进行过滤,如果不在其中则直接过滤,从而减轻数据库层面的压力。

3.空值缓存:一种比较简单的解决办法,在第一次查询完不存在的数据后,将该key与对应的空值也放入缓存中,只不过设定为较短的失效时间,例如几分钟,这样则可以应对短时间的大量的该key攻击,设置为较短的失效时间是因为该值可能业务无关,存在意义不大,且该次的查询也未必是攻击者发起,无过久存储的必要,故可以早点失效。

缓存雪崩

因为缓存服务挂掉或者热点缓存大面积同时失效,大量的请求都去查数据库,导致数据库连接不够或者数据库处理不过来,从而导致整个系统不可用。

解决方案:

加锁排队、 设置过期标志更新缓存 、 设置过期标志更新缓存 、二级缓存(引入一致性问题)、 预热、 缓存与服务降级。

1.线程互斥:只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据才可以,每个时刻只有一个线程在执行请求,减轻了db的压力,但缺点也很明显,降低了系统的qps。

2.交错失效时间:批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好了,这样可以保证数据不会在同一时间大面积失效

缓存击穿

缓存击穿实际上是缓存雪崩的一个特例,缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。击穿与雪崩的区别即在于击穿是对于某一特定的热点数据来说,而雪崩是全部数据。

解决方案:

1.缓存设置不过期。

从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是物理不过期。但是它会遇到一个数据更新的问题,或者说数据不一致的问题。

在value中存储过期时间,在编码处理的时候,有条件(过期时间小于一分钟)对缓存数据进行更新,这个方案对性能最佳。

2.使用锁工具(分布式锁)

缓存预热

缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

解决思路:

1、直接写个缓存刷新页面,上线时手工操作下;

2、数据量不大,可以在项目启动的时候自动进行加载;

3、定时刷新缓存;

缓存热点重建优化

场景:
  • 当一个 key 是一个热点 key( 同一个key,同一个时候有几十万请求),并发量非常高
  • 重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的 SQL、多次 IO、多个依赖等。
在缓存失效的瞬间,有大量线程来重建缓存 ( 如下图),造成后端负载加大,甚至可能会让应用崩溃。
image.png

解决方法

一、分布式的互斥步锁
image.png
代码演示
String setHotKey(String hotkey) {
    // 从Redis中获取数据
    String value = cache.get(hotkey);
    // 如果value为空,则开始重构缓存
    if(value == null) {
        // 只允许一个线程重构缓存,
        String lockHotKey = "lockHotKey :" + key;
        //使用nx,并设置过期时间ex防止死锁
        if(cache.set(lockHotKey , "1", "ex 180", "nx")) {
            // 从数据源获取数据
            value = JSON.toString(dbMapper.selectByKey(hotkey));
            // 回写Redis,并设置过期时间
            cache.setex(hotkey, timeout, value);
            // 删除lockHotKey 
            cache.delete(lockHotKey);
        }else {
          //获取锁失败的他线程休息50毫秒,后重试
            Thread.sleep(50);
            setHotKey(hotkey);
        }
    }
    return value;
}

优点:思路简单,数据一致性好
缺点:使用锁需要等待,对系统产生了一定的资源的开销,只是数据库的压力减轻了,还可能因为操作不当而造成线程死锁问题。

二、让热键永远不过期
  • 缓存层面:不要设置key过期时间,不会出现热点key过期后产生的问题
  • 功能层面:为每个value添加逻辑过期时间,当逻辑判断value过期后,会使用单独的线程去构建缓存
image.png
代码演示
String setHotKey(final String hotkey) {
    V v = cache.get(hotkey);
    String value = v.getValue();
    // 逻辑过期时间
    long oldTimeout = v.getTimeout();
    // 如果逻辑过期时间小于当前时间,开始后台构建
    if(v.oldTimeout <= System.currentTimeMillis()) {
        String lockHotKey = "lockHotKey :" + key;
        if(cache.set(lockHotKey , "1", "ex 180", "nx")) {
            // 重构缓存
            threadPool.execute(new Runnable(){
                public void run() {
                    newValue = JSON.toString(dbMapper.selectByKey(hotkey));;
                    cache.setex(hotkey, newValue , newTimeout);
                    cache.delete(lockHotKey);
                }
            });
        }
    }
    return value;
}

优点:解决了互斥锁对系统资源的开销,无需同步等待,不会死锁
缺点:数据一致性差

各个数据类型的应用场景

String应用场景

分布式锁

简单的存储一个json

List应用场景

Hash应用场景

Set应用场景

Zset应用场景

相关文章

  • Redis基础复习

    其他命令 info:查看redis系统信息,包括库的信息 Keyspaceselect:Keyspace中选择db...

  • 20171116 Redis

    NoSQLRedis基础Redis配置文件基础Redis的持久化Redis的复制Redis的集群 一、NoSQL ...

  • redis常用命令教程

    Redis 基础教程 Redis 教程、Redis 安装、Redis 配置、Redis 数据类型 Redis 命令...

  • Redis的基础数据结构与使用

    Redis的基础数据结构与使用 Redis系统介绍: Redis的基础介绍与安装使用步骤:https://www....

  • Redis的基础介绍与安装使用步骤

    Redis的基础介绍与安装使用步骤 Redis系统介绍: Redis的基础介绍与安装使用步骤:https://ww...

  • Redis学习笔记二(主从备份及集群配置)

    Redis基础入门学习 Redis主从备份 1.创建Redis节点 我们在redis-3.2/redis_clus...

  • Redis深度历险笔记

    Redis深度历险笔记 基础与应用 Redis基础数据结构 5种基础数据结构:string、list、hash(字...

  • Redis学习资料

    redis基础知识:http://www.runoob.com/redis/redis-tutorial.html...

  • 安装mockbin服务

    一、安装基础软件 二、配置Redis 修改/etc/redis.conf或者/etc/redis/redis.co...

  • Redis

    Redis 内容:1、Redis简介2、Redis 安装和基础管理3、Redis 数据类型4、Redis 的消息模...

网友评论

      本文标题:Redis基础复习

      本文链接:https://www.haomeiwen.com/subject/lnafohtx.html