Redis相关

一。Redis的持久化机制以及RDB和AOF的优缺点。

redis的RDB和AOF两种持久化机制的介绍

RDB是Redis默认的持久化方式。按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二 进制文件。即Snapshot快照存储,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定 义快照的周期。( 快照可以是其所表示的数据的一个副本,也可以是数据的一个复制品。)
AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件,在redis重启对时候,可以通过回放AOF日志中写入的指令来重新构建整个的数据集。
如果同时使用AOF和RDB两种持久化机制 ,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加的完整。

 RDB持久化机制的优缺点

优点
(1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备。可以将文件存储到云端,本地磁盘等等。
(2)RDB机制对redis对外提供读写服务时候的影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB的持久化即可。
(3)相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加的快速。
缺点
(1)如果想让redis出现故障,尽可能的少丢失数据,那么RDB没有AOF好。因为一般来说,RDB数据快照文件,基本上都是每隔5分钟或者更长的时间,生成一次,这个时候,如果一旦发生宕机,那么就会把这段时间内的数据都丢失掉。
(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。

AOF持久化机制的优缺点

优点
(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行fsync操作,最多丢失1秒钟的数据。
(2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易受损,即使文件尾部受损,也能很容易恢复,打开文件,把后面损坏的数据删除即可。
(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据对最小日志出来,再创建新日志文件的时候,老日志文件还是会照常写入指令,当新的日志文件生成好之后,会将旧日志文件中后面写入的指令合并到新的日志文件中,这个新的merge后的日志文件,会在ready的时候,与旧的日志文件进行交换。之后就会把旧的日志文件删除掉。
(4)AOF文件中保存的是执行的指令,所以这个特性非常适合做灾难性的误操作紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么久可以立即拷贝这个AOF文件出来,将最后一条flushall命令删除,然后再将AOF文件放回去,就可以通过恢复机制,自动的恢复所有数据了。
缺点
(1)对于同一份数据来说,AOF的日志文件通常要比RDB的数据快照文件要大。
(2)AOF开启之后,Redis服务支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然每秒一次fsync的性能也还是很高的。
(3)以前的AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来,所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge,而是基于当时内存中的数据进行指令的重新构建,这样健壮性能更好一些。

二。Memcache和Redis的区别有哪些。

1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis 有部份存在硬盘上,redis可以持久化其数据

2)、数据支持类型 memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据 类型 ,提供list,set,zset,hash等数据结构的存储

3)、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自 己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

4)、 value 值大小不同:Redis 最大可以达到 1gb;memcache 只有 1mb。

5)、redis的速度比memcached快很多

6)Redis支持数据的备份,即master-slave模式的数据备份。

三。Redis数据结构以及使用场景,常用命令。

 Redis常用数据结构有5中:

    1) 字符串-string   String 这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。

    2)Map-hash   用来存储java中一个完整的自定义对象的对象集合,这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候, 就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟 出类似session的效果。

    3)列表-list    采用链表结构进行数据储存(左进右出右进左出),可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基 于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适—取行情信息。就也是个生产 者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。

    4)无需集合-set  存入set集合中的数据是唯一的,不能有重复的数据,因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去 重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去 重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

    5)有序集合zset  如果存入重复数据,则后一个数据会覆盖原有数据  (自动排序,给每个元素绑定了一个浮点型的score分值,通过分值来升序排列,如果分值一致则按照其值得字典顺序),可以做排行榜应用,取TOP N 操作。

常用命令:   

     String 操作以及服务器相关操作:

select       选择库      案例:seletc  db1

keys         取出key    案例:用表达式 key mylist *,代表取出所有以mylist开头的key。

exists       确认一个key是否存在    案例:exists age ,返回 0 :不存在  1:存在

del            删除一个key  案例: del  key

expire       设置可以的过期时长  案例:expire addr  10

ttl              获取key的过期时长    案例:ttl   expire 

set            设置一个key  案例:set age 30

get            获取一个key  案例:get age

persist      移除keyd的过期时间 案例:persist age

rename     重命名key    案例:rename  age  age1

type           查看返回值类型  案例:type age

ping           测试连接是否存活  案例:ping   返回PONG就是连接正常

quit            退出连接

dbsize        返回当前库的所有key的数目

info             获取服务器的信息

config get   获取配置信息     案例:config  get  dir

flushdb       删除当前库所有的key

flushall        删除所有库的key

    Hash操作:  1)hset key field  设置值  案例:hset user:1 name Tom   

