当前位置:   article > 正文

Redis分片集群模式以及整合SpringBoot_springboot集群redis

springboot集群redis

1.分片集群结构

哨兵模式只有一个主节点,如果写操作频率过高,那么就会导致主节点出现宕机问题,就需要使用分片集群模式

分片集群结构图:这些主从都会存在哨兵模式

使用了分槽技术,默认集群槽的数量为16384个。而每个槽可以存放若干个数据。如果搭建redis集群模式会为主节点平均分配这些槽。

原理:Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384计算这个key应该分布到哪个hash slot中,一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区,每个分区里有很多key。

2.如何搭建redis分片集群

准备6台redis服务:3台主节点和3台从节点,这里为了操作就在一台虚拟机上启动6个redis服务,修改端口号分别为为7001、7002、7003、7004、7005、7006

修改redis集群中6台配置文件:如果是多台虚拟机的话就不必要修改名称,这里是为了分辨

1.修改端口号:

2.修改快照.rdb文件的名称防止一样

3.必须开启aof模式并修改.aof文件的名称

4.开启redis集群模式 cluster-enabled yes

5.修改集群文件名 cluster-config-file nodes-7001.conf

6.设置允许任意ip访问 bind * -::*

启动6台redis服务

为上面6台redis设置主从关系并分配槽:

redis-cli --cluster create --cluster-replicas 1 192.168.61.223:7001 192.168.61.223:7002 192.168.61.223:7003 192.168.61.223:7004 192.168.61.223:7005 192.168.61.223:7006

中途输入yes

完成

分配了三主三从:

启动redis客户端:redis-cli -c -h 192.168.61.223 -p 7001 这个ip和端口输入开启6台的任意一台都可以

测试:可以看到通过crc16算法进入了12706所在的分区进入了7003

测试关掉7001主节点看7001的从节点(7006)会不会上位

发现7006接替了7001的主节点

3.java连接redis

可以使用jedis完成java与redis之间的连接

依赖:

  1. <dependencies>
  2. <dependency>
  3. <groupId>redis.clients</groupId>
  4. <artifactId>jedis</artifactId>
  5. <version>3.6.0</version>
  6. </dependency>
  7. </dependencies>

