刷新RedisTemplate

时间:2017-06-23 18:09:56

标签: redis jedis spring-data-redis

我正在使用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用于冗余和故障转移。

我对这个问题感到震惊了两天。任何帮助都非常感谢。

1 个答案:

答案 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得到了这个想法。