Redis面试题

  1. 什么是redis?
    Redis 是完全开源免费的,是一个高性能的key-value数据库。它可以用作数据库、缓存和消息中间件。 
    Redis 与其他 key - value 缓存产品有以下三个特点:
    1. Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
    2. Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
    3. Redis支持数据的备份,即master-slave模式的数据备份。
  2. Redis是单进程单线程
    redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销
    也就能实现分布式锁的一个原因
  3. Reids的特点  
    1. Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。
    2. Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一个功能加强版的memcached来用。
    3. Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
  4. 使用redis有哪些好处?   
    1. 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) 
    2. 支持丰富数据类型,支持string,list,set,sorted set,hash 
    3. 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 
    4. 丰富的特性:可用于缓存,消息队列,按key设置过期时间,过期后将会自动删除
  5. redis相比memcached有哪些优势?   
    1. memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 
    2. redis的速度比memcached快很多
    3. redis可以持久化其数据
  6. Memcache与Redis的区别都有哪些? 
    1. 存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。 
    2. 数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。 
    3. 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。 
  7. Redis与其他key-value存储有什么不同?
    Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

    Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
  8. 一个字符串类型的值能存储最大容量是多少?
    值的长度不能超过512 MB
  9. 一个Redis实例最多能存放多少的keys?
    官方说单例能处理key:2.5亿个,一个key或是value大小最大是512M。
    List、Set、Sorted Set他们最多能存放多少元素? 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
  10. Redis支持的Java客户端都有哪些?
    官方推荐用哪个?Redisson,Jedis,lettuce等等,官方推荐使用Redisson
  11. 说说Redis哈希槽的概念?
    https://www.cnblogs.com/zhuifeng-mayi/p/9306998.html
  12. 查看Redis使用情况及状态信息用什么命令?
    INFO
  13. 修改配置不重启Redis会实时生效吗?
    不需要
  14. 为什么redis需要把所有数据放到内存中?
    Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。
    如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。
  15. 怎么查看redis中的数据?
    可以使用可视化工具
  16. redis发布订阅是工作原理是什么?
    Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
    Redis 客户端可以订阅任意数量的频道。
  17. redis脚本使用什么来执行?常用命令是什么?
    redis脚本使用lua解释器来执行脚本。redis 2.6版本通过内嵌支持lua环境。
    执行脚本的常用命令为eval。
    语法:eval命令的基本语法如下: redis 127.0.0.1:6379> eval script numkeys [key...] arg [arg...]
  18. 什么是redis管道技术?redis管道技术有什么作用?我们提高redis服务性能可以使用什么技术? 
    一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。这就是管道(pipelining)
    Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。
    这意味着通常情况下一个请求会遵循以下步骤:
    1. 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
    2. 服务端处理命令,并将结果返回给客户端。

      redis管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
      redis管道技术最显著的的优势是提高了redis的服务性能。
      使用redis管道技术
  19. Redis如何做内存优化?都有哪些办法可以降低Redis的内存使用情况呢?
    1. 尽可能使用散列表(hashes)
      小散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面.
    2. 如果 maxmemory 没有设置,redis就会一直向OS申请内存,直到OS的所有内存都被使用完。所以通常建议设置上redis的内存限制。
      设置了maxmemory后,当redis的内存达到内存限制后,再向redis发送写指令,会返回一个内存耗尽的错误。错误通常会触发一个应用程序错误,但是不会导致整台机器宕掉.

20.事务

1.redis事务的作用?redis事务需要保证什么?一个事务从开始到执行会经历哪几个阶段?
redis事务可以一次执行多个命令。
两个重要保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

一个事务从开始到执行会经历以下三个阶段:

  1. 开始事务。
  2. 命令入队。
  3. 执行事务。

事务的几个重要命令:

  • multi 标记一个事务块的开始
  • discard 取消事务,放弃执行事务块内的所有命令
  • exec 执行所有事务块内的命令

最重要的是记住这样一条, 即使事务中有某条/某些命令执行失败了, 事务队列中的其他命令仍然会继续执行 —— Redis 不会停止执行事务中的命令。

2.为什么 Redis 不支持回滚(roll back)

如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。

以下是这种做法的优点:

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

3.使用 check-and-set 操作实现乐观锁

WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。

被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。 并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。

 

22.过期expire 

