项目笔记总结-Redis

Redis

    • 1、Redis的优势
    • 2、redis的持久化
    • 3、BIO和NIO
    • 4、Redis为什么快
    • 5、主从复制
    • 6、cluster集群
    • 7、redis缓存穿透
    • 8、redis缓存雪崩
    • 9、redis缓存击穿
    • 10、布隆过滤器
    • 11、redis缓存--Java中的使用

1、Redis的优势

  1. 性能高:redis的读写能力一秒上万次,是单线程的
  2. 数据类型丰富:支持String,hash,set,list,zset
  3. 原子:所有操作都是原子的,同时支持对多个操作合并后的原子执行
  4. 支持过期键:到时间后,自动删除
  5. 保证备份和恢复:redis将内存的数据保存到硬盘中
  6. 支持发布和订阅:对多个客户端发送广播
  7. 允许复制功能:分担压力和提高安全
  8. 集群:创建分布式数据库,一部分数据库读,另一部分写

2、redis的持久化

  1. 将数据从内存写到内存上,持久化的方式:RDB,AOf(在redis.config配置文件中)
  2. RDB:数据快照,保存数据用单独的线程将数据写到rdb二进制文件中
  1. redis会fork一个和当前线程一样的线程,作为当前线程的子线程,这个子线程会将数据写到rdb临时文件中,这个过程主线程不进行IO操作
  2. RDB的底层用到了‘写时复制技术’,不是直接将内存中的数据同步到rdb文件中,而是在内存中开辟一个临时空间,将内存中的数据同步到临时空间中,再将临时空间中的数据同步到rdb文件中
  3. 存储的是快照文件,恢复数据方便
  4. 缺点:会丢失最近一次快照之后的数据;当redis数据库比较大时,写入磁盘时线程占用时间比较长
  1. AOF:记录下所有执行过的写操作,当文件中追加不可以更改,在redis重启时,会将日志文件从头执行一遍重新构建数据
  2. AOF的执行流程:
  1. AOF和RDB同时开启,redis会默认读取AOF(数据不会丢失)
  2. 客户端的每次写操作,都会被append追加到AOF缓存区中
  3. 缓存中会根据同步策略(always,everysec,no)将操作同步到磁盘的AOF文件中
  4. 当AOF文件大小超过规定的阈值时(文件是原来重写文件的2倍时,到达阈值)(有大量的无效数据时,文件会变大,操作会变慢),执行rewirte命令,压缩AOF文件
  5. redis重启时,就会执行AOF的文件

3、BIO和NIO

  1. BIO:同步阻塞时期,抛出一个线程,线程去kernal中读取网卡的socket连接,当连接还没到,别的连接到达时,别的连接会被阻塞,那么某一刻的时间片并没有处理数据,所以总的来说BIO的cpu并没有时刻在处理真正到达的数据,tomcat7.0以前也是阻塞的IO
  2. NIO:同步非阻塞时期,抛出线程,线程去kernal中读取网卡的socket的连接时,设置成while死循环轮询处理,先去read-socket连接8,8没有就去读9,也就是在任意一个时刻的时间片一直在处理数据,效率更高

4、Redis为什么快

  1. 内存存储,数据存储在内存上,没有IO从磁盘读取数据这一步(可以用RGB和AOF实现数据持久化到磁盘上)
  2. 高效的数据结构
  1. String使用的数据结构是SDS,时间复杂度是O(1),SDS的长度变短时,空余出来的空间直接被标记,然后倍使用,不需要分配
  2. hash使用的是压缩链表+哈希表,可以直接通过key拿到对应的值,时间复杂度是O(1),当列表的元素小于512个,且每个元素小于64个字节使用压缩链表
  3. list使用的是压缩链表+linklist
  4. zset使用的是压缩链表+跳表(跳表就是在原来单链表的基础上加入索引,降低时间复杂度,平均是logN,最差是N)
  1. 单线程模式:避免了切换上下文和竞争资源,因为是单线程,要少使用执行时间长的命令lrange,hgetall等命令
  1. 其实单线程指的是文件事件处理器是单线程的,也就是工作线程是单线程的,所以说redis是单线程的
  2. 文件事件处理器使用IO多路复用处理请求socket,每个socket可能对应着不同的事件,把这些socket放到队列中,使用while做轮询处理
  1. redis有自己的虚拟内存(VM)机制,实现数据的冷热分离(把不常用的冷数据通过VM虚拟内存交换到磁盘上,腾出空间来存储经常使用的热数据),加快检索的速度

5、主从复制

  1. 主从复制可以实现读写分离(master写slave读),容灾处理(当一台从机挂掉了,从另一台从机读取),解决单点故障问题
  2. 那如果是主机挂掉了,怎么办?
  1. 复制多个主从模式,实现集群的概念
  1. master挂掉后,slave依然是从服务器不会上位
  2. 主从复制的原理:
  1. slave成功连接到一个master之后,会发送sync请求同步数据的命令
  2. master接到命令会进行快照生成RDB文件,将RDB文件发送给从服务器
  3. 全量复制:slave服务器收到文件后,将数据存盘并加载到内存中
  4. 增量复制:每次master做完写操作后,就会主动和slave进行数据同步
  5. 复制延时:所有的写操作都在master上,所有的读操作都在slave上,数据同步时有一定的延时,当系统繁忙时,这个问题更加严重
  1. 哨兵模式:slave里的哨兵,时刻监视master的状态,如果主机挂了,让slave上位,哨兵之间相互监视,(当之前的mater重新启动时,就会变成slave),那该如何从slave中选取新的master呢?
  1. 选举成为新master的条件:
    配置文件中priority的优先级小的
    偏移量大的
    runid最小的从服务器:redis实例重启后会随机生成runid
  2. 选出新的master后,sentinal会向其他slave发送新的master的命令,其他的从slave发送请求同步数据的请求
  3. 当挂掉的master重新上线时,哨兵发送slaveof命令,让她成为从机

