一、Redis分片机制阐明
1.一致性hash算法
1.1 一致性Hash算法介绍
一致性哈希算法在1997年由麻省理工学院提出,是一种非凡的哈希算法,目标是解决分布式缓存的问题。 [1] 在移除或者增加一个服务器时,可能尽可能小地扭转已存在的服务申请与解决申请服务器之间的映射关系。一致性哈希解决了简略哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动静伸缩等问题 [2] 。
1.2 一致性Hash原理阐明
常识:
1).对雷同的数据hash失去的后果雷同
2).常见hash值 8位16进制数 2^32种可能性
1.3 平衡性阐明
阐明: 平衡性是指hash的后果应该平均分配到各个节点,这样从算法上解决了负载平衡问题 .
如果发现数据分布不平均,则采纳虚构节点的形式,实现数据的均衡. 如果一次均衡不能达到目标则屡次生成虚构节点.然而数据均衡没有方法做到相对的均匀.
1.4 枯燥性阐明
枯燥性是指在新增或者删减节点时,不影响零碎失常运行
如果新增或者删除节点,则尽可能不要扭转原有的数据结构.
1.5 分散性
分散性是指数据应该扩散地寄存在分布式集群中的各个节点(节点本人能够有备份),不用每个节点都存储所有的数据
鸡蛋不要放到一个篮子里.
二、redis分片机制配置
1. redis性能优化
阐明: 单台redis内存容量是无限的.然而如果有海量的数据要求实现缓存存储,则应该应用多个Redis节点.
2. Redis分片机制定义
3. 配置布局
阐明: 筹备3台redis服务器 别离为 6379/6380/6381
3.1 筹备3个配置文件
批改各自端口号 改为6380 6381
3.2 启动redis服务器
3.3 查看redis启动状态
3.4 redis分片入门案例
4. Redis分片机制配置
阐明:依据redis节点个数.拼接字符串
#配置单台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`
4.1 编辑RedisConfig配置类
@Configuration //标识我是一个配置类 个别与@Bean注解联用@PropertySource("classpath:/properties/redis.properties")public class RedisConfig { @Value("${redis.nodes}") private String nodes; //node,node,node @Bean public ShardedJedis shardedJedis(){ List<JedisShardInfo> shards = new ArrayList<>(); String[] nodeArray = nodes.split(","); for( String node :nodeArray){ //node=host:port String host = node.split(":")[0]; int port = Integer.parseInt(node.split(":")[1]); JedisShardInfo info = new JedisShardInfo(host,port); shards.add(info); } return new ShardedJedis(shards); } }
4.2 批改CacheAOP中的注入
二、 Redis哨兵机制
1. Redis分片机制问题
阐明: 如果redis分片中有一个节点宕机,则可能会影响整个服务的运行. redis分片没有实现高可用.
2. Redis主从构造搭建
2.1 复制配置文件
2.2 筹备3台redis
2.3 主从搭建
命令1: info replication
命令2: slaveof IP PORT 主从挂载命令
查看主从构造状态
对于主从构造阐明:
主和从都晓得 以后的主从的状态, 并且只有主机能够写操作.从机只能读操作.
3. Redis哨兵机制工作原理
1).当哨兵启动时,首先会监控主机,从主机中获取以后所有的节点的状态,同时哨兵开启心跳检测机制.
2).当主机产生宕机的景象时,因为哨兵有PING-PONG机制 发现主机宕机,则哨兵开始进行选举.
3).当选举胜利之后,新的主机入选之后,其余的节点当新主机的从.
3.1 编辑哨兵配置文件
1)敞开保护模式
2).开启后盾运行
3).编辑监控配置
4).批改选举工夫
3.2 启动哨兵服务
命令: redis-sentinel sentinel.conf
高可用查看:
1).先敞开主机 期待10秒查看是否进行选举.
2).启动6379. 查看是否入选新主机的从.
3.3 哨兵测试API
/** * 测试哨兵 */ @Test public void testSentinel(){ Set<String> set = new HashSet<>(); set.add("192.168.126.129:26379"); JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(1000); poolConfig.setMaxIdle(40); poolConfig.setMinIdle(10); JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster",set,poolConfig); Jedis jedis = sentinelPool.getResource(); jedis.set("sentinel", "哨兵机制测试"); System.out.println(jedis.get("sentinel")); jedis.close(); }
4.springBoot整合哨兵机制
4.1 编辑pro配置文件
4.2 编辑配置类
4.3 编辑CacheAOP
4.4 对于分片/哨兵总结
1.Redis分片次要的作用实现内存的扩容,毛病:没有实现高可用的成果.
2.Redis哨兵次要的作用实现了redis节点高可用. 毛病:没有实现内存扩容
Redis哨兵机制本质就是引入第三方的监控,然而须要保障第三方的高可用.就必须引入更多的资源.
三、Redis集群
参见搭建文档.
1. 集群搭建谬误解决方案
注意事项: redis集群搭建要求节点的数据必须为null.
1).将所有的redis节点全副敞开 sh stop.sh
2).删除多余的文件
3).重启redis集群
redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005
2 Redis集群入门案例
@Test public void testCluster(){ Set<HostAndPort> nodes = new HashSet<>(); nodes.add(new HostAndPort("192.168.126.129", 7000)); nodes.add(new HostAndPort("192.168.126.129", 7001)); nodes.add(new HostAndPort("192.168.126.129", 7002)); nodes.add(new HostAndPort("192.168.126.129", 7003)); nodes.add(new HostAndPort("192.168.126.129", 7004)); nodes.add(new HostAndPort("192.168.126.129", 7005)); JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(1000); poolConfig.setMaxIdle(40); poolConfig.setMinIdle(20); JedisCluster jedisCluster = new JedisCluster(nodes,poolConfig); jedisCluster.set("jedisCluster", "redis集群搭建"); System.out.println(jedisCluster.get("jedisCluster")); }
3. 面试问题
1).redis集群中一共能够存储16384个数据?
不对: redis中存储多少数据齐全由内存决定
hash(key1)=3000
hash(key2)=3000
2).redis集群中最多能够有多少个redis主机? 16384台主机 一台主机治理一个槽位.
4. SpringBoot整合Redis集群
4.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哨兵机制#redis.node=192.168.126.129:26379#配置redis集群redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005`
4.2 编辑配置类
@Configuration //标识我是一个配置类 个别与@Bean注解联用@PropertySource("classpath:/properties/redis.properties")public class RedisConfig { @Value("${redis.nodes}") private String nodes; //node,node,node @Bean public JedisCluster jedisCluster(){ Set<HostAndPort> nodesSet = new HashSet<>(); String[] nodeArray = nodes.split(","); for (String node : nodeArray){ //host:port String host = node.split(":")[0]; int port = Integer.parseInt(node.split(":")[1]); HostAndPort hostAndPort = new HostAndPort(host, port); nodesSet.add(hostAndPort); } JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(1000); config.setMaxIdle(60); config.setMinIdle(20); return new JedisCluster(nodesSet,config); } }
4.3 编辑CacheAOP
@Aspect //标识是个切面@Component //将对象交给spring容器治理public class CacheAop { @Autowired //private Jedis jedis;//单台测试 //private ShardedJedis jedis;//实现分片操作 //private JedisSentinelPool sentinelPool; //注入池对象 哨兵机制 private JedisCluster jedis;//注入集群对象 /** * 实现思路: * 1.动静获取key 用户自定义的前缀+用户的参数[0,xx] * 2.判断key是否存在 * 存在: 间接从redis中获取数据 JSON, 须要将json转化为具体对象 依照返回值类型进行转化 * 不存在: 执行指标办法.取得返回值数据. 将返回值后果转化为JSON格局. 之后保留到缓存中. * @param joinPoint * @return */ @Around("@annotation(cacheFind)") public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){ //Jedis jedis=sentinelPool.getResource(); Object result=null; //1.获取key的前缀 String key = cacheFind.key(); //2.获取办法参数 String argString = Arrays.toString(joinPoint.getArgs()); key = key + "::" + argString; try { //3.判断缓存在是否有key if (jedis.exists(key)){ String json=jedis.get(key); //5.获取返回值类型 MethodSignature methodSignature= (MethodSignature) joinPoint.getSignature(); result=ObjectMapperUtil.toObject(json,methodSignature.getReturnType()); System.out.println("AOP查问redis缓存"); }else { //示意缓存中没有数据 result=joinPoint.proceed(); String json= ObjectMapperUtil.toJson(result); //4.判断数据中是否有超时工夫 if (cacheFind.seconds()>0){ jedis.setex(key,cacheFind.seconds(),json); }else { jedis.set(key,json); } System.out.println("AOP执行数据库调用!!!!"); } result = joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); throw new RuntimeException(throwable); } //jedis.close(); //还池操作 return result; }