3.1连接单机版:

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. //1.创建连接对象
  4. Jedis jedis = new Jedis("192.168.61.223",6379);
  5. //查看所有key
  6. Set<String> keys = jedis.keys("*");
  7. System.out.println("所有的key"+keys);
  8. //设置key的值为字符串类型
  9. jedis.set("k1","v1");
  10. //设置有效时间
  11. jedis.expire("k1",20L);
  12. //查看有效时间
  13. Long time = jedis.ttl("k1");
  14. System.out.println("有效时间"+time);
  15. //删除key为k1
  16. // Long flag = jedis.del("k1");
  17. // System.out.println(flag);
  18. //判断当前key是否存在
  19. System.out.println(jedis.exists("k1"));
  20. System.out.println("-----String类型-----");
  21. //设置key的值为字符串类型的value
  22. jedis.set("k1","v1");
  23. //根据key获取对应的value值
  24. String k1 = jedis.get("k1");
  25. System.out.println(k1);//v1
  26. //设置多个key-value
  27. jedis.mset("k1","v1","k2","v2");
  28. //获取多个key对应的value值
  29. List<String> mget = jedis.mget("k1", "k2", "k3", "k4"); //[v1, v2, null, null]
  30. System.out.println(mget);
  31. //如果指定的key存在则不存入,如果不存在才存入
  32. jedis.setnx("k1","v4");
  33. //为指定的key递增 必须为整数
  34. jedis.set("k3","2");
  35. jedis.incr("k3");
  36. //为指定的key递减 必须为整数
  37. jedis.decr("k3");
  38. //为指定的key递增指定的值
  39. jedis.incrBy("k3",2L);
  40. //为指定的key递减指定的值
  41. jedis.decrBy("k3",2L);
  42. System.out.println("-----hash类型-----");
  43. //存放hash类型的数据
  44. jedis.hset("k4","name","zs");
  45. jedis.hset("k4","age","20");
  46. //或者
  47. HashMap<String, String> map = new HashMap<>();
  48. map.put("name","ls");
  49. map.put("age","20");
  50. jedis.hset("k5",map);
  51. //获取相应key中field对应的数据
  52. System.out.println(jedis.hget("k5", "name")); //ls
  53. //获取key对应hash数据内容
  54. System.out.println(jedis.hgetAll("k4")); //{name=zs, age=20}
  55. //获取hash中所有field字段
  56. System.out.println(jedis.hkeys("k4"));//[name, age]
  57. //获取hash中所有value字段
  58. System.out.println(jedis.hvals("k4"));//[zs, 20]
  59. System.out.println("-----list列表类型-----");
  60. //从左边存放列表数据
  61. jedis.lpush("k6","v1","v2","v3","v4","v5");
  62. //从左边取出元素 (指最后存入的)
  63. String k6 = jedis.lpop("k6");//v5
  64. System.out.println(k6);
  65. // 从左边获取指定范围的元素
  66. System.out.println(jedis.lrange("k6", 0, -1)); //[v4, v3, v2, v1]
  67. System.out.println("-----set集合类型");
  68. //存放set类型的元素
  69. jedis.sadd("k7","v1","v2","v3","v4","v5");
  70. //获取指定key对应的所有元素。
  71. System.out.println(jedis.smembers("k7"));//[v1, v2, v3, v4, v5]
  72. //随机获取集合中一个或多个元素
  73. System.out.println(jedis.srandmember("k7"));//v2
  74. //求多个集合的交集
  75. jedis.sadd("k8","v3","v4","v5","v6","v7");
  76. System.out.println(jedis.sinter("k7","k8"));
  77. //随机移除一个或多个元素
  78. System.out.println(jedis.spop("k8"));//v7
  79. System.out.println("-----sorted set集合类型-----");
  80. // 添加有序集合
  81. jedis.zadd("k9",10,"v1");
  82. HashMap<String, Double> map1 = new HashMap<>();
  83. map1.put("v1",10.);
  84. map1.put("v2",20.);
  85. map1.put("v3",30.);
  86. map1.put("v4",40.);
  87. map1.put("v5",50.);
  88. jedis.zadd("k10",map1);
  89. //从小到大的顺序获取集合中的元素
  90. System.out.println(jedis.zrange("k10", 0, -1));//[v1, v2, v3, v4, v5]
  91. //从大到小的顺序获取集合中的元素
  92. Set<String> k10 = jedis.zrevrange("k10", 0, -1);//[v5, v4, v3, v2, v1]
  93. System.out.println(k10);
  94. //从小到大的顺序获取集合中的元素和分数
  95. Set<Tuple> k101 = jedis.zrevrangeWithScores("k10", 0, -1);//[[v5,50.0], [v4,40.0], [v3,30.0], [v2,20.0], [v1,10.0]]
  96. System.out.println(k101);
  97. }
  98. }

3.2连接集群版:

  1. public class Test02 {
  2. public static void main(String[] args) {
  3. //java连接redis集群
  4. HashSet<HostAndPort> hostAndPorts = new HashSet<>();
  5. hostAndPorts.add(new HostAndPort("192.168.61.223",7001));
  6. hostAndPorts.add(new HostAndPort("192.168.61.223",7002));
  7. hostAndPorts.add(new HostAndPort("192.168.61.223",7003));
  8. hostAndPorts.add(new HostAndPort("192.168.61.223",7004));
  9. hostAndPorts.add(new HostAndPort("192.168.61.223",7005));
  10. hostAndPorts.add(new HostAndPort("192.168.61.223",7006));
  11. //创建一个Jedis集群对象---需要传入redis集群服务的地址信息
  12. JedisCluster jedisCluster = new JedisCluster(hostAndPorts);
  13. jedisCluster.set("k1","v1");
  14. System.out.println(jedisCluster.get("k1"));
  15. }
  16. }

4.使用springboot连接redis

springboot在整合redis时会自动封装了两个类:RedisTemplate和StringRedisTemplate. StringRedisTemplate它是RedisTemplate的子类,StringRedisTemplate它里面存储的key和value都是字符串类型。

依赖:springboot版本为:2.3.2.RELEASE

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-web</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-test</artifactId>
  13. <scope>test</scope>
  14. </dependency>
  15. </dependencies>

4.1单机版

修改配置文件:

  1. spring.redis.port=6379
  2. spring.redis.host=192.168.61.223