1.规则:

  1. 未设置过期:通常Redis keys创建时没有设置相关过期时间。他们会一直存在,除非使用显示的命令移除,例如,使用DEL命令。
  2. 设置了过期:设置key的过期时间,超过时间后,将会自动删除该key。超时后只有对key执行DEL命令或者SET命令或者GETSET时才会清除。 这意味着,从概念上讲所有改变key的值的操作都会使他清除。
  3. 永久不过期:使用 persist  命令可以清除超时,使其变成一个永久的key
  4. rename 命令:如果key rename命令修改,相关的超时时间会转移到新key上面。
    例如:如果key 使用rename命令修改,比如原来就存在Key_A,然后调用RENAME Key_B Key_A命令,这时不管原来Key_A是永久的还是设置为超时的,都会由Key_B的有效期状态覆盖。
  5. 重新设置过期:对已经有过期时间的key执行EXPIRE操作,将会更新它的过期时间。

2. Redis如何淘汰过期的keys

Redis keys过期有两种方式:被动和主动方式。

  • 被动:当一些客户端尝试访问它时,key会被发现并主动的过期。
  • 主动
    当然,这样是不够的,因为有些过期的keys,永远不会访问他们。 无论如何,这些keys应该过期,所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。
    具体就是Redis每秒10次做的事情:
    1. 测试随机的20个keys进行相关过期检测。
    2. 如果有多于25%的keys过期,删除所有已经过期的keys。(lru算法)
    3. 重复步奏1.

这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys。

3. 在复制AOF文件时如何处理过期
为了获得正确的行为而不牺牲一致性,当一个key过期,DEL将会随着AOF文字一起合成到所有附加的slaves。在master实例中,这种方法是集中的,并且不存在一致性错误的机会。
然而,当slaves连接到master时,不会独立过期keys(会等到master执行DEL命令),他们任然会在数据集里面存在,所以当slave当选为master时淘汰keys会独立执行,然后成为master。

4. 过期(Expires):Redis允许为每一个key设置不同的过期时间,当它们到期时将自动从服务器上删除。有哪些命令?

  1. expire key time  设置主键过期的时间 ,设置成功返回 1;当 key 不存在或者不能为 key 设置生存时间时,返回 0 。
  2. ttl key查询主键过期的剩余的时间
  3. presist key 设置主键永久不过期

 

23.redis的缓存失效策略*

当Redis被当做缓存来使用,当你新增数据时,让它自动地回收旧数据是件很方便的事情。LRU是Redis唯一支持的回收方法。

作为缓存系统都要定期清理无效数据,就需要一个缓存失效策略.

  1. 第一步:最大缓存配置
    maxmemory配置指令用于配置Redis存储数据时指定限制的内存大小。通过redis.conf可以设置该指令,或者之后使用CONFIG SET命令来进行运行时配置。
    设置maxmemory为0代表没有内存限制。对于64位的系统这是个默认值,对于32位的系统默认内存限制为3GB。如果有新的数据添加,超过最大内存,则会使redis崩溃,所以一定要设置
    当指定的内存限制大小达到时,就会实行数据淘汰策略
  2. 第二步:设置失效策略:
    当maxmemory限制达到的时候Redis会使用的行为由 Redis的maxmemory-policy配置指令来进行配置。
    以下6种数据淘汰策略是可用的:
    1. noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外),也就是不回收策略
    2. allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
    3. volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
    4. allkeys-random: 回收随机的键使得新添加的数据有空间存放。
    5. volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
    6. volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

      volatile和allkeys规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据
  3. 策略选取一般的经验规则:
    1. 使用allkeys-lru策略:当你希望你的请求符合一个幂定律分布,也就是说,你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么,这是个很好的选择。
    2. 使用allkeys-random:如果你是循环访问,所有的键被连续的扫描,或者你希望请求分布正常(所有元素被访问的概率都差不多)。
    3. 使用volatile-ttl:如果你想要通过创建缓存对象时设置TTL值,来决定哪些对象应该被过期。

      allkeys-lru 和 volatile-random策略对于当你想要单一的实例实现缓存及持久化一些键时很有用。不过一般运行两个实例是解决这个问题的更好方法。

      为了键设置过期时间也是需要消耗内存的,所以使用allkeys-lru这种策略更加高效,因为没有必要为键取设置过期时间当内存有压力时。
  4. Redis回收进程如何工作的?理解回收进程如何工作是非常重要的:
    1. 一个客户端运行了新的命令,添加了新的数据。
    2. Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
    3. 一个新的命令被执行,等等。
    4. 所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。
  5. Redis的内存用完了会发生什么?
    如果没有设置maxmemory,用完后崩溃。
    如果设置了maxmeory,用完后会返回错误或者执行回收策略。

24. mySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

 

25.Redis持久化

1.Redis 提供了两种持久化方式:

  1. RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
  2. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
  3. 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
  4. 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.

2.RDB的优点

  • RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.
  • RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心,非常适用于灾难恢复.
  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.

RDB的缺点

  • 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.
  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.

工作方式

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

  • Redis 调用forks. 同时拥有父进程和子进程。
  • 子进程将数据集写入到一个临时 RDB 文件中。
  • 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。

RDB开启方式

  • 在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。
    save 900 1   //15min内有1个键被改动
    save 300 10  //5min内有10个键被改动
    save 60 10000//60 秒内有至少有 1000 个键被改动
    
  • 调用 SAVE或者 BGSAVE , 手动让 Redis 进行数据集保存操作。

3.AOF 优点

  • 使用AOF 会让你的Redis更加耐久: 
    AOF有多耐用? 你可以配置 Redis 多久才将数据 fsync 到磁盘一次。有三种方式:
    • 每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全
    • 每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。
    • 从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。
    • 推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。
  • 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)。

工作原理

AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

  • Redis 执行 fork() ,现在同时拥有父进程和子进程。
  • 子进程开始将 现有 AOF 文件的内容写入到临时文件(新文件)。
  • 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
  • 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
  • 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。

AOF开启方式

  • 你可以在配置文件中打开AOF方式:
    appendonly yes
  • 手动执行 BGREWRITEAOF 命令可以重写
  • 配置可以自动触发 AOF 重写
    当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage参数,不设置默认为100%)

4.如何选择使用哪种持久化方式?

  • 一般来说, 如果要保证 的数据安全性, 你应该同时使用两种持久化功能。
  • 如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
  • 有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。

AOF如何缩减自身文件大小

AOF缩减自身文件大小的时候,数据库来了新的操作怎么办?

redis用的哪个版本

如何搭建redis集群

redis如何主从同步

redis分布式锁注意事项

redis持久化的方式以及区别

redis持久化方式及区别


 

26.分区

分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。

分区的优势:
    1.通过利用多台计算机内存和值,允许我们构造更大的数据库;
    2.通过多核和多台计算机,允许我们扩展计算能力;
    3.通过多台计算机和网络适配器,允许我们扩展网络带宽。

分区的不足:

redis的一些特性在分区方面表现的不是很好:

  1. 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对着两个set执行交集操作。
  2. 涉及多个key的redis事务不能使用;
  3. 当使用分区时,数据处理较为复杂。比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件;
  4. 增加和删除容器也比较复杂。redis集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做persharding的技术对此是有帮助的。

分区类型
Redis 有两种类型分区。 假设有4个Redis实例 R0,R1,R2,R3,和类似user:1,user:2这样的表示用户的多个key,对既定的key有多种不同方式来选择这个key存放在哪个实例中。也就是说,有不同的系统来映射某个key到某个Redis服务。

  1. 范围分区
    最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的Redis实例。
    比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。
    这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法。
  2. 哈希分区
    hash分区:另外一种分区方法是hash分区。这对任何key都适用,也无需是object_name:这种形式,像下面描述的一样简单:
    用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数。对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现。

 

27.Redis如何设置密码及验证密码?

默认情况下 requirepass 参数是空的,这就意味着你无需通过密码验证就可以连接到 redis 服务。

查看是否设置了密码验证:127.0.0.1:6379> CONFIG get requirepass
设置密码:CONFIG set requirepass "w3cschool.cc"
验证密码:127.0.0.1:6379> AUTH password

28.java怎么使用redis

  1. 确保你的机器能够正常使用java。
  2. 安装redis服务。
  3. 下载java  redis驱动(jedis.jar最新驱动包)
  4. 在你的classpath中包含该驱动包。
  5. 连接本地redis服务
  6. //连接本地的 Redis 服务
    Jedis jedis = new Jedis("localhost");

