Redis一些基础知识

Redis 为什么这么快

  1. 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在內存中。
  2. 数据结构简单,对数据的操作也简单。
  3. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
  4. 使用多路I/O复用模型,非阻塞IO;

ps:6.0之后加入多线程,注意:
Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。

数据类型

数据类型存储的值应用场景
String字符串做简单的键值对缓存
List列表存储一些列表型的数据结构,类似文章评论等
Set无序集合交集并集差集的操作
Hash包含键值对的无序散列表结构化的数据,比如一个对象
Zset有序集合去重但可以排序,如获取排名前几的用户

持久化

Redis有两种持久化RDB(默认)AOF

RDB

RDB是 Redis默认的持久化方式。按照一定的时间将内存的数据以快照的开式保存到硬盘中,对应产生的数据文件为 dump.rabe通过配置文件中的save参数来定义快照的周期。
优点:

  1. 只有一个文件 dump. rdb,方便持久化
  2. 容灾性好,一个文件可以保存到安全的磁盘。
  3. 性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能
  4. 相对于数据集大时,比AOF的启动效率更高。

缺点:
5. 数据安全性低。RDB是间隔一段时间进行持久化,如果持久化之间 redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)

AOF

AOF持久化(即 Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。
优点:

  1. 数据安全,AOF持久化可以配置 appendfsync属性,有 always,每进行一次命令操作就记录到aof文件中一次。
  2. 通过 append模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。
  3. AOF机制的 rewrite模式。AOF文件没被 rewrite之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(flushall)

缺点:

  1. AOF文件比RDB文件大,且恢复速度慢。
  2. 数据集大的时候,比rdb启动效率低。

过期策略

过期策略通常有三种

  • 定期过期
    毎个设置过期时间的key都需要创建一个定时器,到过期时间就会立即凊除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
  • 惰性过期
    只有当访向key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能岀现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
  • 定期抽查
    每隔一定的时间,会扫描一定数量的数据库的 expires字典中一定数量的key,并清除其中已过期的keγ。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和毎次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到优的平衡效果。
    redis 目前同时使用了前两种方案

内存淘汰策略

Redis的内存淘汰策略是指在 Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
全局的键空间选择性移除

  • eviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)。
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。

缓存异常

缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:

  1. 缓存数据的过期时间设置随机,防止同时间大量数据过期现象发生。
  2. 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
  3. 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

缓存穿透

緩存穿透是指緩存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:

  1. 接口层增加校验,如用户鉴权校验,i做基础校验,id<=0的直接拦截;
  2. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将 key-value对写为key-nu,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
  3. 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap中,一个定不存在的数据会被这个 bitmap拦截掉,从而避免了对底层存储系统的查询压力。

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读緩存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:

  1. 设置热点数据(长时间)
  2. 加互斥锁

缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
解决方案:

  • 直接写个缓存刷新页面/接口,上线时手动触发一下
  • 数据量不大,可以在项目启动时自动加载
  • 定时刷新缓存

redis 分布式锁

/**
* 尝试获取分布式锁
*
* @param lockKey 锁
* @param expireTime 超期时间 300(秒)
* @return 是否获取成功
*/
public boolean lock(String lockKey, long expireTime) {
String uuid = UUID.randomUUID().toString();
String value = jedisCmd.set(lockKey, uuid, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (value != null && value.equals("OK")) {
threadLocal.set(uuid);
return true;
}
return false;
}

/**
* 释放分布式锁
*git
* @param lockKey 锁
* @return 是否释放成功
*/
public boolean unLock(String lockKey) {
String key = jedisCmd.get(lockKey);
//可能会存在锁失效的时候
if (key == null) {
return true;
}
//保持原子性 (Get —>判断 -> del )操作
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end ";
Object object = jedisCmd.eval(script, Collections.singletonList(lockKey), Collections.singletonList(threadLocal.get()));
if (RELEASE_SUCCESS.equals(object)) {
return true;
}
return false;
}

注意点:
lock:

  1. 这里使用的不是setnx,需要使用set增加过期时间
  2. 对于lock来说如果说没有获取到锁,有以下几种情况:
    2.1 自旋来循环获取锁(对于并发量较大的请求不适用)
    2.2 直接丢弃

unlock:

  1. 注意这里需要原子性操作(使用lua脚本):
    (Get —>判断 -> del )
    if redis.call(‘get’,KEYS[1]) == ARGV[1] then return redis.call(‘del’,KEYS[1]) else return 0 end

如何保证缓存与数据库数据一致?

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
更新的时候,先更新数据库,然后再删除缓存(这里不是更新缓存,因为有可能缓存值是计算得来的,这里不用再次计算,只有查询是才是,且如果更新频繁,还会涉及内存的多次修改)。

最初级的缓存不一致问题及解决方案:
先删除缓存,再修改数据库。如果数据库修改失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致。因为读的时候缓存没有,则读数据库中旧数据,然后更新到缓存中。

高并发下会出问题:
并发量大时,可能导致更新缓存时,另一个请求已经将新值写入数据库,那么可能造成数据库与缓存数据不一致。
解决方法:
转载

跳跃表

转载

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值