4.1.1使用StringRedisTemplate

  1. @SpringBootTest
  2. class SpringbootRedis01ApplicationTests {
  3. @Autowired
  4. private StringRedisTemplate redisTemplate; //starter自动完成了redis的装配
  5. @Test
  6. void contextLoads() {
  7. //获取所有的key
  8. System.out.println(redisTemplate.keys("*")); //[]
  9. //是否存在指定的key
  10. System.out.println(redisTemplate.hasKey("k1"));//false
  11. //删除指定的key
  12. System.out.println(redisTemplate.delete("k1"));//false
  13. //设置有效时间
  14. // redisTemplate.expire("k1",20, TimeUnit.SECONDS);
  15. //查看有效时间
  16. System.out.println(redisTemplate.getExpire("k1"));//-2
  17. System.out.println("--------------操作String字符串类型---------------");
  18. ValueOperations<String, String> string = redisTemplate.opsForValue();
  19. //设置value为string的
  20. string.set("k1", "v1");
  21. //获取key为k1
  22. System.out.println(string.get("k1"));//v1
  23. //设置多个key-value
  24. HashMap<String, String> hashMap = new HashMap<>();
  25. hashMap.put("k1","v1");
  26. hashMap.put("k2","v2");
  27. hashMap.put("k3","v3");
  28. string.multiSet(hashMap);
  29. //获取多个key对应的value值
  30. ArrayList<String> list1 = new ArrayList<>();
  31. list1.add("k1");
  32. list1.add("k2");
  33. list1.add("k3");
  34. list1.add("k4");
  35. System.out.println(string.multiGet(list1));//[v1, v2, v3, null]
  36. //如果指定的key不存在存入,存在则不存入
  37. System.out.println(string.setIfAbsent("k1", "v1"));//false
  38. //为指定的key递增 必须为整数
  39. string.set("k2","1");
  40. System.out.println(string.increment("k2"));//2
  41. //为指定的key递增指定的数 必须为整数
  42. System.out.println(string.increment("k2", 3));//5
  43. //为指定的key递减 必须为整数
  44. System.out.println(string.decrement("k2"));//4
  45. //为指定的key递减指定的数 必须为整数
  46. System.out.println(string.decrement("k2",2));//2
  47. System.out.println("-------------------操作hash类型--------------------");
  48. HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
  49. //存放hash类型的数据
  50. hash.put("k4","name","张三");
  51. //存放多个
  52. HashMap<String, String> k4 = new HashMap<>();
  53. k4.put("age","20");
  54. k4.put("address","河南");
  55. hash.putAll("k4",k4);
  56. //获取相应key中field对应的数据
  57. System.out.println(hash.get("k4", "name"));//张三
  58. //获取hash中key对应的所有数据内容
  59. Map<Object, Object> k41 = hash.entries("k4");
  60. System.out.println(k41);//{name=张三, address=河南, age=20}
  61. //获取key对应的所有field
  62. System.out.println(hash.keys("k4"));//[name, address, age]
  63. //获取key对应的所有value字段
  64. System.out.println(hash.values("k4"));//[张三, 河南, 20]
  65. System.out.println("-------------------list列表类型-------------------");
  66. ListOperations<String, String> list = redisTemplate.opsForList();
  67. //从左边存放列表数据
  68. list.leftPushAll("k5","v1","v2");
  69. ArrayList<String> list2 = new ArrayList<>();
  70. list2.add("v2");
  71. list2.add("v3");
  72. list2.add("v4");
  73. //或者
  74. list.leftPushAll("k6",list2);
  75. //从左边取出一个元素 (最后存入的)
  76. System.out.println(list.leftPop("k5"));//v2
  77. //从左边获取指定范围的元素
  78. System.out.println(list.range("k6", 0, -1));//[v4, v3, v2]
  79. System.out.println("-----------------set集合类型-------------------");
  80. SetOperations<String, String> set = redisTemplate.opsForSet();
  81. //存放set类型的元素
  82. set.add("k7","v1","v2","v3","v4");
  83. //获取key对应的所有元素
  84. System.out.println(set.members("k7"));//[v1, v2, v3, v4]
  85. //随机获取集合中一个或多个元素
  86. System.out.println(set.randomMember("k7"));//v3
  87. //求多个集合的交集
  88. set.add("k8","v3","v4","v5","v6");//[v3, v4]
  89. System.out.println(set.intersect("k7", "k8"));
  90. //随机移除一个元素
  91. System.out.println(set.pop("k8"));//v6
  92. System.out.println("--------------------sorted set集合类型----------------------");
  93. ZSetOperations<String, String> zSet = redisTemplate.opsForZSet();
  94. //添加有序集合
  95. zSet.add("k9","v1",10);
  96. //添加多个
  97. Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>();
  98. tuples.add(new DefaultTypedTuple<>("v1",10.));
  99. tuples.add(new DefaultTypedTuple<>("v2",20.));
  100. tuples.add(new DefaultTypedTuple<>("v3",30.));
  101. zSet.add("k9",tuples);
  102. //从小到大的顺序获取集合中的元素
  103. System.out.println(zSet.range("k9", 0, -1));//[v1, v2, v3]
  104. //从大到小的顺序获取集合中的元素
  105. System.out.println(zSet.reverseRange("k9",0,-1));//[v3, v2, v1]
  106. //从小到大的顺序获取元素和分数
  107. System.out.println(zSet.rangeWithScores("k9", 0, -1));//[org.springframework.data.redis.core.DefaultTypedTuple@c45c123c, org.springframework.data.redis.core.DefaultTypedTuple@c64c123d, org.springframework.data.redis.core.DefaultTypedTuple@c782123e]
  108. for (ZSetOperations.TypedTuple<String> k9 : zSet.rangeWithScores("k9", 0, -1)) {
  109. System.out.println(k9.getScore());
  110. System.out.println(k9.getValue());
  111. }
  112. //10.0
  113. //v1
  114. //20.0
  115. //v2
  116. //30.0
  117. //v3
  118. }
  119. }

