1 需求数据
如果需要在redis中进行海量的数据存储,如果只有一台redis显然不能实现该功能.如果通过扩大内存的方式也不能达到要求.因为时间都浪费在寻址中. 如何有效的存储海量的数据呢???
2 Redis分片说明
说明:一般采用多台redis,分别保存用户的数据,从而实现内存数据的扩容.
对于用户而言:将redis分片当做一个整体,用户不在乎数据到底存储到哪里,只在乎能不能存.
分片主要的作用: 实现内存扩容.
3 Redis分片准备
3.1 创建目录
说明:在redis根目录中创建一个shards目录
3.2 分片搭建策略
说明:由于Redis启动是根据配置文件运行的,所以如果需要准备3台redis,则需要复制3份配置文件redis.conf. 端口号依次为6379/6380/6381
复制配置文件:
修改端口号:
根据配置文件名称,动态修改对应的端口即可.
快速查询端口 : /port
启动redis:
redis-server 6379.conf
redis-server 6380.conf
redis-server 6381.conf
检查服务是否启动:
启动多台redis
命令: [root@localhost shards]# redis-server 6379.conf & redis-server 6380.conf & redis-server 6381.conf &
3.3 Redis分片入门案例
/**
* 测试Redis分片机制
* 业务思路:
* 用户需要通过API来操作3台redis.用户无需关心数据如何存储,
* 只需要了解数据能否存储即可.
* 思考: 2005的数据存储到哪台redis中
* redis分片是如何实现数据存储的!
*/
@Test
public void testShards(){
List<JedisShardInfo> list = new ArrayList<>();
list.add(new JedisShardInfo("192.168.126.129", 6379));
list.add(new JedisShardInfo("192.168.126.129", 6380));
list.add(new JedisShardInfo("192.168.126.129", 6381));
ShardedJedis shardedJedis = new ShardedJedis(list);
shardedJedis.set("2005", "redis分片学习");
System.out.println(shardedJedis.get("2005"));
}
4 一致性hash算法
4.1 算法介绍
一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题。 [1] 在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题 [2] 。
4.2 常识介绍
1.常见hash多少位16进制数? 8位16进制数
2.16进制数取值有哪些 0-9 A-F 共16个数
3. hash的取值范围从 00000000 ~ FFFFFFFF (24)8
4. 上述取值的个数共有多少个??? 要求以2为底 2^32 幂
5. 对相同的数据进行hash值一致
4.3 一致性hash说明
步骤:
1.首先计算node节点
2.将用户的key进行hash计算,之后按照顺时针的方向找到最近的node节点之后链接,执行set操作.
4.3 特性一 平衡性
①平衡性是指hash的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题 [4] 。
说明: 如果发现节点中存储的数据负载不均,则采用虚拟节点的方式实现数据的平衡(相对平衡)
4.3 特性一 单调性
②单调性是指在新增或者删减节点时,不影响系统正常运行 [4] 因为可以实现自动的数据迁移.。
原则: 在进行数据迁移时 应该尽可能少的改变原有的数据.
4.4 特性一 分散性
③分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据 [4] 。
鸡蛋不要放在一个篮子里
关于计算机进制问题
二进制: 规则逢2进1 值: 0 -电位 1 +电位 二进制数:111 ---->十进制=
八进制: 规则逢8进1 值: 0-7 八进制数是3位2进制数
十六进制: 规则逢16进1 值: 0-9 A-F A=10 F=15 十六进制可以换算为4位个2进制数
练习: 二进制数110110110110是十六进制数的多少???
Spring整合Redis分片
1.1 关于分片说明
Redis分片的主要的作用是实现内存数据的扩容,Redis分片如果宕机不能实现高可用!!!
Redis的分片的计算发生在业务服务器中 将需要保存的数据存储到redis中.
Redis分片的执行的效率是最高的.
1.2 Spring整合Redis分片
1.2.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
1.2.2 编辑Redis配置类
package com.jt.config;
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 org.springframework.context.annotation.Scope;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import java.util.ArrayList;
import java.util.List;
@Configuration //标识我是一个配置类
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {
@Value("${redis.nodes}")
private String nodes; //node,node,node
/**
* 添加Redis分片的配置
* 需求1: 动态的获取IP地址/PORT端口
* 动态的获取多个的节点信息. 方便以后扩展
*/
@Bean
public ShardedJedis shardedJedis(){
List<JedisShardInfo> list = new ArrayList<>();
String[] strArray = nodes.split(","); //[node,node,node]
for (String node : strArray){ //ip:port
String host = node.split(":")[0];
int port = Integer.parseInt(node.split(":")[1]);
list.add(new JedisShardInfo(host,port ));
}
return new ShardedJedis(list);
}
/* @Value("${redis.host}") //spel表达式 yml为准
private String host;
@Value("${redis.port}")
private Integer port;
*//**
* 将jedis对象交给spring容器管理
*//*
@Bean //默认条件下是单例对象
//@Scope("prototype") //设置为多利对象
public Jedis jedis(){
//由于将代码写死不利于扩展,所以将固定的配置添加到配置文件中
return new Jedis(host,port);
}*/
}
1.2.3 编辑 CacheAOP中的注入项
说明:将AOP缓存中的注入项 改为分片对象