redis 的高并发的理解

redis 的特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

 

 

 

 

redis 在并发下出现的情况:

缓存穿透:

  用户发送数据(一条数据库中存在、redis中不存在的) 到redis中没有就去DB中查,如果DB中没有查询到,就返回给用户;若黑客使用这个漏洞 进行对数据库的攻击就会给数据库击垮。

解决的办法:

  1、添加过期时间

  2、添加一个布隆过滤器   

  布隆过滤器( 加载120万的数据需要 9秒,)是数据哈希到一个足够大额 bigMap 中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力,但是布隆过滤器有个一误判率是大约是3%

  DB查询到数据为空的时候, 把数据写入到redis中 key对应的value就是空值, 并设置key 的过期时间,设置过期时间最好使用1-5的随机数,

  

缓存击穿:

  用户发送请数据到redis中 发现redis的数据过期了。这个时候就会去查询数据库, 如果有大量的并发请求,发现有大量的数据在redis中过期了。这个时候就会给DB造成巨大的压力。

  解决的方法:

  1、设置redis中的key 为过期时间为随机数最大不超过5, 

  2、 在访问DB的时候加上锁, 如果是分布式就使用分布式锁。  使用互斥锁  (setNx )

缓存雪崩:

  当redis中数据在某一个时间段存在大量的过期时间,就会去请求DB 这样会给数据库带来巨大的压力或者是击垮数据库。

解决方法:

  在访问数据库的时候加锁

  设置队列关系

缓存预热:

  就系统上线的时候需要把数据库中的数据缓存到redis中,这个样就可以避免用户在查询的数据时候在从数据库中查了。 

解决的方法:

  1,系统上线后 实现都写好的执行缓存的刷新的页面进行操作。2,也可以手动的更新,3、定时刷新缓存 

如果缓存的数据不多的话  设置项目启动就可以启动缓存更新。

缓存更新:

  Redis默认的有6中策略可供选择

     比较常用有两种方案:

  1、定时去清理过期的缓存,

  2、 用户请求过来的时候,发现缓存中的数据过期了,在去数据库查在去根性·更新redis。

 

缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。

降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。

以参考日志级别设置预案:

(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;

(2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;

(3)错误:比如可用率低

 

 

redis  的命令 使用  :  

 

与String相关的常用命令:

  • SET:为一个key设置value,可以配合EX/PX参数指定key的有效期,通过NX/XX参数针对key是否存在的情况进行区别操作,时间复杂度O(1)

  • GET:获取某个key对应的value,时间复杂度O(1)

  • GETSET:为一个key设置value,并返回该key的原value,时间复杂度O(1)

  • MSET:为多个key设置value,时间复杂度O(N)

  • MSETNX:同MSET,如果指定的key中有任意一个已存在,则不进行任何操作,时间复杂度O(N)

  • MGET:获取多个key对应的value,时间复杂度O(N)

与List相关的常用命令:

  • LPUSH:向指定List的左侧(即头部)插入1个或多个元素,返回插入后的List长度。时间复杂度O(N),N为插入元素的数量

  • RPUSH:同LPUSH,向指定List的右侧(即尾部)插入1或多个元素

  • LPOP:从指定List的左侧(即头部)移除一个元素并返回,时间复杂度O(1)

  • RPOP:同LPOP,从指定List的右侧(即尾部)移除1个元素并返回

  • LPUSHX/RPUSHX:与LPUSH/RPUSH类似,区别在于,LPUSHX/RPUSHX操作的key如果不存在,则不会进行任何操作

  • LLEN:返回指定List的长度,时间复杂度O(1)

  • LRANGE:返回指定List中指定范围的元素(双端包含,即LRANGE key 0 10会返回11个元素),时间复杂度O(N)。应尽可能控制一次获取的元素数量,一次获取过大范围的List元素会导致延迟,同时对长度不可预知的List,避免使用LRANGE key 0 -1这样的完整遍历操作。


    应谨慎使用的List相关命令:

  • LINDEX:返回指定List指定index上的元素,如果index越界,返回nil。index数值是回环的,即-1代表List最后一个位置,-2代表List倒数第二个位置。时间复杂度O(N)

  • LSET:将指定List指定index上的元素设置为value,如果index越界则返回错误,时间复杂度O(N),如果操作的是头/尾部的元素,则时间复杂度为O(1)

  • LINSERT:向指定List中指定元素之前/之后插入一个新元素,并返回操作后的List长度。如果指定的元素不存在,返回-1。如果指定key不存在,不会进行任何操作,时间复杂度O(N)

由于Redis的List是链表结构的,上述的三个命令的算法效率较低,需要对List进行遍历,命令的耗时无法预估,在List长度大的情况下耗时会明显增加,应谨慎使用。

与Hash相关的常用命令:

  • HSET:将key对应的Hash中的field设置为value。如果该Hash不存在,会自动创建一个。时间复杂度O(1)

  • HGET:返回指定Hash中field字段的值,时间复杂度O(1)

  • HMSET/HMGET:同HSET和HGET,可以批量操作同一个key下的多个field,时间复杂度:O(N),N为一次操作的field数量

  • HSETNX:同HSET,但如field已经存在,HSETNX不会进行任何操作,时间复杂度O(1)

  • HEXISTS:判断指定Hash中field是否存在,存在返回1,不存在返回0,时间复杂度O(1)

  • HDEL:删除指定Hash中的field(1个或多个),时间复杂度:O(N),N为操作的field数量

  • HINCRBY:同INCRBY命令,对指定Hash中的一个field进行INCRBY,时间复杂度O(1)

应谨慎使用的Hash相关命令:

 

  • HGETALL:返回指定Hash中所有的field-value对。返回结果为数组,数组中field和value交替出现。时间复杂度O(N)

  • HKEYS/HVALS:返回指定Hash中所有的field/value,时间复杂度O(N)

 

上述三个命令都会对Hash进行完整遍历,Hash中的field数量与命令的耗时线性相关,对于尺寸不可预知的Hash,应严格避免使用上面三个命令,而改为使用HSCAN命令进行游标式的遍历,具体请见 

https://redis.io/commands/scan

 

--

为什么redis是单线程模型也能效率也很高?

  1 纯内存操作

  2 核心是基于非阻塞的 io 多路复用机制

  3 单线程 反而避免了多线程上下文切换的问题。

 

 

redis分布式锁:

设置分布式锁 set my:lock 随机值 NX PX 30000
(my 可以用 用户id或者是订单id等,随机值不能重复。NX:存在设置失败,反之就成功,px 设置过期时间)
释放锁。 就是删除key 是根据随机值, 是根据redis中的随机值和key对应的随机值一致就删除。

 

posted @ 2020-09-23 19:17  那一的眸相遇  阅读(573)  评论(0编辑  收藏  举报