Redis分片机制说明
1.1 一致性hash算法
1.1.1 一致性hash算法介绍
一致性哈希算法是一种特殊的哈希算法,目的是为了解决分布式缓存的问题。在移除或者添加一个服务器的时候,能够尽可能小的改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表中存在的动态伸缩问题。
1.1.2 一致性Hash原理说明
常识:
1. 对相同的数据hash得到的结果相同
2. 常见的hash值 8位十六进制数 2^32种可能性
哈希环: 在哈希环上存放着缓存服务器中的多个节点,服务器的节点存放位置是根据服务器的节点得到的哈希值来确定的,当进行缓存数据存储的时候,对key值进行hash计算,获取到hash值,判断在hash环上的位置,根据key的哈希值所在哈希环的位置,根据顺时针进行服务器选取,将数据存储到缓存服务器中.
1.1.3 平衡性说明
说明: 平衡性是指hash的结果应该平均分配到各个节点,这样从算法上解决
了负载均衡问题,如果发现数据分部不均匀,则采用虚拟节点的方式,实现数据的平衡,如果一次平衡不能达到目标则多次生成虚拟节点,但是数据平衡没有办法做到绝对的平均
1.1.4 单调性
是指分布式缓存在新增或删减节点时,不影响系统的正常运行
如果是新增或者删减节点时,尽可能不改变原有的数据结构
1.1.4 分散性
分散性是指缓存中的数据应该分散的存放在分布式集群的各个缓存节点中,不必每个节点都存储所有的数据,(每个节点都有其自己的备份)[其实也就是缓存扩容的结果将多个节点看做是一个大的缓存服务器]
2. redis哨兵机制(sentinel: 哨兵)
相当于是tomcat服务器的代理服务器nginx,实现服务器的高可用(使用代理管理多台tomcat服务器的请求分发,缓解单个服务器访问压力),在数据库服务器中也要实现数据库的高可用,高可用的前提是实现数据库之间的主从挂载,同样使用代理服务器mycat完成对多台服务器之间的的高可用配置,使用mycat管理的主从服务器之间想要实现数据库高可用,还需要考虑数据库安全问题,如果主机发生宕机现象,由从机代理执行主机功能,所以单一的主从挂载不足以满足次要求,需要设置主从服务器之间的数据同步,方便主机同步从机数据(也就是数据库的互为主从挂载)
redis实现服务器高可用功能的前提是redis服务器的主从挂载,但是仅仅是前提,实现高可用的主要操作还是要依赖于redis的哨兵机制,哨兵机制其实就是一个针对多个redis主从服务器的管理服务器,通过对主机状态的监控,当主机遇到异常宕机时使用哨兵进行选取一个从机当做主机继续提供服务,实现服务器的高可用
2.1 redis分片机制问题
说明: 如果redis分片中有一个节点宕机,则可能影响整个服务器运行,redis分片并没有实现高可用(仅仅是实现了redis缓存的扩容)
2.2 redis实现主从结构构建
2.2.1 赋值配置文件(创建多个redis服务器,直接复制多个conf配置文件即可)
2.2.2 准备三台redis
###2.2.3
命令1: info replication
命令2; slaveof IP PORT 主从挂载命令(在从机中执行此命令,表示向指定ip地址端口号的服务器设置为自己的主机)
检查主机状态
关于主从结构说明:
主和从都知道,当前的主从的状态,并且只有主机可以进行写操作,从机只能进行读操作(如果在从机中进行写操作,控制台会直接报错,表示该服务器是一个从机不能进行写操作)
2.2 redis哨兵机制工作原理
- 当哨兵启动时,首先会监控主机,从主机中获取当前所有的节点的状态,同时哨兵开启心跳检测机制
- 当主机发生宕机的现象时,由于哨兵有PING-PONG机制,发现主机宕机,则哨兵进行选举
- 当选举成功之后,新的主机当选之后,其他的节点当新主机的从机(原先的主机恢复后,并不像数据库服务器主机修复之后,同步从机数据继续当主机,而是充当新主机的从机进行工作)
2.3 编辑哨兵配置文件
- 关闭保护模式
- 开启后台运行
- 编辑监控配置
注意事项: mymaster为配置的主机名,主机名可以自己定义 - 修改选举时间
2.4 启动哨兵服务
命令: redis-sentinel sentinel.conf
所谓的哨兵服务其实就是一个特别的redis服务,依旧需要使用配置文件开启服务,与一般的redis缓存服务器相同,只不过是设计的时候加入了一些特有的功能,让其成为了一个redis哨兵服务器
高可用检查:
1. 先关闭主机,等待10秒钟检查是否进行选举(10s为设置的哨兵选取新的主机时限)
2. 启动6379,检查是否当选新主机的从机
哨兵机制设置出现问题解决方案:
重新复制主从服务器的配置文件,不能使用之前配置未生效的服务器的配置文件,因为在哨兵机制中哨兵服务器启动时,就会对其他缓存服务器的配置文件进行控制,也就是虽然哨兵没有生效但是已经对管理的缓存服务器配置文件作出了修改,所以如果还是用原先的配置文件启动服务器,有可能还是会出现问题,所以最直接的方法就是完整的重新配置哨兵机制需要一切文件
2.5 哨兵测试API
/**
* 测试redis哨兵机制:
* 此时的哨兵管理着多个redis服务器,但是使用的时候还是将主从挂载的多个服务器当做一个服务器进行使用
* 使用时还需要使用一个哨兵池对象,获取到一个哨兵对象,因为一个哨兵对象其实就相当于是一个redis服务器对象
*/
@Test
void testSentinel(){
Set<String> set=new HashSet<>();
set.add("192.168.126.129:26379");//创建哨兵池对象时需要传递一个set集合,集合中存储的是找到对应哨兵服务器的ip地址及端口号,
JedisPoolConfig poolConfig = new JedisPoolConfig();//这是一个配置对象,配置的是哨兵池的配置属性,当
//创建哨兵池对象的时候,需要此配置对象参数
poolConfig.setMaxTotal(1000);//设置哨兵池的最大连接数
poolConfig.setMaxIdle(40);//设置哨兵池最大闲置哨兵数
poolConfig.setMinIdle(10);//设置哨兵池最小闲置哨兵数
JedisSentinelPool sentinelPool=new JedisSentinelPool("mymaster", set, poolConfig);
//从池中取出一个哨兵对象,实际上取出的是哨兵选取出来的redis服务器对象
Jedis jedis = sentinelPool.getResource();
jedis.set("sentinel", "哨兵机制测试");
String sentinel = jedis.get("sentinel");
System.out.println(sentinel);
//因为是从池中获取到的redis服务器对象,使用完毕之后,需要归还连接(使用close()归还连接)
jedis.close();
}
2.6 Springboot整合哨兵机制
2.6.1 编辑Pro配置文件
2.6.2 编辑配置类
2.6.3 编辑CacheAOP
2.6.4 关于分片/哨兵总结
- redis分片主要的作用实现内存的扩容,缺点: 没有实现高可用(缓存数据高可用是在主从挂载服务器的基础上使用哨兵机制对主从挂载的缓存服务器进行管理控制,减少服务器不能提供服务的时间)
- redis哨兵主要的作用就是实现了redis节点高可用,缺点: 没有实现缓存扩容(因为哨兵控制的多台服务器只能当做一台服务器进行使用,不能同时进行工作,但如果提供多个哨兵的话,不好实现,以为本来哨兵服务器就是一个三级缓存服务器(引入的第三方监控),充当用户和缓存服务器之间的媒介,使用多个哨兵服务器不合适)
redis哨兵机制实际上就是引入第三方的监控,但是需要保证第三方的高可用,就必须引入更多的资源
3. Redis集群参见京淘新版本资料
3.1 集群搭建错误解决方案
注意事项: redis集群搭建要求节点的数据必须为null
将所有的redis节点服务全部关闭 sh stop.sh (使用设计好的shall命零)
- 删除多余的文件(服务器运行产生的nodes.conf和持久化文件dump.rdb文件)
然后重启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
3.2 Redis集群入门案例
/**
* 测试redis集群: 使用的api为
*/
@Test
void testCluster(){
Set<HostAndPort> set=new HashSet<>();
set.add(new HostAndPort("192.168.126.129", 7000));
set.add(new HostAndPort("192.168.126.129", 7001));
set.add(new HostAndPort("192.168.126.129", 7002));
set.add(new HostAndPort("192.168.126.129", 7003));
set.add(new HostAndPort("192.168.126.129", 7004));
set.add(new HostAndPort("192.168.126.129", 7005));
JedisPoolConfig config=new JedisPoolConfig();//使用jedis池配置类配置集群中节点的最大连接数(因为jedis池对象中默认的最大连接数为8,我们需要创建
//集群对象的时候传递一个集群中池配置对象 )
config.setMaxTotal(1000);//配置最大连接节点数为1000
config.setMaxIdle(40);
config.setMinIdle(10);
JedisCluster jedisCluster=new JedisCluster(set,config);
//集群对象可以自动的对缓存数据库进行管理,我们只需要操作集群对象操作缓存数据库即可,其实也就相当于一种反向代理,处理请求的方式,用户不知道访问的是哪个redis缓存服务器
jedisCluster.set("cluster", "测试redis集群配置");
String cluster = jedisCluster.get("cluster");
System.out.println(cluster);
}
3.3 redis集群面试题
- redis集群中一共可以存储16384个数据?
不对: redis中存储多少数据完全有内存决定(只不过是因为redis集群中对节点存放数据采用的是hash槽算法,将redis集群分为16384个槽位,每个节点管理多少个槽位,并不是只能存储这些个数据,而是经过hash计算属于某些槽位的数据交给相应的节点进行存储) - redis集群中最多可以有多少个redis主机?
redis集群中的主机数是由hash槽的数量决定的一个redis注解至少管理一个槽位的数据,所以集群中最多可以有16384个redis主机(但如果是集群中最多有多少个服务器,从机也算集群管理的服务器)
3.4 SpringBoot整合redis集群
3.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
3.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);
}
}
3.4.3 编辑CacheAOP