springboot怎么整合redis修改分区

springboot整合redis修改分区问题由来

最近使用springboot整合redis,一个系统动态数据源连接不同数据库,缓存使用的redis,那么就需要将不同数据库的数据缓存到redis不同的分区,也就是不同的库中。

老版解决

这里的老版指的是2.0之前的,我使用的1.5.9是ok的。

redis的配置类这里就不贴了,网上很多。

1.使用JedisConnectionFactory修改

@Autowired
JedisConnectionFactory jedisConnectionFactory;

jedisConnectionFactory.setDatabase(database);

2.使用redisTemplate修改

redisTemplate.getConnectionFactory().getConnection().select(database);

以上两种方式不需要再redis配置类中特意添加bean

新版解决

这里的新版指的是2.0之后的,我用的是2.0.3

redis配置类中需要添加以下bean

@Bean
RedisStandaloneConfiguration redisStandaloneConfiguration() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();

redisStandaloneConfiguration.setHostName("
localhost"
);

redisStandaloneConfiguration.setPort(6379);

redisStandaloneConfiguration.setDatabase(0);

return redisStandaloneConfiguration;

}
@Bean
JedisConnectionFactory jedisConnectionFactory(RedisStandaloneConfiguration redisStandaloneConfiguration) {
//redisStandaloneConfiguration.setPassword(RedisPassword.of(password));

JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();

jedisClientConfiguration.connectTimeout(Duration.ofMillis(0));
// connection timeout
JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration,
jedisClientConfiguration.build());

return factory;

}

使用RedisStandaloneConfiguration修改

@Autowired
RedisStandaloneConfiguration redisStandaloneConfiguration;

redisStandaloneConfiguration.setDatabase(database);
redis分区

数据是怎样分布在多个Redis实例上的

分区是将你的数据分布在多个Redis实例上,以至于每个实例只包含一部分数据。

为什么分区是有用的呢