6、cluster集群

  1. 容量不够,redis如何进行扩容?集群,每一个结点存储的是一部分数据
  2. 并发写操作时,redis如何分摊?集群,无中心化配置
  3. redis集群实现了对redis的水平扩容,也就是启动N个结点,将数据分布到这个redis集群中,每个redis结点存储1/N的数据,而且redis还有分区容错性(即使集群中一部分结点失效,集群也会继续处理请求)实现数据扩容和数据分摊
  4. 集群的特点:无中心化,任何一个redis都可以作为集群的入口,即使连接的不是主机,集群也会自动切换主从
  5. redis集群中最少有三个主节点,并为每个主节点创建一个从结点(分配原则是保证每个主节点有不同的IP,主节点和从结点不再同一个IP上)
  6. 一个集群有1万6千个插槽slot,通过key值计算插槽所在的位置,插槽可以理解为负载均衡,降低redis的压力
  7. 当集群中的一个master挂掉后,15秒超时,从机升级为主机,当主结点恢复后,主节点变成从结点
  8. 当cluster中的一组主从挂掉后,cluser-require-full为yes,那整个集群挂掉;如果为no,其他的插槽还是可以使用的(默认是yes)
  9. cluster的不足:
  1. 多键不被直接支持,必须通过组进行添加

7、redis缓存穿透

  1. 发送请求去请求数据,数据库和缓存中都没有,然后我们每次都会把请求穿透到数据库,这就是缓存穿透(一般都是黑客的恶意攻击)
  2. 避免缓存穿透:
  1. 在用户应用层API入口,对参数做校验,过滤非法值
  2. 当查询数据库如果是null,就给缓存设置空值,要设置过期时间,如果有写请求,要更新缓存实现数据一致
  3. 使用布隆过滤器,会将数据库里的key,全部放到布隆中,请求时会先判断布隆中有没有

8、redis缓存雪崩

  1. redis中键在同一时刻大量过期,这时出现了大量访问过期键的请求,这些请求会直接访问数据库,造成数据库压力
  2. 解决:
  1. 设置锁:给数据库上锁,避免高并发下大量请求访问数据库
  2. 过期时间设置的相对分散点,避免集体过期,可以用随机值什么的
  3. 记录key的过期时间,当key过期就触发异步线程,更新key的过期时间

9、redis缓存击穿

  1. redis中的某个热点key过期,此时有大量请求去访问key,这时的请求会直接达到DB上
  2. 解决:
  1. 记录过期时间,当key过期时触发异步线程,更新key的过期时间
  2. 提前预热:在大量请求后来之前,提前加大key的过期时间

10、布隆过滤器

  1. 发送的大量请求数据是数据库没有的,为了避免数据库频繁处理这些无用请求,就出现了布隆过滤器,布隆过滤器用在redis,数据库的最前面,请求先发到布隆上,命中了就将请求压到redis或数据库,无法命中就直接返回false
  2. 布隆过滤器是bitmap一维数组,原始数值都是0,一个数据存储时,会经过三次哈希,拿到数组下标,将bitmap上对应位置变成1,下次数据请求过来就会三次哈希,都命中后,将请求压到数据库
  3. 布隆过滤器的问题,出现误判:一个数据bitmap是1,3,6;第二次数据是3,6,7;有一个数据请求是3,6,7,这就被命中了,其实并没有这个数据,就会误判,而且不支持删除操作,这样就会数据量越大,误判率越高
  4. 解决方案:
  1. 将bitmap换成哈希表,但是空间占用率大
  2. 布谷鸟过滤器
  1. 布谷鸟过滤器:是一个一维数组,存储的是指纹信息(几个bit),其实这样就是用精确度换空间,每个位置上放多个座位(一个位置可以存多个bit);有两个特殊的哈希函数,当这个位置上的指纹被挤兑后,就要去他对偶的位置上查看,可以直接根据当前位置和指纹直接算出对偶位置

fp=fingerprint(x)//根据元素拿到指纹
p1=hash(x)//哈希到位置
p2=fp^p1//根据指纹和位置拿到对偶位置
p1!=p2不然会有自己踢自己,死循环

11、redis缓存–Java中的使用

  1. @EnableCaching表示开始注解
  2. @Cacheable用在类上或方法上:每次执行该方法前都会去缓存中判断是否有key,如果缓存中有,直接拿结果
  3. @CachePut,直接执行方法,不会判断缓存中是否存在
  4. @CacheEvict触发清除操作,这个清除操作发生在value对应的缓存上,要请求的是哪个key,condition表示触发清除操作的条件

你可能感兴趣的:(笔记,redis,缓存,数据库)