2)hget key field 获取值  案例:hget user:1 name   

3)hkeys key 获取所有的key                         

4)hvals key  获取所有的value       

5) hdel key field 删除指定的字段

      列表List操作:

列表的4中操作类型
操作类型 操作
添加 rpush 、lpush、linsert
lrange、lindex、llen
删除 lpop 、rpop、 lrem、ltrim
修改 lset
阻塞操作 blpop、brpop

 

 

 

 

 

 

四、单线程的redis为什么这么快

  • 纯内存操作
  • 单线程操作,避免了频繁的上下文切换
  • 采用了非阻塞I/O多路复用机制

五。Redis数据命中策略。

  根据原因不同,具体方式不同。   

1、如果是内存不够导致频繁淘汰内存,则需要增大最大内存配置,或者调整缓存的淘汰策略。    

2、如果是粒度设计不合理,则更改粒度设计,使粒度变小。但是注意,粒度变小可能同时带来的问题会是内存变大。所以适当考虑对内容做压缩。  

3、过期时间的设定,在业务允许的情况下,可以增加缓存的过期时间。    

4、如果业务场景是访问并发很高,但对数据的时效性要求没有那么高的时候,可以考虑做缓存预热。如果并发度不是很高,访问比较分散的话, 缓存预热反而效果不好。 

六。缓存雪崩和缓存穿透解决方案。

 1)缓存雪崩  我们可以简单的理解为:由于原有缓存失效,新缓存未到期间 (例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访 问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从 而形成一系列连锁反应,造成整个系统崩溃。

解决办法: 大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证不会有大量的线程对数据 库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓 存失效时间分散开。

2)缓存穿透  缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在 缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请 求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。 alter table user_index -- 重新定义字段 MODIFY id int, drop PRIMARY KEY

   解决办法

         a. 最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存 在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。 另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故 障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设 置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单 粗暴。 5TB的硬盘上放满了数据,请写一个算法将这些数据进行排重。如果这些数据是一些32bit大小的数据该 如何解决?如果是64bit的呢? 对于空间的利用到达了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)。

          b .Bitmap: 典型的就是哈希表 缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空 间、时间来完成了。

布隆过滤器(推荐) 就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过 程。 它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。 Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。 Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突, 我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定 不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这 便是Bloom-Filter的基本思想。 Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。

3)、缓存预热 缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解,缓存预热就是系 统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据 库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

   解决思路:  1、直接写个缓存刷新页面,上线时手工操作下;

2、数据量不大,可以在项目启动的时候自动进行加载;

3、定时刷新缓存;

4)、缓存更新 除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的 业务需求进行自定义的缓存淘汰,常

见的策略有两种:

(1)定时去清理过期的缓存;

(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数 据并更新缓存。 两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过 来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。

五、缓存降级 当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然 需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开 关实现人工降级。 降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结 算)。

以参考日志级别设置预案:

