SpringBoot 正确集成Redis+本地缓存

一. 概述

公司架构师团队花了大量时间研发了一个集成redis的框架,命名 HRdis 。 是经过线上的考验了的,大家也可以测试下 。 主要 功能包括:

  • 统一连接池(Lettuce,Jedis),且统一连接池的配置
  • 轻松集成单机或集群模式
  • 本地缓存
  • 一个注解即可完成整个集成

二. 使用教程

添加maven:

<dependency>
	<groupId>com.hadluo</groupId>
	<artifactId>hredis-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

如果你打算 jedis连接池+单机模式+禁止本地缓存, 你只需这样:

@SpringBootApplication
@HRedisConfiguration(type = PoolType.Jedis, cluster = false, openLocalCache = false)
public class OrderApplication {
	public static void main(String[] args) {
		SpringApplication.run(OrderApplication.class, args);
	}
}

@HRedisConfiguration为HRedis的 配置注解,配置如下:

  • type : 指定使用连接池类型,PoolType.Jedis 和 PoolType.Lettuce 。
  • cluster : 代表你的redis是集群模式还是单机模式,true代表集群模式。
  • openLocalCache : 是否打开本地缓存功能,true开启本地缓存。

启动项目,会打印当前配置信息:


如果改成集群+Lettuce 连接池:

@HRedisConfiguration(type = PoolType.Lettuce, cluster = true, openLocalCache = false)

程序打印:


业务那边使用方法

直接@Autowired HRedisSupport 类 , 代码实例:

@RestController
public class OrderController {
	@Autowired
	HRedisSupport redisSupport;
	@GetMapping("/set")
	public void set(@RequestParam("k") String k) {
		redisSupport.set("activitybb", "{我是商品的json信息}");
		
		System.out.println(redisSupport.get("activitybb"));
		
		redisSupport.hset("aa","bb", "dd");
		
		redisSupport.lpop("ff");
		
		redisSupport.del("ff");
	}
}

HRedisSupport 为redis所有命令的操作接口。命名都是跟原生redis命名一致。HRedisSupport 代码如下:

public interface HRedisSupport extends InitializingBean {

	@SetMethod
	String set(String key, String value);

	@GetMethod
	String get(String key);

	@SetMethod
	Long hset(String key, String field, String value);

	@GetMethod
	String hget(String key, String field);

	@GetMethod
	Set<String> zrange(String key, long start, long stop);

	@SetMethod
	Long zadd(String key, Map<String, Double> scoreMembers);

	@SetMethod
	Long zadd(String key, double score, String member);

	@GetMethod
	String lpop(String key);

	@GetMethod
	String rpop(String key);

	@SetMethod
	Long lpush(String key, String... string);

	@SetMethod
	Long rpush(String key, String... string);

	// ------------下面是不参与本地缓存的方法 不用配置 @SetMethod , @SetMethod
	Boolean exists(String key);

	Long expire(String key, int seconds);
	
	Long del(String key);

}

当然,还有很多命令没有包括,后面可以升级加上去。可以联系本人。

连接池配置

redis连接池的配置信息需要在application 配置中声明(jedis,Lettuce 单机集群都一样配置):

# redis集群或单机地址  集群多地址用逗号分开 127.0.0.1:6389,127.0.0.2:6389
spring.redis.nodes = xx.xx.xx.xx:6381
# 没有密码可以不配置
spring.redis.jedis.cluster.password = UEbkh65Yw19


三. 本地缓存

本地缓存是HRdis的一大亮点。是通过访问远程的redis,降级到访问当前机器上的内存。

核心逻辑:

当 执行redis的get,hget,zrange 等取值命令时,会监测本地缓存的元配置信息,如果当前命令和key匹配配置信息,就会代理到从本地缓存中取值,取不到才从redis中取,然后设置到本地缓存,最后返回给用户。下次同样命令和key 的话直接取本地缓存。

当执行redis的set,hget,zrange等设置命令时 , 也是先监测当前设置命令对应的取值命名 get,hget,zrange 和key是否匹配元配置信息,匹配就删除当前key的本地缓存 。 下次就直接从redis里面取最新的。


本地缓存过期

在元配置信息中,会有过期时间的配置,也就是本地缓存的过期时间。 防止永远从本地缓存拿数据。


本地缓存的元配置

本地缓存需要元配置信息来告知哪个redis命名的哪些key走本地缓存(走本地缓存就是缓存到内存,下次直接从内存中取)

例如:

{
    "get":[
        {
            "rule":"item*",
            "expire":20000
        }
    ],
    "zrange":[
        {
            "rule":"pop*",
            "expire":15000
        }
    ],
    "hget":[
        {
        "rule":"activity*",
        "expire":30000
        }
    ]
}

上面配置了三个命令, 注意只能配置redis的取值命令,像del,get等命令没有意义。

针对第一个get 配置解释:

当请求redis的get命名时,如:

// 从缓存中取商品id为 11690 的商品信息
redisSupport.get("item:11690");

会匹配到本地缓存,然后会将key参数 匹配get配置里面的每个rule规则, 我们上面的例子key参数是item:11690 , 由于我们的rule是 item* (只要以item开头的key都会匹配上),所以这里就会匹配上 。 所以上面拿商品就会从本地缓存中取。

expire : 匹配当前规则的本地缓存key 的失效时间。


元配置的动态特性

由于配置是配置到nacos里面的,所以项目不需重启,新的规则即可生效。nacos配置地址可以在application配置中指定:

hredis.conf.nacos.nodes = 127.0.0.1:8848
hredis.conf.nacos.dataId = hredis-conf.json
hredis.conf.nacos.group = DEFAULT_GROUP

注意json格式一定要配置正确,否则会不生效。


四. 本地缓存的测试

先来看个性能测试:

开启本地缓存:

@SpringBootApplication
@HRedisConfiguration(type = PoolType.Jedis, cluster = false, openLocalCache = true)
public class OrderApplication {
	public static void main(String[] args) {
		SpringApplication.run(OrderApplication.class, args);
	}
}

程序会打印:

上面打印了元配置nacos的地址,我们修改nacos配置:

{
    "get":[
        {
            "rule":"item*",
            "expire":100000
        }
    ]
}

我们配置了一个get命令,key规则为以item开头。过期时间100000 毫秒。保存后,程序会动态打印:


测试代码:

@RestController
public class OrderController {
	@Autowired
	HRedisSupport redisSupport;
	@GetMapping("/set")
	public void set(@RequestParam("k") String k) {
		redisSupport.set("item.16384", "{我是商品16384的json信息}");
	}

	@GetMapping("/get")
	public String get(@RequestParam("k") String k) {
		long s = System.currentTimeMillis();
		for (int i = 0; i < 500; i++) {
			System.err.println(redisSupport.get("item.16384") + "  ,  " + i);
		}
		long s2 = System.currentTimeMillis() - s;
		System.err.println("500次请求 ,耗时:" + s2 + "ms");
		return "";
	}
}

先访问set ,将 item.16384 设置到redis里面, 然后访问get :

500次请求 , 耗时119 毫秒。然后关闭本地缓存 , 将openLocalCache 设置成false 。

运行结果:

全部走redis查询, 耗时24秒多。 可以看出 本地缓存还是很优秀的。


五. 代码

代码可以加我 qq:657455400 wx:hadluo 进行索取。

支付宝打赏 微信打赏

如果文章对您有帮助,您可以鼓励一下作者