redis的分布式原理及连接池
redis的分布式结构
数据分片
将计算后的数据分成的不同部分,存储在不同的数据节点中叫做数据分片
hash取余的自定义算法实现分布式
hash取余公式
(key.hashCode()&Integer.MAX_VALUE)%N
括号中的是正整数,N 是分片的节点个数
@Test
@Test public void test05(){ //准备一下连接的所有节点jedis对象 Jedis jedis1=new Jedis("10.9.39.13",6379); Jedis jedis2=new Jedis("10.9.39.13",6380); Jedis jedis3=new Jedis("10.9.39.13",6381); //模拟生成海量数据 int count=0; for(int i=0;i<1000;i++){ String key=UUID.randomUUID().toString(); //利用hash取余算法,处理存储的分布式计算 //key是0/1/2的概率是多少 //获取算法的结果 0 1 2 int n=(key.hashCode()&Integer.MAX_VALUE)%3; if(n==0){ count++; jedis1.set(key, ""); }else if(n==1){ jedis2.set(key, ""); }else{ jedis3.set(key, ""); } } System.out.println("是的概率:"+count/1000.0); }
jedis的分片对象
ShardedJedis
@Test
@Test public void test06(){ //使用jedis提供的分片计算对象实现分布式处理数据 //收集节点信息,告诉jedis到底有多少个分片信息 List<JedisShardInfo> info=new ArrayList<JedisShardInfo>(); //将节点信息封装添加到info info.add(new JedisShardInfo("10.9.39.13", 6379)); info.add(new JedisShardInfo("10.9.39.13", 6380)); info.add(new JedisShardInfo("10.9.39.13", 6381)); //利用节点信息对象info构造一个封装了分片算法的分片对象 ShardedJedis sJedis=new ShardedJedis(info); //通过测试生成的任何key值都会进行分片计算 sJedis.set("name", "王老师"); System.out.println(sJedis.get("name")); System.out.println(sJedis.exists("name")); }
hash一致性计算原理(可搜索图解)
hash一致性,基于一个散列计算的数学计算方法实现
任何计算机中的对象都可以通过散列方法获取一个整数值,整数区间[0,2^32-1]
这个整数区间--hash环
节点映射关系
ip+port
在内存中保存为一个字符串这个字符串通过散列计算,在hash环上映射成一个整数值
key值的映射
先做key的整数映射
key值不变,结果整数同一个
数据分片计算方法
通过找到key值的对应节点关系,寻找key对应的节点
顺时针寻找最近的节点整数
数据平衡性(权重)
虚拟节点:
key顺时针寻找最近节点,对应到虚拟节点后,从虚拟节点和真实节点的关系找到真实节点
只要虚拟节点数量够多,平衡心越高
如何解决扩容迁移量过大的问题
==hash取余==,一种目前比较成熟的计算分片方法,但是在redis结构中不适合
因为造成redis集群扩容,缩容时数据迁移量过大的问题;
hash取余的计算方法造成扩容的迁移量过大,不迁移造成雪崩
==hash一致性算法==,从已有的映射关系环上添加新的节点,节点数量越多,弧线越短(key值量越少);
节点越多,做扩容,缩容时需要迁移的数据量就越少----少到一定程度是,就不需要迁移了
按照默认值计算分片 比重1:1:1
hash一致性的缺点
数据倾斜
key值的对应服务的强耦合
分片连接池
@test
@Test public void test07(){ //最底层连接池 Jedis JedisPool pool=new JedisPool("10.9.39.13", 6379); //pool 获取jedis对象 Jedis jedis = pool.getResource(); pool.returnResource(jedis); //分片连接池 基于jedisPool来创建的 //收集节点信息,告诉jedis到底有多少个分片信息 List<JedisShardInfo> info=new ArrayList<JedisShardInfo>(); //将节点信息封装添加到info info.add(new JedisShardInfo("10.9.39.13", 6379, 1000, 1000, 5)); info.add(new JedisShardInfo("10.9.39.13", 6380)); info.add(new JedisShardInfo("10.9.39.13", 6381)); //构造一个分片连接池需要一些配置信息,连接池的初始化连接数 //最大空闲数,最小空闲数,连接池的连接上限 GenericObjectPoolConfig config= new GenericObjectPoolConfig(); config.setMaxTotal(200);//最大连接数 config.setMaxIdle(8);//最大空闲数 config.setMinIdle(3);//最小空闲数 //构造连接池 ShardedJedisPool sPool=new ShardedJedisPool(config,info); ShardedJedis sJedis = sPool.getResource(); sJedis.set("location", "北京"); System.out.println(sJedis.get("location")); sPool.returnResource(sJedis); }
保存redis相关笔记