八股文之-Redis

Redis默认有16个库(0-15),可在redis.conf中修改
databases 16
默认使用第一个db0, 集群里只能使用第一个db
Redis的存储叫做key-value存储,字典结构,key最大长度限制是512M

Redis的数据类型?
String  Hash  Set  List  Zset  Hyperloglog  Geo   Steeams

1.String

存储类型:INT(整数)  float(单精度浮点数) String(字符串)
Redis的最外层是通过hashtable实现的,我们把这个叫做外层的哈希
Redis每个键值对都是一个dictEntry,key 和value 通过指针引用 next,存储了指向下一个键值对的指针

redisObject的定义:

String类型的Value redisObject就会指向一个SDS

String有3种编码:
 int:存储8个字节的长整型(long,2^63-1)
 embstr:存储小于44字节的字符串
 raw:存储大于44字节的字符串
 
 SDS是什么?
 Redis中实现的字符串,Simple Dynamic String
 因为C语言本身没有字符串类型,只能用char[],这就导致:
 1.使用字符数组必须先分配足够的内存空间,否则会溢出
 2.要获取字符串长度,必须遍历数组
 3.字符串长度变更会对字符数组做内存重分配
 4.以‘\0’标记字符串的结束,不能存储二进制内容
 
 SDS优点:
 1.不用担心内存溢出,如有需要会对SDS扩容
 2.取字符串长度时间复杂度为O(1),因为定义了len属性
 3.通过空间预分配和惰性空间释放,防止多次重分配内存
 4.判断是否结束的标志是len属性,可以存储二进制
 
 embstr的使用只分配一次内存空间:因为RedisObject和SDS是连续的,缺点:字符串长度增加需要重新分配内存时,RedisObject和SDS都需要重新分配空间
 因此embstr不可修改
 
 raw需要分配两次内存空间 分别为RedisObject和SDS分配


 
2.Hash哈希


 用来存储多个无序的键值对,最大存2^32-1个
 Hash的value只能是字符串,Field不能单独设置过期时间
 
 数据结构:ziplist,hashtable
 ziplist:压缩列表:由连续内存块组成的双向链表,不存储上一个节点和下一个节点的指针,而是存储长度,节省内存
 哈希对象的键值对数量<512个,redistribution.conf中配置:hash-max-ziplist-entrys
 所有键值对的键和值的字符串长度都<64byte  hash-max-ziplist-value
 ziplist结构:
 
 
 hashtable:哈希表 是一个数组+链表的结构
 对Redis的KV结构dictEntry进行了多层封装:
 从最底层到最高层:dictEntry--dictht--dict,
 
 
 redis的hash默认使用的是ht[0],ht[1]不会初始化和分配空间
 dictht通过链地址法解决碰撞问题,性能取决于大小(size)和保存的节点数量(used)的比率
 在1:1时哈希表性能最好,如果比例很大ratio=5,一个ht存储5个entry,退化成链表。
 
 如果单个哈希表的节点数量过多,需要rehash扩容:
 1.为ht[1]哈希表分配空间,大小等于第一个大于等于ht[0].used*2的 2的N次幂。
 2.将所有的ht[0]上节点rehash到ht[1]上,重新计算hash值和索引
 3.等ht[0]全部迁移到ht[1],释放ht[0]的空间,将ht[1]设置为ht[0],并创建ht[1],为下次rehash做准备
 
 触发扩容的时机:
 dict_can_resize=1://是否需要扩容
 dict_force_redize_ratio=5;//扩容因子
 


3.List列表


 存储有序的字符串,元素可重复,最大数量2^23-1
 
 早期版本,数据量较小时用ziplist,达到临界值转换为linkedlist
 3.2版本之后统一用quicklist:一个双向链表,每个节点都是一个ziplist
 

4.Set集合


 存储无序的String,
 数据结构:intset(元素都是整数)
           hashtable(元素个数超过512个:set-max-intset-entries),value存null
          

 
5.ZSet 有序集合


    存储有序的元素,每个元素有个score,按score从小到大
    score相同时,按key的ASCII码排序
    
    默认使用ziplist,内部按照score递增存储
    skiplist+dict:元素数量大于等于128或任一member长度大于等于64字节
    
    skiplist跳表:
    不同元素根据算法决定放在哪一层
    

6.BitMaps
  在字符串类型上面定义的位操作
  节省空间,做大数据量的统计:在线用户数,留存数
  

7.Hyperloglogs
  不太精准的基数统计,统计一个集合中不重复的元素个数,网站UV。
    
8.Geo 
  地址处理,计算距离

9.Streams  
  5.0推出的。支持多播的可持久化的消息队列 ,用来实现发布订阅功能
  
  
  总结:
  

缓存穿透

缓存穿透。产生这个问题的原因可能是外部的恶意攻击,例如,对用户信息进行了缓存,但恶意攻击者使用不存在的用户id频繁请求接口,导致查询缓存不命中,然后穿透 DB 查询依然不命中。这时会有大量请求穿透缓存访问到 DB。

解决的办法如下。

  1. 对不存在的用户,在缓存中保存一个空对象进行标记,防止相同 ID 再次访问 DB。不过有时这个方法并不能很好解决问题,可能导致缓存中存储大量无用数据。
  2. 使用 BloomFilter 过滤器,BloomFilter 的特点是存在性检测,如果 BloomFilter 中不存在,那么数据一定不存在;如果 BloomFilter 中存在,实际数据也有可能会不存在。非常适合解决这类的问题。

缓存击穿

缓存击穿,就是某个热点数据失效时,大量针对这个数据的请求会穿透到数据源。

解决这个问题有如下办法。

  1. 可以使用互斥锁更新,保证同一个进程中针对同一个数据不会并发请求到 DB,减小 DB 压力。
  2. 使用随机退避方式,失效时随机 sleep 一个很短的时间,再次查询,如果失败再执行更新。
  3. 针对多个热点 key 同时失效的问题,可以在缓存时使用固定时间加上一个小的随机数,避免大量热点 key 同一时刻失效。

缓存雪崩

缓存雪崩,产生的原因是缓存挂掉,这时所有的请求都会穿透到 DB。

解决方法:

  1. 使用快速失败的熔断策略,减少 DB 瞬间压力;
  2. 使用主从模式和集群模式来尽量保证缓存服务的高可用。

实际场景中,这两种方法会结合使用。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值