【问题标题】:RedisClient fails strategyRedisClient 失败策略
【发布时间】:2014-12-24 15:39:07
【问题描述】:

我正在使用带有 scala 的播放框架。我还使用 RedisScala 驱动程序(这个 https://github.com/etaty/rediscala )与 Redis 进行通信。如果 Redis 不包含数据,那么我的应用程序正在 MongoDB 中查找数据。 当 Redis 失败或由于某种原因不可用时,应用程序等待响应的时间过长。在这种情况下如何实施故障转移策略。如果请求时间过长,我想停止请求 Redis。并在 Redis 重新上线后开始使用它。 为了澄清这个问题,我的代码现在如下所示

private def getUserInfo(userName: String): Future[Option[UserInfo]] = {
    CacheRepository.getBaseUserInfo(userName) flatMap{
      case Some(userInfo) =>
        Logger.trace(s"AuthenticatedAction.getUserInfo($userName). User has been found in cache")
        Future.successful(Some(userInfo))
      case None =>
        getUserFromMongo(userName)
    }
  }

【问题讨论】:

    标签: scala playframework redis


    【解决方案1】:

    我认为您需要区分以下情况(按发生的可能性顺序):

    1. 缓存中没有数据(Redis) - 我猜在这种情况下,Redis 会很快返回,你必须从 Mongo 获取它。在上面的代码中,您需要在从 Mongo 获取数据后在 Redis 中设置数据,以便将其保存在缓存中以供后续调用。

      您需要将 RedisClient 包装在您的应用程序代码中,以了解任何断开/重新连接。基本上有两种状态 - 首先,当 Redis 正常工作时,其次,当 Redis 宕机/缓慢时。

    2. Redis 很慢 - 这可能是由于以下原因之一。
      2.1. 网络很慢:同样,您对此无能为力,只能向您的客户返回一条消息。如果您的网络本身很慢,那么使用 Mongo 不太可能解决此问题。

      2.2。 操作很慢:例如,如果您尝试获取大量数据或在排序集上运行范围查询,则会发生这种情况。在这种情况下,您需要重新访问您正在使用的 Redis 数据结构,以了解您在 Redis 中存储的数据量。但是,在您的示例中,这不会成为问题。单个 Redis 获取操作通常在 LAN 上具有低延迟。

    3. Redis 节点不可访问 - 我不确定这种情况多久会发生一次,除非您的网络出现故障。在这种情况下,您也将无法连接到 MongoDB。我相信当运行 Redis 的节点关闭或磁盘已满等时也会发生这种情况。所以你应该在设计中处理这个问题。话虽如此,Rediscala 客户端会自动检测任何断开连接并重新连接自动。我个人已经这样做了。停止并升级 Redis 版本并重新启动 Redis,而无需接触我正在运行的客户端(JVM)。

    最后,您可以在上面的程序中使用带有超时的 Future(参见 - Scala Futures - built in timeout?)。如果 Future 未在超时之前完成,您可以采取其他操作(转到 Mongo 或向用户返回错误消息)。鉴于 #1 和 #2 可能比 #3 更频繁地发生,您的超时值应该反映这两种情况。鉴于 #1 和 #2 在 LAN 上速度很快,您可以从 100 毫秒的超时值开始。

    【讨论】:

    • 感谢您提供如此详细的概述。第一点正是我目前正在做的。我的问题主要是关于第 3 点。据我所知,RedisScala 客户端有 Actor,它试图每 2 秒重新连接一次,但我不知道如何从中获取有关连接的信息。如果我可以从 RedisScala 获取这些信息,那么我可能会错过从 Redis 请求数据的步骤。感谢您的帮助。
    【解决方案2】:

    Soumya Simanta 提供了详细的答案,我只想发布我用于超时的代码。该代码需要在我的项目中使用的 Play 框架

    private def get[B](key: String, valueExtractor:  Map[String, ByteString] => Option[B], logErrorMessage: String): Future[Option[B]] = {
        val timeoutFuture = Promise.timeout(None, Duration(Settings.redisTimeout))
        val mayBeHaveData = redisClient.hgetall(key) map { value =>
          valueExtractor(value)
        } recover{
          case e =>
            Logger.info(logErrorMessage + e)
            None
        }
    
        // if timeout occurred then None will be result of method
        Future.firstCompletedOf(List(mayBeHaveData, timeoutFuture))
      }
    

    【讨论】:

      猜你喜欢
      • 2016-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-29
      • 2014-05-23
      • 1970-01-01
      • 2015-01-01
      • 2015-04-30
      相关资源
      最近更新 更多