>> Cluster 的能力。
>> 处理热点的能力。
以往在memcached server 之间是没有交集的,在groupcache 则是cluster 起来。另外以前在memcached 会因为同时存取同一个key 而造成single CPU overloading 的问题,在groupcache 则透过auto-mirror 机制解决。参考:http://blog.csdn.net/songbohr/article/details/16349989。其中groupcache与memcached最大的区别是不需要启动额外的服务。groupcache作为lib库缓存数据,不需要单独开启服务器,减少了服务器额外维护的代价。
groupcache也常被推荐为适合Golang初学者分析的代码段,这几天我也抽空分析了一下具体的实现,并结合Play With Groupcach简单的测试了GroupCache,实现的基本结构如下所示:

点击(此处)折叠或打开
-
package main
-
-
import (
-
"flag"
-
"fmt"
-
"github.com/golang/groupcache"
-
"groupcache/api"
-
"groupcache/client"
-
"net"
-
"net/http"
-
"net/rpc"
-
"os"
-
"strconv"
-
)
-
-
type Frontend struct {
-
cacheGroup *groupcache.Group //groupcache Group
-
}
-
-
func (s *Frontend) Get(args *api.Load, reply *api.ValueResult) error { //从cache中去取key值,实际是rpc的函数
-
var data []byte
-
fmt.Printf("cli asked for %s from groupcache\n", args.Key)
-
-
err := s.cacheGroup.Get(nil, args.Key, groupcache.AllocatingByteSliceSink(&data)) //groupcache中获取数据
-
-
reply.Value = string(data)
-
return err
-
}
-
-
func NewServer(cacheGroup *groupcache.Group) *Frontend {
-
server := new(Frontend)
-
server.cacheGroup = cacheGroup //cachegroup
-
return server
-
}
-
-
func (s *Frontend) Start(port string) { //tcp的rpc服务
-
rpc.Register(s)
-
rpc.HandleHTTP()
-
l, e := net.Listen("tcp", port)
-
if e != nil {
-
fmt.Println("fatal")
-
}
-
http.Serve(l, nil)
-
}
-
-
func main() {
-
var port = flag.String("port", "8001", "groupcache port")
-
flag.Parse()
-
-
peers := groupcache.NewHTTPPool("" + *port) //注册groupcache的http服务
-
client := new(client.Client)
-
var stringcache = groupcache.NewGroup("SlowDBCache", 64<<20, groupcache.GetterFunc( //该函数用于获取实际的数据,这部分通常是从源获取数据
-
func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
-
result := client.Get(key)
-
fmt.Printf("asking for %s from dbserver\n", key)
-
dest.SetBytes([]byte(result))
-
return nil
-
})) //创建一个Group
-
-
peers.Set("8001", "8002", "8003") //设置对端信息
-
frontendServer := NewServer(stringcache) //rpc的服务器
-
i, err := strconv.Atoi(*port)
-
if err != nil {
-
fmt.Println(err)
-
os.Exit(2)
-
}
-
-
var frontEndport = ":" + strconv.Itoa(i+1000) //prc的端口为900x
-
go frontendServer.Start(frontEndport) //启动rpc的服务,goroutine,这部分用于cli、db之间的交互
-
-
fmt.Println(stringcache)
-
fmt.Println("cachegroup slave string on " + *port)
-
fmt.Println("fronend start on " + frontEndport)
-
http.ListenAndServe("127.0.0.1:"+*port, http.HandlerFunc(peers.ServeHTTP)) //启动http的服务,实际上是启动了GroupCache的服务
- }
>> 首先创建一个GroupCache的HTTPool, peers。
>> 创建Group对象, 设置该Group Cache的大小,数据实际获取的方法,其中的 groupcache.GetterFunc对应着实际从源头加载数据的方法,比如从数据库中获取、从文件中获取等。这也是必须的。groupcache.GetterFunc实际上是groupcache.Getter的接口实例。
>> 设置对端GroupCache的地址信息。peers.Set(url1, url2, ...)
>> 启动GroupCache的Http服务。在http.ListenAndServe("xxxx", http.HandlerFunc(peers.ServeHTTP))
>> 要获取数据只需要通过创建的Group对象来获取即可。group.Get(xxx)。
后续将对groupcache的代码进行进一步的分析。