我正在编写一些Go webservices(也使用http.ListenAndServe在Go中实现Web服务器)。 我有一个结构图,我想保留在内存中(大约数据大小为100Kb),供不同的http请求使用。
在Go中实现这一目标的最佳方法是什么? 根据您的经验,使用全局包变量或缓存系统(如memcache / groupcache)是否更好?
答案 0 :(得分:12)
除了您已收到的答案之外,请考虑使用接收方式method values和http.HandlerFunc。
如果您的数据是在流程开始之前加载的数据,您可以使用以下内容:
type Common struct {
Data map[string]*Data
}
func NewCommon() (*Common, error) {
// load data
return c, err
}
func (c *Common) Root(w http.ResponseWriter, r *http.Request) {
// handler
}
func (c *Common) Page(w http.ResponseWriter, r *http.Request) {
// handler
}
func main() {
common, err := NewCommon()
if err != nil { ... }
http.HandleFunc("/", common.Root)
http.HandleFunc("/page", common.Page)
http.ListenAndServe(...)
}
如果所有Common
数据都是只读的,这很有效。如果{/ 1}}数据是可读/写的,那么您将需要更多类似的内容:
Common
其余部分基本相同,除了不通过接收者的字段直接访问数据,您可以通过getter和setter访问它们。在正在读取大部分数据的Web服务器中,您可能需要RWMutex,以便可以彼此同时执行读取。第二种方法的另一个优点是您已经封装了数据,因此如果您的应用程序需要增加,您可以在将来添加透明写入和/或读取内存缓存或组缓存或其他类似内容。< / p>
我真的喜欢将处理程序定义为对象上的方法,因为它可以更轻松地对它们进行单元测试:您可以轻松定义包含所需值的table driven test并输出您期待而不必捣乱全局变量。
答案 1 :(得分:3)
仍然可以解决问题的简单解决方案通常是正确的方法。在服务器本地缓存数据既简单又高效,即使使用更丰富的系统,也可以在许多情况下完成。
作为一个例子,上个月我实施了快速黑客攻击(http://ubuntu-edge.info)由于围绕众筹活动传播的新闻而受到一些负担,并且Go流程的负载非常低时间,在一台小型EC2机器上。数据很简单,只是缓存在内存中,每分钟从外部进程更新的数据库刷新一次。
我一般看看memcache(现在是groupcache),自己这样做会意味着复制更多的功能。例如,当要在内存中保留太多数据时,或丢失服务器可能会影响整个系统的性能,因为缓存的数据一下子全部消失,或者因为性能受到争用的影响。
作为旁注,groupcache实际上是一个库,因此您可以将其嵌入到服务器中,而不是作为一个实际的外部系统。
答案 2 :(得分:2)
不要沉迷于过早的优化。定义Go包API以封装数据,然后您可以随时更改实现。例如,只是涂鸦,
package data
type Key struct {
// . . .
}
type Data struct {
// . . .
}
var dataMap map[Key]Data
func init() {
dataMap = make(map[Key]Data)
}
func GetData(key Key) (*Data, error) {
data := dataMap[key]
return &data, nil
}