我正在创建一个架构,其中大多数数据非常稳定,不需要对其进行严格更新,并且不经常更新。此外,该信息的大小并不多(大约几MB)。
因此,当我在Google AppEngine中初始化一个实例(使用GoLang)时,不是使用Memcached,而是首先获取所有信息,将其作为热身缓存在内存中,并使用它。
但我需要每x次更新一次。因此,我需要一种方法来处理特定实例并更新它的内存缓存。
如果有不同的解决方案:
使用Basic Scaling可以解决特定的实例,但我找不到使用Automatic Scaling的方法,如下所示:https://cloud.google.com/appengine/docs/standard/go/how-instances-are-managed
所以...,你能想象一下优雅的方式来一次更新所有实例的内存状态而不会打扰客户端吗? 如何单独点击AppEngine的所有实例来更新内存缓存?
答案 0 :(得分:3)
访问所有动态实例通常很麻烦,而且你不应该依赖它。
而是重新设计并使用不同的方法。
让所有实例都使用内存缓存,但使用缓存数据的到期时间。每当需要这样的数据时,首先检查数据是否仍然有效(检查到期时间),如果是,请继续使用它。如果已过期,则从“某个”位置获取新的实际数据。这个“一些”的地方可能是Memcache或数据存储区,或者可选择两者都喜欢在Memcache中首先尝试,如果没有,那么从Datastore;或者它可能位于完全不同的地方,即使在Google Cloud Platform之外也是如此。获取新数据应包含其到期时间。
此方法不要求您访问动态实例,它们会在过期后自动刷新缓存数据。
如果从多个goroutine访问,则必须同步对缓存数据的访问。最好的方法是使用sync.RWMutex
,这样就可以允许多个读取器互不阻塞(频繁操作),只有在缓存数据已过期且需要刷新时才能获取写锁定。
以下是此类内存缓存的示例实现:
func getFreshData() (data interface{}, expires time.Time, err error) {
// Implement getting fresh data here:
return nil, time.Now().Add(time.Minute), nil
}
type cachedData struct {
sync.RWMutex
data interface{}
expires time.Time
}
var cd = new(cachedData) // zero value is ready to use
func Get() (data interface{}, err error) {
cd.RLock()
if time.Now().Before(cd.expires) {
// We're done: we can use the cached data:
data = cd.data
cd.RUnlock()
return
}
cd.RUnlock()
// Either we don't have cached data or it has expired.
// Acquire write lock and get data
cd.Lock()
defer cd.Unlock()
// But once we have the write lock, check again, as another competing
// goroutine might have fetched data before us:
if time.Now().Before(cd.expires) {
// Another goroutine fetched fresh data:
return cd.data, nil
}
// Nope, we have to do it ourselves:
data, expires, err = getFreshData()
if err == nil {
// Also put fresh data into the cache:
cd.data = data
cd.expires = expires
} else {
// There was an error getting it, set a 5 sec timeout to not keep calling:
cachedData.data = nil
cachedData.expires = time.Now().Add(5 * time.Second)
}
return
}
答案 1 :(得分:0)
除了icza的答案:
仅当使用手动缩放时,才能定位特定实例:
如果使用的是手动扩展服务,则可以通过包含实例ID来确定目标并将请求发送到实例。实例ID是一个整数,范围是0到正在运行的实例总数,可以指定如下:
将请求发送到特定实例中的特定服务和版本:
https://[INSTANCE_ID]-dot-[VERSION_ID]-dot-[SERVICE_ID]-dot-[MY_PROJECT_ID].appspot.com
http://[INSTANCE_ID].[VERSION_ID].[SERVICE_ID].[MY_CUSTOM_DOMAIN]
注意:在配置为自动缩放或基本缩放的服务中不支持定位实例。实例ID必须是0到运行实例总数之间的整数。无论您使用的是缩放类型还是实例类,都无法在不针对该实例内的服务或版本的情况下向特定实例发送请求。
答案 2 :(得分:0)
我建议:
在3中,您可以返回旧数据,但会触发更新。如果这样做不好,请考虑在应用引擎中使用Cron。