4.1.2使用RedisTemplate

  1. @SpringBootTest
  2. public class SpringbootApplicationTests {
  3. @Autowired
  4. private RedisTemplate redisTemplate;
  5. @Test
  6. void test01(){
  7. ValueOperations string = redisTemplate.opsForValue();
  8. string.set("k1","v1");
  9. }
  10. }

在运行时发现存入的key和value都为乱码

这是因为RedisTemplate默认使用的是jdk序列化,而StringRedisTemplate使用的是StringRedisSerializer()序列化,所以我们需要设置序列化方式

因为不知道以后value要传入什么类型。所以value指定为json类型,Jackson2JsonRedisSerializer(Object.class));

hash中key和value也需要设置序列化:

  1. @SpringBootTest
  2. public class SpringbootApplicationTests {
  3. @Autowired
  4. private RedisTemplate redisTemplate;
  5. @Test
  6. void test01(){
  7. //指定了key的序列化
  8. redisTemplate.setKeySerializer(new StringRedisSerializer());
  9. //指定了value的序列化
  10. redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
  11. //指定hash的key的序列化
  12. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  13. //制定了hash的value的序列化
  14. redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
  15. ValueOperations string = redisTemplate.opsForValue();
  16. string.set("k1","v1");
  17. //hash操作
  18. HashOperations hashOperations = redisTemplate.opsForHash();
  19. hashOperations.put("k55","name","张三");
  20. }
  21. }

每次使用redistemplate时都需要配置这些序列化,所以我们可以将这些创建为一个配置类交于spring管理

  1. @Configuration
  2. public class RedisConfig {
  3. @Bean
  4. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
  5. RedisTemplate<String, Object> template = new RedisTemplate<>();
  6. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
  7. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  8. template.setConnectionFactory(factory);
  9. //key序列化方式
  10. template.setKeySerializer(redisSerializer);
  11. //value序列化
  12. template.setValueSerializer(jackson2JsonRedisSerializer);
  13. //hashmap序列化key
  14. template.setHashKeySerializer(redisSerializer);
  15. //hashmap序列化value
  16. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  17. return template;
  18. }
  19. }

4.2集群版

  1. # 集群redis
  2. spring.redis.cluster.nodes=192.168.61.223:7001,\
  3. 192.168.61.223:7002,\
  4. 192.168.61.223:7003,\
  5. 192.168.61.223:7004,\
  6. 192.168.61.223:7005,\
  7. 192.168.61.223:7006

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/808411
推荐阅读
相关标签
  

闽ICP备14008679号