当前位置: 首页 > 知识库问答 >
问题:

如何在Spring Boot中防止像Redis服务器这样的外部连接故障fail fast?

韩景辉
2023-03-14
spring.cloud.config.fail-fast=true

您可以通过关闭Redis服务器来使用我为我的问题创建的这个项目来重现。

下面是我的代码的样子-

@Lazy
@Configuration
public class RedisConfiguration {
    @Value("${spring.redis.sentinel.master}")
    private String SENTINEL_MASTER;

    @Value("${spring.redis.sentinel.nodes}")
    private String SENTINEL_NODES;

    @Value("${spring.redis.security.enabled:false}")
    private boolean REDIS_SECURITY_ENABLED;

    @Value("${spring.redis.security.password:}")
    private String REDIS_PASSWORD;

    @Lazy
    @Bean // somehow this always gets initialized
    public RedisConnectionFactory jedisConnectionFactory() { 
        // create set of sentinel nodes
        System.out.println(SENTINEL_NODES);
        Set<String> sentinelNodesSet = new HashSet<>(5);
        StringTokenizer st = new StringTokenizer(SENTINEL_NODES, ",");
        while (st.hasMoreTokens())
            sentinelNodesSet.add(st.nextToken());
        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration(SENTINEL_MASTER, sentinelNodesSet);
        if (REDIS_SECURITY_ENABLED) {
            sentinelConfig.setPassword(REDIS_PASSWORD);
        }
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinelConfig);
        return jedisConnectionFactory;
    }

下面是异常跟踪-

简而言之:

  1. @lazy注释适用于RedisstandalOneConfiguration而不适用RedissentinelConfiguration,不确定原因吗?
  2. 使用@lazy注释是有风险的,因为您需要确保使用redis的所有服务都是懒散加载的。
  3. 正在查找为spring Cloud提供的类似spring.cloud.config.fail-fast=true的解决方案。

更新:

共有1个答案

魏翔
2023-03-14

在hood下,Spring Cloud Config使用spring-retry和AOP(spring-boot-starter-aop)配置重试机制。

此过程在ConfigServiceBootstrapConfiguration中实现。

守则的有关部分如下:

/* @ConditionalOnProperty("spring.cloud.config.fail-fast") */
@ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class })
@Configuration(proxyBeanMethods = false)
@EnableRetry(proxyTargetClass = true)
@Import(AopAutoConfiguration.class)
@EnableConfigurationProperties(RetryProperties.class)
protected static class RetryConfiguration {

  @Bean
  @ConditionalOnMissingBean(name = "configServerRetryInterceptor")
  public RetryOperationsInterceptor configServerRetryInterceptor(
      RetryProperties properties) {
    return RetryInterceptorBuilder.stateless()
        .backOffOptions(properties.getInitialInterval(),
            properties.getMultiplier(), properties.getMaxInterval())
        .maxAttempts(properties.getMaxAttempts()).build();
  }

}

正如您所看到的,基本思想是提供一个RetryConfiguration,它在认为应用程序失败之前处理一定数量的重试。

Spring Cloud Client的文档提供了更多关于用于配置该机制的不同属性的信息。您还可以在RetryProperties类的源代码中看到默认值。

请尝试将两个必需的依赖项spring-retryspring-boot-starter-aop以及retryconfiguration作为主配置的子项,为重试机制的配置属性提供一些合理的默认值,然后看看会发生什么。

您可以将解决方案推向极限,并尝试在非常多的场合重新连接,也许增加它们之间的抑扬顿挫,等待服务器可用。

我认为@lazy注释不再是必需的,可以安全地删除。

编辑

查看错误堆栈跟踪,您还可以尝试禁用字符串引导Redis自动配置类。

@SpringBootApplication(
  exclude = { RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class }
)
spring.autoconfigure.exclude= \
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration, \
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration

您还可以使用此属性禁用Redis存储库配置:

spring.data.redis.repositories.enabled: false

一旦您禁用了Redis自动配置,您将可以自由地实例化redistemplate或您认为合适时与Redis交互所需的东西。