(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;

(2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级, 并发送告警;

(3)错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的 最大阀值,此时可以根据情况自动降级或者人工降级;

(4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。 服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要 的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查 询,而是直接返回默认值给用户。

七。如果redis正在给线上业务提供服务,那使用keys指令会有什么问题。

  Redis是单线程的,keys指令会导致线程阻塞一段时间,线上服务会停顿直到指令执行完毕,服务才能恢复,这个时候可以用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但会有一定的重复概率,在客户端做一次去重就好了,但是整体所花费的时间会比直接使用keys指令长。

八。简述Redis布隆过滤器底层原理

  将一个元素用多个哈希函数映射到一个位图中,被映射到的位置bit置为1。在查找时用这些哈希函数计算查找对象的每个哈希值对应位图的bit位置储存的是否为0,值要有一个零,就代表该对象一定不再位图中,否则的可能在。

 个人理解:底层维护的是一个二进制的数据。根据key值进行各种加密取模运算得出储存位置将值变为1,下次key来,当有客户端请求访问时,会先取布隆过滤器通过加密运算去模,查看二进制数据是否全部为   1,如果是则存在数据,如果有一个为0则不存在该数据。

九。redis Nx指令实现分布式锁就一定能保证原子性么,为什么

  不一定,

   1. setNx缺点就是拿到锁后没释放锁(服务突然崩溃),会导致后边取锁全部失败

   2. setnx 给锁加超时时间,缺点是如果同步块操作耗时比超时时间长会导致锁失效,后边的请求会并行执行

   3. setnx + watchdog 在锁快过期但是同步代码没执行完时给锁续期(redission封装好类似的功能,锁功能非常丰富)

十。redis的过期策略以及内存淘汰机制

redis采用的是定期删除+惰性删除策略

为什么不用定时删除策略? 定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。 在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.

定期删除+惰性删除是如何工作的呢?

定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是 每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂 不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了 过期时间那么是否过期了?如果过期了此时就会删除。

采用定期删除+惰性删除就没其他问题了么?

不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样, redis的内存会越来越高。那么就应该采用内存淘汰机制。 在redis.conf中有一行配置 该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己)

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰。

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。

no-enviction(驱逐):禁止驱逐数据,新写入操作会报错。

ps:如果没有设置expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

十一。Redis如何做内存优化

   尽可能使用散列表(hashes),散列表(是说散列表里的储存的数少)使用内存非常小,所以你应该尽可能将你的数据模型抽象到一个散列表里面。比如web系统中有一个用户对象,不要为这个用的名称,姓氏,邮箱等单独设置key,二十应该把这个用户的所有信息储存到一张散列表中。

十二。为什么Redis的操作是原子性的,怎么保证原子性的?

  对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。

      Redis的操作之所以是原子性的,是因为Redis是单线程的。 Redis本身提供的所有API都是原子操作,Redis中的事务其实是要保证批量操作的原子性。 多个命令在并发中也是原子性的吗? 不一定, 将get和set改成单命令操作,incr 。使用Redis的事务,或者使用Redis+Lua==的方式实现.

十三。Redis 为什么是单线程的

官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内 存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的 方案了(毕竟采用多线程会有很多麻烦!)Redis利用队列技术将并发访问变为串行访问

1)绝大部分请求是纯粹的内存操作(非常快速)

2)采用单线程,避免了不必要的上下文切换和竞争条 maxmemory-policy volatile-lru 件

3)非阻塞IO优点:

  •  速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度 都是O
  •  支持丰富数据类型,支持string,list,set,sorted set,hash
  •  支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
  •  丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除如何解决redis的并发

竞争key问题 同时有多个子系统去set一个key。这个时候要注意什么呢?

不推荐使用redis的事务机制。因为我们的 生产环境,基本都是redis集群环境,做了数据分片操作。你一个事务中有涉及到多个key操作的时候, 这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。

(1)如果对这个key操作,不要求顺序: 准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可

(2)如果对这个key操作,要求顺序: 分布式锁+时间戳。 假设这会系统B先抢到锁,将key1设置为 {valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操 作了。以此类推。

(3) 利用队列,将set方法变成串行访问也可以redis遇到高并发,如果保证读写key的一致性 对redis的操作都是具有原子性的,是线程安全的操作,你不用考虑并发问题,redis内部已经帮你处理好并 发的问题了。

十四。Redis事务

Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的 Redis会将一个事务中的所有命令序列化,然后按顺序执行。

1.redis 不支持回滚“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可 以保持简单且快速。

2.如果在一个事务中的命令出现错误,那么所有的命令都不会执行;

3.如果在一个事务中出现运行错误,那么正确的命令会被执行。

1)MULTI命令用于开启一个事务,它总是返回OK。 MULTI执行之后,客户端可以继续向服务器发送任 意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中 的命令才会被执行。

2)EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。

3)通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退 出。

4)WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。 可以监控一个或多个键,一旦其 中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。

十五。分布式redis。

redis问题思考:

  1. 假如某天这台redis服务器挂了,redis服务将彻底丧失

  2. redis的读和写都集中到一台机上,如果请求量比较大时,将可能被击溃

 分布式redis三种模式

  • 主从(复制)模式(redis2.8版本之前的模式)

  • 哨兵sentinel模式(redis2.8及之后的模式)

  • redis cluster集群模式(redis3.0版本之后)

1)主从模式

介绍:为了解决上述两个问题,redis提供了主从架构,在主从架构中,主服务器(master)可以进行读写操作,从服务器(slave)一般只进行读操作。缓解了单个redis服务器的压力;

主服务器将所有数据源源不断的同步到从服务器上,一旦主服务器挂了,还有从服务器可以提供服务,redis服务将不会间断。和Mysql主从复制的原因一样,Redis的主从结构可以采用一主多从或者级联结构。

