1、Redis 各种数据类型的基本用法

String 普通字符串

redis如何去重hash redis数据去重_数据库

Hash 类似于map

redis如何去重hash redis数据去重_redis_02

list 有序集合 还可以用作队列

redis如何去重hash redis数据去重_redis_03

set 无序集合,有去重效果

redis如何去重hash redis数据去重_缓存_04

sorted set 有序去重集合

redis如何去重hash redis数据去重_数据库_05

HyperLogLog 用于去重统计

redis如何去重hash redis数据去重_redis如何去重hash_06

 

2、各种使用场景

1、热点数据缓存

比如分布式 session,热点查询数据的缓存。这个就比较简单了,查询数据时先从 redis 里查询,如果查到了直接返回,如果没有查到再从数据库查询,把查询结果缓存到 redis,然后再返回结果

注意点:

缓存的雪崩

当大量的 key 在同一时间过期时,大量的请求都直接访问到数据库,这时数据库可能扛不住压力崩溃,导致服务不可用。

所以尽量避免将大量的 key 设置一个相同的过期时间

缓存的穿透

缓存穿透指的是,请求一个数据库中不存在的记录时,先从缓存中取,取不到,就会访问数据库,结果数据库也查不到记录,所以这时也不会将结果放入缓存,下次请求还会去访问数据库。

这种情况我们可以把空结果缓存到 reids 中

这位大佬讲的很清晰

 

2、分布式锁

redis 有个命令:setnx key value 当值不存在时就设置值,后面还可以为这个key 设置一个过期时间(需要事务)

因为 redis 是单线程的,同时又有上面这个命令,而且它还是个内存数据库,读写速度快,所以很适合用作分布式锁

可以将一下代码在一个事务中执行 EVAL script numkeys key [key ...] arg [arg ...]

if (redis.call('exists', KEYS[1]) == 0)
     then redis.call('hset', KEYS[1], ARGV[2], 1);
     redis.call('pexpire', KEYS[1], ARGV[1]);
     return nil;
 end;
 if (redis.call('hexists', KEYS[1], ARGV[2]) == 1)
     then redis.call('hincrby', KEYS[1], ARGV[2], 1);
     redis.call('pexpire', KEYS[1], ARGV[1]);
     return nil;
 end;
 return redis.call('pttl', KEYS[1]);

用 hash 类型存制定的 key(即分布式锁的键),value 为 1,然后设置一个过期时间,

如果要设置的 key 已存在就把 value + 1,从这里可知,这是一个可重入锁

 

3、list类型实现消息队列

生产者 lpush 在左边加入消息

消费者 rpop 从右边消费消息

客户端需要轮询去消息。如果没有消息客户端会死循环,这样太消耗CPU,最好是每次 sleep(100) 一下

 

4、布隆过滤器 可以进行去重

 

5、HyperLogLog 可以用于统计用户点击量

比如每有一个用户访问了某个接口我们可以把接口地址作为 key 用户的 id 作为 value,它可以自动去重记录总数量,不会保存用户的 id,所以占用空间较小,这也是为什么不用 set 来实现的原因。

 

6、幂等校验

比如有些接口不能重复提交,我们可以把接口名称和参数存入 redis,设置个过期时间。再收到相同的请求时,先查一下 redis 里是否存在,如果存在表示重复提交,拦截请求