吊打面试官之redis篇:一文全懂redis

目录

基本知识

数据类型

持久化

内存相关

线程模型

事务

集群方案

redis集群搭建各种方案了解及优缺点对比:

一. Redis 单副本

二. Redis多副本( 主从 )

三. Redis Sentinel (哨兵)

四. Redis Cluster

redis集群搭建

主从模式

哨兵模式环境搭建

集群模式

Redis 主从架构

分区

分布式问题

缓存异常

常用工具

其他问题

redis配置文件


以下全文为本人学习时整理的资料,如侵权,请联系整改!

基本知识

1.什么是 Redis?

  Redis是一款内存高速缓存数据库,使用C语言编写,Redis是一个key-value存储系统(键值存储系统),支持丰富的数据类型,如:String、list、set、zset、hash。基于内存,可持久化

2. Redis 有哪些优缺点?

优点:

  • 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
  • 支持丰富数据类型,支持string,list,set,sorted set,hash
  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
  • 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
  • 支持数据持久化,支持AOF和RDB两种持久化方式。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点:
  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
  • Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  •  Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。

3.为什么要用 Redis / 为什么要用缓存?

举例:用户a访问系统,请求数据库耗时600ms,用户b访问系统,同样的请求耗时600ms,所以就出现了问题,同样的请求,如果并发量上千成万,每个用户都600ms极大的影响了用户体验,而且,数据库短时间接收大量请求可能会挂掉,所以我们在用户访问系统时,先去缓存中查询,如果缓存中存在就直接从缓存中获取的,从缓存中获取数据的速度比从数据库中获取数据的速度快很多。
 
所以用缓存,主要是为了提高性能和防止高并发。如果数据被多次重复访问,这时我们就可以的考虑的添加缓存了
 

4.为什么要用 Redis 而不用 map/guava 做缓存?

  缓存分为本地缓存和分布式缓存。以 Java 自带的 map 或者 guava为例子, 实现的是本地缓存,最主要的特点是(1)轻量以及快速,生命周期随着 jvm 的销毁而结束,(2)并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。 

  使用 redis 或 memcached 之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。缺点是需要保持 redis 或 memcached服务的高可用,整个程序架构上较为复杂。

主要分为以下几点区别:

  • Redis 可以用几十 G 内存来做缓存,Map 不行,一般 JVM 也就分几个 G 数据就够大了;
  • Redis 的缓存可以持久化,Map 是内存对象,程序一重启数据就没了;
  • Redis 可以实现分布式的缓存,Map 只能存在创建它的程序里;
  • Redis 可以处理每秒百万级的并发,是专业的缓存服务,Map 只是一个普通的对象;
  • Redis 缓存有过期机制,Map 本身无此功能;
  • Redis 有丰富的 API,Map 就简单太多了;
  • redis可单独部署,多个项目之间可以空想,本地内存无法共享;redis有专门的管理工具可以查看缓存数据;
 

5.Redis 为什么这么快?

  • 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。
  • 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
  • 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU;
  • 使用多路I/O复用模型,非阻塞IO;
  • 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

数据类型

6.Redis 有哪些数据类型?

  • String;一般做一些复杂的计数功能的缓存。
  • Hash;
  • List;使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好
  • Set;可以做全局去重的功能,为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
  • SortedSet。以做排行榜应用,取TOP N操作

redis string 是怎么实现的?

Redis 的常用5种数据结构,Redis持久化策略,Redis实现分布式锁,简单发布订阅等等

面试官 :看你简历上写了熟悉常用数据结构,都有哪些说说

本人 :常用有5种,string,list,set,zset,hash(内心很得意)

面试官 :那你说说都用过哪些数据结构

本人 :用的最多的是string,通常会把json字符串存进去

面试官 :那你知道Redis内部是怎么实现它的string的么?

本人 :呃~,我了解Redis是用C语言写的,至于具体实现就不清楚了~

Redis字符串的实现

Redis虽然是用C语言写的,但却没有直接用C语言的字符串,而是自己实现了一套字符串。目的就是为了提升速度,提升性能,可以看出Redis为了高性能也是煞费苦心。

Redis构建了一个叫做简单动态字符串(Simple Dynamic String),简称SDS

1.SDS 代码结构

struct sdshdr{

    //  记录已使用长度

    int len;

    // 记录空闲未使用的长度

    int free;

    // 字符数组

    char[] buf;

};

SDS ?什么鬼?可能对此陌生的朋友对这个名称有疑惑。只是个名次2而已不必在意,我们要重点欣赏借鉴Redis的设计思路。

下面画个图来说明,一目了然。

Redis的字符串也会遵守C语言的字符串的实现规则,即最后一个字符为空字符。然而这个空字符不会被计算在len里头。

2.SDS 动态扩展特点

SDS的最厉害最奇妙之处在于它的Dynamic。动态变化长度。举个例子

如上图所示刚开始s1 只有5个空闲位子,后面需要追加' world' 6个字符,很明显是不够的。那咋办?Redis会做一下三个操作:

  • 计算出大小是否足够

  • 开辟空间至满足所需大小

  • 开辟与已使用大小len相同长度的空闲free空间(如果len < 1M)开辟1M长度的空闲free空间(如果len >= 1M)

看到这儿为止有没有朋友觉得这个实现跟Java的列表List实现有点类似呢?看完后面的会觉得更像了。

Redis字符串的性能优势

  • 快速获取字符串长度

  • 避免缓冲区溢出

  • 降低空间分配次数提升内存使用效率

1.快速获取字符串长度

在看下上面的SDS结构体:

struct sdshdr{

    //  记录已使用长度

    int len;

    // 记录空闲未使用的长度

    int free;

    // 字符数组

    char[] buf;

};

由于在SDS里存了已使用字符长度len,所以当想获取字符串长度时直接返回len即可,时间复杂度为O(1)。如果使用C语言的字符串的话它的字符串长度获取函数时间复杂度为O(n),n为字符个数,因为他是从头到尾(到空字符'\0')遍历相加。

2.避免缓冲区溢出

对一个C语言字符串进行strcat追加字符串的时候需要提前开辟需要的空间,如果不开辟空间的话可能会造成缓冲区溢出,而影响程序其他代码。如下图,有一个字符串s1="hello" 和 字符串s2="baby",现在要执行strcat(s1,"world"),并且执行前未给s1开辟空间,所以造成了缓冲区溢出。

 

 

而对于Redis而言由于每次追加字符串时都会检查空间是否够用,所以不会存在缓冲区溢出问题。每次追加操作前都会做如下操作:

  • 计算出大小是否足够

  • 开辟空间至满足所需大小

3.降低空间分配次数提升内存使用效率

字符串的追加操作会涉及到内存分配问题,然而内存分配问题会牵扯内存划分算法以及系统调用所以如果频繁发生的话影响性能,所以对于性能至上的Redis来说这是万万不能忍受的。所以采取了一下两种优化措施

  • 空间与分配

  • 惰性空间回收

1. 空间预分配

对于追加操作来说,Redis不仅会开辟空间至够用而且还会预分配未使用的空间(free)来用于下一次操作。至于未使用的空间(free)的大小则由修改后的字符串长度决定。

当修改后的字符串长度len < 1M,则会分配与len相同长度的未使用的空间(free)

当修改后的字符串长度len >= 1M,则会分配1M长度的未使用的空间(free)

有了这个预分配策略之后会减少内存分配次数,因为分配之前会检查已有的free空间是否够,如果够则不开辟了~

2. 惰性空间回收

与上面情况相反,惰性空间回收适用于字符串缩减操作。比如有个字符串s1="hello world",对s1进行sdstrim(s1," world")操作,执行完该操作之后Redis不会立即回收减少的部分,而是会分配给下一个需要内存的程序。当然,Redis也提供了回收内存的api,可以自己手动调用来回收缩减部分的内存。

 

7.Redis 的应用场景?

  • 会话缓存(最常用) 
  • 消息队列(支付)
  • 活动排行榜或计数
  • 发布,订阅消息(消息通知)
  • 商品列表,评论列表
 

持久化

8.什么是 Redis 持久化?持久化的实现方式有哪些?

Redis的所有数据都是保存在内存中,redis崩掉的话,会丢失。Redis持久化就是把数据保存到磁盘上(可永久保存的存储设备中),以便数据恢复

redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

持久化的实现方式:

● 快照方式

对数据在某时某点的一种完整备份。例如Redis RDB,MySQL Dump都是这种方式。

● 写日志方式

任何数据的更新都记录在日志当中,某个时候要进行数据的恢复时,重走一遍日志的完整过程。例如MySQL的Binlog,HBase的HLog和Redis的AOF,就是这种方式

 

9.Redis 的持久化机制是什么?各自的优缺点?

Redis 提供两种持久化机制 RDB 和 AOF 机制:
 
(1)RDB Redis DataBase持久化方式:是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件。
持久化 结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优点:
  • 只有一个文件 dump.rdb,方便持久化。
  • 容灾性好,一个文件可以保存到安全的磁盘。
  • 性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能)
  • 相对于数据集大时,比 AOF 的启动效率更高。
 
缺点:
  • 数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生 故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)
(2)AOFAppend-only file)持久化方式:是指所有的命令行记录以 redis 命令请 求协议的格式完全持久化存储)保存为 aof 文件。
 
优点:
  • 数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。
  • 通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。
  • AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))
缺点:
  • AOF 文件比 RDB 文件大,且恢复速度慢。
  • 数据集大的时候,比 rdb 启动效率低

10.什么是快照持久化?rdb和aof的实现原理?rdb触发机制?aof触发机制?极端情况下,当aof文件达到占满磁盘时怎么办?重写机制是什么?你搭建时是如何配置持久化机制的?

Redis通过创建快照来获得存储在内存里面的数据在某个时间节点上的副本。
 

