bitmap 位图:
可以用于记录某个用户的每天的登录情况,
布隆过滤器:
类似于hashset,用于判断某个数据是否存在于集合中,本质上是一个很长的二进制数据(类似bitmap)和一系列的随机映射函数。
a.插入
当有数据插入时,先通过k个映射函数将变量变成k个值,然后再把bitmap上对应的点位设置为1。
查询数据时,如果有任何一个点的值为0,则该数据一定不存在;全为1,则数据可能存在。
b.误判率:
布隆过滤器的误判是指多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的,因此误判的根源在于相同的 bit 位被多次映射且置 1。
这种情况也造成了布隆过滤器的删除问题,因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素共享了某一位。如果我们直接删除这一位的话,会影响其他的元素。
c.特点:
如果查询的元素中,有某个点位是0,则数据一定不存在;全是1则可能存在
只能插入元素,但是不能删除元素,因为删除元素会增加误判率
d.优点:
1、可以表示数据全集,其他任何数据结构都不行
2、不存储元素,对数据保密性高的场合有优势
3、k 为哈希函数个数,m 为布隆过滤器长度,n 为插入的元素个数,p 为误报率
空间复杂度是O(m),时间复杂度是O(k),插入、查询的时间复杂度都是O(k)
e.缺点:
数据量越大,误差率越大。如果想保持误差率在低范围,则要加大数组长度,即占用空间更大
应用场景:
- 网页爬虫对 URL 去重,避免爬取相同的 URL 地址;
- 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱;
- 解决缓存穿透问题,但查询的数据不存在于数据库中,则直接返回,减少数据库不必要的查询。具体过程如下:
当客户端查询时,先通过布隆过滤器查看缓存中是否存在该数据,如果不存在,则直接返回。如果布隆过滤器中显示缓存可能存在,则从缓存中读取数据,如果缓存也不存在,就从数据库中读取。
字符串String:
记录普通的字符串,一个字符串最大可512M
列表list:
链表,插入删除复杂度为O(1),查询为O(n),一个列表最多可以存储2^32 - 1 个元素, 当列表中存储的元素较少时,Redis 会使用一块连续的内存来存储这些元素,这个连续的结构被称为 ziplist(压缩列表),而当数据量较大时,Redis 列表就会是用 quicklist(快速链表)存储元素。quicklist 的结构图如下:
Hash:
适合存储对象,如命令:
hmset user:1004 12580:nums 5 12580:info {json字符串}
用户1004 购买了12580这个商品,数量为5; 后面是12580的信息
当存储的数据量较少的时,hash 采用 ziplist 作为底层存储结构(底层是key value key value ... 这样的数组):
- 哈希对象保存的所有键值对(键和值)的字符串长度总和小于 64 个字节。
- 哈希对象保存的键值对数量要小于 512 个。
当无法满足上述条件时,hash 就会采用第二种方式来存储数据,也就是 dict(字典结构),该结构类似于 Java 的 HashMap
Set:
内部数据不重复, 哈希映射表实现的,所以它的添加、删除、查找操作的时间复杂度为 O(1),可以用类似数学方法对集合进行数据操作
a.情况如下使用 intset (整形数组) :
- 集合内保存的所有成员都是整数值;
- 集合内保存的成员数量不超过 512 个。
b.其他情况用hash table
Order Set(ZSet):压缩列表
和set的区别是可以排序,所以当需要用到不重复需要排序的列表时可以使用,如主播的礼物榜
底层是 zipList(压缩列表)和 skipList(跳跃列表)
以下条件时使用压缩列表:
- 成员的数量小于128 个;
- 每个 member (成员)的字符串长度都小于 64 个字节
HyperLoglog:
适用于海量数据的计算、统计,其特点是占用空间小,计算速度快,每个 HyperLogLog key 只占用 12 KB 内存,所以理论上可以存储大约2^64个值
最典型的应用场景就是统计网站用户月活量,或者网站页面的 UV(网站独立访客)数据等
pfadd pfcount pfmerge
Reids持久化:
一、RDB:
1、手动策略:
又称快照(snapshot)模式(所谓“快照”就是将内存数据以二进制文件的形式保存起来),将数据保存在dump.rdb文件中,保存的命令为save,bgsave
save会阻塞当前程序,不建议使用;bgsave是通过调用fork()函数来保存;以上两种都是手动保存
2、自动策略
在redis配置文件中有
save 900 1 表示在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
save 300 10 表示在 300 秒内,至少更新了 10 条数据,Redis 自动触 BGSAVE 命令,将数据保存到硬盘
save 60 10000 表示 60 秒内,至少更新了 10000 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
只要上述三个条件任意满足一个,服务器就会自动执行 BGSAVE命令。可以根据实际情况自己调整触发策略。
3、优劣势
二、AOF
日志模式,记录redis服务器已经执行过的命令(只记录对数据库有修改的命令),默认是不开启,需要修改配置文件 appendonly no 为 yes,然后重启服务器,AOF包含写入机制和重写机制
1、写入机制:
每执行一条修改命令,redis 服务器先进行相应的校验,如果没问题的话就追加到AOF文件中,然后再执行命令,保证遇到宕机之后,数据不会丢失(为了提升效率,会先将命令写入缓存区,等缓存区满了才真正将内容写进文件)
2、重写机制:
redis在执行过程中,aof文件会越来越大,需要对命令进行整理,减少文件的内存大小,可以 通过 BGREWRITEAOF 命令手动执行重新机制,重新生成新的aof文件;该文件有以下特点:
- 数据库数据和原本文件记录的数据库数据完全一致
- 文件体积更小
- 重写期间,服务器不会阻塞,可以正常执行客户端命令
自动触发功能:
3、配置策略
aof是先将命令写进内存,如果宕机则会丢失,造成数据丢失风险;因此aof提供了3种执行策略:
always 每执行一条命令,就调用一次fsync()函数,将缓冲区的数据写入硬盘
Everysec(默认):服务器每一秒调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据,通常都使用它作为 AOF 配置策略;
No:服务器不主动调用 fsync 函数,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的,所以这种策略,不确定性较大,不安全。
三、AOF和RDB对比
Redis分布式锁:
分布式锁:相当于某个客户端在 redis 服务端占一个坑(设置某个数据),当其他客户端访问的时候,需要等先前的客户端释放锁才能设置,否则只能读取
常用命令:
setnx key val
expire key timeout
del key
说明:如果某个key不存在,则给他设置val,并返回1,否则返回0;然后通过expire设置自动过期时间删除key,避免造成死锁 ,或者手动用del删除key;
但是这样操作,当在setnx命令之后服务器宕机,会导致死锁;
解决方法:
使用set 命令,格式如下
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
- EX second:设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
- PX millisecond:设置键的过期时间为毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecondvalue 。
- NX:只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
- XX:只在键已经存在时,才对键进行设置操作。
Redis缓存问题
为了减轻后台数据库的压力,一般会先将数据读取出来后,缓存到redis中,但用户查询的时候,如果redis中存在则直接返回,否则读取数据库信息,然后返再将数据缓存到redis中并返回给用户
1、缓存穿透:
当用户查询某个数据时,Redis中不存在,即缓存没有命中,此时就会去数据库中查询,结果数据库中也不存在,于是数据库返回空对象,此次查询失败。如果有大量类似的请求,会造成数据库压力过大而奔溃
解决办法:
缓存空对象:当数据库返回空对象时,将该空对象缓存到redis中,并设置一个过期时间,但是占用redis的缓存空间
使用布隆过滤器进行缓存预热:当系统启动时,先将相关数据加载到redis缓存系统中,避免用户请求时再去加载数据
2、缓存击穿:
用户查询的数据,缓存中不存在,然而数据库中存在(一般是因为缓存中的该数据过期了)。单同时有大量的请求到达,要访问某热点数据,结果因Redis中缓存查询不到,导致去查询数据库,造成数据库压力过大崩溃。
解决方法:
1.设置热点数据不会过期。
2.采用分布式锁:
上锁:当某个数据在缓存中查询不到时,先通过分布式锁进行加锁,第一个获取锁的进程访问数据库进行查询,并将结果缓存到redis中,然后解锁
解锁:当其他进程发现锁被占用时,先进入等待状态,直至解锁,然后直接从缓存中读取数据
3、缓存雪崩:
当系统中有大量的key同时过期,而此时服务器访问量非常大,导致数据库压力暴增崩溃。
雪崩是指同时有很多个key过期,而击穿是只有一个key过期。
解决办法:
设置热点数据永不过期
为key设置随机过期时间,避免key集中过期