29.redis 最适合的场景  

  1. 会话缓存(Session Cache)
    最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?
    幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。
  2. 全页缓存(FPC)
    除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。
      再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。
      此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
  3. 队列
      Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
      如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。
  4. 排行榜/计数器
      Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:
      当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
      ZRANGE  user_scores  0 10  WITHSCORES
      Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。
  5. 发布/订阅
      最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。
      Redis提供的所有特性中,我感觉这个是喜欢的人最少的一个,虽然它为用户提供如果此多功能。

30.redis常见性能问题和解决方案:   

  1. Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照
  2. Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
  3. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
  4. Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。

 

31.复制(主从复制)

  1. 概念
    在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。
  2. 这个系统的运行依靠三个主要的机制:
    1. 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave :包括客户端的写入、key 的过期或被逐出等等。
    2. 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
    3. 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。
  3.  Redis 复制的非常重要的事实
    1. Redis 使用异步复制,slave 和 master 之间异步地确认处理的数据量
    2. 一个 master 可以拥有多个 slave
    3. slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构(cascading-like structure)连接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到完全一样的复制流。
    4. Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
    5. 复制在 slave 侧大部分也是非阻塞的。当 slave 进行初次同步时,它可以使用旧数据集处理查询请求,假设你在 redis.conf 中配置了让 Redis 这样做的话。否则,你可以配置如果复制流断开, Redis slave 会返回一个 error 给客户端。但是,在初次同步之后,旧数据集必须被删除,同时加载新的数据集。 slave 在这个短暂的时间窗口内(如果数据集很大,会持续较长时间),会阻塞到来的连接请求。自 Redis 4.0 开始,可以配置 Redis 使删除旧数据集的操作在另一个不同的线程中进行,但是,加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave 。
    6. 复制既可以被用在可伸缩性,以便只读查询可以有多个 slave 进行(例如 O(N) 复杂度的慢操作可以被下放到 slave ),或者仅用于数据安全。
    7. 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf 以避免对磁盘进行持久化,然后连接一个 slave ,其配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。
  4. 当 master 关闭持久化时,复制的安全性
    在使用 Redis 复制功能时的设置中,强烈建议在 master 和在 slave 中启用持久化。当不可能启用时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重置后自动重启

    为了更好地理解为什么关闭了持久化并配置了自动重启的 master 是危险的,检查以下故障模式,这些故障模式中数据会从 master 和所有 slave 中被删除:
    1. 我们设置节点 A 为 master 并关闭它的持久化设置,节点 B 和 C 从 节点 A 复制数据。
    2. 节点 A 崩溃,但是他有一些自动重启的系统可以重启进程。但是由于持久化被关闭了,节点重启后其数据集合为空。
    3. 节点 B 和 节点 C 会从节点 A 复制数据,但是节点 A 的数据集是空的,因此复制的结果是它们会销毁自身之前的数据副本。

      当 Redis Sentinel 被用于高可用并且 master 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, master 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。

      任何时候数据安全性都是很重要的,所以如果 master 使用复制功能的同时未配置持久化,那么自动重启进程这项应该被禁用。
  5. 复制操作

    只需要将以下内容加进 slave 的配置文件:
    当然你需要用你自己的 master IP 地址(或者主机名)和端口替换掉 192.168.1.1 6379。

    slaveof 192.168.1.1 6379

  6. 下面是一个全量同步的工作细节:
    1. master 开启一个后台保存进程,以便于生产一个 RDB 文件。同时它开始缓冲所有从客户端接收到的新的写入命令
    2. 当后台保存完成时, master 将数据集文件传输给 slave, slave将之保存在磁盘上,然后加载文件到内存。
    3. 再然后 master 会发送所有缓冲的命令发给 slave。
  7. 操作注意
    1. 只读性质的 slave
      自从 Redis 2.6 之后, slave 支持只读模式且默认开启。redis.conf 文件中的 slave-read-only 变量控制这个行为,且可以在运行时使用 CONFIG SET 来随时开启或者关闭。
    2. 允许只写入 N 个附加的副本

      从Redis 2.8开始,只有当至少有 N 个 slave 连接到 master 时,才有可能配置 Redis master 接受写查询。
    3. 设置一个 slave 对 master 进行验证
      1. 如果你的 master 通过 requirepass 设置了密码,则在所有同步操作中配置 slave 使用该密码是很简单的。

        要在正在运行的实例上执行此操作,请使用 redis-cli 并输入:

        config set masterauth <password>

        要永久设置的话,请将其添加到您的配置文件中:

        masterauth <password>

  8. Redis 复制如何处理 key 的过期
    Redis 使用三种主要的技术使过期的 key 的复制能够正确工作
    1. slave 不会让 key 过期,而是等待 master 让 key 过期。当一个 master 让一个 key 到期(或由于 LRU 算法将之驱逐)时,它会合成一个 DEL 命令并传输到所有的 slave。
    2. 但是,由于这是 master 驱动的 key 过期行为,master 无法及时提供 DEL 命令,所以有时候 slave 的内存中仍然可能存在在逻辑上已经过期的 key 。为了处理这个问题,slave 使用它的逻辑时钟以报告只有在不违反数据集的一致性的读取操作(从主机的新命令到达)中才存在 key。用这种方法,slave 避免报告逻辑过期的 key 仍然存在。在实际应用中,使用 slave 程序进行缩放的 HTML 碎片缓存,将避免返回已经比期望的时间更早的数据项。
    3. 在Lua脚本执行期间,不执行任何 key 过期操作。当一个Lua脚本运行时,从概念上讲,master 中的时间是被冻结的,这样脚本运行的时候,一个给定的键要么存在要么不存在。这可以防止 key 在脚本中间过期,保证将相同的脚本发送到 slave ,从而在二者的数据集中产生相同的效果。
    4. 一旦一个 slave 被提升为一个 master ,它将开始独立地过期 key,而不需要任何旧 master 的帮助。
  9. 重新启动和故障转移后的部分重同步
  10. 从 Redis 4.0 开始,当一个实例在故障转移后被提升为 master 时,它仍然能够与旧 master 的 slaves 进行部分重同步。为此,slave 会记住旧 master 的旧 replication ID 和复制偏移量,因此即使询问旧的 replication ID,其也可以将部分复制缓冲提供给连接的 slave 。

    但是,升级的 slave 的新 replication ID 将不同,因为它构成了数据集的不同历史记录。例如,master 可以返回可用,并且可以在一段时间内继续接受写入命令,因此在被提升的 slave 中使用相同的 replication ID 将违反一对复制标识和偏移对只能标识单一数据集的规则。

    另外,slave 在关机并重新启动后,能够在 RDB 文件中存储所需信息,以便与 master 进行重同步。这在升级的情况下很有用。当需要时,最好使用 SHUTDOWN 命令来执行 slave 的保存和退出操作。

 

