Spring项目中使用Redis
Redis目前已经非常流行,由于Redis是基于内存存储不同的数据结构的存储系统,可以用作数据库,缓存和消息中间件。用的比较多的还是作为缓存存储系统。并且可以通过集群模式来提高可用性,集群方式有主从,哨兵,自动分区。
目前web服务端使用主体框架还是Spring,当然Spring提供了链接操作redis的方式就是Spring Data Redis。
通过工具去操作任何其他的中间件或者存储系统都是三个步骤,大部分开源框架都是如此做的,以redis为例:
1、与redis服务端建立连接
2、封装数据操作API
3、服务实际通过API实现数据传输
Spring Data Redis
Spring Data Redis主要与目前两个比较流行的Redis开源Java库进行集成。
Jedis和Lettuce都是Redis的client,当然是可以直接连接redis server。
Jedis
Jedis在实现上是直接连接redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
Lettuce
Lettuce连接是基于Netty的,连接实例可以在多个线程间并发访问,是线程安全的,所以一个连接实例就可以满足多线程环境下的并发访问,lettuce主要是利用netty实现与redis的同步与异步通信。
Spring Redis 链接配置
Spring Redis的链接配置方式有很多种,javaconfig,bean-xml,application.yml(Springboot);
目前Springboot是微服务的主流,所以以SpringBoot的yml文件配置为例。
sentinel(哨兵模式):
spring:
redis:
sentinel:
#哨兵模式监控的master的名称
master: masteroo
#哨兵模式下的哨兵IP:PORT
nodes: 127.0.0.1:2379,127.0.0.1:2378,127.0.0.1:2377
cluster集群模式:
spring:
redis:
# redis cluster 集群模式,6001,6002,6003是master,6004,6005,6007分别是它们的从节点
cluster:
nodes: 127.0.0.1:6001,127.0.0.1:6002,127.0.0.1:6003,127.0.0.1:6004,127.0.0.1:6005,127.0.0.1:6006
从上述配置中可知,在哨兵模式下只需要配置哨兵的IP:PORT,Cluster集群模式下需要将所有主节点和从节点的IP:PORT都配置进去。
所以在redis的服务器主节点挂的情况,两种集群的做法是不一致的,哨兵模式是通过哨兵从slave节点选举出新的master作为主节点继续运行,这暂时对项目配置未特别影响,Cluster集群模式是通过其余的master节点投票进行选举新的master节点,但是挂掉的这台master,在lettuce模式连接池中需要重新刷新拓扑网结构,SpringBoot2.X版本开始Redis默认的连接池都是采用的Lettuce,也可以转Jedis连接池。
刷新的代码如下:
@Bean
public LettuceConnectionFactory lettuceConnectionFactory() {
//开启 自适应集群拓扑刷新和周期拓扑刷新
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
// 开启全部自适应刷新
.enableAllAdaptiveRefreshTriggers() // 开启自适应刷新,自适应刷新不开启,Redis集群变更时将会导致连接异常
// 自适应刷新超时时间(默认30秒)
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30)) //默认关闭开启后时间为30秒
// 开周期刷新
.enablePeriodicRefresh(Duration.ofSeconds(20)) // 默认关闭开启后时间为60秒 ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD 60 .enablePeriodicRefresh(Duration.ofSeconds(2)) = .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))
.build();
// https://github.com/lettuce-io/lettuce-core/wiki/Client-Options
ClientOptions clientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions)
.build();
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.poolConfig(genericObjectPoolConfig(redisProperties.getLettuce().getPool()))
//.readFrom(ReadFrom.MASTER_PREFERRED)
.clientOptions(clientOptions)
.commandTimeout(redisProperties.getTimeout()) //默认RedisURI.DEFAULT_TIMEOUT 60
.build();
List<String> clusterNodes = redisProperties.getCluster().getNodes();
Set<RedisNode> nodes = new HashSet<RedisNode>();
clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(), Integer.valueOf(address.split(":")[1]))));
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
clusterConfiguration.setClusterNodes(nodes);
clusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
clusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfiguration, clientConfig);
// lettuceConnectionFactory.setShareNativeConnection(false); //是否允许多个线程操作共用同一个缓存连接,默认true,false时每个操作都将开辟新的连接
// lettuceConnectionFactory.resetConnection(); // 重置底层共享连接, 在接下来的访问时初始化
return lettuceConnectionFactory;
}
Springboot 提供了RedisTemplate模板的bean,启动时装配,同时也可以自定义使用。
扩展
个人觉得Redisson比较好用,相对API比较齐全,封装度高,容易上手,不用思考太多。