rdb触发机制-主要三种方式

  1. save(同步)
  2. bgsave(异步)
  3. 自动
save命令:客户端向Redis发送save命令来创建一个快照文件。
执行save命令的时候,如果存在老的快照文件,新的将会替换老的。
bgsave命令:客户端向Redis发送bgsave命令,Redis调用fork创建一个子进程,然后子进程负责将快照写入硬盘,而而父进程则继续处理命令请求。
 
save命令和bgsave命令对比:
命令
save
bgsave
IO类型
同步
异步
是否阻塞
复杂度
O(n)
O(n)
优点
不会消耗额外内存
不阻塞客户端命令
缺点
阻塞客户端命令
需要fork,消耗内存
自动生成:通过配置,满足任何一个条件就会创建快照文件。
这就是我们redis中配置的方案,可以查看redis配
快照持久化选项:
多久执行一次自动快照操作,60s之内有1000次操作写入时执行
save 60 1000
创建快照失败后是否仍然继续执行写命令
stop-writes-on-bgsave-error no
是否对快照文件进行压缩
rdbcompression yes
命名硬盘上的快照文件
dbfilename dump.rdb

 

最佳配置:
dbfilename dump-${port}.rdb
dir /bigdiskpath
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

 

AOF三种策略

always:每条Redis写命令都同步写入硬盘。
everysec:每秒执行一次同步,将多个命令写入硬盘。
no:由操作系统决定何时同步。
三种策略对比:生产环境中需要根据实际的需求进行选择。
命令 
always
everysec
no
优点 
不丢失数据 
每秒一次fsync 
不用管 
缺点 
IO开销较大,一般的SATA盘只有几百TPS 
丢1s数据 
不可控 

AOF重写

随着Redis的运行,被执行的写命令不断同步到AOF文件中,AOF文件的体积越来越大,极端情况将会占满所有的硬盘空间。如果AOF文件体积过大,还原的过程也会相当耗时。为了解决AOF文件不断膨胀的问题,需要移除AOF文件中的冗余命令来重写AOF。
原生AOF 
AOF重写 
set hello world
set hello java
set hello redis
incr counter
inct counter
rpush mylist a
rpush mylist b
rpush mylist c
过期数据
set hello redis
set counter 2
rpush mylist a b c
 
AOF重写的两种实现方式
  • bgrewriteaof命令
bgrewriteaof命令和bgsave命令的工作原理相似:Redis创建一个子进程,然后由子进程负责对AOF文件进行重写。
 
 
AOF重写配置
配置参数说明:
 
名称 
含义 
auto-aof-rewrite-min-size
AOF文件重写需要的尺寸 
auto-aof-rewrite-percentage
AOF文件增长率
具体配置:
appendonly yes
appendfilename "appendonly-${port}.aof"
appendfsync everysc
dir/bigdiskpath
no-appendfsync-on-rwrite yes
auto-aof-rewrit-percentage 100
auto-aof-rewrite-min-size 64mb

 

11.如何选择合适的持久化方式

在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用快照持久化或AOF持久化的一种,或同时开启快照持久化和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案。

(1)如果Redis中的数据完全丢弃也没有关系(如Redis完全用作DB层数据的cache),那么无论是单机,还是主从架构,都可以不进行任何持久化。

(2)在单机环境下(对于个人开发者,这种情况可能比较常见),如果可以接受十几分钟或更多的数据丢失,选择快照持久化对Redis的性能更加有利;如果只能接受秒级别的数据丢失,应该选择AOF。

(3)但在多数情况下,我们都会配置主从环境,slave的存在既可以实现数据的热备,也可以进行读写分离分担Redis读请求,以及在master宕掉后继续提供服务。在这种情况下,一种可行的做法是:master:完全关闭持久化,这样可以让master的性能达到最好slave:关闭快照持久化,开启AOF(如果对数据安全要求不高,开启快照持久化关闭AOF也可以),并定时对持久化文件进行备份(如备份到其他文件夹,并标记好备份的时间);然后关闭AOF的自动重写,然后添加定时任务,在每天Redis闲时(如凌晨12点)调用bgrewriteaof。

* 一般来说, 如果想达到足以媲美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

* 如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。

* 有很多用户都只使用AOF持久化,但并不推荐这种方式,因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以避免AOF程序的bug。

* 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。

如果有俩种持久化机制,redis重启恢复数据时采用aof机制,因为这种机制数据比较完整。

面试场景:

面试官:在dump.rdb过程中 ,aof如果停止同步,会不会丢失?

答:不会,所有的操作缓存在内存的队列里,dump完成后,统一操作

面试官:aof重写是指什么?

答:aof重写是指把内存中命令,逆话命令,写入到aof日志里。

面试官:如果rdb文件与aof文件同时存在,优先用谁来恢复数据?

答:aof

面试官:恢复时rdb与aof哪个恢复的快?

答:rdb,因为其是数据的内存映射,直接载入到内存。而aof是命令,需要逐条执行

12.Redis 持久化数据和缓存怎么做扩容?(没懂,需要再看)

* 如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
* 如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。
 

13.Redis 的过期键的删除策略

定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作
惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键
定期删除: 每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多个过期键,以及要检查多少个数据库,则由算法决定
第一种和第三种为主动删除策略,而第二种则为被动删除策略

14.Redis key 的过期时间和永久有效分别怎么设置?

EXPIRE 和 PERSIST 命令。

15.我们知道通过 expire 来设置 key 的过期时间,那么对过期的数据怎么处理呢?

内存相关

16.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据

相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

17.Redis 的内存淘汰策略有哪些

redis 提供 6种数据淘汰策略:
voltile-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(驱逐):禁止驱逐数据

18.Redis 主要消耗什么物理资源?

内存

19.redis设置最大内存?一般设置多大

maxmemory 268435456
本机服务器redis配置文件路径:/etc/redis/6379.conf,由于本机自带内存只有1G,一般推荐Redis设置内存为最大物理内存的四分之三,所以设置0.75G,换成byte是751619276.
 
一般情况下,内存占用75%是安全的,实际情况设置50%就可以了。

20. Redis 的内存用完了会发生什么?

如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回。)或者你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

21.redis分区分片如何理解?我们为什么要分区?分区的动机是什么?

分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。
  如果只使用一个redis实例时,其中保存了服务器中全部的缓存数据,这样会有很大风险,如果单台redis服务宕机了将会影响到整个服务。解决的方法就是我们可以采用分片/分区的技术,将原来一台服务器维护的整个缓存,现在换为由多台服务器共同维护内存空间。
 
性能的提升,单机Redis的网络I/O能力和计算资源是有限的,将请求分散到多台机器,充分利用多台机器的计算能力可网络带宽,有助于提高Redis总体的服务能力。
存储的横向扩展,即使Redis的服务能力能够满足应用需求,但是随着存储数据的增加,单台机器受限于机器本身的存储容量,将数据分散到多台机器上存储使得Redis服务可以横向扩展。
总的来说,分区使得我们本来受限于单台计算机硬件资源的问题不再是问题,存储不够?计算资源不够?带宽不够?我们都可以通过增加机器来解决这些问题。

22.分区实现

说明与分析:

  关于redis的安装参照上一篇,默认安装好了redis.
  思路:采用在一台主机上实现分片的方式,所以只需要在该主机上配置启动三台redis的实例即可。因为redis默认使用的端口号为6379,所以这里我们分别使用6379、6380以及6381三个端口来实现。
  

配置:

  1.进入到redis的安装目录下,创建一个shard文件夹,然后将redis的配置文件"redis.conf"复制一份,取名为"redis-6379.conf"(作为6379这台实例的配置文件)。然后将该文件移动到shard文件夹下,再将"redis-6379.conf"复制两份,一个叫"redis-6380.conf"(作为6380这台实例的配置文件),一个叫"redis-6381.conf"(作为6381这台实例的配置文件)。
  
  2. 修改6379这台实例的配置文件,因为端口6379默认就是redis的端口,所以只需要指定该实例的持久化片区(文件)即可。
  
  3. 修改6380实例的配置文件。
  • 修改该实例占用的端口为6380
  
  • 修改pid
  
  • 修改dump文件名
  
  4. 修改6381实例的配置文件。
  • 修改该实例占用的端口为6381
  
  • 修改pid
  
  • 修改dump文件名
  

启动与测试:

  1. 启动3台redis实例
  
  2. 测试
  redis分区有两种方式,对既定的key有不同的方式来选择这个key存放到哪个实例中,也就是说有不同的系统来映射某个key到某个Redis的服务。
  • 最简单的分区方式为 范围分区,就是映射一定范围的对象到特定的Redis实例。比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。
  • 另外一种方式是hash一致算法实现分区,对key值进行hash一致性计算后得到结果,最终将数据保存到某一台redis实例中,具体的hash一致性算法可以自行百度一下。
  说明:测试采用junit写的测试方法,方法中定义了一个redis分片的连接池,分别添加用于测试的三个节点实例,然后向redis中增加10个记录并使用Redis Desktop Manager这个工具查看添加结果。
 
@Test
public void test02(){
   //定义redis的配置
   PoolConfig poolconfig = new PoolConfig();
   poolconfig.setMaxTotal(1000);  //表示redis的最大连接数——最大1000个线程
   poolconfig.setMinIdle(5);  //表示最小空闲数量
   //定义redis的多个节点机器
   List<JedisShardInfo> list = new ArrayList<>();
   //为集合添加参数
   list.add(new JedisShardInfo("192.168.161.139", 6379));
   list.add(new JedisShardInfo("192.168.161.139", 6380));
   list.add(new JedisShardInfo("192.168.161.139", 6381));
   //定义redis分片连接池
   ShardedJedisPool jedisPool = new ShardedJedisPool(poolconfig, list);
   //获取连接操作redis
   ShardedJedis shardedJedis = jedisPool.getResource();
   //向redis中添加20个记录查看分片结果
   for(int i = 0; i < 10; i++){
       //增加的记录格式为   key=NUM_i   value=i
       shardedJedis.set("NUM_"+i, ""+i);
   }
}

  测试结果:

  
  
  
  说明:测试结果发现10个记录中有1个分到了6379区,3个分到了6380区,另外6个分到了6381区,因为是采用记录的key值来进行hash一致性算法来确定记录的存放区域,所以即使重新分区都不会改变记录的存放地址,所以仍然可以根据key值来获取到对应的value值。

