redis的模式
redis总共有四种模式:单体,分片,哨兵,以及集群,我们采用java代码连接redis.
java连接redis的jar包,用很多种,主要有Redisson,Jedis,lettuce.
- redisson默认实现redis分布式锁;
- lettuce是springboot-redis-starter默认支持的redis客户端.
这里我们一jedis客户端来做步骤演示,步骤:
一.单体模式
搭建redis服务器
步骤:
(1)创建一个文件夹single,并且复制redis.conf文件到single目录下
(2)修改redis.conf文件
修改端口号,关闭保护模式
其他的比如密码,持久化策略等咱么测试可以选择不去设置,使用默认的就行.
(3)启动redis服务
编写java后台
(1)导入jar包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
(2) 获取redis的客户端,并注入到springbean容器中
@Bean
@Scope("singleJedis")
public Jedis getJedis(){
String host = xxx;
Integer port = xxx;
Jedis jedis = new Jedis(host, port);
return jedis;
}
(3)业务代码中使用
这里直接使用junit测试
@Test
public void singleRedis(){
//xxx代表的是ip地址
Jedis jedis = new Jedis("xxxx",6390);
//xxx代表的是密码
jedis.auth("xxx");
String result = jedis.set("FirstName", "古");
String firstName = jedis.get("FirstName");
System.out.println(firstName );
}
单体架构的优缺点:
优点:简单,便捷,搭建容易.
缺点:
1.一旦redis服务挂掉,则服务将访问不了缓存,可能导致直接访问数据库,数据库压力增大,导致数据库访问压力过大而崩溃.
2.单台redis的内存受限于服务器的内存,如果服务器内存过小,则我们的redis使用内存也小.
二.分片模式(sharde)
(1)分片概述
解决的问题:扩容,因为单台redis的内存受限于单台服务器,所以我们使用分片,扩大redis的容量.
原理:
采用多台redis服务器,共同维护一整块内存空间大小,最终实现了内存数据的扩容
(2) redis服务器搭建步骤:
1)创建目录shards,并复制一个redis.conf的文件到目录下,并且将redis.conf文件复制3份
2)修改端口号
3)启动三台redis的服务
(3)编写java后台
1)导入依赖
和单体架构相同,这里就省略了
2)编写代码
@Test
public void shardRedis(){
//构建JedisShardInfo这个的list集合
ArrayList<JedisShardInfo> jedisShardList = new ArrayList<>();
//创建JedisShardInfo分片节点对象
JedisShardInfo jedisShardInf1 = new JedisShardInfo("xxx",6380);
JedisShardInfo jedisShardInf2 = new JedisShardInfo("xxx",6381);
JedisShardInfo jedisShardInf3 = new JedisShardInfo("xxx",6382);
jedisShardList.add(jedisShardInf1);
jedisShardList.add(jedisShardInf2);
jedisShardList.add(jedisShardInf3);
//实例化shard对象
ShardedJedis shardedJedis = new ShardedJedis(jedisShardList);
shardedJedis.set("name","xx");
shardedJedis.set("age","28");
shardedJedis.set("citr","成都");
shardedJedis.set("country","中国");
System.out.println(shardedJedis.get("name"));
}
结果如图:
数据就存放在了三个redis服务器中了
(4)原理及问题分析
redis分片,也就是shardJedis怎么分配数据存储呢,会不会导致数据倾斜,也就是一个redis服务存放特别多,其他的redis服务没存多少呢?
解决redis分片的数据倾斜的问题.
1)查看源码:
public String set(String key, String value) {
Jedis j = (Jedis)this.getShard(key);
return j.set(key, value);
}
Hash一致性算法介绍
1 步骤:
- 1.确定节点node的位置.
- 2.对key进行hash运算.获取唯一的位置
- 3.之后顺时针找到最近的节点.
- 4.之后链接节点进行set/get操作.
2 均衡性
说明:为了解决数据分配不均,采用虚拟节点的方式实现数据的均衡(均衡性算法)
问题说明:如果没有虚拟节点平衡数据,则会造成数据负载不均.
3 单调性
说明:当节点新增时,数据可以实现自动的迁移.
重点:一旦节点宕机,则内存缺失.整个分片不能正常使用,因为每一个分片都各自存有数据,并且各分片没有备应用服务器.
原则:如果节点新增,则尽可能保证原有的数据不发生变化.
三.哨兵模式(sentinel)
(1)分片模式概述
功能:
redis分片实现了内存数据的扩容.但是redis分片没有实现高可用的效果.当redis分片的节点node如果宕机.导致整个分片不能正常执行.能否实现redis节点的高可用.
原理分析
实现步骤:
1.哨兵启动时首先监控主机的状态,并且记录主机的全部信息(包括从机的host:port);
2.当主机发生宕机现象时.首先会根据PING-PONG心跳检测机制,查看主机的状态,如果连续3次主机无法响应,则断定主机宕机.
3.由哨兵利用自己的推选的算法.选举出新的主机.并且将其他的节点改为当前主机的从机.
主从复制的原理及过程
1)Redis使用异步复制。但从Redis 2.8开始,从服务器会周期性的应答从复制流中处理的数据量。
2)一个主服务器可以有多个从服务器。
3)从服务器也可以接受其他从服务器的连接。除了多个从服务器连接到一个主服务器之外,多个从服务器也可以连接到一个从服务器上,形成一个图状结构。
4)Redis主从复制不阻塞主服务器端。也就是说当若干个从服务器在进行初始同步时,主服务器仍然可以处理请求。
5)主从复制也不阻塞从服务器端。当从服务器进行初始同步时,它使用旧版本的数据来应对查询请求,假设你在redis.conf配置文件是这么配置的。 否则的话,你可以配置当复制流关闭时让从服务器给客户端返回一个错误。但是,当初始同步完成后,需要删除旧的数据集和加载新的数据集,在这个短暂的时间内,从服务器会阻塞连接进来的请求。
6)主从复制可以用来增强扩展性,使用多个从服务器来处理只读的请求(比如,繁重的排序操作可以放到从服务器去做),也可以简单的用来做数据冗余。
7)使用主从复制可以为主服务器免除把数据写入磁盘的消耗:在主服务器的redis.conf文件中配置“避免保存”(注释掉所有“保存“命令),然后连接一个配
置为“进行保存”的从服务器即可。但是这个配置要确保主服务器不会自动重启(要获得更多信息请阅读下一段)
(2) 搭建服务端
1)创建目录,复制redis.conf文件3份,并且复制sentinel.conf文件
这里默认三个服务都是主节点,我们接下里需要配置哨兵文件也就是sentinel.conf文件.
检查节点状态(info replication)
启动三个服务
2)配置sentinel.conf文件
关闭哨兵保护模式
开启后台启动
修改哨兵监控信息
mymaster:变量名称 标识主机信息
1: 表示哨兵选举的票数. 一般数量> 哨兵 1/2
修改宕机的超时时间,并保存文件
注意这个配置一定要配置到上面的配置之后,也就是下面的行数,因为这行配置会用到我们自定义的master的名字.
启动哨兵
命令:redis-sentinel sentinel.conf
3)检查各个redis的状态
主机6380
从机6381,无法存值,可以取值,该值为主机同步过来的值
从机6382,无法存值,可以取值,该值为主机同步过来的值
4)测试主节点服务宕机,哨兵是否能自动推举新的主节点
步骤:
- 检查当前redis服务
- 停止当前哨兵中的master主服务
- 检查是否从节点升级为master服务
(3) 编写java端代码
@Test
public void sentinelRedis(){
Set<String> sentinels = new HashSet<>();
sentinels.add("127.0.0.0:26379");
JedisSentinelPool pool =
new JedisSentinelPool("mymaster", sentinels);
Jedis jedis = pool.getResource();
jedis.set("test", "redis哨兵测试成功!!!!");
System.out.println(jedis.get("test"));
}
四.集群模式(cluster)
1.概述及原理分析
产生原因:
- 分片模式支持扩容了,但是不能保证高可用性,一台机器宕机则会导致数据丢失,整个服务用不了.
- 哨兵模式支持高可用了,但是如果哨兵宕机了,也不能高可用,并且哨兵中的所有redis服务存放的额数据都相同,不支持扩容.所以产生了集群.
2.搭建集群服务器
1)集群搭建计划
主从划分:
3台主机 3台从机共6台 端口划分7000-7005
通用的概念(不适用redis集群)
通常情况下,集群(哨兵)的数量都是奇数台(包含主从)
集群(哨兵)正常工作的条件 存活的服务器数量 > 总数N/2
1台 不能搭建集群
2台 不能搭建集群
3台 2 > 1.5 搭建集群最小单位3台 最多宕机1台
4台 3 > 2 也可以搭建集群 最多宕机1台
所以集群的数量一般都是奇数台
2)创建一个cluster文件夹
说明:
将redis根目录中的redis.conf文件复制到cluster/7000/ 并以原名保存
命令: cp redis.conf cluster/7000/
cluster目录
3)编写redis.conf配置文件
1.注释本地绑定IP地址
2.关闭保护模式
3.修改端口号
4.启动后台启动
5.修改pid文件
6.修改持久化文件路径
7.设定内存优化策略
8.关闭AOF模式
9.开启集群配置
10.开启集群配置文件
11.修改集群超时时间
4)复制修改后的配置文件并修改
1.说明:将7000文件夹下的redis.conf文件分别复制到7001-7005中
[root@localhost cluster]# cp 7000/redis.conf 7001/
[root@localhost cluster]# cp 7000/redis.conf 7002/
[root@localhost cluster]# cp 7000/redis.conf 7003/
[root@localhost cluster]# cp 7000/redis.conf 7004/
[root@localhost cluster]# cp 7000/redis.conf 7005/
2.批量修改
说明:分别将7001-7005文件中的7000改为对应的端口号的名称,
修改时注意方向键的使用
5) 编写启动脚本和停止脚本
1.创建启动脚本 vim start.sh
2.创建停止脚本 vim shutdown.sh
3.启动redis节点
4.检查启动redis服务
6) 正式以集群方式启动
1.启动所有的服务
命令:sh start.sh
2.检查当前所有redis服务是否启动成功
3.命令
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
说明:在redis 5.0之后才能使用上述方式,5.0之前用的是redis-trib.rb.
输入yes
由此redis集群就搭建好了.
7) 测试集群
1.测试存值取值
登陆服务器命令,这次登陆命令和普通登陆命令有所不同:
redis-cli -c -h yourhost -p yourpost
2.检测节点宕机
6台服务器,3个节点,最多可以宕机2台,集群正常运行.
3.编写java后台程序
/**
* 集群
*/
@Test
public void clusterRedis(){
//1.构建节点对象
HashSet<HostAndPort> nodes = new HashSet<>();
for(int i = 8001;i <= 8006; i ++){
HostAndPort hostAndPort = new HostAndPort("118.190.58.27",i);
boolean add = nodes.add(hostAndPort);
}
//2.创建cluster对象
JedisCluster cluster = new JedisCluster(nodes,5000,1000);
//3.存值
cluster.set("password","123456");
System.out.println(cluster.get("password"));
}
4.redis集群原理及注意事项
原理说明:
Redis的所有节点都会保存当前redis集群中的全部主从状态信息.并且每个节点都能够相互通信.当一个节点发生宕机现象.则集群中的其他节点通过PING-PONG检测机制检查Redis节点是否宕机.当有半数以上的节点认为宕机.则认为主节点宕机.同时由Redis剩余的主节点进入选举机制.投票选举链接宕机的主节点的从机.实现故障迁移.
集群宕机条件
特点:集群中如果主机宕机,那么从机可以继续提供服务,
当主机中没有从机时,则向其它主机借用多余的从机.继续提供服务.如果主机宕机时没有从机可用,则集群崩溃.
答案:9个redis节点,节点宕机5-7次时集群才崩溃.
如图-25所示
Redis hash槽存储数据原理
说明: RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]&16383)映射到0-16384槽内,共16384个槽位,每个节点维护部分槽及槽所映射的键值数据.根据主节点的个数,均衡划分区间.
算法:哈希函数: Hash()=CRC16[key]&16383按位与
如图-26所示
当向redis集群中插入数据时,首先将key进行计算.之后将计算结果匹配到具体的某一个槽的区间内,之后再将数据set到管理该槽的节点中.
如图-27所示
效率高:
分片效率高: 发生在服务器中 redis只负责存取
Redis集群: 发生在redis内部 效率低
5.redis集群主从数据怎么保证一致性
参考文章:
https://blog.csdn.net/cbjcry/article/details/84925440
其实原理就是:
- 一主多从
- 从库要数据,把主库现在有的数据RDB(全量数据)存下来,发给你;
- 把主库接下来收到的指令,发给你.
具体解释
- redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
- 通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。
- 当一个从数据库启动时,会向主数据库发送sync(新版psync)命令,
- 主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来(把我现在有的数据RDB发给你,把我接下来收到的命令也发给你,这下就同步了)
- 当快照完成后,redis会将快照文件和所有缓存的命令发送给从数据库。
- 从数据库收到后,会载入快照文件并执行收到的缓存的命令。