• Redis数据库 专题


    Redis是一种内存型数据库。传统的数据库储存在硬盘中,而Redis数据库存在内存中,所以读写速度非常快。因此redis广泛用于缓存方向,除此之外也经常用于实现分布式锁。redis提供了多种数据类型来支持不同的业务场景。

    除此之外,redis支持事务、持久化、LUA脚本、LRU驱动事件、多种集群方案。

    为什么要用Redis/为什么要用缓存

    高性能高并发

    高性能:从内存读取数据比从硬盘读取要快很多。如果数据库中对应的数据改变之后,同步改变缓存中相应的数据即可。

    高并发:直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以可以考虑将数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。

    Redis为什么那么快

    1. 纯内存操作
    2. 单线程操作,避免了频繁的上下文切换造成的开销
    3. 采用了非阻塞I/O多路复用机制

    Redis常见数据结构

    • String
    • Hash
    • List
    • Set
    • Sorted Set

    Redis内存淘汰机制

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

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

    定时删除,需要用一个定时器来负责监视key,过期自动和三处。虽然内存可以及时释放,但是这十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求上,而不是删除key上。

    定期删除,redis默认每隔100ms检查一下,是否有过期的key,有过期的key则删除。这里需要强调一下的是,redis并不会检查所有的key,而是会随机抽取。如果只采用定期删除策略,会导致很多key到时间而没有删除,于是就需要惰性删除。惰性删除,并不是直接删除,而是你在获取某个key的时候,redis会检查一下是否过期,过期了才删除。

    如果定期删除没有删除key,而且你也没有即时去请求key,惰性删除没有起效果。Redis的内存会越来越高,这时候就需要采用一些内存淘汰机制。

    redis提供6中数据淘汰策略:

    1. volatile-lru:从设置的过期时间数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
    2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。
    3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
    4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
    5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
    6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。

    4.0版本后增加以下两种:

    1. volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰。
    2. allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用key。

    总结:两种操作对象:已设置过期时间的数据集(server.db[i].expires)和数据集(server.db[i].dict),四种机制lrulfurandomttl(仅针对过期时间数据集)加no-eviction

    Redis持久化机制 (重要)

    持久化:将内存中的数据写入到硬盘里面。主要是为了之后重用数据(比如重启、机器故障之后恢复数据),或者为了防止系统故障而将数据备份到一个远程位置。

    Redis不同于memcache很重要的一点在于Redis支持持久化,提供了两种不同的持久化方式快照(snapshotting, RDB),另一种方式是只追加文件(append-only file, AOF)

    快照

    Redis通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。

    AOF(append-only file)持久化

    默认没有开启,可以通过下面的参数开启:

    appendonly yes
    

    开启AOF持久化后每执行一条会更改Redis中的数据的命令。Redis就会将该命令写入硬盘中那个的AOF文件。AOF文件和RDB文件位置相同,可以通过dir参数设置。

    appendfsync always # 每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
    appendfsync everysec # 每秒钟同步一次,显式地将多个写命令同步到硬盘
    appendfsync no # 让操作系统决定何时进行同步 
    

    为了兼顾数据和写入性能,用户可以考虑appendfsync everysec选项,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只丢失一秒之内产生的数据。当硬盘忙于写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

    Redis 4.0开始支持RDB和AOF的混合持久化(默认关闭,可以通过配置项aof-use-rdb-preamble开启)

    开启混合持久化之后,AOF重写的时候就直接把RDB的内容写到AOF文件开头,这样做的好处是可以结合RDB和AOF的优点,快速加载的同时避免丢失过多的数据,当然缺点也是有的,AOF里面RDB部分的压缩格式不再是AOF格式,可读性较差。

    Redis 主从架构

    单机的redis,能够承载的QPS大概在上万或者几万不等。对于缓存来说,一般都是用来支持读高并发的。因此Redis架构实现上会采用主从架构(master-slave)一主多从主节点(master mode)负责,并且将数据复制到其他从属节点,从节点(slave node)负责。即所有的读请求全部走从节点,这样可以轻松实现水平扩容。
    在这里插入图片描述
    redis replication → ightarrow 主从架构 → ightarrow 读写分离 → ightarrow 水平扩容支撑高并发

    Redis Replication的核心机制
    • redis采用异步方式复制数据到slave节点。(redis2.8开始,slave node会周期性地确认自己每次复制的数据量)
    • 一个master node配置多个slave节点
    • slave node也可以连接其他slave node
    • slave node在做复制的时候,不会block master node的工作
    • slave node在做复制的时候,也不会block对自己的查询操作,它会使用旧的数据集来提供服务;但在复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务
    • slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量。

    如果采用了主从架构,那么建议必须开启master node的持久化机制,不建议使用slave node作为master node的数据热备,因为那样的话,如果你关掉master的持久化,可能在master宕机重启的时候数据是空的,然后一经复制,slave node的数据也丢失了。

    另外,master的各种备份方法,也需要做。万一本地的所有文件丢失了,从备份中挑选一份rdb去恢复master,这样才能保证重新启动的时候,是有数据的。slave node可以自动接管master node,但又有可能sentinel还没有检测到master failure,master node就自动重启了,仍有可能导致上述slave node的数据被清空。

    master的持久化和多种备份方案都是为了防止重启是数据不为空从而导致slave结点数据清空。

    Redis主从复制核心原理

    启动一个slave node时,它会发送一个PSYNC命令给master node。如果slave node和master node是初次连接,则会触发一次full resynchronization全量复制。此时master会启动一个后台线程,开始生成一份RDB快照文件,同时还将从客户端client新收到的所有写命令缓存在内存中。RDB文件生成完毕后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后从本地磁盘加载到内存中。接着master会将内存中缓存的写命令发送到slave,slave也会同步这些数据。slave如果跟master之间发生了网络故障,断开了连接,会自动重连,连接之后master node仅会复制给slave部分缺少的数据。
    在这里插入图片描述

    1.主从复制的断点续传。
    mastet node和slave node会在内存中维护一个backlog,同时在backlog中保存一个replica offsetmaster run id。如果master和slave之间的网络连接断掉了,slave会让master从上次replica offset开始复制,如果没有找到对应的offset,那么就会执行一次resynchronization

    master run id的作用:
    根据host+ip来定位master,是不太靠谱的。因为如果master node重启或者数据发生了变化,那么slave node根据run id仍能做出正确区分。

    2.无磁盘化复制
    master在内存中直接创建RDB,然后发送给slave,不会在自己本地落地磁盘。只需要在配置文件中开启repl-diskless-sync yes即可。

    3.过期key处理
    slave不会过期key,只会等待master过期key。如果一个master过期了key,那么会模拟一条del命令发送给slave。

    Redis事务

    Redis通过MULTIEXECWATCH等命令来实现事务(transaction)功能。事务提供了一种将多个请求打包,然后一次性的,按顺序的执行多个命令的机制,并且在事务执行期间,服务不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕。

    Redis中,事务总是具有原子性(Atomicity)一致性(Consistency)隔离性(Isolation),并且当Redis运行在某种特定的持久化模式下时,事务也具有持久性(Durability)

    缓存雪崩和缓存穿透

    缓存雪崩

    缓存同一时间大面积的失效,所以,后面的请求全都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

    解决方法:

    • 事前:尽量保证redis集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
    • 事中:本地ehcache缓存+hystrix限流&降级,避免MySQL崩掉。
    • 事后:利用redis持久化机制保存的数据尽快恢复缓存。

    缓存穿透

    大量请求的key根本不在缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层。

    解决方法:

    • 缓存无效key:如果缓存和数据库都查不到某个key就写一个到redis中并设置过期时间。并不能从根本上解决问题,尽量要将无效的key的过期时间设置短一点。

    • 布隆过滤器:把所有可能请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来请求的值是否存在于布隆过滤器中,存在的话才会走正常流程,不存在的话直接返回请求错误信息。

    如何解决Redis并发竞争key问题

    并发竞争key的问题指的是多个系统同时对一个key进行操作,但最后执行的顺序与我们期望的不同,这样导致了结果的不同。

    分布式锁(zookeeper和redis都可以实现分布式锁)

    基于zookeeper临时有序节点可以实现分布式锁。大致思想为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点序号中的最小的一个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。完成业务流程后,删除对应的子节点释放锁。

    如何保证缓存与数据库双写时的数据一致性

    读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况。

    最好不要使用这个方案,串行之后系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。

    参考

    来自Java Guide面试突击版,百度可得最新版本,这里有删减和修正以及扩充。

    Redis 主从架构

    2020年11个Redis系列高频面试题,哪些你还不会?

  • 相关阅读:
    POJ 1953 World Cup Noise
    POJ 1995 Raising Modulo Numbers (快速幂取余)
    poj 1256 Anagram
    POJ 1218 THE DRUNK JAILER
    POJ 1316 Self Numbers
    POJ 1663 Number Steps
    POJ 1664 放苹果
    如何查看DIV被设置什么CSS样式
    独行DIV自适应宽度布局CSS实例与扩大应用范围
    python 从入门到精通教程一:[1]Hello,world!
  • 原文地址:https://www.cnblogs.com/wanghongze95/p/13842412.html
Copyright © 2020-2023  润新知