分区的不足:

  1. 分区是多台redis共同作用的,如果其中一台出现了宕机现象,则整个分片都将不能使用,虽然是在一定程度上缓减了内存的压力,但是没有实现高可用。
  2. 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。
  3. 涉及多个key的redis事务不能使用。
  4. 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。
  高可用的解决方案:可以采用哨兵机制实现主从复制从而实现高可用。
 
Redis 如何做内存优化?
  • 存储结构由string变为hash
  • 缩减键值对象
  • 字符串优化
  • 编码优化
  • 控制key的数量

线程模型

23.Redis 线程模型

 
 Redis线程模型的组成:
1. 多个socket  
2. IO多路复用程序
3. scocket队列
4. 文件事件分配器
5. 事件处理器(连接应答处理器,命令请求处理器,命令回复处理器) 
 
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。
* 文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字, 并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
* 当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时, 与操作相对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性。
 

 

事务

24.Redis 事务的概念

Redis 事务的本质是通过MULTI、EXEC、WATCH等一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

25.Redis 事务的三个阶段

* 事务开始 MULTI
* 命令入队
* 事务执行 EXEC
事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入队列中排队
  1. Redis 事务相关命令
Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的
Redis会将一个事务中的所有命令序列化,然后按顺序执行。
1. redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速。
2. 如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
3. 如果在一个事务中出现运行错误,那么正确的命令会被执行
* WATCH 命令是一个乐观锁,可以为 Redis 事务提供 check-and-set (CAS)行为。可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。
* MULTI命令用于开启一个事务,它总是返回OK。MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
* EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil 。
* 通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
* UNWATCH命令可以取消watch对所有key的监控。

26.Redis 事务支持隔离性吗

Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。

27.Redis 事务保证原子性吗,支持回滚吗

Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。

 

28.Redis 事务其他实现

* 基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行,
其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续运行完
* 基于中间标记变量,通过另外的标记变量来标识事务是否执行完成,读取数据时先读取该标记变量判断是否事务执行完成。但这样会需要额外写代码实现,比较繁琐

集群方案

29.哨兵模式

sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:
* 集群监控:负责监控 redis master 和 slave 进程是否正常工作。
* 消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
* 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
* 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。
* 故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。
* 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。
 
官方 Redis Cluster 方案(服务端路由查询)

 

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

简介

Redis Cluster是一种服务端Sharding技术,3.0版本开始正式提供。Redis Cluster并没有使用一致性hash,而是采用slot(槽)的概念,一共分成16384个槽。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行

方案说明

1. 通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,默认分配了16384 个槽位
2. 每份数据分片会存储在多个互为主从的多节点上
3. 数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)
4. 同一分片多个节点间的数据不保持一致性
5. 读取数据时,当客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点
6. 扩容时时需要需要把旧节点的数据迁移一部分到新节点
在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是 加1w 的端口号,比如 16379。
16379 端口号是用来进行节点间通信的,也就是 cluster bus 的东西,cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。cluster bus 用了另外一种二进制的协议,gossip 协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。
 
节点间的内部通信机制:
集群元数据的维护有两种方式:集中式、Gossip 协议。redis cluster 节点间采用 gossip 协议进行通信。
 

分布式寻址算法

* hash 算法(大量缓存重建)
* 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
* redis cluster 的 hash slot 算法

优点

* 无中心架构,支持动态扩容,对业务透明
* 具备Sentinel的监控和自动Failover(故障转移)能力
* 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
* 高性能,客户端直连redis服务,免去了proxy代理的损耗

缺点

* 运维也很复杂,数据迁移需要人工干预
* 只能使用0号数据库
* 不支持批量操作(pipeline管道操作)
* 分布式逻辑和存储模块耦合等

 

31.redis分区方案

分区可以在程序的不同层次实现。
* 客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端已经实现了客户端分区。
* 代理分区 意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy
* 查询路由(Query routing) 的意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。
  1. 基于客户端分配
  2. 基于代理服务器分片
  3. Redis集群方案有哪些

单机redis单实例

redis的单机实例并发量在 50k-10k之间, 生产环境下一般在20-50k 以下
memcached可达十几万的并发,生产环境下也可5万以上。

主从模式

这种模式可以方便快速的解决,读多写少的高并发场景,相对较小的缓存应用场景可适用

哨兵模式

sentinel模式,解决了主从模式的下的高可用问题。哨兵模式相当清爽,相当于充当了一群管理员,自动的去完成主从切换,故障迁移等。

集群模式

redis-cluster集群
 
redis-cluster集群是redis服务自带的分部式集群解决方案3.0.版本以上方有该功能。去中心化是它一大特点。
 
Redis的几种使用方式包括:
 
  • Redis 单副本
  • Redis 多副本(主从)
  • Redis Sentinel(哨兵)
  • Redis Cluster
  • Redis 自研
     

redis集群搭建各种方案了解及优缺点对比:

一. Redis 单副本

Redis单副本,采用单个Redis节点部署架构,没有备用节点实时同步数据,不提供数据持久化和备份策略,适用于数据可靠性要求不高的业务场景。
 
 
优点:
  • 架构简单,部署方便。
  • 高性价比:缓存使用时无需备用节点(单实例可用性可以用 supervisor 或 crontab 保证),当然为了满足业务的高可用性,也可以牺牲一个备用节点,但同时刻只有一个实例对外提供服务。
  • 高性能。
缺点:
  • 不保证数据的可靠性。
  • 在缓存使用,进程重启后,数据丢失,即使有备用的节点解决高可用性,但是仍然不能解决缓存预热问题,因此不适用于数据可靠性要求高的业务。
  • 高性能受限于单核 CPU 的处理能力(Redis 是单线程机制),CPU 为主要瓶颈,所以适合操作命令简单,排序、计算较少的场景。也可以考虑用 Memcached 替代。
 

 

二. Redis多副本( 主从 )

 
Redis多副本,采用主从( replication)部署结构, 相较于单副本而言最大特点就是主从实例间数据实时同步,并且提供数据持久化和备份策略。
 
 
主从实例部署在不同的物理服务器上,根据公司的基础环境配置,可以实现同时对外提供服务和读写分离策略。
 
优点:
  • 架构简单,部署方便。
  • 高性价比:缓存使用时无需备用节点(单实例可用性可以用 supervisor 或 crontab 保证),当然为了满足业务的高可用性,也可以牺牲一个备用节点,但同时刻只有一个实例对外提供服务。
  • 高性能。
  • 高可靠性:一方面,采用双机主备架构,能够在主库出现故障时自动进行主备切换,从库提升为主库提供服务,保证服务平稳运行;另一方面,开启数据持久化功能和配置合理的备份策略,能有效的解决数据误操作和数据异常丢失的问题。
  • 读写分离策略:从节点可以扩展主库节点的读能力,有效应对大并发量的读操作。
缺点:
  • 不保证数据的可靠性。
  • 在缓存使用,进程重启后,数据丢失,即使有备用的节点解决高可用性,但是仍然不能解决缓存预热问题,因此不适用于数据可靠性要求高的业务。
  • 高性能受限于单核 CPU 的处理能力(Redis 是单线程机制),CPU 为主要瓶颈,所以适合操作命令简单,排序、计算较少的场景。也可以考虑用 Memcached 替代。
  • 故障恢复复杂,如果没有 Redis HA 系统(需要开发),当主库节点出现故障时,需要手动将一个从节点晋升为主节点,同时需要通知业务方变更配置,并且需要让其他从库节点去复制新主库节点,整个过程需要人为干预,比较繁琐。
  • 主库的写能力受到单机的限制,可以考虑分片。
  • 主库的存储能力受到单机的限制,可以考虑 Pika。
  • 原生复制的弊端在早期的版本中也会比较突出,如:Redis 复制中断后,Slave 会发起 psync,此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时可能会造成毫秒或秒级的卡顿。

三. Redis Sentinel (哨兵)

Redis Sentinel 是社区版本推出的原生高可用解决方案,部署架构主要包括两部分:Redis Sentinel 集群和Redis数据集群。其中,Redis Sentinel 集群是由若干Sentinel 节点组成的分布式集群,可以实现故障发现、故障自动转移、配置中心和客户端通知。Redis Sentinel 的节点数量要满足2n+1(n>=1) 的奇数个。
 
 
 
优点
  • Redis Sentinel 集群部署简单;
  • 能够解决 Redis 主从模式下的高可用切换问题;
  • 很方便实现 Redis 数据节点的线形扩展,轻松突破 Redis 自身单线程瓶颈,可极大满足 Redis 大容量或高性能的业务需求;
  • 可以实现一套 Sentinel 监控一组 Redis 数据节点或多组数据节点。
缺点:
  • 部署相对 Redis 主从模式要复杂一些,原理理解更繁琐;
  • 资源浪费,Redis 数据节点中 slave 节点作为备份节点不提供服务;
  • Redis Sentinel 主要是针对 Redis 数据节点中的主节点的高可用切换,对 Redis 的数据节点做失败判定分为主观下线和客观下线两种,对于 Redis 的从节点有对节点做主观下线操作,并不执行故障转移。
  • 不能解决读写分离问题,实现起来相对复杂
