长篇警告!长篇警告!这篇文章巨巨巨巨长~
如果觉得有帮助的话可以先收藏, 需要时回头再来瞅几眼~
欢迎收藏、转发~~
目录
如果在操作redis时不慎执行了FLUSHALL,如何处理?
问题描述: 如果同时开启了aof模式和rdb模式.问哪个生效?
redis简介
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
什么是redis?
是运行在内存中的数据结构存储系统
redis中的数据类型?
String、散列、list、set 、sSet
redis的并发速度?
读:11.2万/秒 写:8.6万/秒 平均10万/秒 单台
redis默认端口是?
6379,来源于一个意大利女演员的名字对应的手机按键数字

redis的下载及安装(Linux)
国外:redis.io
国内:redis.cn
1.进入Linux环境
先要在Linux系统中进行以下两项操作
yum -y install gcc #安装gcc编译器
yum -y install Irzsz #安装文件上传工具
2.下载redis压缩包
方式一、使用Linux系统中的指令访问网址下载压缩包
点击 链接另存为...

之后,在Linux中使用以下指令直接在线下载
wget (复制链接路径)
方式二、将本地压缩包拖拽上传
演示略.....
3.解压
tar -xvf (redis压缩包名)
4.在redis根目录下执行
注意:请进入redis目录中执行
make
make install
5.修改redis的配置文件
vim redis.conf
关闭IP绑定

关闭保护模式

开启后台启动


redis分片机制
一、什么是分片机制?
如果我们只配置一台redis缓存服务器,那么将会导致redis的内存开销很大,所以,就出现了分片机制,就是配置多台redis缓存服务器,把缓存数据分别由多台缓存服务器承担,以提高读写效率。

搭建分片
1.创建目录

2.将redis.conf文件复制多份到新建的目录中

3.修改conf文件中的端口号 
4.编写启动脚本

5.关闭脚本

6.测试类测试(注意一定要关闭防火墙或者开放端口)
@Test
public void test() {
List<JedisShardInfo> shards=new ArrayList<>();
shards.add(new JedisShardInfo("192.168.126.129",6379));
shards.add(new JedisShardInfo("192.168.126.129",6380));
shards.add(new JedisShardInfo("192.168.126.129",6381));
ShardedJedis shardedJedis = new ShardedJedis(shards);
shardedJedis.set("a", "北京烤鸭");
}
7.Spring boot整合redis分片
#新建redis.properties,配置redis分片
redis.shards=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381
编写配置类
将ShardedJedis 对象交给spring去管理

@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class redisConfig {
@Value("${redis.shards}")
private String shards;
@Bean
public ShardedJedis shardedJedis() {
List<JedisShardInfo> list = new ArrayList<JedisShardInfo>();
//1.将shards字符串转化为node数组
String[] nodes=shards.split(",");
for(String str:nodes) {
String host=str.split(":")[0];
int port = Integer.valueOf((str.split(":")[1]));
//实现节点封装
list.add(new JedisShardInfo(host, port));
}
return new ShardedJedis(list);
}
}
最后,DI注入即可使用


redis哨兵机制
采用分片机制后,如果redis服务器宕机了几台,会影响我们程序的正常运行,因为服务器依然会访问宕机的redis

可以配置多个备用的redis服务器,如果主服务器宕机,备用服务器将会立即补位,并且要求备用服务器中的数据与主服务器中的数据一致。


配置主从服务器
先将redis.conf文件复制多份,修改端口等操作
1.配置备用服务器
slaveof 主机IP 主机端口 #在从机中配置主机IP+端口
选定目标从机后,在其客户端,使用以上命令挂载主机

2.在客户端查看当前服务器的信息
info replication #查看当前服务器信息

1.当主从结构搭建成功之后,主机的数据,从机中可以同步
2.搭建主从结构之后,从机属于只读状态,不可写入数据
3.这种主从配置的有效期是基于内存的,如果服务器关机,结构失效
4.如果想长期有效,可以使用哨兵机制、集群机制完成
哨兵机制原理

