Redis

一 、基础数据类型有哪些,常用应用是什么

        redis的存储数据类型,都是一个key对应的一种存储类型,所以我们在讲Redis的数据类型的时候,讲的都是它的value有哪些数据类型

        基础数据类型有:String List Hash Set Zset (五种)

String:可以存放任何类型的数据,可以是字符串、浮点数、序列化文件

应用场景:缓存、redis锁、计数器等,

        缓存:讲部分数据放入redis可以避免直接前台频繁访问数据库给数据库造成压力

        计数器:由于redis是单线程模型,所以执行完当前命令才会执行下一条,用作计数器会比较简单和安全。

List:Redis的List数据类型是双向列表数据结构,并且允许有重复元素存在

应用场景:消息排队(微博的最新资讯timeline),消息队列

        消息排队:可以将最新的消息用Lpush从左侧推入进去,这样消息会形成时间线格式排列

        消息队列:可以用Lpush或Rpush选择将新元素从左侧放入还是右侧放入,然后用Lpop或Rpop选择从左侧弹出,可以轻松完成消息队列的功能

Hash:它的结构和java的hashMap特别像,适合用来做缓存存储对象,会比String更加直观

应用场景:缓存

Set:是一个无序的,且其中的元素不可以重复的数据类型。

应用场景:抽奖、添加标签、点赞

        抽奖:因为是唯一且无序,符合抽奖的场景。

        添加标签:可以给自己选择想要看什么样标签的人,那么拥有这些标签的人可以做到自动推荐的功能。

Zset:也是一个元素唯一的集合,但是和Set有区别的一点就是Zset有一个Double分数机制,Zset中的元素是依靠Double分数机制给其中的分数做排序处理的。

应用场景: 排行榜

        排行榜:可以根据每个元素所对应的分数高低来做排行榜功能

Redis分布式锁:

        关于集群项目或分布式项目不适用分布式锁的坏处就不再赘述,无非就是讲讲:单体项目为什么没必要使用redis锁、集群项目如果使用普通线程锁会发生什么问题

        首先在使用分布式锁的时候应该是一步步考虑可能会发生什么问题并想出解决的方案:

1.最为简陋的redis锁是直接使用redis的String数据类型的SetNX方法,锁住一个产品ID即可完成Redis锁

解读:SetNX方法不同于Set方法,SetNX方法会在插入的时候判断当前要插入的值是否已经存在于redis中,如果存在了,那么不进行插入,如果不存在,即代表可以插入这个元素,并且会返回一个boolean值作为反馈。

问题:在给某个产品ID上锁后应当使用完要做删除操作,保证后面的请求进来也能对此做上锁处理

2.应当在做redis锁的时候使用try、finally操作,也就是说不管操作失败成功最终都要做解锁处理

问题:如果说系统在这个请求上锁后,还未到解锁的时候,服务器突然挂了,会导致这个锁一直存在于redis,从而达到死锁,那么后面的请求再也无法获取到锁,并且这问题也很难发现

3.为了解决一个key死锁,我们可以在上锁的时候给他设定一个过期时间,这样就算服务中途挂掉也不会造成死锁,顶多让下一个线程多等待几秒

问题:如果A线程进来获取到锁,设置了过期时间10秒,但是中间的逻辑要处理15秒,在执行到10秒的时候,key过期了,B线程进来也获取到锁了,此时又过了5秒,A线程执行完了代码走到了finally,将这个key删掉了,由于A使用的key本来就是过期掉了,所以A会删掉B线程刚获取到的锁,这就是误删锁,导致了锁失效的问题

4.为解决锁失效问题,我们给产品ID设置了key后,可以对value做一点操作,比如我们使用UUID给value赋值,在finally里面删除之前判断一下,如果获取到key锁对应的value是当前线程进来创建的uuid,则代表,现在删除的锁是自己创建的锁,即可以删除

问题:但是这只是解决了误解锁的问题,没有解决过期解锁导致后面线程也来处理键库存的操作

5.这时候就考虑到,redis锁上锁的时间应该设置为多少,其实设置多少都是不重要的,而是应当考虑怎么能分辨出,当前的线程是否处理完业务代码。所以可以在上锁的时候,同时分出另一个线程,专门做定时检查,查看TTL查看当前key的锁还有多久失效,如果处于正在使用状态,给他做续命操作,也就是重新设置过期时间,至于间隔多久检查一次,可以设置为过期时间的三分之一。

