文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
Redis常见的数据类型有哪些?
string 字符串
字符串类型是 Redis 最基础的数据结构,首先键是字符串类型,而且其他几种结构都是在字符串类型基础上构建的。
字符串类型实际上可以是字符串:
- 简单的字符串、XML、JSON
- 数字:整数、浮点数
- 二进制:图片、音频、视频。
使用场景:
- 缓存、计数器、共享 Session、限速。
Hash(哈希)
在 Redis中哈希类型是指键本身是一种键值对结构
- 如
value={{field1,value1},……{fieldN,valueN}}
使用场景:
哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。
- 所以常常用于用户信息等管理,但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的
- 而关系型数据库是完全结构化的,关系型数据库可以做复杂的关系查询
- 而 Redis 去模拟关系型复杂查询开发困难且维护成本高。
List(列表)
列表类型是用来储存多个有序的字符串,列表中的每个字符串成为元素,一个列表最多可以储存
2^32–1
个元素在 Redis 中,可以队列表两端插入和弹出,还可以获取指定范围的元素列表、获取指定索引下的元素等
- 列表是一种比较灵活的数据结构,它可以充当栈和队列的角色。
使用场景:
- Redis 的
lpush+brpop
命令组合即可实现阻塞队列,生产者客户端是用lpush
从列表左侧插入元素
- 多个消费者客户端使用
brpop
命令阻塞式的抢列表尾部的元素
- 多个客户端保证了消费的负载均衡和高可用性。
ZSet的底层是如何实现的?
Redis的有序集合(
Zset
)是一种既可以看作是Set,又可以看作是Hash的数据结构
- 其底层实现主要使用了哈希表和跳跃表。
哈希表:
- 在Redis的Zset中,每个元素是唯一的,同时与每个元素关联的还有一个分数(
Score
)。- 元素的唯一性保证可以由哈希表来实现。
- 即Redis的
Zset
将元素作为哈希表的键,将对应的分数作为哈希表的值。跳跃表:
- Redis的Zset还需要依据分数来对元素进行排序,这个特性是通过跳跃表来实现的。
- 跳跃表是一种可以进行快速查找的数据结构。
- 由于跳跃表的特性,对于分数的查找、插入、删除都具有较好的时间复杂度。
Zset的基本形状就是:
- 哈希表确保了成员的唯一性和查找的速度,跳跃表确保了有序性以及区间查找。
什么是跳跃表?
跳跃表(
Skip List
)是一种可以替代平衡树的数据结构。在它的简单形式中,跳跃表和链表是一致的,只不过在跳跃表中
- 链表的每个节点可能有多个指向其后继的指针,这样可以实现快速查找等操作。
跳跃表最主要的特点是它的查找,插入,删除操作的时间复杂度都是
O(logn)
。基本思想:
假设我们有一个有序链表,我们想要查找一个元素,需要从头开始,一步一步的查找
- 这种情况下查找的时间复杂度是
O(n)
。现在,我们对链表做一些增强,我们抽取出部分数据在上一级创建一个新的链表,上级链表的元素个数是下级链表的1/2
- 同理,我们再在上级链表的基础上抽取出数据在更高级别创建链表,这样就构成了多级索引。
level3: ---------------63 level2: ----31---------63 level1: ----31----47---63 level0: 15--31--47--63
如上,我们有一个包含4个元素
{15,31,47,63}
的链表
- 我们在这个链表的基础上创建了三个更高级别的链表,最高级别的链表只包含一个元素。
- 这样构成的数据结构就是跳跃表。
现在,如果我们想要查找47,我们可以从最高级别的链表开始,63>47
- 所以我们到第二级别的链表查找,31<47,再向右走,到达63,63>47
- 所以我们进入下一级链表,47就在这里。在跳跃表中,47这样的查找就是
logn
的复杂度。跳跃表不仅能提供较快的查找速度,而且插入和删除元素也相对简单,主要是调整索引,改变指针的指向即可。
因此,跳跃表在很多场景下,例如Redis的
Sorted Set
,都有被广泛应用。
什么是缓存穿透?怎么解决?
缓存穿透是指在使用缓存系统时,恶意请求或者不存在的数据频繁地被发送到缓存中,导致缓存无法命中
- 最终请求会直接落到后端数据库,造成数据库压力过大。
缓存穿透可能出现的原因包括:
恶意攻击:
- 攻击者有意发送不存在的数据请求,试图使缓存失效,以达到影响系统性能或者触发系统错误的目的。
随机查询:
- 大量并发的随机查询请求,其中大部分请求的数据都不存在于缓存中。
存在但很少访问的数据:
- 一些数据很少被访问,经常被请求但却不存在于缓存中,导致缓存穿透。
为了解决缓存穿透问题,可以采取以下措施:
布隆过滤器(Bloom Filter):
布隆过滤器是一种高效的数据结构,用于判断某个元素是否存在于集合中。
在请求到来时,先使用布隆过滤器进行判断,如果被拦截则不再继续访问缓存和数据库,减轻了数据库的压力。
缓存空对象(Cache Null Object):
- 当某个请求查询的数据不存在时,将空对象或者
null
放入缓存,以防止相同的请求频繁查询数据库。- 在一定时间内,如果有相同的请求再次到来,则直接从缓存中获取到空对象,避免了对数据库的重复查询。
数据预热(Cache Pre-warming):
- 在系统启动时,将一些常用或重要的数据预先加载到缓存中
- 提前热身缓存,避免了对这部分数据的缓存穿透问题。
异步加载(Asynchronous Loading):
- 对于即将过期的缓存数据,可以在后台异步地进行数据加载和缓存的更新,避免了数据过期期间的缓存穿透。
限流和防护机制:
- 通过对请求进行限流、IP白名单校验和请求验证等手段,防止恶意攻击和异常流量对缓存系统造成压力。