我们可以配置一个哨兵来检测主服务器的状态,利用心跳检测机制实现,如果超过三次没有PING通,则判断主服务器宕机,之后,通过算法选举出新的主服务器。当哨兵选举出新的主机之后,为了保证主从的关系,则会动态的修改各自的redis.conf配置文件.并且将其他的节点标识为新主机的从机。
1.复制哨兵配置文件到目标目录
cp sentinel.conf sentinel

2.编辑哨兵配置文件
关闭保护模式

开启后台启动

修改哨兵监控
sentinel monitor mymaster 192.168.126.129 6379 1
哨兵 监控 监控主机名 IP+端口 表示1票同意

调整选举时间
选举最大时长,如果到达没能选举出,则开启新的选举
哨兵机制的测试
启动哨兵机制
redis-sentinel sentinel.conf

故意关闭主机
redis-cli -p 6379 shutdown
重启主机观察主机状态

SpringBoot中测试哨兵机制
public class TestRedisSentinel {
@Test
public void test01() {
//定义哨兵的集合信息 host:port
Set<String> sentinels = new HashSet<String>();
sentinels.add("192.168.126.129:26379");
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
Jedis jedis = pool.getResource();
jedis.set("a", "你好我是哨兵机制!!!!");
System.out.println(jedis.get("a"));
}
}
分片机制与哨兵机制的优缺点
1.分片机制实现了内存数据的扩容
2.分片机制缺失高可用的实现,如果一台服务器宕机,则用户将不能正常访问数据
3.Redis分片机制中,是业务服务器进行一致性hash的计算.而redis服务器只需要负责数据的存储即可.所以redis分片机制性能更高.
3.哨兵实现了高可用机制,主机宕机后,从机立即补位
4.哨兵机制缺少对内存的合理扩容
6.哨兵本身没有实现高可用.哨兵如果宕机,则直接影响用户使用


redis集群策略
集群策略其实就是将哨兵机制与分片机制的优点进行了实现。
让服务器即实现高可用机制又具备内存的扩容
1.准备集群文件夹
mkdir cluster
2.在文件夹中创建对应端口的目录
mkdir 5000 5001 ......

3.拷贝redis.conf文件到一目录中

4.打开拷贝好的redis.conf文件
5.注释本地绑定IP地址

6. 关闭保护模式

7.修改端口号

8.启动后台启动

9.修改pid文件
绝对路径配置,redis.pid文件会在当前目录下生成

10.修改持久化文件路径
绝对路径配置,持久化文件会在当前目录下生成

11.设定内存优化策略

12.关闭AOF模式

13.开启集群配置

14.开启集群配置文件

15.修改集群超时时间

16.复制配置好的redis.conf文件
说明:将5000文件夹下配置完毕的redis.conf文件分别复制到5001-5008中
[root@localhost cluster]# cp 5000/redis.conf 5001/
[root@localhost cluster]# cp 5000/redis.conf 5002/
[root@localhost cluster]# cp 5000/redis.conf 5003/
[root@localhost cluster]# cp 5000/redis.conf 5004/
....
17.批量修改
说明:分别将5001-5008文件中的5000改为对应的端口号的名称
:%s/5000/5001/g
5000 #需要替换的数据
5001 #替换的数据
g #全部替换

18.创建redis集群
#5.0版本执行 使用C语言内部管理集群
redis-cli --cluster create --cluster-replicas 1
192.168.126.129:5000 192.168.126.129:5001
192.168.126.129:5002 192.168.126.129:5003
(IP+端口)......
#1的意思是一台主机后面有几台从机
#一般redis会将前面几台作为主机


redis集群原理

在集群机制中,Redis的所有节点都会保存当前redis集群中的全部主从状态信息,各个节点能够相互通信,通过心跳监测机制相互监控,如果超过一半的节点认为某节点的主机已经宕机,则会通过选举机制,投票选举链接宕机的备用机。
redis集群整合SpringBoot
1.redis.pro配置文件

#定义redis节点信息 (redis集群的IP+端口)
redis.cluster=192.168.126.129:5000,192.168.126.129:5001...
#如果在pro文件中配置了以下属性,则在配置类中无需再次添加
#最小空闲数
redis.minIdle=100
#最大空闲数
redis.maxIdle=300
#最大连接数
redis.maxTotal=1000
#=====================
2.编写配置类

