Caching Redis实例缺少缓存经常使用go-lang客户端redigo
我正在为博客或在线发布网站开发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不会关闭与客户端的连接:连接将永远保持打开状态。所以我不确定我的设置到底发生了什么。我的代码的相关部分如下: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
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。非常感谢,它似乎确实解决了现在的问题,而且负载测试的结果也得到了改进。