zoukankan      html  css  js  c++  java
  • redis你要知道的事

    redis 的使用很普遍,如果你没有使用过 redis,都不好意思说自己是开发界的老司机。今天又到了知识普及时间。

    聊到 redis,首先想到的是它的老表--Memcached。那么相比较它的老表,redis 有哪些闪光点呢?

    1、持久化机制,可以定期将内存中的数据持久化到硬盘上。

    2、binlog功能,可以将所有操作写入日志,当redis出现故障,可依照binlog进行数据恢复。

    3、支持virtual memory,可以限定内存使用大小,当数据超过阈值,则通过类似LRU的算法把内存中的最不常用数据保存到硬盘的页面文件中。

    4、支持的数据类型更多,使用的想象空间更大。

    5、支持实物。

    当然,这些也可以看做 redis  的优点。除了这些,被大家熟知的就是--快。对滴,就是快,redis 是一个快男,但是有时候快并不一定坏事。

    redis 优点

    1、速度快。

    2、支持丰富数据类型: String ,List,Set,Sorted Set,Hash 。

    3、丰富的特性。如订阅发布 Pub / Sub 功能、key 过期策略等。

    4、持久化存储。

    redis 缺点

    1、过于依赖内存。

    2、redis是单线程的,单台服务器无法充分利用多核服务器的CPU。

    redis 是如何让自己变成快男的呢?

    1、纯内存操作。

    2、单线程,避免频繁上下文切换。

    3、采用了非阻塞I/O多路复用机制。

    4、使用底层模型不同,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。(有钱真的可以为所欲为,自给自足。)

    redis 使用久了,不可避免的会暴露出一些问题。小场面,不要慌,一切困难都是纸老虎,干就完了。

    1、缓存穿透

    - 恶意攻击,查询数据库中不存在的数据(未记录缓存)

    - 方案:

    1、利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。

    2、用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。

    3、提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。

    2、缓存雪崩

    - 缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。

    - 方案:

    1、缓存时间加随机数,设置不同有效期,避免同时失效。

    2、分布式部署,数据分散在不同的redis和数据库。

    3、永不过期(不建议)

    3、缓存击穿

    - 单一  key 非常热点,失效后直接请求数据库。

    - 方案:

    1、永不过期

    2、互斥锁

    4、redis 和数据库双写一致性问题

    - 分布式常见问题。数据库和缓存双写,就必然会存在不一致的问题。

    - 方案:首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。

    5、redis 并发竞争 key 问题。

    - 同时有多个子系统去set一个key。

    - 方案:

    1、redis 事物机制,不适用 redis 集群(可能多个 key 不存储在一个 redis-server 上)。

    2、(1)如果对这个key操作,不要求顺序

    这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。

    (2)如果对这个key操作,要求顺序

    假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.

    期望按照key1的value值按照 valueA-->valueB-->valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下

    系统A key 1 {valueA  3:00}
    系统B key 1 {valueB  3:05}
    系统C key 1 {valueC  3:10}

    那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。

    其他方法,比如利用队列,将set方法变成串行访问也可以。总之,灵活变通。

    redis 过期策略及内存淘汰机制

    以下完全复制来的,博主写的已经非常好了,不需要再修饰了,哈哈哈。

    分析:

    这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来。比如你redis只能存5G数据,可是你写了10G,那会删5G的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到了,内存占用率还是比较高,有思考过原因么?

    回答:

    redis采用的是定期删除+惰性删除策略。

    为什么不用定时删除策略?

    定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.。

    定期删除+惰性删除是如何工作的呢?

    定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。

    于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

    采用定期删除+惰性删除就没其他问题了么?

    不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制

    在redis.conf中有一行配置

    # maxmemory-policy volatile-lru

    该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己)

    1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。
    2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。
    3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
    4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐
    5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐
    6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐

    ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

     

    老规矩,遇到好的文章要分享。

    https://mp.weixin.qq.com/s/gEU8HtsQNPXY8bzkK-Qllg

    https://zhuanlan.zhihu.com/p/106863808

    https://zhuanlan.zhihu.com/p/134104400

  • 相关阅读:
    python2代码转为python3
    Python3.7安装
    Fiddler配置与使用
    postman安装与使用
    kali-linux-2016.2-amd64安装步骤流程
    RedHat7.1_x64位安装步骤
    httpclient配置,使用
    Sentinel限流规则介绍
    mysql修改root用户密码
    winsw打包jar(WINDOWS服务)
  • 原文地址:https://www.cnblogs.com/suojian/p/13300017.html
Copyright © 2011-2022 走看看