建议:
  • 如果监控同一业务,可以选择一套 Sentinel 集群监控多组 Redis 数据节点的方案,反之选择一套 Sentinel 监控一组 Redis 数据节点的方案。
  • sentinel monitor <master-name> <ip> <port> <quorum> 配置中的<quorum>建议设置成 Sentinel 节点的一半加 1,当 Sentinel 部署在多个 IDC 的时候,单个 IDC 部署的 Sentinel 数量不建议超过(Sentinel 数量 – quorum)。
  • 合理设置参数,防止误切,控制切换灵敏度控制:    a. quorum;  b. down-after-milliseconds 30000; c. failover-timeout 180000; d. maxclient; e. timeout
  • 部署的各个节点服务器时间尽量要同步,否则日志的时序性会混乱。
  • Redis 建议使用 pipeline 和 multi-keys 操作,减少 RTT 次数,提高请求效率。
  • 自行搞定配置中心(zookeeper),方便客户端对实例的链接访
  •  

四. Redis Cluster

Redis Cluster 是社区版推出的Redis分布式集群解决方案,主要解决Redis分布式方面的需求,比如,当遇到单机内存,并发和流量等瓶颈的时候,Redis Cluster 能起到很好的负载均衡的目的。
Redis Cluster 集群节点最小配置6个节点以上(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
Redis Cluster 采用虚拟槽分区,所有的键根据哈希函数映射到 0~16383 个整数槽内,每个节点负责维护一部分槽以及槽所映射的键值数据。
 
 
优点:
  • 无中心架构;
  • 数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布;
  • 可扩展性:可线性扩展到 1000 多个节点,节点可动态添加或删除;
  • 高可用性:部分节点不可用时,集群仍可用。通过增加 Slave 做 standby 数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升;
  • 降低运维成本,提高系统的扩展性和可用性
缺点:
  • Client 实现复杂,驱动要求实现 Smart Client,缓存 slots mapping 信息并及时更新,提高了开发难度,客户端的不成熟影响业务的稳定性。目前仅 JedisCluster 相对成熟,异常处理部分还不完善,比如常见的“max redirect exception”。
  • 节点会因为某些原因发生阻塞(阻塞时间大于 clutser-node-timeout),被判断下线,这种 failover 是没有必要的。
  • 数据通过异步复制,不保证数据的强一致性。
  • 多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
  • Slave 在集群中充当“冷备”,不能缓解读压力,当然可以通过 SDK 的合理设计来提高 Slave 资源的利用率。
  • Key 批量操作限制,如使用 mset、mget 目前只支持具有相同 slot 值的 Key 执行批量操作。对于映射为不同 slot 值的 Key 由于 Keys 不支持跨 slot 查询,所以执行 mset、mget、sunion 等操作支持不友好。
  • Key 事务操作支持有限,只支持多 key 在同一节点上的事务操作,当多个 Key 分布于不同的节点上时无法使用事务功能。
  • Key 作为数据分区的最小粒度,不能将一个很大的键值对象如 hash、list 等映射到不同的节点。
  • 不支持多数据库空间,单机下的 redis 可以支持到 16 个数据库,集群模式下只能使用 1 个数据库空间,即db  0 。
  • 复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
  • 避免产生 hot-key,导致主库节点成为系统的短板。
  • 避免产生 big-key,导致网卡撑爆、慢查询等。
  • 重试时间应该大于 cluster-node-time 时间。
  • Redis Cluster 不建议使用 pipeline和multi-keys 操作,减少 max redirect 产生的场景

redis集群搭建

主从模式

redis 一主二从

1.redis 安装

  安装教程:https://www.cnblogs.com/zwcry/p/9505949.html

2.redis主从

  1)创建主从目录

mkdir /usr/local/redis-ms
cd /usr/local/redis-ms/
mkdir 6381
mkdir 6382
mkdir 6382

  2)复制redis.conf到主从目录    

cp /usr/local/redis/redis.conf ./6381/
cp /usr/local/redis/redis.conf ./6382/
cp /usr/local/redis/redis.conf ./6383/

  3)修改主./6381/redis.conf   

vim ./6381/redis.conf
#修改如下key的值
bind 0.0.0.0#任意ip都可以连接
protected-mode no#关闭保护,允许非本地连接
port 6381#端口号
daemonize yes#后台运行
pidfile /var/run/redis_6381.pid#进程守护文件,就是存放该进程号相关信息的地方
dir /usr/local/redis-ms/6381/#db等相关目录位置
appendonly yes#开启日志形式

  4)修改从./6382/redis.conf    

vim ./6382/redis.conf
#修改如下key的值
bind 0.0.0.0#任意ip都可以连接
protected-mode no#关闭保护,允许非本地连接
port 6382#端口号
daemonize yes#后台运行
pidfile /var/run/redis_6382.pid#进程守护文件,就是存放该进程号相关信息的地方
dir /usr/local/redis-ms/6382/#db等相关目录位置
slaveof 192.168.194.131 6381#主信息
appendonly yes#开启日志形式

  5)修改从./6383/redis.conf  

vim ./6383/redis.conf 
#修改如下key的值
bind 0.0.0.0#任意ip都可以连接
protected-mode no#关闭保护,允许非本地连接
port 6383#端口号
daemonize yes#后台运行
pidfile /var/run/redis_6383.pid#进程守护文件,就是存放该进程号相关信息的地方
dir /usr/local/redis-ms/6383/#db等相关目录位置
slaveof 192.168.194.131 6381#主信息
appendonly yes#开启日志形式

3.启动测试

  1)启动    

cd /usr/local/redis-ms/
/usr/local/redis/src/redis-server ./6381/redis.conf
/usr/local/redis/src/redis-server ./6382/redis.conf
/usr/local/redis/src/redis-server ./6383/redis.conf
ps -ef|grep redis

    

    #查看主从是否搭建成功    

/usr/local/redis/src/redis-cli -p 6381
info

    如图:

    

  2)测试

/usr/local/redis/src/redis-cli -p 6381 --raw
set name '丁洁'
get name

       

/usr/local/redis/src/redis-cli -p 6382 --raw
get name

         

/usr/local/redis/src/redis-cli -p 6382 --raw
get name

    

    注:主6381设置name值,可以在从6382、6383取到,但是从不能设置值。

4.开机自启服务

  mkdir /usr/local/redis-ms/script

  cd /usr/local/redis-ms/script/

  1)start.sh启动脚本

 vim ./start.sh

#!/bin/sh

/usr/local/redis/src/redis-server /usr/local/redis-ms/6381/redis.conf

/usr/local/redis/src/redis-server /usr/local/redis-ms/6382/redis.conf

/usr/local/redis/src/redis-server /usr/local/redis-ms/6383/redis.conf

     2)stop.sh停止脚本    

vim ./stop.sh    

#!/bin/sh

/usr/local/redis/src/redis-cli -p 6381 shutdown

/usr/local/redis/src/redis-cli -p 6382 shutdown

/usr/local/redis/src/redis-cli -p 6383 shutdown

  3)restart.sh重启脚本

    vim ./restart.sh

#!/bin/sh

systemctl stop redis-ms

