Caching Redis实例缺少缓存经常使用go-lang客户端redigo

Caching Redis实例缺少缓存经常使用go-lang客户端redigo,caching,go,redis,Caching,Go,Redis,我正在为博客或在线发布网站开发api,为其内容开发推荐引擎。 由于我的api为相同的url请求返回相同的json,所以我决定使用Redis作为高流量网站的缓存,将url作为键传递,json作为值传递。我最近正在go lang中开发这个api,并一直在使用redigo与我们的Redis实例进行对话。我决定构建我的系统的方式是检查客户端博客发送的查询的url,并在redis中搜索它。但是,如果未缓存中的url响应执行301重定向到另一个api,该api应用逻辑为该特定url生成json响应,并设置r

我正在为博客或在线发布网站开发api,为其内容开发推荐引擎。 由于我的api为相同的url请求返回相同的json,所以我决定使用Redis作为高流量网站的缓存,将url作为键传递,json作为值传递。我最近正在go lang中开发这个api,并一直在使用redigo与我们的Redis实例进行对话。我决定构建我的系统的方式是检查客户端博客发送的查询的url,并在redis中搜索它。但是,如果未缓存中的url响应执行301重定向到另一个api,该api应用逻辑为该特定url生成json响应,并设置redis缓存。然而,当我在测试我的Redis是否工作正常时,我意识到它丢失缓存的频率比我想要的要高很多。它肯定在缓存映射到url的json响应,这一点通过在Redis cli中执行一个简单的GET来确认,但在3-4次点击后,我可以再次看到Redis缺少缓存。我还是个新手,所以我不确定我的实现中是否遗漏了什么。另外,我想知道在什么情况下Redis实例会丢失缓存?它不能超时,因为Redis文档说,默认情况下,如果客户端空闲数秒,最新版本的Redis不会关闭与客户端的连接:连接将永远保持打开状态。所以我不确定我的设置到底发生了什么。我的代码的相关部分如下:

package main

import (
    "flag"
    "fmt"
    "github.com/garyburd/redigo/redis"
    "log"
    "net/http"
    "time"
)

var (
    port          int
    folder        string
    pool          *redis.Pool
    redisServer   = flag.String("redisServer", "redisip:22121", "")
    redisPassword = flag.String("redisPassword", "", "")
)

func init() {
    flag.IntVar(&port, "port", 80, "HTTP Server Port")
    flag.StringVar(&folder, "folder", "www", "Serve this folder")
}

func newPool(server, password string) *redis.Pool {
    return &redis.Pool{
        MaxIdle:     3,
        MaxActive:   25000,
        IdleTimeout: 30 * time.Second,
        Dial: func() (redis.Conn, error) {
            c, err := redis.Dial("tcp", server)
            if err != nil {
                return nil, err
            }
            return c, err
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            return err
        },
    }
}

func main() {
    flag.Parse()
    pool = newPool(*redisServer, *redisPassword)
    httpAddr := fmt.Sprintf(":%v", port)
    log.Printf("Listening to %v", httpAddr)
    http.HandleFunc("/api", api)

    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(folder))))
    log.Fatal(http.ListenAndServe(httpAddr, nil))

}

func api(w http.ResponseWriter, r *http.Request) {
    link := r.URL.Query().Get("url")
    fmt.Println(link)
    heading := r.URL.Query().Get("heading")
    conn := pool.Get()
    reply, err := redis.String(conn.Do("GET", link))
    defer conn.Close()
    if err != nil {
        fmt.Println("Error for link %v:%v", heading, err)
        http.Redirect(w, r, "json-producing-api", 301)
    }
    fmt.Fprint(w, reply)

}
这里我还必须提到,在上面的代码中,我的redis实例实际上是由twitter构建的twemproxy客户端,它代理在三个不同端口上运行的三个不同的redis客户端。昨天一切似乎都正常,我成功地完成了5k并发任务的负载测试。然而,当我今天查看日志时,一些查询被redis遗漏,并被重定向到我的json生成api,我可以看到redigo:nil错误。我完全搞不清楚到底出了什么问题?任何帮助都将不胜感激

编辑:根据下面的讨论,我正在详细说明我在Redis中设置数据所使用的代码

func SetIntoRedis(key string, value string) bool {
    // returns true if successfully set, returns false in case of an error
    conn := pool.Get()
    _, err := conn.Do("SET", key, value)
    if err != nil {

        log.Printf("Error Setting %v : %v", key, err)
        return false
    }
    return true
}
twemproxy客户端的配置

leaf:
  listen: 0.0.0.0:22121
  hash: fnv1a_64
  distribution: ketama
  redis: true
  auto_eject_hosts: true
  server_retry_timeout: 3000
  server_failure_limit: 3
  servers:
   - 127.0.0.1:6379:1
   - 127.0.0.1:6380:1
   - 127.0.0.1:6381:1

只要您的Redis实例保持运行,您就不应该丢失数据。展示如何在Redis中存储项目,并提供有关twemproxy配置的更多信息。有几点吹毛求疵:对每一笔借款都吹毛求疵是过分的。我会在没有ping的情况下运行这个。MaxIdle为25000是过度的。在达到此限制之前,您可能会运行fds。MaxIdle为3可能较低。我想用仪器看看你拨电话的频率,增加MaxIdle是合适的。使用redis.Bytes而不是redis.String来保存对字符串和返回字节的一些无意义的转换。使用w.Writep,其中p是从redis.Bytes返回的。感谢您的回复ThunderCat,这里有一些非常好的见解。我现在已删除PING和监视。事实上,我昨天在进行负载测试,预计会出现高流量,所以将设置保留在这个上限。除此之外,我还分享了在Redis和twemproxy config中存储项目的代码。事实上,当我面临这个问题时,我意识到我也无法从Redis cli中看到任何数据,这意味着出于某种原因,我的数据没有被持久化。我删除了twemproxy,但问题仍然存在,任何想法??SetIntoRedis不会关闭连接。问题可能与此资源泄漏有关。Go的最佳实践是在获取资源的语句之后立即延迟释放资源的调用。移动延迟连接。关闭api中的一行。将延迟添加到SetIntoRedis。非常感谢,它似乎确实解决了现在的问题,而且负载测试的结果也得到了改进。