一个Rdis分布锁基本解决这些问题,已经适用于大多数需要锁的场景了

服务雪崩、缓存穿透、缓存击穿:

        为了缓解数据库的访问压力,会将部分数据放到redis中做缓存,理想状态下客户端请求进来会先访问redis缓存,如果缓存有数据则从缓存返回,如果缓存没有缓存则进入数据库查询数据然后同步到缓存中,但这种做法就会引起三种常见问题:缓存雪崩、缓存击穿、缓存穿透。

        缓存雪崩:

        问题原因:为了让缓存中的数据保持最新,所以会给数据加上一个过期时间,当数据过期会从数据库查询数据再同步到缓存中从而达到更新数据的作用,但是如果大量数据同时过期,会导致大量请求访问数据库。或者redis宕机,也会使请求直接进入数据库,从而使数据库崩溃。

        通过问题可以分为两类解决方法:过期导致、宕机导致

        过期:1.都设置不同的过期时间,可以用随机数给字段设置过期时间,让数据不要同时一起失效。

                    2.互斥锁,当发现请求的数据不存在于缓存中时,添加一个互斥锁,只允许一个请求查询数据库然后同步到缓存当中,同步完成后释放掉锁。未获取到锁的可以重新读取缓存或者返回空值。

                     3.双key,缓存中每个数据都有两个,一个有过期时间,另一个没有过期时间,key不同但是value一样,相当于给key做了备份,当第一个key失效的时候,直接用第二个key,然后再到数据库更新数据同步缓存。

        宕机:1.可以做个熔断器,如果缓存失效则暂停这个功能,来保护数据库,或者使用请求限流,让请求量慢慢进入数据库访问,以达到数据库稳定状态。

                    2.创建redis的集群,主节点如果宕机由从节点顶上

        缓存击穿:

        问题原因:有些热点数据的访问量特别高,如果热点数据过期,同一时间请求量大,同时访问数据库使数据库崩溃。

        解决:缓存击穿和缓存雪崩其实很类似,只不过缓存击穿使少量热点数据过期

        1.添加互斥锁,限制访问数据库的数量,少量请求访问数据库后同步到缓存做更新处理

        2,热点数据不设置过期时间,或者安排后台进程定期检查热点数据的过期时间,快过期的时候更新过期时间

        缓存穿透:

        问题原因:前面两种都是数据库有数据,可以给缓存更新数据,但是穿透不一样,是缓存没数据,数据库也没有数据,通常来说要么是业务操作问题,要么是恶意攻击。

        解决:1.如果发现数据库也没有的数据,则给这样的数据赋予空值,下次这样访问缓存就可以直接返回空值。

                2.判断请求过来的信息是否符合我们规定的参数

                3.使用布隆过滤器:布隆过滤器存在于redis和数据库之间,当发现redis中没有需要的数据时,会访问过滤器,过滤器会返回一个初步结果“数据库中有没有这个值”。如果有这个值则进入数据库访问,如果不存在这个值则直接返回空。

                布隆过滤器的特点:

                1.结构是通过一个大的二进制数组,与多个hash函数组成的

                2.会将元素进行n次无偏hash,然后将hash后的结果找到对应的数组下标处的数据从0改成1。那么访问过滤器是否存在某数据的时候,将数据同样的操作然后判断对应的下标处的值是否符合,有任意一个下标处为0 则表示要查找的数据不存在数据库中。

                3.从上面可以猜想到,既然是通过hash算法得到的下标处,就有可能发生hash冲突,确实如此,这也是布隆过滤器的特点,过滤器告诉你数据库存在这个数据,数据库不一定真的存在这个数据,但是过滤器返回不存在这个数据,那么数据库就肯定不会有这个数据。

                4.由于过滤器的结构简单,导致过滤器的处理速度是很快的

        

redis是怎么判断哪些key过期时间到了应当被删除了

        在redis种如果不给key设置过期时间,key将会一直存在于redis中,占用内存,那么设置过期时间的key会有过期删除的策略来删除,分为:被动删除、主动删除。

        被动删除: 这是一种惰性删除,当访问到这个key的时候会判断key是否过期,如果过期则删除。

        主动删除:光是被动删除满足不了删除的需求,如果key过期了但一直没有被访问,那么会一直存在于内存中占用资源,所以可以用主动删除来删除过期的key,主动删除又分为:定期删除、定时删除。

        定时删除:设置定时器,到了时间就删除

        定期删除:会从设置了过期时间的key当中随机抽样,然后删除过期的key。过期删除的频率默认一秒10次,删除过程会有3个步骤。

        1.从设置了过期时间的key中随机抽取20个。

        2.删除过期的key。

        3.如果删除的个数占25%,则从第一步再来一次。

        定期任务的频率可以通过修改配置hz参数来调整,频率越高cpu使用量越高,修改需谨慎