package com.jt.config;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class redisConfig {
/** 单体Redis的整合配置
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private int port;
//将那个对象交给容器,返回值就是谁
@Bean
public Jedis jedis() {
Jedis jedis=new Jedis(host,port);
return jedis;
}*/
/** 分R片edis的整合配置
@Value("${redis.shards}")
private String shards;
@Bean
public ShardedJedis shardedJedis() {
List<JedisShardInfo> list = new ArrayList<JedisShardInfo>();
//1.将shards字符串转化为node数组
String[] nodes=shards.split(",");
for(String str:nodes) {
String host=str.split(":")[0];
int port = Integer.valueOf((str.split(":")[1]));
//实现节点封装
list.add(new JedisShardInfo(host, port));
}
return new ShardedJedis(list);
}
*/
//Redis集群的配置
@Value("${redis.cluster}")
private String cluster;
@Bean
public JedisCluster Jediscluster() {
String[] split = cluster.split(",");
Set<HostAndPort> nodes=new HashSet<>();
for (String str : split) {
String[] HostAndPort = str.split(":");
String host=HostAndPort[0];
int port=Integer.valueOf(HostAndPort[1]);
nodes.add(new HostAndPort(host, port));
}
//定义redis链接池
JedisPoolConfig pool=new JedisPoolConfig();
pool.setMaxTotal(1000);
pool.setMaxIdle(20);//允许空闲链接最大数
return new JedisCluster(nodes,pool);
}
}
3.DI注入即可


HASH槽(redis集群算法)
HASH槽是redis集群中的数据存储策略,所有的键根据哈希函数(CRC16(key)%16384),将键映射到到0-16383槽内,而这些槽位由不同的节点所管理,每个节点维护部分槽及槽所映射的键值数据,槽的分区会根据节点的数量均匀分配。

redis会先将键进行哈希函数运算,计算的结果会匹配到对应的槽的区间,之后再set数据,将数据保存到管理改槽的节点中。

一致性HASH(redis分片、哨兵算法)
它是一种特殊的哈希算法,目的是解决分布式缓存的问题,在新增/移除节点.要求尽可能小的改变原有的映射关系,解决了分布式环境下的存储动态伸缩性(弹性)问题.

一致性HASH具有三个特点
1.平衡性
该特点是说:hash的节点应该互相均衡,这样才能达到负载均衡的目的
因为,节点是通过hash得到的所以会出现节点不均匀的现象,所以,出现了虚拟节点,虚拟节点可以解决此类问题,它会为负载小的节点创建虚拟节点

2.单调性
单调性是指在删除或者新增节点的时候,不会影响系统正常运行,数据会随着迁移

3.分散性
分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据
redis持久化策略
因为redis是基于内存工作的,如果遇到宕机或者意外情况造成服务器关闭,则数据就会流失,这是我们不想看到的,为了解决这个问题,就需要定期将数据持久化保存,假如发生意外情况,可以根据持久化文件恢复数据。
RDB模式
redis默认情况下使用的持久化模式,该模式会定期将数据以快照的形式保存在文件中,RDB模式由于记录的是内存数据的快照所以持久化的效率较高,新的快照会覆盖旧的快照.每次保留的都是最新的数据. 持久化文件的大小相对固定.
redis.conf文件中的相关配置
持久化文件名配置

持久化文件的路径(./表示的是当前路径,也就是conf文件的当前路径)

相关指令
save #表示立即持久化,属于同步操作,持久化的过程中阻塞其他线程
bgsave #表示立即持久化,属于异步操作
save 900 1 如果在900秒内,用户执行了1次更新操作,则持久化1次
save 300 10 如果在300秒内,用户执行了10次更新操作,则持久化1次
save 60 10000 如果在60秒内,用户执行了10000次更新操作,则持久化1次
思考问题:
设置save 1 1 可以吗?
答:由于save指令是阻塞的,所以该操作会极大的影响执行效率.
设置bgsave 1 1 可以吗?
答:异步操作 有可能导致内存数据与持久化文件中的数据不一致.
AOF模式
AOF模式默认是关闭状态,需要手动开启,此模式记录的是用户的操作,持久化文件大,持久效率慢
开启AOF(开启之后需要重启redis)

默认文件名

AOF持久化策略

