视频上传网站建设,为网站吸引流量的方法,三水网站建设,seo搜索引擎优化知乎目录 Redis持久化机制:RDB和AOF
Redis线程模型有哪些#xff1f;单线程为什么快#xff1f;
Redis的过期键有哪些删除策略#xff1f;
Redis集群方案有哪些#xff1f;
redis事务怎么实现#xff1f;
为什么redis不支持回滚#xff1f;
redis主从复制的原理是什么 …目录 Redis持久化机制:RDB和AOF
Redis线程模型有哪些单线程为什么快
Redis的过期键有哪些删除策略
Redis集群方案有哪些
redis事务怎么实现
为什么redis不支持回滚
redis主从复制的原理是什么
Redis复制功能是如何工作
缓存雪崩、缓存穿透、缓存击穿在实际中如何处理 Redis持久化机制:RDB和AOF
Redis提供了不同级别的持久化方式:RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大. 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式. 你也可以同时开启两种持久化方式,在这种情况下当redis重启的时候会优先载入AOF文件来恢复原始的数据因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整. 最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始
RDB的优点
RDB是一个非常紧凑的文件;它保存了某个时间点得数据集,非常适用于数据集的备份;比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集. RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密)非常适用于灾难恢复. RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做父进程不需要再做其他lO操作所以RDB持久化方式可以最大化redis的性能. 与AOF相比,在恢复大的数据集的时候RDB方式会更快一些.
RDB缺点
如果你希望在redis意外停止工作例如电源中断)的情况下丢失的数据最少的话 那么RDB不适合你.虽然你 可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Red is要完整的保存整个数据集 是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存;万一在Redis意外宕机,你可能会丢失几分钟的数据. RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.
AOF优点 使用AOF会让你的Redis更加耐久:你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求);一旦出现故障你最多丢失1秒的数据. AOF文件是一个只进行追加的日志文件所以不需要写入seek,即使由于某些原因(磁盘空间已满写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题. Redis 可以在AOF文件体积变得过大时自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的因为Redis在创建新AOF文件的过程中会继续将命令追加到现有的AOF文件里面即使重写过程中发生停机现有的AOF文件也不会丢失。而一旦新AOF文件创建完毕Redis就会从旧AOF文件切换到新AOF文件并开始对新AOF文件进行追加操作。
AOF文件有序地保存了对数据库执行的所有写入操作这些写入操作以Redis协议的格式保存因此AOF文件的内容非常容易被人读懂对文件进行分析(parse)也很轻松。导出 (export)AOF文件也非常简单:举个例子如果你不小心执行了FLUSHALL命令但只要AOF文件未被重写那么只要停止服务器移除AOF文件末尾的FLUSHALL 命令并重启Redis就可以将数据集恢复到FLUSHALL执行之前的状态。
AOF缺点 对于相同的数据集来说AOF文件的体积通常要大于RDB文件的体积。 根据所使用的fsync策略AOF的速度可能会慢于RDB。在一般情况下每秒fsync的性能依然非常局而关闭fsync可以让AOF的速度和RDB一样快即使在高负荷之下也是如此。不过在处理巨大的写入载入时RDB可以提供更有保证的最大延迟时间(latency)。
Redis线程模型有哪些单线程为什么快
IO模型维度的特征
IO模型使用了多路复用器在linux系统中使用的是EPOLL 类似netty的BOSS,WORKER使用一个EventLoopGroup(threads1) 单线程的Reactor模型每次循环取socket中的命令然后逐一操作可以保证socket中的指令是按顺序的不保证不同的socket也就是客户端的命令的顺序性 命令操作在单线程中顺序操作没有多线程的困扰不需要锁的复杂度在操作数据上相对来说是原子性质的
架构的设计模型
自身的内存存储数据读写操作不设计磁盘IO redis除了提供了Value具备类型还为每种类型实现了一些操作命令 实现了计算向数据移动而非数据向计算移动这样在IO的成本上有一定的优势 且在数据结构类型上丰富了一些统计类属性读写操作中写操作会O1负载度更新length类属性使得读操作也是O(1)的
Redis的过期键有哪些删除策略
过期精度 在Redis 2.4及以前版本过期期时间可能不是十分准确有O-1秒的误差。
从Redis 2.6起过期时间误差缩小到0-1毫秒。
过期和持久 Keys的过期时间使用Unix时间戳存储(从Redis 2.6开始以毫秒为单位)。这意味着即使Redis实例不可用时间也是一直在流逝的。 要想过期的工作处理好计算机必须采用稳定的时间。如果你将RDB文件在两台时钟不同步的电脑间同步有趣的事会发生(所有的keys装载时就会过期)。 即使正在运行的实例也会检查计算机的时钟例如如果你设置了一个key的有效期是1000秒然后设置你的计算机时间为未来2000秒这时key会立即失效而不是等1000秒之后。
Redis如何淘汰过期的keys
Redis keys过期有两种方式:被动和主动方式。 当一些客户端尝试访问它时key会被发现并主动的过期。 当然这样是不够的因为有些过期的keys永远不会访问他们。无论如何这些keys应该过期所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。 具体就是Redis每秒10次做的事情: 1.测试随机的20个keys进行相关过期检测。
2.删除所有已经过期的keys。 3.如果有多于25%的keys过期重复步骤1.
这是一个平凡的概率算法基本上的假设是我们的样本是这个密钥控件并且我们不断重复过期检测直到过期的keys的百分百低于25%,这意味着在任何给定的时刻最多会清除1/4的过期keys.在复制AOF文件时如何处理过期 为了获得正确的行为而不牺牲一致性当一个key过期DEL将会随着AOF文字一起合成到所有附加的slaves。在master实例中这种方法是集中的并且不存在一致性错误的机会。 然而当slaves连接到master时不会独立过期keys(会等到master执行DEL命令)他们任然会在数据集里面存在所以当slave当选为master时淘汰keys会独立执行然后成为master。Redis缓存如何回收
noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令但DEL和几个例外) allkeys-1ru:尝试回收最少使用的键LRU)使得新添加的数据有空间存放。 volatile-1ru:尝试回收最少使用的键LRU)但仅限于在过期集合的键,使得新添加的数据有空间存放。
allkeys-random:回收随机的键使得新添加的数据有空间存放。 volatile-random:回收随机的键使得新添加的数据有空间存放但仅限于在过期集合的键。 volatile-tt1:回收在过期集合的键并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
volatile-7fu:从所有配置了过期时间的键中驱逐使用频率最少的键 a7lkeys-7fu:从所有键中驱逐使用频率最少的键
如果没有键满足回收的前提条件的话策略volatile-lru, volatile-random以及volatile-ttl就和noeviction差不多了。 选择正确的回收策略是非常重要的这取决于你的应用的访问模式不过你可以在运行时进行相关的策略调整并且监控缓存命中率和没命中的次数通过RedisINFO命令输出以便调优。—般的经验规则: ·使用allkeys-lru策略:当你希望你的请求符合一个幂定律分布也就是说你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么这是个很好的选择。. ·使用alkeys-random:如果你是循环访问所有的键被连续的扫描或者你希望请求分布正常(所有元素被访问的概率都差不多)。 ·使用volatile-ttl:如果你想要通过创建缓存对象时设置TTL值来决定哪些对象应该被过期。allkeys-ru和volatile-random策略对于当你想要单一的实例实现缓存及持久化一些键时很有用。不过一般运行两个实例是解决这个问题的更好方法。 为了键设置过期时间也是需要消耗内存的所以使用allkeys-lru这种策略更加高效因为没有必要为键取设置过期时间当内存有压力时。 Redis集群方案有哪些
常见集群分类:主从复制集群、分片集群 Redis集群有哪些
主从复制集群手动切换
带有哨兵的HA的主从复制集群
客户端实现路由索引的分片集群
使用中间件代理层的分片集群
redis自身实现的cluster分片集群
redis事务怎么实现
MULTI、EXEC、DISCARD和WATCH是Redis事务相关的命令。事务可以一次执行多个命令并且带有以下两个重要的保证:
1、事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中不会被其他客户端发送来的命令请求所打断。 2、事务是一个原子操作:事务中的命令要么全部被执行要么全部都不执行。
EXEC命令负责触发并执行事务中的所有命令: 如果客户端在使用MULTI开启了一个事务之后却因为断线而没有成功执行 EXEC 那么事务中的所有命令都不会被执行。 另一方面如果客户端成功在开启事务之后执行EXEC 那么事务中的所有命令都会被执行。
当使用AOF方式做持久化的时候 Redis 会使用单个write(2)命令将事务写入到磁盘中。 然而如果Redis服务器因为某些原因被管理员杀死或者遇上某种硬件故障那么可能只有部分事务命令会被成功写入到磁盘中。 如果Redis在重新启动时发现AOF文件出了这样的问题那么它会退出并汇报一个错误。 使用redis-check-aof程序可以修复这一问题:它会移除AOF文件中不完整事务的信息确保服务器可以顺利启动。 从2.2版本开始Redis 还可以通过乐观锁optimistic lock)实现CAS (check-and-set)操作。
事务中的错误
使用事务时可能会遇上以下两种错误: 事务在执行 EXEC之前入队的颌令可能会出错。比如说命令可能会产生语法错误参数数量错误参数名错误等等或者其他更严重的错误比如内存不足如果服务器使用maxmemory 设置了最大内存限制的话)。 命令可能在EXEC 调用之后失败。举个例子事务中的命令可能处理了错误类型的键比如将列表命令用在了字符串键上面诸如此类。
对于发生在EXEC执行之前的错误客户端以前的做法是检查命令入队所得的返回值:如果命令入队时返回QUEUED那么入队成功;否则就是入队失败。如果有命令在入队时失败那么大部分客户端都会停止并取消这个事务。 不过从Redis 2.6.5开始服务器会对命令入队失败的情况进行记录并在客户端调用EXEC命令时拒绝执行并自动放弃这个事务。 在Redis 2.6.5以前,Redis只执行事务中那些入队成功的命令而忽略那些入队失败的命令。而新的处理方式则使得在流水线(pipeline)中包含事务变得简单因为发送事务和读取事务的回复都只需要和服务器进行一次通讯。 至于那些在EXEC_命令执行之后所产生的错误并没有对它们进行特别处理:即使事务中有某个/某些命令在执行时产生了错误事务中的其他命令仍然会继续执行。
为什么redis不支持回滚
如果你有使用关系式数据库的经验那么“Redis在事务失败时不进行回滚而是继续执行余下的命令这种做法可能会让你觉得有点奇怪。 以下是这种做法的优点:
Redis 命令只会因为错误的语法而失败并且这些问题不能在入队时发现)或是命令用在了错误类型的键上面:这也就是说从实用性的角度来说失败的命令是由编程错误造成的而这些错误应该在开发的过程中被发现而不应该出现在生产环境中。 因为不需要对回滚进行支持所以Redis的内部可以保持简单且快速。 有种观点认为Redis处理事务的做法会产生bug然而需要注意的是在通常情况下回滚并不能解决编程错误带来的问题。举个例子如果你本来想通过INCR命令将键的值加上1却不小心加上了2又或者对错误类型的键执行了INCR回滚是没有办法处理这些情况的。
redis主从复制的原理是什么
主从复制机制
当一个master实例和一个 slave实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新以便于将自身数据集的改变复制给slave , :包括客户端的写入、key 的过期或被逐出等等。 当master和 slave 之间的连接断开之后因为网络问题、或者是主从意识到连接超时 s7ave重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程例如 master需要创建所有数据的快照将之发送给slave ,之后在数据集更改时持续发送命令流到s1ave主从复制的关注点
Redis使用异步复制slave 和 master 之间异步地确认处理的数据量 一个master 可以拥有多个 slave
slave可以接受其他 slave 的连接。除了多个 slave可以连接到同一个 master之外 slave 之间也可以像层叠状的结构(cascading-1ike structure)连接到其他 slave 。自Redis 4.0起所有的 sub-slave 将会从master收到完全一样的复制流。 Redis复制在 master侧是非阻塞的。这意味着master 在一个或多个slave进行初次同步或者是部分重同步时可以继续处理查询请求。 复制在 slave侧大部分也是非阻塞的。当 slave进行初次同步时它可以使用旧数据集处理查询请求假设你在redis.conf中配置了让 Redis这样做的话。否则你可以配置如果复制流断开, Redis slave 会返回一个error给客户端。但是在初次同步之后旧数据集必须被删除同时加载新的数据集。 slave 在这个短暂的时间窗口 内如果数据集很大会持续较长时间)会阻塞到来的连接请求。自 Redis 4.0开始 可以配置Redis使删除旧数 据集的操作在另一个不同的线程中进行但是加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave 。 复制既可以被用在可伸缩性以便只读查询可以有多个 slave 进行例如 o(N)复杂度的慢操作可以被下放到 slave或者仅用于数据安全。 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf以避免对磁盘进行持久化然后连接一个 slave ,其配置为不定期保存或是启用AOF。但是这个设置必须小心处理因为重新启动的 master程序将从一个空数据集开始:如果一个 slave试图与它同步那么这个 slave也会被清空。 任何时候数据安全性都是很重要的所以如果 master使用复制功能的同时未配置持久化那么自动重启进程这项应该被禁用。
Redis复制功能是如何工作
每一个Redis master都有一个replication ID:这是一个较大的伪随机字符串标记了一个给定的数据集。每个master也持有一个偏移量master将自己产生的复制流发送给slave时发送多少个字节的数据自身的偏移量就会增加多少目的是当有新的操作修改自己的数据集时它可以以此更新slave的状态。复制偏移量即使在没有—个slave连接到master时也会自增所以基本上每一对给定的。
Replication lD, offset 都会标识一个master数据集的确切版本。 当slave连接到master时它们使用PSYNC命令来发送它们记录的旧的 master replication lD和它们至今为止处理的偏移量。通过这种方式, master能够仅发送slave所需的增量部分。但是如果master的缓冲区中没有足够的命令积压缓冲记录或者如果slave 引用了不再知道的历史记录(replication ID)则会转而进行一个全量 重同步:在这种情况下 slave 会得到一个完整的数据集副本从头开始。 下面是一个全量同步的工作细节: master开启一个后台保存进程以便于生产一个RDB文件。同时它开始缓冲所有从客户端接收到的新的写入命令。当后台保存完成时,master将数据集文件传输给slave,slave将之保存在磁盘上然后加载文件到内存。再然后master会发送所有缓冲的命令发给slave。这个过程以指令流的形式完成并且和Redis 协议本身的格式相同。 缓存雪崩、缓存穿透、缓存击穿在实际中如何处理
缓存穿透 缓存穿透是指查询一个一定不存在的数据由于缓存是不命中时被动写的并且出于容错考虑如果从存储层查不到数据则不写入缓存这将导致这个不存在的数据每次请求都要到存储层去查询失去了缓存的意义。在流量大时可能DB就挂掉了要是有人利用不存在的key频繁攻击我们的应用这就是漏洞。
解决方案 有很多种方法可以有效地解决缓存穿透问题最常见的则是采用布隆过滤器将所有可能存在的数据哈希到一个足够大的bitmap中一个一定不存在的数据会被这个bitmap拦截掉从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法我们采用的就是这种)如果一个查询返回的数据为空(不管是数据不存在还是系统故障)我们仍然把这个空结果进行缓存但它的过期时间会很短最长不超过五分钟。
缓存击穿 对于一些设置了过期时间的ey如果这些key可能会在某些时间点被超高并发地访问是一种非常热点的数据。这个时候需要考虑一个问题:缓存被击穿的问题这个和缓存雪崩的区别在于这里针对某一key缓存前者则是很多key。 缓存在某个时间点过期的时候恰好在这个时间点对这个Key有大量的并发请求过来这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存这个时候大并发的请求可能会瞬间把后端DB压垮。解决方案 缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开比如我们可以在原有的失效时间基础上增加一个随机值比如1-5分钟随机这样每一个缓存的过期时间的重复率就会降低就很难引发集体失效的事件。
缓存雪崩 缓存雪崩是指在我们设置缓存时采用了相同的过期时间导致缓存在某一时刻同时失效请求全部转发到DBDB瞬时压力过重雪崩。
解决方案 1.使用互斥锁(mutex key) 业界比较常用的做法是使用mutex。简单地来说就是在缓存失效的时候判断拿出来的值为空)不是立即去load db而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key当操作返回成功时再进行load db的操作并回设缓存;否则就重试整个get缓存的方法。SETNX是「SETif Not eXists」的缩写也就是只有不存在的时候才设置可以利用它来实现锁的效果。在redis2.6.1之前版本未实现setnx的过期时间
2.提前使用互斥锁(mutex key): 在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。总结 穿透:缓存不存在数据库不存在高并发少量key
击穿:缓存不存在数据库存在高并发少量key
雪崩:缓存不存在数据库存在高并发大量key
语义有些许差异但是都可以使用限流的互斥锁保障数据库的稳定