同步类型与同步过程

 根据同步是否全量分为:全量同步和部分同步(增量同步)。

  • 全量同步 指主服务器每次与从服务器同步都是同步全部数据。主服务器持久化数据为一个rdb文件,在此期间用缓存区把所有对主服务器的写操作命令存储起来,然后再rdb传给从服务器,再把储存起来的命令也传过去;从服务器从接收到的rdb文件加载数据,然后再加载传过来的命令。

  • 部分同步 指主服务器每次与从服务器同步都是只同步增量数据。

 Redis的主从复制分为同步(sync)命令传播两个操作。我们向从服务器发送SLAVEOF命令(异步命令),从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成。步骤如下(全量同步),一般发生在SLAVE初始化阶段,需要将MASTER的数据全部复制一份:

(1)从服务器连接主服务器,发送SYNC命令;

(2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件,并使用缓冲区记录此后执行的所有写命令;

(3)主服务器BGSAVE执行完后,向【所有】从服务器发送快照文件,并在发送期间继续记录被执行的写命令;

(4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;

(5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;

(6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。

edis命令传播是指同步操作完毕后,开始正常工作时主服务器发生的写操作同步到从服务器的过程。命令传播的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

  • 主服务器通过向从服务器传播命令(主服务器执行的写命令)来更新从服务器的状态,保存主从服务器一致。

  • 从服务器则通过向主服务器发送命令(每秒发送1次REPLCONF ACK命令)来进行心跳检测。以此来检测主从服务器的网络连接状态和检测命令丢失。

主从复制的特点

  • 一台主服务器(也称为master node)可以连接多台从服务器(也称为slave node)
  • 从服务器也可以连接其他redis服务器,作为其他redis服务器的主服务器,从而形成一条链
  • 从服务器在复制的时候,不会阻塞主服务器的正常工作,同时也不会阻塞自己的查询操作,它会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了;
  • 从服务器主要用来进行横向扩容,做读写分离,提高读的吞吐量

主从复制的优缺点

优点(开始的两个问题):

  • 解决数据备份问题

  • 做到读写分离,提高服务器性能

缺点:

  • 每个客户端连接redis实例的时候都是指定了ip和端口号的,如果所连接的redis实例因为故障下线了,而主从模式也没有提供一定的手段通知客户端另外可连接的客户端地址,因而需要手动更改客户端配置重新连接

  • 主从模式下,如果主节点由于故障下线了,那么从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作

  • 无法实现动态扩容

2)哨兵Sentinel模式(基于主从模式)

使用哨兵模式进行主从替换与故障恢复!

Redis Sentinel 是一个分布式系统, 可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

  • 哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程(独立的redis节点,不存储数据,只支持部分命令),实际上是一个运行在特殊模式下的一个redis服务器,独立运行。

  • 哨兵与服务器之间会创建两个连接,命令连接和订阅连接,哨兵与哨兵之间只会创建命令连接。

  • 其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

  • 启动一个普通的redis服务器之后,通过--sentinel来启动Redis Sentinel

Redis 2.8版开始正式提供名为Sentinel的主从切换方案,通俗的来讲,Sentinel可以用来管理多个Redis服务器实例,可以实现一个功能上实现HA的集群,Sentinel主要负责三个方面的任务:

  • 监控:通过发送命令,不间断的监控Redis服务器运行状态,包括主服务器和从服务器。

  • 提醒:当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

  • 自动故障迁移(核心任务):当哨兵监测到主服务器宕机,会自动在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器将其转换为主服务器(自动切换)。然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

多哨兵模式:一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,多哨兵可以防止误判并且使整个哨兵集合更加健壮。

用文字描述一下故障切换(failover)的过程。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。

当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。

对于不可用描述术语总结:

  • 主观下线(SDOWN):单个哨兵实例对主节点做出下线判断。

  • 客观下线(ODOWN):多个哨兵实例对主节点做出下线判断。

  • 主节点有主观和客观下线,从节点只有主观下线

领导者哨兵选举流程:

当确定redis服务器确实挂了以后,哨兵要进行故障转移,并且只能有一个哨兵去完成该操作,所以这时候就要选举出一名哨兵来当此重任。

  • 每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵3)主节点下线时,会向其它哨兵发is-master-down-by-addr命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;

  • 当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者;

  • 如果哨兵3发现自己在选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举…………

讲讲slave->master选举算法(怎么完成故障迁移)

如果master被判odown了,大部分哨兵允许主备切换,那么需要选举一个slave,依次考虑如下:

  • 看slave-priority:选择slave优先级最高的;

  • 看offset:选择复制offset(偏移量)最大的,指复制最完整的从节点

  • 看runid:程序id,就选runid最小的,越早开启的

自动发现机制(三个定时任务)

监控redis服务器的运行状态:

  • 以10秒一次的频率,向被监控的master发送Info命令,根据回复获取当前master信息。这个任务达到两个目的:发现slave节点和确定主从关系

  • 以1秒一次的频率,向所有的redis服务器包括 Sentinel 发送ping命令,通过回复判断服务器是否在线,这个其实是一个心跳检测,是失败判定的依据。

  • 以2秒一次的频率,向master节点的channel交换信息(pub/sub)。master节点上有一个发布订阅的频道(__sentinel__:hello)。sentinel节点通过__sentinel__:hello频道进行信息交换(对节点的"看法"和自身的信息),达成共识。

哨兵模式的优缺点

优点:

  • 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都有。

  • 主从可以自动切换,系统更健壮,可用性更高

缺点:

  • redis较难支持在线扩容,在集群容量达上限时在线扩容变的很复杂。

ps:“高可用性”(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性。

3)Redis Cluster集群模式

1. redis 集群模式的工作原理能说一下么?在集群模式下,****redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?

工作原理:

集群是Redis提供的分布式数据库方案,集群通过分片来进行数据共享,并提供复制和故障转移功能。一个Redis集群通常由多个节点组成;最初,每个节点都是独立的,需要将独立的节点连接起来才能形成可工作的集群。

Redis Cluster并没有使用一致性hash,而是采用hash slot(哈希槽) 算法,一共分成16384个槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽(每个节点对应若干个槽)。

关键点:

  • 自动将数据进行分片(通过hash方式),每个 master 上放一部分数据(均分存储一定哈希槽区间的数据),先写入主节点,再写入从节点。注:同一分片多个节点间的数据不保持一致性

  • 提供内置的高可用支持,部分 master 不可用时(注意:key找的是哈希槽),还是可以继续工作的,哈希槽会迁移。将请求发送到任意节点(这个key可能不在这个节点上),接收到请求的节点会将查询请求发送到正确的节点上执行(返回转向指令)。

redis cluster架构下的每个redis都要开放两个端口号,比如一个是6379,另一个就是加1w的端口号16379。

  • 6379端口号就是redis服务器入口。

  • 16379端口号是用来进行节点间通信的,也就是 cluster bus 的东西,cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。cluster bus 用的是一种叫gossip 协议的二进制协议,用于节点间高效的数据交换,占用更少的网络带宽和处理时间。

节点间的内部通信机制

写在前:任何文件系统中的数据分为数据和元数据。数据是指普通文件中的实际数据,而元数据指用来描述一个文件的特征的系统数据,诸如访问权限、文件拥有者以及文件数据块的分布信息(inode...)等等。

在集群文件系统中,分布信息包括文件在磁盘上的位置以及磁盘在集群中的位置。用户需要操作一个文件必须首先得到它的元数据,才能定位到文件的位置并且得到文件的内容或相关属性。

基本通信原理,集群元数据的维护有两种方式:集中式、Gossip 协议(分布式)。redis cluster 节点间采用 gossip 协议进行通信。

  • 集中式管理:集中式是将集群元数据(节点信息、故障等等)集中存储在某个节点上。集中式元数据集中存储的一个典型代表,就是大数据领域的 storm。它是分布式的大数据实时计算引擎,是集中式的元数据存储的结构,底层基于 zookeeper(分布式协调的中间件)对所有元数据进行存储维护。

    优缺点:元数据的读取和更新,时效性非常好,一旦元数据出现了变更,就立即更新到集中式的存储中,其它节点读取的时候就可以感知到;但可能会存在存储压力和单点失效问题。

  • 分布式管理:redis 维护集群元数据采用另一个方式, gossip 协议:所有节点都持有一份元数据,不同的节点如果出现了元数据的变更,就不断将元数据发送给其它的节点,让其它节点也进行元数据的变更。

    优缺点:元数据存储比较分散,降低了元数据存储压力;但元数据更新会延迟,可能导致集群中的一些操作会有一些滞后,实现较复杂,一致性维护复杂。

十六。为什么Rdeis需要把所有数据放到内存中。

  Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。 如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

十七。有哪些方法可以降低Rdeis的内存使用情况。

      1. 如果使用的是32位的Redis实例,可以好好利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的key- value可以用更紧凑的方式存放,例如用户信息有姓名,年龄,存储的时候直接从hash方式用 user 方式,不要单独set name  ,set  age这种方式。

      2。短结构。

      3。分片结构

      参考: https://www.cnblogs.com/manfuzhuji/p/14359611.html

posted @   风光小磊  阅读(56)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示