例如,当实际需要时,您可以按需初始化它,尝试通过初始化所有所需的工厂来建立到Redis的连接。您可以使用trycatch包围初始化Redis连接所需的逻辑,并且只有在连接可用时才初始化Redistemplate(如下所示)。

public RedisConnectionFactory jedisConnectionFactory() { 
    try {
      // create set of sentinel nodes
      System.out.println(SENTINEL_NODES);
      Set<String> sentinelNodesSet = new HashSet<>(5);
      StringTokenizer st = new StringTokenizer(SENTINEL_NODES, ",");
      while (st.hasMoreTokens())
          sentinelNodesSet.add(st.nextToken());
      RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration(SENTINEL_MASTER, sentinelNodesSet);
      if (REDIS_SECURITY_ENABLED) {
          sentinelConfig.setPassword(REDIS_PASSWORD);
      }
      JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinelConfig);
      return jedisConnectionFactory;
    } catch (redis.clients.jedis.exceptions.JedisConnectionException re) {
      logger.error("Unable to initialize Redis connection factory", re);
      return null;
    }
}

另一方面:

public RedisTemplate getRedisTemplate() {
  // We can assume that both methods are defined in the same class, 
  // although it is not necessary
  final RedisConnectionFactory redisConnectionFactory = this.jedisConnectionFactory();
  if (redisConnectionFactory == null) {
    return null;
  }

  final RedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory);
  return redisTemplate;
}

您可以以您认为合适的方式使用这个redistemplate,当然,还可以根据需要缓存和重用它。

这些方法可以在为此任务创建的服务或帮助器类中定义,当然,不能在您的配置类中定义。

 类似资料:
  • 问题内容: 我的一台Redis服务器今天反复停机,没有任何明显的可诊断原因。我所有的用户最终都会遇到错误。 查看处的日志,最后几行捕获的内容比计划的备份更为有害: pid文件仍然存在。这意味着服务器没有被正式关闭,redis仍被守护? 我登录到系统,并做了两次以使其启动并运行。除了这些日志,我还能如何诊断可能出了什么问题? 更新:我注意到在第一次崩溃时,磁盘交换开始发生。这从未发生过。此外,确认将

  • 问题内容: 在我的 主服务器上 ,我从可通过api访问的外部/单独的 redis服务器中 获取数据 。但是,api是不安全的。而且由于我希望将 Redis服务器 分开,因此该技术不适合我的情况。 在我来说,我想有2台独立的服务器, 一个 和 乙 。 A 应该在不使用api或url调用的情况下从 B 加载数据…而是应使用 port (例如)。这样,服务器 乙 只能从访问的 一个 。 我希望这种方法适

  • 问题内容: 我认为我非常接近让Java服务器应用程序通过WebRTC与浏览器页面对话,但是我不能完全使其正常工作。我感觉自己缺少一些小东西,因此希望这里有人可以提出建议。 我仔细研究了WebRTC示例- Java单元测试()和示例Android应用()。根据所学知识,我编写了一个Java应用程序,该应用程序使用WebSockets进行信号传输并尝试将视频流发送到Chrome。 问题是,即使我所有的

  • 我想连接到树莓Pi节点。我从网络外部设置的js服务器。 我的路由器声称端口是开放的。我尝试在127.0.0.0、0.0.0.0和我的公共IP地址运行服务器。 我曾尝试使用ngrok打开端口8080,服务器在其中托管一个简单的网页,但尝试访问myIP:8080不起作用。 有人能帮我吗?

  • 问题内容: 我显然正在运行一个实例,因为当我尝试通过输入来启动新服务器时,遇到了以下问题: 我不知道如何停止此服务器并启动新服务器。 在CLI中键入命令时,可以追加任何命令吗? 我的操作系统是Ubuntu 10.04。 问题答案: 连接到节点实例并使用shutdown命令,或者如果您在ubuntu上,则可以尝试通过init.d重新启动Redis服务器: 或停止/启动它: 在Mac上

  • 我有3个复制的Redis实例运行在3台不同的机器上:A、B和C。我最初选择A作为我的主机。我还有3个哨兵(每台机器上有1个)监视A。