RedisClient失败了策略

时间:2014-12-24 15:39:08

标签: scala playframework redis

我正在使用scala的play框架。我还使用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)
    }
  }

2 个答案:

答案 0 :(得分:2)

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

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

    您需要在应用程序代码中包含RedisClient,以了解任何断开连接/重新连接。基本上有两种状态 - 第一种,当Redis正常工作时,第二种,当Redis下降/慢时。

  2. Redis很慢 - 由于以下原因之一,可能会发生这种情况 2.1。 网络速度慢:同样,您无法对此做多少工作,只能向客户端发送消息。如果你的网络本身很慢,那么去Mongo不太可能解决这个问题。

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

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

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

答案 1 :(得分:0)

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))
  }