32.集群

1.什么是redis集群?什么是节点?命令格式?原理?

  • 一个 Redis 集群通常由多个节点(node)组成, 在刚开始的时候, 每个节点都是相互独立的, 它们都处于一个只包含自己的集群当中, 要组建一个真正可工作的集群, 我们必须将各个独立的节点连接起来, 构成一个包含多个节点的集群。
  • 节点是运行在集群模式下的 Redis 服务器
  • 连接各个节点的工作可以使用 CLUSTER MEET 命令来完成, 该命令的格式如下:
    CLUSTER  MEET  <ip> <port>
  • 向一个节点 node 发送 CLUSTER MEET 命令, 可以让 node 节点与 ip 和 port 所指定的节点进行握手(handshake), 当握手成功时, node节点就会将 ip 和 port 所指定的节点添加到 node 节点当前所在的集群中。

复制(仅仅复制原理)、主备(复制+哨兵监控,主节点出错,哨兵将故障转移)、集群(复制+哨兵的结合)

Redis集群的主从复制模型是怎样的?

Redis集群会有写操作丢失吗?为什么?

Redis集群之间是如何复制的?

Redis集群最大节点个数是多少?

Redis集群如何选择数据库?

Redis集群方案应该怎么做?都有哪些方案?

Redis集群方案什么情况下会导致整个集群不可用?

分布式Redis是前期做还是后期规模上来了再做好?为什么?

53、什么是高可用分布式集群?什么高可用?什么是分布式?
https://blog.csdn.net/guchuanyun111/article/details/52092479

 

33.为什么redis可以实现分布式锁?

不同的进程必须以独占资源的方式实现资源共享

