zoukankan      html  css  js  c++  java
  • redis知识汇总

    转自:https://www.cnblogs.com/yangtze-yufei/p/9141385.html

    redis是一个内存数据库,使用key-value形式在内存中管理数据。

    一、redis使用场景

      1、热数据存储。对于需要频繁读写的数据,可以放到redis中,不用频繁的请求数据库。再设置策略持久化到数据库中。

      2、token管理。用户登录成功后,生成token,存储到redis中,并设置过期时间,可以模拟session,用于做认证中心。

      3、缓解数据库压力。大量并发请求访问数据库会造成数据库崩溃,可以使用redis做缓冲,先访问redis。 

    二、redis为啥这么块

      主要有3个原因:

    • 纯内存操作。所有的操作都是在内存中进行。
    • 单线程操作。单线程操作避免了频繁的上下文切换。
    • 使用非阻塞I/O多路复用机制。客户端会产生具有不同事件类型的socket。在服务端,有一段I/0多路复用程序,将socket置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。

    三、redis数据结构

    • string 就是常规的set/get操作
    • list 队列
    • set 不重复的集合
    • sorted set 有序的不重复集合
    • hash 结构化的对象。

    四、redis持久化

      在因为故障等原因导致服务停止时,内存的数据就会丢失。因此,需要将内存的数据持久化到硬盘上。

      redis持久化有两种方式:RDB、AOF

      1、RDB方式持久化

      是通过快照来完成的。当满足一定条件时,redis会将内存中的数据进行快照并存储到硬盘上。

      进行快照的条件在配置文件中配置,由两个参数构成:时间、改动键的个数。当在指定时间内,被改动键的个数大于指定个数时,则触发RDB持久化。

      配置文件中默认有3个条件,这些条件是或的关系。  

    1 save 900 1 # 15分钟内至少有一个键被更改 
    2 save 300 10 # 5分钟内至少有10个键被更改
    3 save 60 10000 # 1分钟内至少有10000个键被更改

      默认的rdb文件在当前的目录,文件名是dump.rdb。

      可以对Redis执行手动快照操作,命令是:save、bgsave。两者有区别:save是由主进程进行快照,会阻塞其他请求。bgsave通过fork子进程进行快照。

      注意:由于Redis使用fork来复制一份当前进程,那么子进程就会占有和主进程一样的内存资源,比如说主进程8G内存,那么在备份的时候,必须保证有16G的内存,要不然会启用虚拟内存,性能非常的差。

      2、AOF方式持久化

      是将发送到Redis服务端的每一条命令都记录下来,并且保存在硬盘的AOF文件中。

      可以通过参数appendonly来设置是否启用AOF。AOF文件的位置和RDB的位置相同,都是通过dir参数设置,默认的文件名是appendonly.aof,可以通过appendfilename参数修改。

    五、redis过期删除策略以及内存淘汰机制

      过期删除策略有:定时删除、惰性删除。

      定时删除:有一个定时器在定时随机扫描一些key,key过期了则删除。这种策略因为定时器一直在扫描,很消耗系统资源。同时有一些key到了过期时间也没有删除。

      惰性删除:在使用key的时候,再检查是否过期,过期了就删除。

      定时删除和惰性删除可以配合使用。

      有个问题是:如果有些key没有被定时删除任务扫描到,同时又长时间没有被调用到,那么这些key是不会被删除的。长期这样会占用大量内存。

      这就需要使用到内存淘汰机制。

      内存淘汰机制在配置文件中开启和配置:

      在redis.conf中有一行配置

    # maxmemory-policy volatile-lru

      有6种内存淘汰机制,一般使用的是:allkeys-lru。当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。

    六、问题

      1、redis和数据库一致性问题

        数据库和缓存双写,必然存在数据不一致问题,对数据有强一致性要求的不能将数据放到缓存中。

      2、缓存穿透。

        大量的请求没有请求缓存,而是都请求数据库了。一般发生在黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。 

      解决方案:

      (一)利用互斥锁。当请求从缓存中得不到数据时,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试,这样能避免大量的请求数据库。

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

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

      3、缓存雪崩

        缓存在同一时间大面积失效,这时候又有大量的请求,则这些请求会请求到数据库,导致数据库异常。

      解决方案:

      (一)给缓存的失效时间加上一个随机值,避免集体失效。

      (二)使用互斥锁,避免大量数据库请求。

      (三)双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点:

    • 从缓存A读数据库,有则直接返回。
    • A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程。
    • 更新线程同时更新缓存A和缓存B。

      4、redis并发竞争key

        多个子系统去set一个value。

      解决方案:

      1、设置分布式锁,抢到锁的就去set。

      2、设置队列,根据实际需求将set操作变成串行。

  • 相关阅读:
    查看文件的首尾行
    快捷键
    lua中奇葩用法
    lua中特殊用法
    CVPR2015一些文章整理
    hdu5371 最长回文子串变形(Manacher算法)
    SVN合并(merge)的使用
    atitit. 集合groupby 的实现(2)---自己定义linq查询--java .net php
    王立平--SQLite,SQLiteOpenHelper的简单应用
    Vim 经常使用快捷键及键盘图
  • 原文地址:https://www.cnblogs.com/taozi32/p/9151527.html
Copyright © 2011-2022 走看看