我正在使用spring quartz作业连接到Redis来执行操作。我已将RedisTemplate配置为仅连接到主节点。
当在Redis中发生故障转移并且选择了新的主服务器时,我会通过sentinel.conf中的client-reconfig-script
通知我。在此之后,我试图重新连接我的RedisTemplate与新主人交谈。这个重新布线部分不起作用。
quartz作业和RedisTemplate的Spring启动配置:
package com.XXX.XXX;
import org.quartz.JobDetail;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import de.chandre.quartz.spring.AutowiringSpringBeanJobFactory;
import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
@SpringBootApplication(exclude = { QuartzSchedulerAutoConfiguration.class })
public class OrderProcessorApplication {
public static void main(String[] args) {
SpringApplication.run(OrderProcessorApplication.class, args);
}
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(OrderProcessorJob.class);
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
@Value("${job.interval}")
private int interval;
@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(job);
trigger.setRepeatInterval(interval);
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
return trigger;
}
@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
schedulerFactory.setJobFactory(springBeanJobFactory());
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
return schedulerFactory;
}
@Autowired
private ApplicationContext ap;
@Bean
@Primary
public SpringBeanJobFactory springBeanJobFactory() {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(ap);
return jobFactory;
}
// @Bean
// @Qualifier("sentinel")
// public RedisTemplate<String, Object> createRedisTemplate() {
// RedisSentinelConfiguration sc = new RedisSentinelConfiguration()
// .master("redis-cluster")
// .sentinel("127.0.0.1", 26179)
// .sentinel("127.0.0.1", 26381);
//
// JedisConnectionFactory jcf = new JedisConnectionFactory(sc);
// jcf.setUsePool(true);
// jcf.afterPropertiesSet();
//
// RedisTemplate rt = new RedisTemplate();
// rt.setConnectionFactory(jcf);
// rt.afterPropertiesSet();
// return rt;
// }
@Bean
@Primary
public RedisTemplate<String, Object> createMasterOnlyRedisTemplate() {
JedisConnectionFactory jcf = new JedisConnectionFactory();
jcf.setHostName("127.0.0.1");
jcf.setPort(6379);
jcf.setUsePool(true);
jcf.afterPropertiesSet();
RedisTemplate rt = new RedisTemplate();
rt.setConnectionFactory(jcf);
rt.afterPropertiesSet();
return rt;
}
}
刷新由sentinel调用的REST服务:
package com.store.platform;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.kohls.store.platform.common.model.ui.UpdateRedisMaster;
@RestController
@RequestMapping(path = "/refresh", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public class Test {
@Autowired
private RedisTemplate<String, Object> rt;
@RequestMapping(method = RequestMethod.POST)
public void refresh(@RequestBody UpdateRedisMaster um) {
JedisConnectionFactory jcf = (JedisConnectionFactory) rt.getConnectionFactory();
jcf.setHostName(um.getIp());
jcf.setPort(um.getPort());
jcf.setShardInfo(null);
jcf.afterPropertiesSet();
}
}
成功调用刷新后,接下来石英作业尝试连接到Redis我得到以下异常:
org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:204) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:348) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:129) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:92) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:79) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:194) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:169) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:91) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:182) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
at com.XXX.platform.OrderProcessorJob.execute(OrderProcessorJob.java:32) ~[classes/:na]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.0.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.3.0.jar:na]
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:53) ~[jedis-2.9.0.jar:na]
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226) ~[jedis-2.9.0.jar:na]
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:16) ~[jedis-2.9.0.jar:na]
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:194) ~[spring-data-redis-1.8.4.RELEASE.jar:na]
... 11 common frames omitted
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused (Connection refused)
at redis.clients.jedis.Connection.connect(Connection.java:207) ~[jedis-2.9.0.jar:na]
at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:93) ~[jedis-2.9.0.jar:na]
at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1767) ~[jedis-2.9.0.jar:na]
at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:106) ~[jedis-2.9.0.jar:na]
at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:868) ~[commons-pool2-2.4.2.jar:2.4.2]
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435) ~[commons-pool2-2.4.2.jar:2.4.2]
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363) ~[commons-pool2-2.4.2.jar:2.4.2]
at redis.clients.util.Pool.getResource(Pool.java:49) ~[jedis-2.9.0.jar:na]
... 14 common frames omitted
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_121]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_121]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_121]
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_121]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_121]
at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_121]
at redis.clients.jedis.Connection.connect(Connection.java:184) ~[jedis-2.9.0.jar:na]
... 21 common frames omitted
我想获得一致的数据,这就是为什么我想使用master进行读写,以及slave用于冗余和故障转移。
我对这个问题感到震惊了两天。任何帮助都非常感谢。
答案 0 :(得分:0)
我能够通过创建自己的RedisConnectionFactory来解决我的问题。
public class SPRedisConnectionFactory implements InitializingBean, RedisConnectionFactory, DisposableBean {
private Jedis jedis;
private String[] nodes;
private Map<String, String[]> nodeMap;
@Value("${master.node}")
private String masterNode;
@Override
public void afterPropertiesSet() throws Exception {
nodeMap = Arrays.stream(this.nodes)
.map(n -> n.split(":"))
.collect(toMap(n -> n[0] + ":" + n[1], n -> n));
System.out.println(nodeMap);
}
@Override
public RedisConnection getConnection() {
String[] master = nodeMap.get(masterNode);
jedis = new Jedis(master[0], parseInt(master[1]), 2000);
jedis.connect();
JedisConnection c = new JedisConnection(jedis);
return c;
}
@Override
public RedisClusterConnection getClusterConnection() {
throw new UnsupportedOperationException();
}
@Override
public boolean getConvertPipelineAndTxResults() {
return false;
}
@Override
public RedisSentinelConnection getSentinelConnection() {
throw new UnsupportedOperationException();
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException e) {
return null;
}
@Override
public void destroy() throws Exception {
jedis.disconnect();
}
}
从Connections to multiple Redis servers with Spring Data Redis得到了这个想法。