Groupcache: 频繁更新缓存条目的最佳实践

创建于 2015-03-08  ·  9评论  ·  资料来源: golang/groupcache

我的问题有点类似于问题https://github.com/golang/groupcache/issues/3。

我有一个地图,目前在单个实例上的 go 应用程序的 RAM 中进行管理。 我想在多个实例之间共享此地图以进行缩放。 我已经在使用 consul 来发现对等实例,我目前正在使用 redis 解决这个问题,但是我对我没有利用每台机器的 RAM 的事实不满意(所以从这个意义上说,我觉得 redis 更像是一个数据库而不是一个缓存)。 这就是我喜欢 groupcache 的原因之一。

不过我有一个限制:我的地图一直在变化(我收到了通过 http 更新它的请求)。 因此,对于映射中的键 K1,m[K1] 很可能会非常频繁地更新(可能每 1 秒或更短)。

所以我的问题是:

  1. 我是否选择了错误的架构? 我应该使用 Redis 或 memecached 之类的东西吗?
  2. 如果 groupcache 对于我的用例来说是一个很好的解决方案,我是否必须不断地删除和添加(比如在 LRU 缓存中)还是有更聪明的方法?

谢谢!

最有用的评论

嘿@orcaman。 我只是另一个 Groupcache 用户,但我希望我能回答你的问题。

首先,要记住的两件最重要的事情是 Groupcache 是只读缓存,这意味着您无法更新其中的键。 其次,该数据被认为是不可变的且不会过期。 它基本上只是一个分布式 LRU。 所以如果你需要经常更新密钥,GC 不是一个好的选择。

但是,您可以通过键操作来模拟现有数据的过期或更改。

就我而言,我需要大约一个小时的密钥过期时间。 我所做的是将下一轮小时的时间戳添加到我想要获取的任何密钥中。 因此,当一个小时过去后,我的应用程序请求更改密钥的这一部分,从 Groupcache 的角度来看,我正在请求一个新密钥。 旧的将通过 LRU 机制被驱逐,因为没有人再接触它。

但是,如果您需要不断地写入密钥,并在第二个分辨率下过期,则最好使用 redis 或 memcache。 我会选择 memcache,因为它更容易扩展更多的服务器。

所有9条评论

嘿@orcaman。 我只是另一个 Groupcache 用户,但我希望我能回答你的问题。

首先,要记住的两件最重要的事情是 Groupcache 是只读缓存,这意味着您无法更新其中的键。 其次,该数据被认为是不可变的且不会过期。 它基本上只是一个分布式 LRU。 所以如果你需要经常更新密钥,GC 不是一个好的选择。

但是,您可以通过键操作来模拟现有数据的过期或更改。

就我而言,我需要大约一个小时的密钥过期时间。 我所做的是将下一轮小时的时间戳添加到我想要获取的任何密钥中。 因此,当一个小时过去后,我的应用程序请求更改密钥的这一部分,从 Groupcache 的角度来看,我正在请求一个新密钥。 旧的将通过 LRU 机制被驱逐,因为没有人再接触它。

但是,如果您需要不断地写入密钥,并在第二个分辨率下过期,则最好使用 redis 或 memcache。 我会选择 memcache,因为它更容易扩展更多的服务器。

谢谢@dvirsky
我想我明白了。

没问题,虽然我有点希望在以色列场景中更多地采用 Groupcache。 你知道还有其他公司在使用它吗? :)

我们可能仍在使用它,只是等待正确的用例。 :-)
我不知道以色列场景中有很多地鼠,所以我不知道 Groupcache 用户。 期待在即将到来的 go 聚会中与您会面(如果您来了,那就是)。

凉爽的。 我们将其用作传出 HTTP 缓存(即我们向第 3 方发出的缓存请求)。 我们可能会在某个时候打开这个实现。
不确定 Go 聚会,希望我能成功。

@dvirsky@bradfitz - 在我的用例中,我想处理 TTL [计划将当前小时时间戳添加到密钥]。 我有以下问题,

1.LRU机制是如何去除key的。 我们可以设置不使用密钥的最短持续时间[将其标记为过期]吗?
2.如果不是,这取决于为缓存分配的内存。 当数据超过分配的最近最少使用的将被删除? 在这种情况下,我们如何处理内存平衡以不删除当前小时数据?

你能就此提出一些建议吗?

@dvirsky感谢您的出色回答.. 但是,当项目同时被“驱逐”时,您是否每小时看到 CPU 和内存的小高峰?

@qbig这取决于您如何实施到期。 这是我所做的:

// turn a ttl into an expiration timestamp, using discrete time windows.
// i.e. ask for an hour and get the nearest hour end as the expiration point.
//
// We pad these discrete boundaries  pseudo random margin (based on hashing the key)
// to avoid hitting the cache too hard if all requests expire at once
//
// This can be seconds from now even if you cache for days :)
func calcExpiration(ttl int64, key string, now int64) int64 {
    //we calculate the non discrete expiration, relative to current time
    expires := now

    var padding int64 = 0
    if ttl > 0 {
        // now we want to pad it so we'll no expire all reqeusts for a given time window at once
        // to be consistent, the seed of the padding is a hash on the url
        h := fnv.New32a()
        h.Write([]byte(key))
        padding = int64(h.Sum32()) % ttl

               // not sure this is correct - I wrote it long ago :)
        expires += (ttl - (expires % ttl)) - padding
        if expires < now {
            expires += ttl
        }

    }

    return expires

}

@orcaman看看https://tarantool.org/

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

AlexanderChen1989 picture AlexanderChen1989  ·  6评论

yml picture yml  ·  3评论

cowboyrushforth picture cowboyrushforth  ·  5评论

abennett picture abennett  ·  3评论

satb picture satb  ·  3评论