1.首先Redis是单线程的,这里的单线程指的是网络请求模块使用了一个线程(所以不需要考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。如果使用redis实现分布式,请使用redission的jar包,而不是使用jedis包。

34.redis实现分布式锁的方式

实现Redis分布式锁的最简单的方法就是在Redis中创建一个key,这个key有一个失效时间(TTL),以保证锁最终会被自动释放掉(这个对应特性2)。当客户端释放资源(解锁)的时候,会删除掉这个key。

3个必要条件:

  1. 加锁
  2. 解锁
  3. 不会死锁
  4. 可重入
  5. 阻塞

方式:

  • 单Redis实例实现分布式锁的正确方法
    1. 获取锁使用命令:
          SET resource_name my_random_value NX PX 30000
      这个命令仅在不存在key的时候才能被执行成功(NX选项),并且这个key有一个30秒的自动失效时间(PX属性)。这个key的值是“my_random_value”(一个随机值),这个值在所有的客户端必须是唯一的,所有同一key的获取者(竞争者)这个值都不能一样。
    2. 解锁
      value的值必须是随机数主要是为了更安全的释放锁,释放锁的时候使用脚本告诉Redis:只有key存在并且存储的值和我指定的值一样才能告诉我删除成功。可以通过以下Lua脚本实现:
      if redis.call("get",KEYS[1]) == ARGV[1] then
          return redis.call("del",KEYS[1])
      else
          return 0
      end
  • (N)个Redis实例上使用此方法获取和释放锁来实现分布式锁

    N个Redis master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。
    1. 从N个实例,使用相同的key和随机值获取锁,并设置过期时间
    2. 释放锁比较简单,向所有的Redis实例发送释放锁命令即可,不用关心之前有没有从Redis实例成功获取到锁.
    3. 如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。
  • 主从节点实现分布式锁
  • redis集群实现分布式锁

34.zookeeper为什么可以实现分布式锁?

zookeeper是一个分布式的、开放源码的分布式应用协调服务,是Hadoop和HBase的重要组件。

 

对于缓存而言,

  1. 约束好key的规范,合理确定Val值的大小,来选择缓存的介质(相应的根据实际的业务情况分析,哪种缓存方式合适 redis、zk、memcached 亦或者 local)。(生产实际案例:redis做缓存,因Val值过大的key太多,导致reids的性能出现了问题,造成业务不可用)
  2. 合理分配缓存失效时间(缓存是物理有失效时间 ? 亦或者 在缓存的对象里增加一个虚拟的失效时间,而物理上是没有过期时长的或比较长的过期时间)
  3. 缓存没值,是继续轮询获取呢? 还是暂缓本次获取(retry 次数和超时时间)?还是竞争锁去查db呢?
  4. 合理加锁控制分布式下全局单线程查询DB写缓存操作

缓存穿透

缓存穿透是指查询一个一不存在的数据。例如:从缓存redis没有命中,需要从mysql数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。

解决思路:

如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。设置一个过期时间或者当有值的时候将缓存中的值替换掉即可。

可以给key设置一些格式规则,然后查询之前先过滤掉不符合规则的Key。

https://www.jb51.net/article/163820.htm

缓存雪崩

指的是大量缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

解决办法

  1. 这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布,设置不同的过期时间。
  2. 设置一个合适的缓存失效策略(allkey-lua策略)
  3. 用加分布布式锁或者分布式队列的方式保证缓存的单线程(进程)写 (eg. redis的 SETNX),从而避免失效时大量的并发请求落到底层存储系统上。在加锁方法内先从缓存中再获取一次(防止另外的线程优先获取锁已经写入了缓存),没有再查DB写入缓存。 (当然也可以: 在没有获取锁(tryLock)的线程中一直轮询缓存,至超限时)

缓存击穿

指的是热点key在某个特殊的场景时间内恰好失效了,恰好有大量并发请求过来了,造成DB压力。

解决方案

  1.  使用互斥锁(mutex key)

    业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
  2. "提前"使用互斥锁(mutex key):

    在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。
  3.  "永远不过期":  
    这里的“永远不过期”包含两层意思:
    1. 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
    2. 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期
  4. 资源保护:

    采用netflix的hystrix,可以做资源的隔离保护主线程池,如果把这个应用到缓存的构建也未尝不可

 

redis用的哪个版本

如何搭建redis集群

redis如何主从同步

redis分布式锁注意事项

redis持久化方式及区别

在项目中怎么使用redis、键值保存方式、缓存什么信息(订单信息),项目中使用redis需要注意什么。百度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值