systemctl start redis-ms

  4)改变权限

    chmod 777 ./*

    

  5)编写开机服务

    cd /usr/lib/systemd/system/

    vim redis-ms.service

。。。。。。

哨兵模式环境搭建

Redis哨兵机制,一主二从

二、哨兵配置(sentinel.conf)

  cd /usr/local/redis-ms/  

  1.创建哨兵目录

mkdir -p ./sentinel/26001/tmp
cp /usr/local/redis/sentinel.conf ./sentinel/26001/

  2.修改./sentinel/.conf    

cd /usr/local/redis-ms/sentinel/
vim ./26001/sentinel.conf
 #修改如下键值对
# bind 127.0.0.1 192.168.1.1#注释掉或者值为0.0.0.0
protected-mode no#关闭保护模式
port 26001#端口号
daemonize yes#后台运行
dir /usr/local/redis-ms/sentinel/26001/tmp#解除挂载信息目录
sentinel monitor mymaster 192.168.194.131 6381 1#设置 主名称 ip地址 端口号 参入选举的哨兵数
entinel down-after-milliseconds mymaster 3000#sentinel心跳检测主3秒内无响应,视为挂掉,开始切换其他从为主
sentinel parallel-syncs mymaster 1#每次最多可以有1个从同步主。一个从同步结束,另一个从开始同步。
sentinel failover-timeout mymaster 18000#主从切换超时时间

三、启动哨兵配置

  1.先启主从redis   

/usr/local/redis/src/redis-server /usr/local/redis-ms/6381/redis.conf
/usr/local/redis/src/redis-server /usr/local/redis-ms/6382/redis.conf
/usr/local/redis/src/redis-server /usr/local/redis-ms/6383/redis.conf
ps -ef|grep redis

    如图已经启动

    

    且信息正确   

/usr/local/redis/src/redis-cli -p 6381
info

    

   2.启动哨兵

/usr/local/redis/src/redis-sentinel /usr/local/redis-ms/sentinel/26001/sentinel.conf 
ps -ef|grep redis

    如图已经启动

    

    且信息正确   

/usr/local/redis/src/redis-cli -p 26001
info

     

  3.测试

    1)主6381停掉后变成从,原有的两个从,有一个升级为主。      

/usr/local/redis/src/redis-cli -p 6381 shutdown
/usr/local/redis/src/redis-cli -p 26001
info

      

    2)6381再次启动后,依然是从      

/usr/local/redis/src/redis-server /usr/local/redis-ms/6381/redis.conf
/usr/local/redis/src/redis-cli -p 6381
info

      

五、哨兵集群

cd /usr/local/redis-ms/sentinel/

  1.复制26001

 cp -r 26001 26002

  2.修改26002/sentinel.conf

 vim 26002/sentinel.conf
 #将文本中26001替换为26002
 :%s/26001/26002/g

  3.启动

    

/usr/local/redis/src/redis-sentinel /usr/local/redis-ms/sentinel/26002/sentinel.conf
info
usr/local/redis/src/redis-cli -p 26002

    

6.哨兵开机启动

  注:redis开机启动参照https://www.cnblogs.com/zwcry/p/9046207.html  

  1.创建sh脚本目录

    mkdir /usr/local/redis-ms/sentinel/script

    cd /usr/local/redis-ms/sentinel/script/

  2.编辑start.sh

    vim start.sh   

#!/bin/sh

/usr/local/redis/src/redis-sentinel /usr/local/redis-ms/sentinel/26001/sentinel.conf

/usr/local/redis/src/redis-sentinel /usr/local/redis-ms/sentinel/26002/sentinel.conf

  3.编辑stop.sh

    vim stop.sh

#!/bin/sh

/usr/local/redis/src/redis-cli -p 26001 shutdown

/usr/local/redis/src/redis-cli -p 26002 shutdown

  4.编辑restart.sh

    vim restart.sh   

#!/bin/sh

systemctl stop redis-sentinel

systemctl start redis-sentinel

  5.编写redis-sentinel.service

    cd /usr/lib/systemd/system/

    vim redis-sentinel.service

    #建议启动redis服务后,再启动哨兵  

  6.命令行

    改变权限

      chmod 777 redis-sentinel.service

      chmod 777 /usr/local/redis-ms/sentinel/script/*

    进程服务重加载

      systemctl daemon-reload

    开机启动哨兵

      systemctl enable redis-sentinel.service

    启动哨兵

      systemctl start redis-sentinel.service

    关闭哨兵

      systemctl stop redis-sentinel.service

    重启哨兵

      systemctl restart redis-sentinel.service

备注:哨兵集群服务自主关联响应,如果需要更多哨兵集群,按照26002的方式复制26003...26006即可

集群模式

简介
 redis cluster: 自动做master+slave复制和读写分离,master+slave高可用和主备切换,支持多个master的hash slot支持数据分布式存储。
 
环境准备
redis cluster集群,要求至少3个master,去组成一个高可用,健壮的分布式的集群,每个master都建议至少给一个slave,
3个master,3个slave。正式环境下,建议都是说在6台机器上去搭建。3台机器的话要保证,每个master都跟自己的slave
不在同一台机器上,如果master和slave都在同一台机器的话,出了问题会一起死掉。
 
我们这里的三台机器如下:
eshop-cache01(192.168.191.101),
eshop-cache02(192.168.191.102),
eshop-cache03(192.168.191.103),
 
在三台服务器上建立如下文件夹
 
创建6个配置文件,因为我们是3个master,3个slave,所以我们需要不同的实例端口
配置文件分别为:7001.conf,7002.conf,7003.conf,7004.conf,7005.conf,7006.conf
端口:7001,7002,7003,7004,7005,7006
文件分配:
 
       eshop-cache01(192.168.191.101)---->7001.conf,7002.conf
       eshop-cache02(192.168.191.102)---->7003.conf,7004.conf
       eshop-cache03(192.168.191.103)---->7005.conf,7006.conf
 
提前将工作目录建好:
    eshop-cache01(192.168.191.101)
   
mkdir -p /var/redis/7001
mkdir -p /var/redis/7002

 eshop-cache02(192.168.191.102)

mkdir -p /var/redis/7003
mkdir -p /var/redis/7004

eshop-cache03(192.168.191.103)

mkdir -p /var/redis/7005
mkdir -p /var/redis/7006  
修改redis.conf配置文件名为7001.conf,并且修改文件内容,如下:
 
#端口为5000
port 7001
#如果配置yes则开启集群功能,此redis实例作为集群的一个节点,否则,它是一个普通的单一的redis实例
cluster-enabled yes
#虽然此配置的名字叫"集群配置文件",但是此配置文件不能人工编辑,它是集群节点自动维护的文件,主要用于记录集群中有哪些节点
#他们的状态以及一些持久化参数等,方便在重启时恢复这些状态。通常是在收到请求之后这个文件就会被更新。
#集群搭建成功后会自动生成,在工作目录下
cluster-config-file /etc/redis-cluster/node-7001.conf
#节点宕机发现时间,可以理解为主节点宕机后从节点升级为主节点时间
cluster-node-timeout 15000
#守护进程模式
daemonize yes
#pid file所在目录
pidfile "/var/run/redis_7001.pid"
#指定工作目录,rdb,aof持久化文件将会放在该目录下,不同实例一定要配置不同的工作目录
dir "/var/redis/7001"
#指明日志文件名
logfile "/var/log/redis/7001.log"
#设置绑定IP地址
bind192.168.191.101 127.0.0.1
#开启AOF模式
appendonly yes

将文件上传到/etc/redis目录下。

继续创建7002.conf,7003.conf,7004.conf,7005.conf,7006.conf,并重新修改
 
port 、dir、cluster-config-file ,pidfile,logfile,bind等6个属性,根据不同的服务器地址修改,
 
最后将这些文件按照分配分发到不同机器的/etc/redis目录下。
 
eshop-cache01(192.168.191.101)---->7001.conf,7002.conf
 
eshop-cache02(192.168.191.102)---->7003.conf,7004.conf
 
eshop-cache03(192.168.191.103)---->7005.conf,7006.conf
 
准备环境的启动脚本,在/etc/init.d下,将/usr/local/module/redis-5.0.5/utils目录下redis_init_script拷贝到/etc/init.d下,分别
 
名称为redis_7001, redis_7002, redis_7003, redis_7004, redis_7005, redis_7006
 
eshop-cache01(192.168.191.101)---->redis_7001, redis_7002
 
eshop-cache02(192.168.191.102)---->redis_7003, redis_7004
 
eshop-cache03(192.168.191.103)----> redis_7005, redis_7006
 
修改内容:将REDISPORT修改为指定的7001,7002,7003,7004,7005,7006即可
 
 
 
在/etc/init.d下,分别通过redis_7001, redis_7002, redis_7003, redis_7004, redis_7005, redis_7006启动redis
例如:
 
 
安装ruby
构建 redis集群需要使用到ruby 并且版本ruby版本必须大于2.0 但是针对redis版本低于5.0的版本,对于高于5.0的版本在构建中
不需 要安装ruby,就能进行redis集群的构建。需要的话命令如下:

yum install -y ruby
yum install -y rubygems
gem install redis
cp /usr/local/module/redis-5.0.5/src/redis-trib.rb /usr/local/bin

用redis-cli创建整个redis集群(redis5以前的版本集群是依靠ruby脚本redis-trib.rb实现),进入/etc/init.d目录下

命令:
redis-cli --cluster create --cluster-replicas 1 192.168.191.101:7001 192.168.191.101:7002 192.168.191.102:7003 192.168.191.102:7004 192.168.191.103:7005 192.168.191.103:7006

--replicas: 每个master有几个slave

6台机器,3个master,3个slave,集群会尽量自己让master和slave不在一台机器上
 
 
 
目前的集群状态
 
读写分离:每个master都有一个slave
高可用:master宕机,slave自动被切换过去
 
多master:横向扩容支持更大数据量
使用redis-cli --cluster check 192.168.191.101:7001检查集群状态slots详细分配
 
 
 
上图可以发现显示了每个节点所分配的slots(哈希槽),这里总共6个节点,其中3个是从节点,所以3个主节点分别
 
映射了0-5460、5461-10922、10933-16383 solts。
测试效果
 
⑴实验多master写入 -> 海量数据的分布式存储
 
        a:连接7001,插入数据
             
 
 原因:
            在redis cluster写入数据的时候,其实是你可以将请求发送到任意一个master上去执行,但是,每个master都会计算这个key对应的CRC16值,然后对16384个hashslot取模,找到key对应的hash slot,找到hash slot对应的master,如果对应的master就在自己本地的话,set mykey1 v1,mykey1这个key对应
的hashslot就在自己本地,那么自己就处理掉了,但是如果计算出来的hashslot在其他master上,那么就会给客户端返回一个moved error,告诉你,你得到哪个master上去执行这条写入的命令。什么叫做多master的写入?就是每条数据只能存在于一个master上,不同的master负责存储不同的数据,分布式的数据存储。100w条数据,5个master,每个master就负责存储20w条数据,分布式数据存储.
所以我们到103服务器执行一下(获取也是一样):
 
              
 
 
⑵实验不同master各自的slave读取 -> 读写分离
 
       在这个redis cluster中,如果你要在slave读取数据,那么需要带上readonly指令,get mykey1,比如102服务器的7004
 
   就是101服务器7001的slave,我们获取一下:
 
       
 
 或者使用 redis-cli -h 192.168.191.102 -p 7004 -c启动,就会自动进行各种底层的重定向的操作
 
     
 
 
 redis cluster的架构下,实际上本身master就是可以任意扩展的,你如果要支撑更大的读吞吐量,或者写吞吐量,
 
      或者数据量,都可以直接对master进行横向扩展就可以了,也可以实现支撑更高的读吞吐的效果,所以说扩容
 
      master,跟之前扩容slave,效果是一样的。
 
⑶实验自动故障切换 -> 高可用性
 
    比如把master1,101服务器的7001,杀掉,看看它对应的102:7004能不能自动切换成master,可以自动切换
 
检测集群状态:

Redis 主从架构

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

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有 N-1 个复制品.

33.生产环境中的 redis 是怎么部署的?

面试官心理分析
看看你了解不了解你们公司的redis生产整合的部署架构,如果你不了解,那么确实你就很失职了,你的redis是主从架构?构造架构?用了可行的方案?有没有做redis给几个G的内存?设置了什么参数?压测后你们redis占用了多少QPS?高可用保证?有没有开启持久化机制确保可以进行数据恢复?
兄弟,这些你必须是门儿清的,否则你确实是没好好思考过。
面试题剖析
redis群集,10台机器,5台机器部署了redis主实例,另外5台机器部署了redis的从实例,每个主实例挂了一个从实例,5个分组对外提供读写服务,每个队列的读写高峰qps可能可以达到每秒5万,5台机器最多是25万读写请求/ s。
32G内存+ 8核CPU + 1T磁盘,但是分配给redis进程的是10g内存,一般在线生产环境,redis的内存尽量不要超过10g,超过10g可能会有问题。
5台机器对外提供读写,一共有50g内存。
因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例停机机,都会自动故障迁移,redis从实例会自动变成主实例继续提供读写服务。
你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是10kb。100条数据是1mb,10万条数据是1g。常驻内存的是200万条商品数据,占用内存是20g,仅不到总内存的50%。目前高峰期每秒就是3500左右的请求量。

33.说说 Redis 哈希槽的概念?

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通 过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

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

Redis并不能保证数据的强一致性,这意味着在实际中集群在特定的条件下可能会丢失写操作。

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

异步复制

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

16384 个。原因如下:
Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 算法计算的结果,对 16384 取模后放到对应的编号在 0-16383 之间的哈希槽,集群的每个节点负责一部分哈希槽

37.redis寻址算法

分布式寻址算法
  • hash 算法(大量缓存重建)
  • 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
  • redis cluster 的 hash slot 算法

hash 算法

来了一个 key,首先计算 hash 值,然后对节点数取模。然后打在不同的 master 节点上。一旦某一个 master 节点宕机,所有请求过来,都会基于最新的剩余 master 节点数去取模,尝试去取数据。这会导致大部分的请求过来,全部无法拿到有效的缓存,导致大量的流量涌入数据库。
 
一致性 hash 算法
一致性 hash 算法将整个 hash 值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,下一步将各个 master 节点(使用服务器的 ip 或主机名)进行 hash。这样就能确定每个节点在其哈希环上的位置。
来了一个 key,首先计算 hash 值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,遇到的第一个 master 节点就是 key 所在位置。
在一致性哈希算法中,如果一个节点挂了,受影响的数据仅仅是此节点到环空间前一个节点(沿着逆时针方向行走遇到的第一个节点)之间的数据,其它不受影响。增加一个节点也同理。
燃鹅,一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。为了解决这种热点问题,一致性 hash 算法引入了虚拟节点机制,即对每一个节点计算多个 hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
 
 
 
增加节点和删除节点不方便,会影响数据迁移
 

redis cluster 的 hash slot 算法

Redis并没有直接使用一致性hash,而是采用了哈希槽,采用循环冗余校验CRC16.Redis 集群包含了 16384 个哈希槽,每个 Key 经过计算后会落在一个具体的槽位上,而槽位具体在哪个机器上是用户自己根据自己机器的情况配置的,机器硬盘小的可以分配少一点槽位,硬盘大的可以分配多一点。如果节点硬盘都差不多则可以平均分配。所以哈希槽这种概念很好地解决了一致性的弊端
 
 
 
另外在容错性和扩展性上与一致性哈希一样,都是对受影响的数据进行转移而不影响其它的数据。而哈希槽本质上是对槽位的转移,把故障节点负责的槽位转移到其他正常的节点上。扩展节点也是一样,把其他节点上的槽位转移到新的节点上。
redis cluster 有固定的16384个 hash slot,对每个key计算CRC16值,然后对16384取模,可以获取 key 对应的 hash slot。
redis cluster 中每个 master 都会持有部分 slot,比如有 3 个 master,那么可能每个 master 持有 5000 多个 hash slot。hash slot 让 node 的增加和移除很简单,增加一个 master,就将其他 master 的 hash slot 移动部分过去,减少一个 master,就将它的 hash slot 移动到其他 master 上去。移动 hash slot 的成本是非常低的。客户端的 api,可以对指定的数据,让他们走同一个 hash slot,通过hash tag来实现。
任何一台机器宕机,另外两个节点,不影响的。因为 key 找的是 hash slot,不是机器。

39.Redis 集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。
 

分区

40.Redis 是单线程的,如何提高多核CPU的利用率?

可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU,你可以考虑一下分片(shard)。

41.为什么要做 Redis 分区?

分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。

42.你知道有哪些 Redis 分区实现方案?

* 客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端已经实现了客户端分区。
* 代理分区 意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy
* 查询路由(Query routing) 的意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。

43.Redis 分区有什么缺点?

* 涉及多个key的操作通常不会被支持。例如你不能对两个集合求交集,因为他们可能被存储到不同的Redis实例(实际上这种情况也有办法,但是不能直接使用交集指令)。
* 同时操作多个key,则不能使用Redis事务.
* 分区使用的粒度是key,不能使用一个非常长的排序key存储一个数据集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set)
* 当使用分区的时候,数据处理会非常复杂,例如为了备份你必须从不同的Redis实例和主机同时收集RDB / AOF文件。
* 分区时动态扩容或缩容可能非常复杂。Redis集群在运行时增加或者删除Redis节点,能做到最大程度对用户透明地数据再平衡,但其他一些客户端分区或者代理分区方法则不支持这种特性。然而,有一种预分片的技术也可以较好的解决这个问题。

分布式问题

44.Redis 实现分布式锁

Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系Redis中可以使用SETNX命令实现分布式锁。
当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
返回值:设置成功,返回 1 。设置失败,返回 0 。
 
使用SETNX完成同步锁的流程及事项如下:
使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功
为了防止获取锁后程序出现异常,导致其他线程/进程调用SETNX命令总是返回0而进入死锁状态,需要为该key设置一个“合理”的过期时间
释放锁,使用DEL命令将锁数据删除

45.如何解决 Redis 的并发竞争 Key 问题

所谓 Redis 的并发竞争 Key 的问题也就是多个系统同时对一个 key 进行操作,但是最后执行的顺序和我们期望的顺序不同,这样也就导致了结果的不同!
推荐一种方案:分布式锁(zookeeper 和 redis 都可以实现分布式锁)。(如果不存在 Redis 的并发竞争 Key 问题,不要使用分布式锁,这样会影响性能)
基于zookeeper临时有序节点可以实现的分布式锁。大致思想为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。完成业务流程后,删除对应的子节点释放锁。
在实践中,当然是从以可靠性为主。所以首推Zookeeper。

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

既然Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有一台服务器,你也可以一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。
一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。
这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的Redis实例从第一台机器迁移到第二台机器。
 
可以只有一台机器,但是搭建多实例

47.什么是 RedLock

Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock,此种方式比原先的单节点的方法更安全。它可以保证以下特性:
1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁
2. 避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区
3. 容错性:只要大部分 Redis 节点存活就可以正常提供服务

缓存异常

48.缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案
1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2. 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
3. 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

49.缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
 
解决方案
1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
3. 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力
 
附加
对于空间的利用到达了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)。
Bitmap:典型的就是哈希表
缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了。
布隆过滤器(推荐)
就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。
它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想。
Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在

50.缓存击穿

 
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数库。
解决方案:
* 设置热点数据永远不过期。
* 加互斥锁,互斥锁

51.缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
 
解决方案:
* 直接写个缓存刷新页面,上线时手工操作一下;
* 数据量不大,可以在项目启动的时候自动进行加载;
* 定时刷新缓存;

52.缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
缓存降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。
在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:
1. 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
2. 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
3. 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
4. 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。
服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。
 
 

常用工具

53.Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?

Redisson、Jedis、lettuce等等,官方推荐使用Redisson。

54.Redis 和 Redisson 有什么关系?

Redisson是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象

55.Jedis 与 Redisson 对比有什么优缺点?

Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
 

其他问题

56.Redis 与 Memcached 的区别

(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis的速度比memcached快很多
(3) redis可以持久化其数据

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

你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?
一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案,读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况
串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。
还有一种方式就是可能会暂时产生不一致的情况,但是发生的几率特别小,就是先更新数据库,然后再删除缓存

58.Redis 常见性能问题和解决方案?

1.Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。
2. 如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
3. 为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。
4. 尽量避免在压力较大的主库上增加从库
5. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
6. 为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:Master<–Slave1<–Slave2<–Slave3…,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

59.Redis 官方为什么不提供 Windows 版本?

因为目前Linux版本已经相当稳定,而且用户量很大,无需开发windows版本,反而会带来兼容性等问题

60.一个字符串类型的值能存储最大容量是多少?

512M

61.Redis 如何做大量数据插入?

Redis2.6开始redis-cli支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。

62.假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。
 
对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
 
答:这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。

63.使用 Redis 做过异步队列吗,是如何实现的

使用list类型保存数据信息,rpush生产消息,lpop消费消息,当lpop没有消息时,可以sleep一段时间,然后再检查有没有信息,如果不想sleep的话,可以使用blpop, 在没有信息的时候,会一直阻塞,直到信息的到来。redis可以通过pub/sub主题订阅模式实现一个生产者,多个消费者,当然也存在一定的缺点,当消费者下线时,生产的消息会丢失。

64.Redis 如何实现延时队列

使用sortedset,使用时间戳做score, 消息内容作为key,调用zadd来生产消息,消费者使用zrangbyscore获取n秒之前的数据做轮询处理
 
Redis 回收进程如何工作的?
 
1. 一个客户端运行了新的命令,添加了新的数据。
2. Redis检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
3. 一个新的命令被执行,等等。
4. 所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。
如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。
 

65.Redis 回收使用的是什么算法?

LRU算法
66.如果大量过期key堆积在内存里,导致redis内存块耗尽了,怎么办?
内存淘汰机制:
redis.conf中配置:
# maxmemory-policy noeviction  
noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
allkeys-lru:在主键空间中,优先移除最近未使用的key。
volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
allkeys-random:在主键空间中,随机移除某个key。
volatile-random:在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
 

redis配置文件

66.redis配置文件了解吗?

以下是配置文件分模块解释
此次安装的版本为: 5.0.3

[root@localhost local]# redis-server --version
Redis server v=5.0.3 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=afabdecde61000c3

###################################  NETWORK  ###################################

# 指定 redis 只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求
bind 127.0.0.1
#是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,
拒绝外部访问。要是开启了密码和bind,可以开启。否则最好关闭,设置为no
protected-mode yes
#redis监听的端口号
port 6379
#此参数确定了TCP连接中已完成队列(完成三次握手之后)的长度, 当然此值必须不大于Linux系统定义
的/proc/sys/net/core/somaxconn值,默认是511,而Linux的默认参数值是128。当系统并发量大并且客户端
速度缓慢的时候,可以将这二个参数一起参考设定。该内核参数默认值一般是128,对于负载很大的服务程序来说
大大的不够。一般会将它修改为2048或者更大。在/etc/sysctl.conf中添加:net.core.somaxconn = 2048,
然后在终端中执行sysctl -p
tcp-backlog 511
#此参数为设置客户端空闲超过timeout,服务端会断开连接,为0则服务端不会主动断开连接,不能小于0
timeout 0
#tcp keepalive参数。如果设置不为0,就使用配置tcp的SO_KEEPALIVE值,使用keepalive有两个好处:检测挂
掉的对端。降低中间设备出问题而导致网络看似连接却已经与对端端口的问题。在Linux内核中,设置了
keepalive,redis会定时给对端发送ack。检测到对端关闭需要两倍的设置值
tcp-keepalive 300
#是否在后台执行,yes:后台运行;no:不是后台运行
daemonize yes
#redis的进程文件
pidfile /var/run/redis/redis.pid
#指定了服务端日志的级别。级别包括:debug(很多信息,方便开发、测试),verbose(许多有用的信息,
但是没有debug级别信息多),notice(适当的日志级别,适合生产环境),warn(只有非常重要的信息)
loglevel notice
#指定了记录日志的文件。空字符串的话,日志会打印到标准输出设备。后台运行的redis标准输出是/dev/null
logfile /usr/local/redis/var/redis.log
#是否打开记录syslog功能
# syslog-enabled no
#syslog的标识符。
# syslog-ident redis
#日志的来源、设备
# syslog-facility local0
#数据库的数量,默认使用的数据库是0。可以通过”SELECT 【数据库序号】“命令选择一个数据库,序号从0开始
databases 16


################################### SNAPSHOTTING ###################################


#RDB核心规则配置 save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘
中。官方出厂配置默认是 900秒内有1个更改,300秒内有10个更改以及60秒内有10000个更改,则将内存中的
数据快照写入磁盘。
若不想用RDB方案,可以把 save "" 的注释打开,下面三个注释
# save ""
save 900 1
save 300 10
save 60 10000
#当RDB持久化出现错误后,是否依然进行继续进行工作,yes:不能进行工作,no:可以继续进行工作,可以通
过info中的rdb_last_bgsave_status了解RDB持久化是否有错误
stop-writes-on-bgsave-error yes
#配置存储至本地数据库时是否压缩数据,默认为yes。Redis采用LZF压缩方式,但占用了一点CPU的时间。若关闭该选项,
但会导致数据库文件变的巨大。建议开启。
rdbcompression yes
#是否校验rdb文件;从rdb格式的第五个版本开始,在rdb文件的末尾会带上CRC64的校验和。这跟有利于文件的
容错性,但是在保存rdb文件的时候,会有大概10%的性能损耗,所以如果你追求高性能,可以关闭该配置
rdbchecksum yes
#指定本地数据库文件名,一般采用默认的 dump.rdb
dbfilename dump.rdb
#数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录
dir /usr/local/redis/var

################################# REPLICATION #################################


# 复制选项,slave复制对应的master。
# replicaof <masterip> <masterport>
#如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。masterauth就是用来
配置master的密码,这样可以在连上master后进行认证。
# masterauth <master-password>
#当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:1) 如果slave-serve-stale-data设置为
yes(默认设置),从库会继续响应客户端的请求。2) 如果slave-serve-stale-data设置为no,
INFO,replicaOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG,SUBSCRIBE, UNSUBSCRIBE,
PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB,COMMAND, POST, HOST: and LATENCY命令之外的任何请求
都会返回一个错误”SYNC with master in progress”。
replica-serve-stale-data yes
#作为从服务器,默认情况下是只读的(yes),可以修改成NO,用于写(不建议)
#replica-read-only yes
# 是否使用socket方式复制数据。目前redis复制提供两种方式,disk和socket。如果新的slave连上来或者
重连的slave无法部分同步,就会执行全量同步,master会生成rdb文件。有2种方式:disk方式是master创建
一个新的进程把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave。socket是master创建一个新的进
程,直接把rdb文件以socket的方式发给slave。disk方式的时候,当一个rdb保存的过程中,多个slave都能
共享这个rdb文件。socket的方式就的一个个slave顺序复制。在磁盘速度缓慢,网速快的情况下推荐用socket方式。
repl-diskless-sync no
#diskless复制的延迟时间,防止设置为0。一旦复制开始,节点不会再接收新slave的复制请求直到下一个rdb传输。
所以最好等待一段时间,等更多的slave连上来
repl-diskless-sync-delay 5
#slave根据指定的时间间隔向服务器发送ping请求。时间间隔可以通过 repl_ping_slave_period 来设置,默认10秒。
# repl-ping-slave-period 10
# 复制连接超时时间。master和slave都有超时时间的设置。master检测到slave上次发送的时间超过repl-timeout,即认为slave离线,清除该slave信息。slave检测到上次和master交互的时间超过repl-timeout,则认为master离线。需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时
# repl-timeout 60
#是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。默认是no,即使用tcp nodelay。如果
master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带
宽。但是这也可能带来数据的延迟。默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes
repl-disable-tcp-nodelay no
#复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。这样在slave离线的时候,不需要完
全复制master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状
态。缓冲区的大小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。没有
slave的一段时间,内存会被释放出来,默认1m
# repl-backlog-size 1mb
# master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒。
# repl-backlog-ttl 3600
# 当master不可用,Sentinel会根据slave的优先级选举一个master。最低的优先级的slave,当选master。
而配置成0,永远不会被选举
replica-priority 100
#redis提供了可以让master停止写入的方式,如果配置了min-replicas-to-write,健康的slave的个数小于N,mater就禁止写入。master最少得有多少个健康的slave存活才能执行写命令。这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。设置为0是关闭该功能
# min-replicas-to-write 3
# 延迟小于min-replicas-max-lag秒的slave才认为是健康的slave
# min-replicas-max-lag 10
# 设置1或另一个设置为0禁用这个特性。
# Setting one or the other to 0 disables the feature.
# By default min-replicas-to-write is set to 0 (feature disabled) and
# min-replicas-max-lag is set to 10.
#requirepass配置可以让用户使用AUTH命令来认证密码,才能使用其他命令。这让redis可以使用在不受信任的
网络中。为了保持向后的兼容性,可以注释该命令,因为大部分用户也不需要认证。使用requirepass的时候需要
注意,因为redis太快了,每秒可以认证15w次密码,简单的密码很容易被攻破,所以最好使用一个更复杂的密码
# requirepass foobared
#把危险的命令给修改成其他名称。比如CONFIG命令可以重命名为一个很难被猜到的命令,这样用户不能使用,而
内部工具还能接着使用
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#设置成一个空的值,可以禁止一个命令
# rename-command CONFIG ""

 #################################  CLIENTS #################################


# 设置能连上redis的最大客户端连接数量。默认是10000个客户端连接。由于redis不区分连接是客户端连接还
是内部打开文件或者和slave连接等,所以maxclients最小建议设置到32。如果超过了maxclients,redis会给
新的连接发送’max number of clients reached’,并关闭连接
# maxclients 10000
redis配置的最大内存容量。当内存满了,需要配合maxmemory-policy策略进行处理。注意slave的输出缓冲区
是不计算在maxmemory内的。所以为了防止主机内存使用完,建议设置的maxmemory需要更小一些
maxmemory 122000000
#内存容量超过maxmemory后的处理策略。
#volatile-lru:利用LRU算法移除设置过过期时间的key。
#volatile-random:随机移除设置过过期时间的key。
#volatile-ttl:移除即将过期的key,根据最近过期时间来删除(辅以TTL)
#allkeys-lru:利用LRU算法移除任何key。
#allkeys-random:随机移除任何key。
#noeviction:不移除任何key,只是返回一个写错误。
#上面的这些驱逐策略,如果redis没有合适的key驱逐,对于写命令,还是会返回错误。redis将不再接收写请求,只接收get请求。写命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby getset mset msetnx exec sort。
# maxmemory-policy noeviction
# lru检测的样本数。使用lru或者ttl淘汰算法,从需要淘汰的列表中随机选择sample个key,选出闲置时间最长的key移除
# maxmemory-samples 5
# 是否开启salve的最大内存
# replica-ignore-maxmemory yes
#以非阻塞方式释放内存
#使用以下配置指令调用了
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no

 ########################   APPEND ONLY MODE    ###########################

#Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写
操作,并追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。但是redis如果中途宕机,会导致可
能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的
持久化特性。Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这
个文件的数据读入内存里,先忽略RDB文件。若开启rdb则将no改为yes
appendonly no
指定本地数据库文件名,默认值为 appendonly.aof
appendfilename "appendonly.aof"
#aof持久化策略的配置
#no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快
#always表示每次写入都执行fsync,以保证数据同步到磁盘
#everysec表示每秒执行一次fsync,可能会导致丢失这1s数据
# appendfsync always
appendfsync everysec
# appendfsync no
# 在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行
fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的
应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。设置为yes表
示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。Linux的
默认fsync策略是30秒。可能丢失30秒数据
no-appendfsync-on-rewrite no
#aof自动重写配置。当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件
增长到一定大小的时候Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得
到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程
auto-aof-rewrite-percentage 100
#设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写
auto-aof-rewrite-min-size 64mb
#aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。重启可能发生在redis所
在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项(redis宕机或者异常终止不会造
成尾部不完整现象。)出现这种现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,
当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-
check-aof修复AOF文件才可以
aof-load-truncated yes
#加载redis时,可以识别AOF文件以“redis”开头。
#字符串并加载带前缀的RDB文件,然后继续加载AOF尾巴
aof-use-rdb-preamble yes
# 如果达到最大时间限制(毫秒),redis会记个log,然后返回error。当一个脚本超过了最大时限。只有
SCRIPT KILL和SHUTDOWN NOSAVE可以用。第一个可以杀没有调write命令的东西。要是已经调用了write,只能
用第二个命令杀
lua-time-limit 5000
# 集群开关,默认是不开启集群模式
# cluster-enabled yes
#集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息。这个文件并不需要手动
配置,这个配置文件有Redis生成并更新,每个Redis集群节点需要一个单独的配置文件,请确保与实例运行的系
统中配置文件名称不冲突
# cluster-config-file nodes-6379.conf
#节点互连超时的阀值。集群节点超时毫秒数
# cluster-node-timeout 15000
#在进行故障转移的时候,全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间
了,导致数据过于陈旧,这样的slave不应该被提升为master。该参数就是用来判断slave节点与master断线的时
间是否过长。判断方法是:
#比较slave断开连接的时间和(node-timeout * slave-validity-factor) + repl-ping-slave-period
#如果节点超时时间为三十秒, 并且slave-validity-factor为10,假设默认的repl-ping-slave-period是10
秒,即如果超过310秒slave将不会尝试进行故障转移
# cluster-replica-validity-factor 10
# master的slave数量大于该值,slave才能迁移到其他孤立master上,如这个参数若被设为2,那么只有当一
个主节点拥有2 个可工作的从节点时,它的一个从节点会尝试迁移
# cluster-migration-barrier 1
#默认情况下,集群全部的slot有节点负责,集群状态才为ok,才能提供服务。设置为no,可以在slot没有全
部分配的时候提供服务。不建议打开该配置,这样会造成分区的时候,小分区的master一直在接受写请求,而
造成很长时间数据不一致
# cluster-require-full-coverage yes
#*群集公告IP
#*群集公告端口
#*群集公告总线端口
# Example:
#
# cluster-announce-ip 10.1.1.5
# cluster-announce-port 6379
# cluster-announce-bus-port 6380

 #############################  SLOW LOG #################################


# slog log是用来记录redis运行中执行比较慢的命令耗时。当命令的执行超过了指定时间,就记录在slow log
中,slog log保存在内存中,所以没有IO操作。
#执行时间比slowlog-log-slower-than大的请求记录到slowlog里面,单位是微秒,所以1000000就是1秒。注
意,负数时间会禁用慢查询日志,而0则会强制记录所有命令。
slowlog-log-slower-than 10000
#慢查询日志长度。当一个新的命令被写进日志的时候,最老的那个记录会被删掉。这个长度没有限制。只要有足
够的内存就行。你可以通过 SLOWLOG RESET 来释放内存
slowlog-max-len 128
#延迟监控功能是用来监控redis中执行比较缓慢的一些操作,用LATENCY打印redis实例在跑命令时的耗时图表。
只记录大于等于下边设置的值的操作。0的话,就是关闭监视。默认延迟监控功能是关闭的,如果你需要打开,也
可以通过CONFIG SET命令动态设置
latency-monitor-threshold 0

  #######################  EVENT NOTIFICATION ###########################


#键空间通知使得客户端可以通过订阅频道或模式,来接收那些以某种方式改动了 Redis 数据集的事件。因为开启键空间通知功能需要消耗一些 CPU ,所以在默认配置下,该功能处于关闭状态。
#notify-keyspace-events 的参数可以是以下字符的任意组合,它指定了服务器该发送哪些类型的通知:
##K 键空间通知,所有通知以 __keyspace@__ 为前缀
##E 键事件通知,所有通知以 __keyevent@__ 为前缀
##g DEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知
##$ 字符串命令的通知
##l 列表命令的通知
##s 集合命令的通知
##h 哈希命令的通知
##z 有序集合命令的通知
##x 过期事件:每当有过期键被删除时发送
##e 驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
##A 参数 g$lshzxe 的别名
#输入的参数中至少要有一个 K 或者 E,否则的话,不管其余的参数是什么,都不会有任何 通知被分发。详细使用可以参考http://redis.io/topics/notifications
notify-keyspace-events ""
# 数据量小于等于hash-max-ziplist-entries的用ziplist,大于hash-max-ziplist-entries用hash
hash-max-ziplist-entries 512
# value大小小于等于hash-max-ziplist-value的用ziplist,大于hash-max-ziplist-value用hash
hash-max-ziplist-value 64
#-5:最大大小:64 KB<--不建议用于正常工作负载
#-4:最大大小:32 KB<--不推荐
#-3:最大大小:16 KB<--可能不推荐
#-2:最大大小:8kb<--良好
#-1:最大大小:4kb<--良好
list-max-ziplist-size -2
#0:禁用所有列表压缩
#1:深度1表示“在列表中的1个节点之后才开始压缩,
#从头部或尾部
#所以:【head】->node->node->…->node->【tail】
#[头部],[尾部]将始终未压缩;内部节点将压缩。
#2:[头部]->[下一步]->节点->节点->…->节点->[上一步]->[尾部]
#2这里的意思是:不要压缩头部或头部->下一个或尾部->上一个或尾部,
#但是压缩它们之间的所有节点。
#3:[头部]->[下一步]->[下一步]->节点->节点->…->节点->[上一步]->[上一步]->[尾部]
list-compress-depth 0
# 数据量小于等于set-max-intset-entries用iniset,大于set-max-intset-entries用set
set-max-intset-entries 512
#数据量小于等于zset-max-ziplist-entries用ziplist,大于zset-max-ziplist-entries用zset
zset-max-ziplist-entries 128
#value大小小于等于zset-max-ziplist-value用ziplist,大于zset-max-ziplist-value用zset
zset-max-ziplist-value 64
#value大小小于等于hll-sparse-max-bytes使用稀疏数据结构(sparse),大于hll-sparse-max-bytes使
用稠密的数据结构(dense)。一个比16000大的value是几乎没用的,建议的value大概为3000。如果对CPU要
求不高,对空间要求较高的,建议设置到10000左右
hll-sparse-max-bytes 3000
#宏观节点的最大流/项目的大小。在流数据结构是一个基数
#树节点编码在这项大的多。利用这个配置它是如何可能#大节点配置是单字节和
#最大项目数,这可能包含了在切换到新节点的时候
# appending新的流条目。如果任何以下设置来设置
# ignored极限是零,例如,操作系统,它有可能只是一集
通过设置限制最大#纪录到最大字节0和最大输入到所需的值
stream-node-max-bytes 4096
stream-node-max-entries 100
#Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用。当你
的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置
为no。如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存
activerehashing yes
##对客户端输出缓冲进行限制可以强迫那些不从服务器读取数据的客户端断开连接,用来强制关闭传输缓慢的客户端。
#对于normal client,第一个0表示取消hard limit,第二个0和第三个0表示取消soft limit,normal
client默认取消限制,因为如果没有寻问,他们是不会接收数据的
client-output-buffer-limit normal 0 0 0
#对于slave client和MONITER client,如果client-output-buffer一旦超过256mb,又或者超过64mb持续
60秒,那么服务器就会立即断开客户端连接
client-output-buffer-limit replica 256mb 64mb 60
#对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就
会立即断开客户端连接
client-output-buffer-limit pubsub 32mb 8mb 60
# 这是客户端查询的缓存极限值大小
# client-query-buffer-limit 1gb
#在redis协议中,批量请求,即表示单个字符串,通常限制为512 MB。但是您可以更改此限制。
# proto-max-bulk-len 512mb
#redis执行任务的频率为1s除以hz
hz 10
#当启用动态赫兹时,实际配置的赫兹将用作作为基线,但实际配置的赫兹值的倍数
#在连接更多客户端后根据需要使用。这样一个闲置的实例将占用很少的CPU时间,而繁忙的实例将反应更灵敏
dynamic-hz yes
#在aof重写的时候,如果打开了aof-rewrite-incremental-fsync开关,系统会每32MB执行一次fsync。这
对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值
aof-rewrite-incremental-fsync yes
#在rdb保存的时候,如果打开了rdb-save-incremental-fsync开关,系统会每32MB执行一次fsync。这
对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值
rdb-save-incremental-fsync yes
# 已启用活动碎片整理
# activedefrag yes
# 启动活动碎片整理的最小碎片浪费量
# active-defrag-ignore-bytes 100mb
# 启动活动碎片整理的最小碎片百分比
# active-defrag-threshold-lower 10
# 我们使用最大努力的最大碎片百分比
# active-defrag-threshold-upper 100
# 以CPU百分比表示的碎片整理的最小工作量
# active-defrag-cycle-min 5
# 在CPU的百分比最大的努力和碎片整理
# active-defrag-cycle-max 75
#将从中处理的set/hash/zset/list字段的最大数目
#主词典扫描
# active-defrag-max-scan-fields 1000

 

 
 
 
 
 
 
 
 
 

 

  1.  

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值