优缺点:

        被动删除

               优点:cpu的使用量很小,删除会使用cpu,只有在访问的时候决定是否删除

                缺点:惰性删除很可能导致删除不及时,导致key一直存在于内存当中,占用内存

        定时删除:

                优点:能第一时间删除过期key

                缺点:对cpu的使用量过大,因为定时器需要占用cpu

        定期删除:

                优点:能最少量的使用cpu,也能删除过期key

                缺点:不好决定删除频率

        redis默认使用的是被动删除和定期删除

redis的持久化机制

        为什么要持久化机制?因为redis的数据存在于内存,如果服务器宕机会导致数据丢失,所以需要将内存中的数据持久化倒硬盘当中长久保存,如果服务器宕机再将数据复原到redis中使用

        RDB:将当前内存中的数据保存快照版本到磁盘

        AOF:将redis执行的每一行数据都生成日志保存到磁盘

        RDB:

        会每间隔一段时间执行一次快照保存到磁盘,恢复的时候直接将快照文件读取到内存中即可,持久化可以是手动持久化也可以是自动持久化。

        手动save:手动save的时候会阻塞进程,在快照的过程中主进程无法处理任何请求,只有当快照结束后才会释放进程。

        bgsave:可以在配置文件中配置一些快照规则,比如多少秒内修改了多少条数据时出发,bgsave的快照流程:fork一个线程来处理快照过程,主进程继续执行其余的操作,所以在快照的过程中不会影响到主进程的正常使用。

        优缺点:

                  优点:1.默认使用bgsave,消耗的时间少,只有fork的一瞬间会阻塞进程。

                             2.快照的持久化时间很快,快照后的文件大小也会小很多.

                             3.在回复备份文件的时候RDB比AOF快很多。

                缺点:如果在快照过程中或两次快照期间服务器挂掉了,容易丢失数据

        AOF:

        默认不开启AOF,如果对数据非常重视的时候才会打开,会把redis每次执行的命令写到日志中,然后存放到磁盘中,其实AOF默认情况下不是实时持久化到磁盘中的,每次做修改操作会将命令写到磁盘缓存中,默认间隔30s才会将缓存中的数据写到磁盘中,如果这30s中服务器宕机会使数据丢失,既然使用了AOF就是想要保证数据不丢失,所以可以修改配置调整同步频率。

                文件越来越大怎么办?AOF有对应机制,如果日志的命令达到阈值,会对日志进行压缩重写,重写指的不是对现有的日志进行整理,而是针对目前缓存的键值对,用最短的命令去形容,然后用新日志替换旧日志 

                比如:set vip 666 执行一千次,vip还是等于666,压缩后将一千条命令变成一条命令。

                如果重写过程有新命令怎么办?AOF的重写过程是,fork子进程(不会影响主进程执行任务),对目前的数据进行快照,对快照的数据逐一处理写到新日志中,如果在重写过程中主进程有新的命令,会将命令放到缓存区,这缓存区是专门单独开辟的缓存空间,用来放重写过程中的新命令,等子进程重写完毕后再将新命令添加到日志末尾,再替换文件。

        优缺点:

                优点:对数据的完整性保证较高,默认开启快速缓存,一般来说也就丢失一秒的数据

                缺点:因为持久化频率高,性能没有RDB好。因为日志文件大,占用的资源比RDB大

        

redis集群哨兵模式

        用于针对redis主从模式,在普通主从模式下,主机负责写,并且同步给从机,从机只用负责读操作,如果主机宕机,需要手动的将从机替换上去,那么这是不符合高可用场景的,于是有了哨兵,来自动化的做这件事。

        哨兵不具备读写功能,仅用来监控redis节点,在一开始哨兵会收集主从的个体信息,并且保持心跳监听,如果发现主机宕机那么哨兵之间会通过选举来决定谁来做故障转移,也就是将从机安排到主机位置。

        心跳机制:也就是每间隔秒向所有的主机发送一个ping请求,如果返回时间大于三十秒证明主机宕机。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值