共计 5582 个字符,预计需要花费 14 分钟才能阅读完成。
- Redis 分片机制
=============
1.1 为什么须要分片机制
如果须要存储海量的内存数据, 如果只应用一台 redis, 无奈保障 redis 工作的效率. 大量的工夫都节约到了寻址当中. 所以须要一种机制可能满足该要求.
采纳分片机制实现:
1.2 Redis 分片搭建
1.2.1 搭建注意事项
Redis 服务的启动须要依赖于 redis.conf 的配置文件. 如果须要筹备 3 台 redis. 则须要筹备 3 个 redis.conf 的配置.
筹备端口号:
1.6379
2.6380
3.6381
1.2.2 分片实现
批改端口号: 将各自的端口号进行批改.
启动 3 台 redis 服务器
校验服务器是否失常运行
1.2.3 对于分片的注意事项
1. 问题形容:
当启动多台 redis 服务器之后, 多台 redis 临时没有必然的分割, 各自都是独立的实体. 能够数据数据的存储. 如图所示.
2. 如果将分片通过程序的形式进行操作, 要把 3 台 redis 当做一个整体, 所以与上述的操作齐全不同. 不会呈现一个 key 同时保留到多个 redis 的景象.
1.3 分片入门案例
`/**
* 测试 Redis 分片机制
* 思考: shards 如何确定应该存储到哪台 redis 中呢???
*/
@Test
public void testShards(){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("shards","redis 分片测试");
System.out.println(shardedJedis.get("shards"));
}`
1.4 一致性 hash 算法
1.4.0 常识阐明
常识 1: 个别的 hash 是 8 位 16 进制数. 0-9 A-F (24)8 = 2^32
常识 2: 如果对雷同的数据进行 hash 运算 后果必然雷同的.
常识 3: 一个数据 1M 与数据 1G 的 hash 运算的速度统一.
1.4.1 一致性 hash 算法介绍
一致性哈希算法在 1997 年由麻省理工学院提出,是一种非凡的哈希算法,目标是解决分布式缓存的问题。[1] 在移除或者增加一个服务器时,可能尽可能小地扭转已存在的服务申请与解决申请服务器之间的映射关系。一致性哈希解决了简略哈希算法在分布式哈希表(Distributed Hash Table,DHT) 中存在的动静伸缩等问题 [2]。
1.4.2 个性 1 - 平衡性
概念: 平衡性是指 hash 的后果应该平均分配到各个节点,这样从算法上解决了负载平衡问题 [4]。(大抵均匀)
问题形容: 因为节点都是通过 hash 形式进行合计. 所以可能呈现如图中的景象., 导致负载重大不均衡
解决办法: 引入虚构节点
1.4.3 个性 2 - 枯燥性
特点: 枯燥性是指在 新增 或者 删减 节点时,不影响零碎失常运行 [4]。
1.4.4 个性 3 - 分散性
谚语: 鸡蛋不要放到一个篮子里.
③分散性是指数据应该扩散地寄存在分布式集群中的各个节点(节点本人能够有备份),不用每个节点都存储所有的数据 [4]
1.5 SpringBoot 整合 Redis 分片
1.5.1 编辑配置文件
`# 配置 redis 单台服务器
redis.host=192.168.126.129
redis.port=6379
# 配置 redis 分片机制
redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381`
1.5.2 编辑配置类
`@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {@Value("${redis.nodes}")
private String nodes; //node,node,node.....
// 配置 redis 分片机制
@Bean
public ShardedJedis shardedJedis(){nodes = nodes.trim(); // 去除两边多余的空格
List<JedisShardInfo> shards = new ArrayList<>();
String[] nodeArray = nodes.split(",");
for (String strNode : nodeArray){ //strNode = host:port
String host = strNode.split(":")[0];
int port = Integer.parseInt(strNode.split(":")[1]);
JedisShardInfo info = new JedisShardInfo(host, port);
shards.add(info);
}
return new ShardedJedis(shards);
}
}`
1.5.3 批改 AOP 注入项
2 Redis 哨兵机制
2.1 对于 Redis 分片阐明
长处: 实现内存数据的扩容.
毛病: 如果 redis 分片中有一个节点呈现了问题., 则整个 redis 分片机制用户拜访必然有问题 间接影响用户的应用.
解决方案: 实现 redis 高可用.
2.2 配置 redis 主从的构造
策略划分: 1 主 2 从 6379 主 6380/6381 从
1. 将分片的目录复制 改名位 sentinel
- 重启三台 redis 服务器
3. 查看 redis 节点的主从的状态
4. 实现主从挂载
5. 查看主机的状态
2.3 哨兵的工作原理
原理阐明:
1. 配置 redis 主从的构造.
2. 哨兵服务启动时, 会监控以后的主机. 同时获取主机的详情信息(主从的构造)
3. 当哨兵利用心跳检测机制(PING-PONG) 间断 3 次都没有收到主机的反馈信息则判定主机宕机.
4. 当哨兵发现主机宕机之后, 则开启选举机制, 在以后的从机中筛选一台 Redis 当做主机.
5. 将其余的 redis 节点设置为新主机的从.
2.4 编辑哨兵配置文件
1). 复制配置文件
cp sentinel.conf sentinel/
2). 批改保护模式
3). 开启后盾运行
4). 设定哨兵的监控
其中的 1 示意投票失效的票数 以后只有一个哨兵所以写 1
5). 批改宕机的工夫
6). 选举失败的工夫
阐明: 如果选举超过指定的工夫没有完结, 则从新选举.
7). 启动哨兵服务
2.5 Redis 哨兵高可用实现
测试步骤:
1. 查看主机的状态
2. 将 redis 主服务器宕机 期待 10 秒 之后查看从机是否入选新的主机
3. 重启 6379 服务器., 查看是否成为了新主机的从.
2.6 哨兵入门案例
`/**
* 测试 Redis 哨兵
*/
@Test
public void testSentinel(){Set<String> set = new HashSet<>();
//1. 传递哨兵的配置信息
set.add("192.168.126.129:26379");
JedisSentinelPool sentinelPool =
new JedisSentinelPool("mymaster",set);
Jedis jedis = sentinelPool.getResource();
jedis.set("aa","哨兵测试");
System.out.println(jedis.get("aa"));
}`
2.7 SpringBoot 整合 Redis 哨兵 (10 分钟)
2.7.1 编辑 pro 配置文件
`# 配置 redis 单台服务器
redis.host=192.168.126.129
redis.port=6379
# 配置 redis 分片机制
redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381
# 配置哨兵节点
redis.sentinel=192.168.126.129:26379`
2.7.2 编辑 redis 配置类
`@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {@Value("${redis.sentinel}")
private String sentinel; // 临时只有单台
@Bean
public JedisSentinelPool jedisSentinelPool(){Set<String> sentinels = new HashSet<>();
sentinels.add(sentinel);
return new JedisSentinelPool("mymaster",sentinels);
}
}`
2.7.3 批改 CacheAOP 中的注入项
`package com.jt.aop;
import com.jt.anno.CacheFind;
import com.jt.config.JedisConfig;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.ShardedJedis;
import java.lang.reflect.Method;
import java.util.Arrays;
@Aspect // 我是一个 AOP 切面类
@Component // 将类交给 spring 容器治理
public class CacheAOP {
@Autowired
//private Jedis jedis; // 单台 redis
//private ShardedJedis jedis; // 分片机制
private JedisSentinelPool jedisSentinelPool;
/**
* 切面 = 切入点 + 告诉办法
* 注解相干 + 盘绕告诉 控制目标办法是否执行
*
* 难点:
* 1. 如何获取注解对象
* 2. 动静生成 key prekey + 用户参数数组
* 3. 如何获取办法的返回值类型
*/
@Around("@annotation(cacheFind)") // 参数传递变量的传递
//@Around("@annotation(com.jt.anno.CacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
// 从池中获取 jedis 对象
Jedis jedis = jedisSentinelPool.getResource();
Object result = null;
try {
//1. 拼接 redis 存储数据的 key
Object[] args = joinPoint.getArgs();
String key = cacheFind.preKey() +"::" + Arrays.toString(args);
//2. 查问 redis 之后判断是否有数据
if(jedis.exists(key)){
//redis 中有记录, 无需执行指标办法
String json = jedis.get(key);
// 动静获取办法的返回值类型 向上造型 向下造型
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class returnType = methodSignature.getReturnType();
result = ObjectMapperUtil.toObj(json,returnType);
System.out.println("AOP 查问 redis 缓存");
}else{
// 示意数据不存在, 须要查询数据库
result = joinPoint.proceed(); // 执行指标办法及告诉
// 将查问的后果保留到 redis 中去
String json = ObjectMapperUtil.toJSON(result);
// 判断数据是否须要超时工夫
if(cacheFind.seconds()>0){jedis.setex(key,cacheFind.seconds(),json);
}else {jedis.set(key, json);
}
System.out.println("aop 执行指标办法查询数据库");
}
} catch (Throwable throwable) {throwable.printStackTrace();
}
jedis.close(); // 将应用实现的链接记得敞开.
return result;
}
}`
作业
1. 预习 Redis 集群搭建步骤
2. 理解 redis 集群工作原理