appendfsync always 当用户更新了redis,则追加用户操作记录到aof文件中
appendfsync everysec 每秒持久化一次. 略低于rdb模式.
appendfsync no 不持久化(不主动持久化,由操作系统决定什么时候持久化) 该操作一般不配.
如果在操作redis时不慎执行了FLUSHALL,如何处理?
1.首先关闭所有的redis
2.找到redis的AOF文件. 将FLUSHALL命令删除.之后重启redis服务器即可.

如何合理选择:
1.如果内存数据可以允许少量的数据丢失,则首选rdb
2.如果内存数据存储的是业务数据不允许丢失,则选用aof模式.(AOF文件相对较大,所以定期维护.)
3.redis中所有的操作都是单进程单线程操作.(串行的)所以不会造成线程并发性问题
redis中的缓存淘汰策略
在redis中内存是有限的,如果数据过多,redis会根据相关算法清除数据,redis中提供了9种内存机制,可以根据其中不同的算法,实现内存数据的优化。
1.修改redis内存

2.换算进制

3.各种淘汰算法

1.volatile-lru 在设定了超时时间的数据中采用 lru算法
2.allkeys-lru . 所有数据采用lru算法
3.volatile-lfu 在设定了超时时间的数据中采用lfu算法
4.allkeys-lfu 所有数据采用lfu算法
5.volatile-random 设定了超时时间的数据采用随机算法
6.allkeys-random ->随机删除数据
7.volatile-ttl 设定了超时时间的数据,采用ttl算法
8.noeviction 不删除任何数据,只是报错返回.
4.选择一种适合的淘汰策略即可

redis的缓存问题
缓存穿透
如果用户一直在访问数据库中压根不存在的数据,请求不会走redis缓存,而是都发送到了服务器上,导致服务器压力过大,存在宕机风险,这种现象称为缓存穿透。
解决方案:
一般做数据的有效性的校验.
缓存击穿
由于某一个热点数据超时后,大量用户访问此数据,短时间内数据库访问压力加大,这种现象称为缓存击穿。
如何解决:
1.将热点数据永久保存.
2.添加互斥(排它)锁(每次只能有一个用户访问数据库/第二次走缓存) lock操作
缓存雪崩
在redis内存中的数据,在一定的时间内,有大量的缓存数据失效(多个),这时用户大量的访问缓存服务器,但是缓存中没有指定数据,则访问数据库.容易出现数据库宕机,这种现象称为缓存雪崩。
如何解决:
1.让热点数据永久有效
2.设定超时时间采用随机数. 让超时的数据不要在同一时间发生
3.设定多级缓存
相关文章推荐:https://blog.youkuaiyun.com/zeb_perfect/article/details/54135506
面试题
问题描述: 如果同时开启了aof模式和rdb模式.问哪个生效?
1.默认条件下redis采用rdb模式,如果开启了AOF模式,则以aof模式为主
2.同时可以通过save指令,实现rdb模式的持久化操作
问题描述:为什么不使用Redis中的事务控制?
说明:虽然redis提供了事务操作.但是该事务是一种弱事务.
只对单台redis有效.
如果有多台redis,如果需要使用事务控制,则一般使用队列的形式.
@Test
public void testTX() {
Transaction transaction = jedis.multi(); //开始事务
try {
transaction.set("a", "a");
transaction.set("b", "b");
//int a = 1/0;
transaction.exec(); //提交事务
} catch (Exception e) {
e.printStackTrace();
transaction.discard(); //事务回滚
}
}
问题描述:为什么在分布式集群中节点要使用奇数台?
节点的数量要满足以下公式
公式:剩余存活节点 > 总节点/2
根据公式我们得知最小的节点个数为3
假如准备3个节点
3台宕机1台
2 > 3/2=1.5
如果再次宕机
1 < 3/2=1.5
显然,如果是3个节点,允许最多宕机1台
假如我们多搭建一个节点,允许宕机的个数会不会增长呢?
假如准备4个节点
4台宕机1台
3 > 4/2=2
如果再次宕机
2 = 4/2=2
如果搭建4个节点,发现允许宕机的最大节点数依然是1台
3台与4台的结果相同,在节省资源的前提下,选择前者

3万+

被折叠的 条评论
为什么被折叠?