Redis分区有两个主要目标:

  • 它允许更大的数据库,用许多计算机的内存总和。如果不进行分区,你将会受限于单台计算机的内存。

  • 它允许将计算能力扩展到多核和多台计算机,将网络带宽扩展到多台计算机和网络适配器。

  • 假设我们有4个Redis实例(R0, R1, R2, R3),其上有许多代表用户的key,比如user:1, user:2, ... 等等,那么在存储一个key的时候我们有多种方式。

    最简单的一种方式是按照范围分区,即根据对象的映射范围将数据分配到指定的Redis实例上。例如,我们规定ID为0~10000的就分到R0,10001~20000到R1,以此类推。这种方式是可以的,但是有一个缺点是需要一张表来维护这个映射关系。这个表需要管理起来,而且每一个key都需要一个这样的表,因此Redis中的范围分区通常是不受欢迎的,因为它比其他分区方法效率低得多。

    除了范围分区以外,另一种方法是哈希分区(hash partitioning):

    第1步、取key,并应用哈希函数将其转换为一个数。例如,如果key是foobar,哈希函数式crc32,那么crc32(foobar)将输出93024922。

    第2步、对这个数字使用模运算(取模)将它转换成0到3直接的数字,这样这个数字就可以映射到我的四个Redis实例之一。例如,93024922 % 4 = 2,因此foobar应该存储到R2实例上。

    (PS:首先,对key做哈希运算,得到一个数字,然后对这个数字取模,以决定最终数据应该存放在哪个实例上)

    分区的方法还有很多种,通过上面两个示例,你应该可以理解。哈希分区的一种高级形式称为一致性哈希,由几个Redis客户端和代理实现。

    不同的分区实现

    客户端分区 : 对于一个给定的key,客户端直接选择正确的节点来进行读写。许多Redis客户端都实现了客户端分区。

    代理分区 : 客户端发送请求到一个代理,由代理来和Redis通信,代理会根据我们的配置来选择正确的Redis实例。

    查询路由 : 你可以将你的查询发送到任何一个Redis实例,实例会将你的查询重定向到正确的服务器。

    (PS:对于一个给定的key,分区的工作就是选择一个正确的Redis实例,那么这个选择的过程可以由客户端、代理 或者 Redis实例来做)

    分区的不足之处

    1、涉及多个key的操作通常是不支持的。对于映射到两个不同的Redis实例的key,你不能往这两个上执行插入操作。

    2、涉及多个key的操作不能用Redis事务

    3、分区粒度是key,因此不可能将一单个非常巨大的key(比如,一个非常大的sorted set)去切分数据

    4、当使用分区的时候,数据处理会更复杂,对于实例你必须处理多个RDB/AOF文件,为了备份数据,需要从多个实例和主机聚合持久文件。

    5、增加和删除容量(空间)变得更复杂。例如,Redis集群支持在运行时添加和删除节点的透明数据再平衡,但其他系统如客户端分区和代理不支持此功能。然而,一种叫做预分片的技术在这方面有帮助。

    数据存储还是缓存?

    当Redis用作数据存储时,给定的key必须总是映射到相同的Redis实例。当作为缓存时,如果给定节点不可用它不是一个大问题。

    如果给定key的首选节点不可用,一致哈希实现通常能够切换到其他节点。类似地,如果添加一个新节点,部分新keys将开始存储在新节点上。

    • 如果使用Redis作为缓存,使用一致哈希很容易进行伸缩。

    • SpringBoot实战如何用简单步骤整合Redis修改分区

      如果Redis用作存储,则使用固定的keys-to-nodes映射,因此节点的数量必须是固定的,且不能改变。如果需要重新平衡节点之间的key,那么Redis集群是一种可行的系统。



    Redis 作为一个数据缓存和内存存储系统,越来越广泛地应用于大规模分布式系统中。Spring Boot 作为一种快速开发、便捷部署的框架,也可以完美地与 Redis 集成,以实现各种应用场景的需求。本文将详细介绍如何利用 Spring Boot 对 Redis 进行分区管理的扩展操作,帮助读者更好地实现分布式系统的横向扩展。
    一、Redis 分区管理概述
    使用 Redis 进行数据缓存的时候,我们通常需要进行分区管理,以充分利用系统各节点的存储容量,实现数据的高效读写操作。Redis 的分区管理包括两种类型:数据分区和功能分区。数据分区即将缓存数据分成多个逻辑分区,每个分区存储一部分数据;功能分区则是将 Redis 的功能按照不同的逻辑功能分组存储,以实现更好的功能扩展。
    二、Spring Boot 集成 Redis
    在 Spring Boot 中集成 Redis 非常简单,只需要引入相应的依赖包,并修改配置文件即可。首先,需要在 Maven 或 Gradle 中引入 Redis 相关的依赖包,在 pom.xml 或 build.gradle 中分别添加以下代码:

    org.springframework.boot
    spring-boot-starter-data-redis

    dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-redis')
    }
    然后,在 application.properties 或 application.yml 中添加 Redis 的配置,其中 host、port 和 password 是 Redis 的相关参数,以下是一个典型的 Redis 配置:
    spring.redis.host=localhost
    spring.redis.port=6379
    spring.redis.password=
    三、Redis 分区管理核心代码
    接下来,我们需要编写一些核心代码来实现 Redis 的分区管理。首先,需要编写一个 JedisConnectionFactory 的工厂类,来创建连接 Redis 的工厂。代码如下:
    @Configuration
    public class RedisConfig {

    @Value(\"${spring.redis.host}\")
    private String redisHostName;

    @Value(\"${spring.redis.port}\")
    private int redisPort;

    @Value(\"${spring.redis.password}\")
    private String redisPassword;

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {

    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();

    jedisConnectionFactory.setHostName(redisHostName);
    jedisConnectionFactory.setPort(redisPort);
    jedisConnectionFactory.setPassword(redisPassword);

    return jedisConnectionFactory;
    }
    }
    接下来在配置文件中添加以下配置:
    spring.redis.jedis.pool.max-active=8
    spring.redis.jedis.pool.max-wait=-1
    spring.redis.jedis.pool.max-idle=8
    spring.redis.jedis.pool.min-idle=0
    最后,我们需要在 Spring Boot 应用中定义一个 RedisTemplate 对象,作为与 Redis 进行交互的核心类。RedisTemplate 支持各种 Redis 数据类型的操作,并且这个对象可以被注入到任何需要使用 Redis 的类中。示例代码如下:
    @Configuration
    public class RedisTemplateConfig {

    @Autowired
    JedisConnectionFactory jedisConnectionFactory;

    @Bean
    RedisTemplate> redisTemplate() {
    final RedisTemplate> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(jedisConnectionFactory);

    return redisTemplate;
    }
    }
    四、Redis 数据分区管理
    首先,在 Redis 的数据分区管理中,我们需要将数据分成多个逻辑分区,然后在应用中使用节点的自定义逻辑来指定数据存储在哪个分区中。这样可以充分利用各个节点的存储空间,提高系统的性能。示例代码如下:
    @FunctionalInterface
    public interface RedisPartitioner {
    String partition(Object key, int numOfNodes);
    }
    然后,我们需要在 RedisTemplateConfig 中配置 Redis 的数据分区管理器。如下代码中的 partitioner 是通过实现 RedisPartitioner 接口而得到的分区管理器:
    @Configuration
    public class RedisTemplateConfig {

    @Autowired
    JedisConnectionFactory jedisConnectionFactory;

    private RedisPartitioner partitioner = new MD5RedisPartitioner();

    @Bean
    RedisTemplate longRedisTemplate() {
    RedisTemplate template = new RedisTemplate<>();
    template.setConnectionFactory(jedisConnectionFactory);
    template.setHashKeySerializer(RedisSerializer.java());
    template.setKeySerializer(RedisSerializer.java());
    template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setEnableTransactionSupport(true);
    template.afterPropertiesSet();
    return template;
    }
    }
    五、Redis 功能分区管理
    Redis 的功能分区管理是将 Redis 的功能按照不同的逻辑功能分组存储,以实现更好的功能扩展。这个和数据库中的分表、分库类似,不同的是,Redis 的功能分区不是把数据存储到不同的表或库中,而是把 Redis 的功能按照不同的逻辑功能分组存储。
    首先,我们需要定义一个新的 RedisTemplate 封装类,用于实现 Redis 的不同功能分区。实现代码如下:
    public class RedisTemplateShardedService {
    private List redisTemplateList;

    /**
    * 根据 key 选择 RedisTemplate 对象
    * @param key
    * @return
    */
    public RedisTemplate getRedisTemplateByKey(Object key) {
    int index = key.hashCode() % redisTemplateList.size();
    return redisTemplateList.get(index);
    }

    /**
    * 获取 RedisTemplateList 对象
    * @return
    */
    public List getRedisTemplateList() {
    return redisTemplateList;
    }

    /**
    * 设置 RedisTemplateList 对象
    * @param redisTemplateList
    */
    public void setRedisTemplateList(List redisTemplateList) {
    this.redisTemplateList = redisTemplateList;
    }
    }
    然后,我们需要在 RedisTemplateConfig 中配置 Redis 的功能分区管理器。示例代码如下:
    @Configuration
    public class RedisTemplateConfig {

    @Autowired
    JedisConnectionFactory jedisConnectionFactory;

    private RedisPartitioner partitioner = new MD5RedisPartitioner();

    @Bean
    public RedisTemplateShardedService redisTemplateShardedService() {
    RedisTemplateShardedService redisTemplateShardedService = new RedisTemplateShardedService();
    List redisTemplateList = new ArrayList<>();

    for (int i = 0; i < 2; i++) {
    RedisTemplate template = new RedisTemplate<>();
    template.setConnectionFactory(jedisConnectionFactory);
    template.setHashKeySerializer(RedisSerializer.java());
    template.setKeySerializer(RedisSerializer.java());
    template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setEnableTransactionSupport(true);
    template.afterPropertiesSet();
    redisTemplateList.add(template);
    }

    redisTemplateShardedService.setRedisTemplateList(redisTemplateList);
    return redisTemplateShardedService;
    }
    }
    六、Redis 分区管理测试
    为了测试 Redis 分区的效果,我们需要编写一些相应的测试代码。首先,我们可以编写一段关键词搜索的测试代码,依次向各个 Redis 分区中存储一些关键词,然后从 Redis 分区中搜索相应的关键词。
    @Test
    public void testRedisSharding() throws Exception {
    redisTemplateShardedService.save(userId, user, redisTemplateShardedService.getRedisTemplateByKey(userId));
    User result = redisTemplateShardedService.get(userId, redisTemplateShardedService.getRedisTemplateByKey(userId));
    Assert.assertEquals(user.getName(), result.getName());
    }
    然后,我们可以编写一段豆瓣电影搜索的测试代码,依次向各个 Redis 分区中存储一些电影数据,然后从 Redis 分区中搜索相应的电影数据。
    @Autowired
    private RedisTemplate longRedisTemplate;

    @Test
    public void testRedisSharding() throws Exception {
    longRedisTemplate.opsForValue().set(movie.getId(), movie);
    Movie result = longRedisTemplate.opsForValue().get(movie.getId());
    Assert.assertEquals(movie.getTitle(), result.getTitle());
    }
    七、总结
    本文详细讲述了如何利用 Spring Boot 对 Redis 进行分区管理,并实现分布式系统的横向扩展。通过简单的步骤和示例代码,读者可以轻松地理解 Redis 的分区管理,并用于自己所开发的分布式系统中。此外,我们还介绍了 Redis 的数据分区管理和功能分区管理,帮助读者更好地利用 Redis 的各种特性,实现更高效的数据存储和管理。