1、数据类型:
string实现方式
- 整数值,添加字符串自动转成raw简单动态字符串。
- embstr编码,是只读的,修改时自动转成动态字符串。
- SDS简单动态字符串。
与C字符串的区别:
sds:1、获取字符串的长度为O(1),因为保存了字符串的长度。2、API是安全的,不会照成缓冲区的溢出。3、空间预分配,惰性释放空间。4、可以保存文本货二进制数。
list实现方式
- ziplist压缩列表,保存的所有字符串元素的长度都小于64字节,保存的元素数量小于512个。
- 双端链表。
hash实现方式
- ziplist压缩列表,保存的所有键和值长度都小于64字节,保存的键值对数量小于512个。
- 字典
set的实现方式
- intset整数集合,保存的所有元素都是整数,保存的元素数量小于512个。
- 字典
zset的实现方式
- ziplist压缩列表,保存的所有元素的长度小于64字节,保存的元素数量小于128个。
- 跳跃表和字典
2、redis的持久化方式
RDB持久化:
- 将某个时间点的内存中的数据快照保存到磁盘中,持久化到硬盘上。
- SAVE命令由服务器直接进行保存操作,会阻塞服务器。
- BGSAVE由子进程进行保存操作,不会阻塞服务器。
- 可以设置持久化的触发条件,当任意一个保存条件满足时,会自动触发执行BGSAVE命令进行持久化。
AOF持久化
- 是将服务器执行的命令保存到AOF文件中,持久化到硬盘上。
- 先将写入的数据保存在内存缓冲区中,等到缓冲区空间快被填满或者超过了指定的时限会将缓冲区数据写到磁盘里面。
- AOF重写:AOF文件有大量的写命令,但是不需要这么多命令,所以需要一个文件只包含当前数据库状态必须的命令,AOF重写是在子进程中进行的,AOF重写开始后,客户端发来的命令会追加到AOF重写缓冲区中,子进程操作完成后会给父进程发送一个信号,父进程接受到信号后会将AOF缓冲区中的所有内容追加到新AOF文件中去。
AOF和RDB的区别:
- AOF通常比RDB 数据快照文件更大。
- RDB数据文件来重启和恢复Redis比AOF快。AOF存放日志指令,恢复是要执行这些指令,RDB存放数据库状态,直接加载到内存中即可。
- RDB比AOF容易丢失数据。RDB是将数据以快照的方式写入磁盘中,可能存在某些数据还未写入磁盘就发烧了宕机导致数据丢失。
3、复制
- 从服务器第一次向主服务器发送SYNC同步命令,主服务器会先执行BGSAVE命令生成RDB文件并发送给从服务器,从服务器接收并载入RDB文件后,主服务器会将缓冲区的命令发送给从服务器,此时主从服务器状态相同,如果客户端再次向主服务器写命令时,主服务器会将该命令同步给从服务器。
同步分为完整重同步和部分重同步
- 完整重同步:用于初次复制或者断线太久超过复制积压缓冲区中保存的内容时。
- 部分重同步:用于断线后重新连接后的复制。通过服务器ID、复制偏移量、复制积压缓冲(固定长度的先进先出队列)区实现的。
从服务器第一次复制主服务器时,主服务器会将自己的运行ID发送给从服务器,从服务器会保存这个ID。执行复制的主服务器和从服务器会分别维护一个复制偏移量,主服务器每次向从服务器传播数据时会将复制偏移量的值加上传播数据长度,从服务器在接受传播数据时也会加上传播数据长度。如果主从处于一致状态,复制偏移量时相同的,如果复制偏移量不同,说明主从数据库状态不一致。需要判断进行完整重同步还是部分重同步。在主服务器进行命令传播时,不仅将写命令传播给从服务器,还将写命令入队到复制积压缓冲区。在复制偏移量不同时,主服务器会根据复制偏移量看要复制的数据是否在复制积压缓冲区中,如果在就进行部分重同步,否则进行完整重同步。
4、哨兵
哨兵来监视任意多个主服务器以及这些主服务器的从服务器, 在被监视的主服务器下线时,该下线主服务器下的某个从服务器会升级为新的主服务器,其他从服务器变为新主服务器的从服务器。
每个sentinel将一个主服务器判断为主观下线之后会向同样监视这个主服务器的其他sentinel进行询问该主服务器的状态,如果接收到足够数量的已下线状态后,sentinel会将该主服务器判断为客观下线。此时,监视这个客观下线主服务器的sentinel会选举出一个领头sentinel,这个领头sentinel对下线主服务器进行故障转移操作。
故障转移:1、在已下线的从服务器中选出一个从服务器作为新的主服务器。2、让剩下所有从服务器复制新的主服务器。3、将已下线的主服务器设置为新主服务器的从服务器。
5、过期数据的删除策略
- 定期删除:使用定时器,定时删除过期键。优点:过期键尽可能快的被删除。缺点:对CPU占用高。
- 惰性删除 :只删除当前处理的键。优点:对CPU比较友好。缺点:过期键不能及时被删除,可以导致内存泄漏。
批量删除key:
[root@node1 src]# ./redis-cli -h 127.0.0.1 -p 6379 keys "java_suisui*" | xargs ./redis-cli -h 127.0.0.1 -p 6379 del (integer) 4
注意:
redis是单线程架构,如果redis包含了大量的键,执行keys命令可能会造成redis阻塞,所以一般建议不要在生产环境下使用keys命令。如果非要遍历键删除的话,可以在以下三种情况使用:
(1).在一个不对外提供服务的Redis从节点上执行,这样不会阻塞到客户端的请求,但是会影响到主从复制。
(2).如果确认键值总数确实比较少,可以执行该命令。
(3).使用scan命令渐进式的遍历所有键,可以有效防止阻塞。
[root@node1 src]# ./redis-cli -h 127.0.0.1 -p 6379 --scan --pattern 'java*' | xargs ./redis-cli -h 127.0.0.1 -p 6379 del (integer) 4
scan:(scan 命令提供三个参数,第一个是cursor,第二个是要匹配的正则,第三个是单次遍历的槽位)
例如:scan 0 match key99* count 1000 解释:从0开始遍历,匹配key99*,总数是1000 ,1000不是结果数量,是redis单次遍历字典槽位数量(约等于)
- 复杂度虽然也是 O(n),通过游标分步进行不会阻塞线程;
- 有限制参数 COUNT ;
- 同 keys命令 一样提供模式匹配功能;
- 服务器不需要为游标保存状态,游标的唯一状态就是 scan 返回给客户端的游标整数;
xargs 可以将管道或标准输入(stdin)数据转换成命令行参数。
HTTP 请求头各参数具体含义_xiaochengyihe的博客-CSDN博客_http请求标头参数
6、内存淘汰机制
7、缓存击穿
在高并发场景下,某个热点数据在缓存中过期或者被清空,此时多个并发请求同时对该数据进行访问,由于缓存中没有该数据,导致请求都落到了数据库上,从而导致了数据库压力激增,甚至宕机的情况。
1、设置热点数据永远不过期。
2 、增加互斥锁,避免同一时间访问数据库造成数据库压力,加锁让获取锁的线程先从数据库查询出来数据放入缓存,其他线程自旋一会,在访问缓存。
八、缓存雪崩
是指在某一个时间段,缓存集中过期失效。
解决办法:
1、为key设置不同的缓存失效时间。
2、设置缓存自动刷新,避免缓存中多有的数据在同一时间失效。
3、使用限流措施,控制并发量,避免缓存并发量过大
4、使用多级缓存,将数据分散到不同的缓存集群中去,避免缓存集中失效。
九、缓存穿透
是指恶意请求访问缓存中不存在的数据(可能数据库中也不存在),由于缓存中没有该数据,请求都落到了数据库上,从而导致了数据库压力激增。
解决办法:1、缓存空对象,当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;
十、redis和memcached、Mongodb区别
redis支持的数据类型丰富,memcached只支持k/v的数据类型,MongoDB的存储格式是文档类型,是一种类型json的格式
reids、MongoDB支持数据持久化, memcached不支持。
reids、memcached可以设置过期时间,MongoDB不可以。
十一、redis分布式锁
分布式锁超时怎么处理:
用Redisson实现,我们可以先给锁设置一个LockTime,然后启动一个守护线程,让守护线程在一段时间后,重新去设置这个锁的LockTime。
分布式锁超时问题的处理(只是参考,推荐使用redission框架和ZK做分布式锁)_jaryle的博客-CSDN博客_分布式锁超时处理
十二、bitmap
bitmap同样是一种可以统计基数的方法,可以理解为用bit数组存储元素,例如01101001,表示的是[1,2,4,8],bitmap中1的个数就是基数。bitmap也可以轻松合并多个集合,只需要将多个数组进行异或操作就可以了。bitmap相比于Set也大大节省了内存,我们来粗略计算一下,统计1亿个数据的基数,需要的内存是:100000000/8/1024/1024 ≈ 12M。
十三、HyperLogLog
PFADD hll ele
:将ele添加进hll的基数计算中。流程:
- 先对ele求hash(使用的是一种叫做MurMurHash的算法)
- 将hash的低14位(因为总共有2的14次方个桶)作为桶的编号,选桶,记桶中当前的值为count
- 从的hash的第15位开始数0,假设从第15位开始有n个连续的0(即前导0)
- 如果n大于count,则把选中的桶的值置为n,否则不变