16.go开源groupcache项目笔记——部署

来源:互联网 发布:js提示信息 编辑:程序博客网 时间:2024/06/08 18:03

16.go开源groupcache项目笔记——部署

 

groupcache没有服务端与客户端之分。本身没有main函数就是一个库,可以被其他应用集成到代码中。

主要结构说明:

consistenthash一致性hash哈希算法,

lru(提供了LRU缓存算法,最终存数据的地方,里面使用了两种数据结构,maplistmap用来保存key-value数据,list按访问顺序保存value,这样实现lru,在清理数据的时候,将最久未访问的数据清除掉。

singleflight实现多次相同请求只去获取值一次,减少资源消耗。不会都将请求发到数据库或者其他的实例中,以此来避免惊群

groupcachepb同一个group中的多个实例交互数据,使用pb,减少数据体积。

其他源文件:

byteview.go 可以理解为一种数据格式,在groupcache中,将所有的value都保存为byteview的格式。优先使用[]byte表示,否则使用string

peers.go同一个group里可以有多个节点,peers是用来表示这种关系的

sinks.go这个东西用来接收Get到的数据,

groupcache.go主代码核心,定义了groupcache的核心数据结构—group,以及围绕groupget等核心操作。

http.go 这里是业务和groupcache交互的接口

Get代码流程

描述一次Get请求在groupcache里经过的历程。代码在groupcache.go中。

1.      首先Group会去初始化它的peers节点,但是又不能每次get的时候都去调用,所以这里采用了sync.once用来保证只执行一次。

2.      GETS状态+1,跟我们在memcache中看到的各种统计信息一样,用来统计Cache GetCache Miss

3.      从当前节点获取缓存内容,从mainCache中获取,如果没有从hotCache中获取。

4.      如果当前节点没有获取到结果,则会从peers的节点中获取内容,如果没有,则会从用户定义的getter方法中获取信息(此时会使用singleflight,来保证只有1个请求会真正发起请求,也就是,如果对当前节点有5个对key=test的请求,则只有1个会真正向peers发起请求,而其他四个请求会block,直到请求返回。而且先从peers请求,再从getter中获取也是有讲究的,因为,如果在3台业务机上同时对key=test发起请求,那么会保证只会调用一次getter,从而避免memcache等缓存的业务冷启动问题)

5.      将获取的结果返回

部署

部署框架如下1

注意点

(摘自网络)

§ 需要监听两个地方,一个是监听节点,一个是监听请求

§ 在批量设置节点地址的时候需要在地址前面加上http://,如果没有加上去,所以缓存信息就不能再节点之间交互

§ 启动的节点地址要与设置的节点地址一致:数量和地址值。少一个就无法在节点间交互。

测试代码

packagemain

import(

    "flag"

    "fmt"

    "io/ioutil"

    "log"

    "net/http"

    "os"

    "strconv"

    "strings"

 

    "github.com/golang/groupcache"

)

 

var(

    //peers_addrs=[]string{"127.0.0.1:8001","127.0.0.1:8002","127.0.0.1:8003"}

    //rpc_addrs=[]string{"127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"}

    index=flag.Int("index",0,"peerindex")

)

 

funcmain(){

    flag.Parse()

    peers_addrs:=make([]string,3)

    rpc_addrs:=make([]string,3)

    iflen(os.Args)>0{

        fori:=1;i<4;i++{

            peers_addrs[i-1]=os.Args[i]

            rpcaddr:=strings.Split(os.Args[i],":")[1]

            port,_:=strconv.Atoi(rpcaddr)

            rpc_addrs[i-1]=":"+strconv.Itoa(port+1000)

        }

    }

    if*index<0||*index>=len(peers_addrs){

        fmt.Printf("peer_index%dnotinvalid\n",*index)

        os.Exit(1)

    }

    peers:=groupcache.NewHTTPPool(addrToURL(peers_addrs[*index]))

    varstringcache=groupcache.NewGroup("SlowDBCache",64<<20,groupcache.GetterFunc(

        func(ctxgroupcache.Context,keystring,destgroupcache.Sink)error{

            result,err:=ioutil.ReadFile(key)

            iferr!=nil{

                log.Fatal(err)

                returnerr

            }

            fmt.Printf("askingfor%sfromdbserver\n",key)

            dest.SetBytes([]byte(result))

            returnnil

        }))

 

    peers.Set(addrsToURLs(peers_addrs)...)

 

    http.HandleFunc("/zk",func(rwhttp.ResponseWriter,r*http.Request){

        log.Println(r.URL.Query().Get("key"))

        vardata[]byte

        k:=r.URL.Query().Get("key")

        fmt.Printf("cliaskedfor%sfromgroupcache\n",k)

        stringcache.Get(nil,k,groupcache.AllocatingByteSliceSink(&data))

        rw.Write([]byte(data))

    })

    gohttp.ListenAndServe(rpc_addrs[*index],nil)

    rpcaddr:=strings.Split(os.Args[1],":")[1]

    log.Fatal(http.ListenAndServe(":"+rpcaddr,peers))

}

 

funcaddrToURL(addrstring)string{

    return"http://"+addr

}

 

funcaddrsToURLs(addrs[]string)[]string{

    result:=make([]string,0)

    for_,addr:=rangeaddrs{

        result=append(result,addrToURL(addr))

    }

    returnresult

}

执行方式:./test127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003

启动了一个节点,设置节点地址个数为3个,所以在启动其它节点的时候变换下地址的顺序,使第一个地址三次都不一样就好了。这样同样方法启动三个节点。

打开浏览器访问127.0.0.1:9001?key=1.txt,这里1.txt是需要获取数据的之际地方,类似于实际中的数据库,我这里直接用一个文件代替了。

访问使用9000是因为在测试代码中将端口加上了1000.

友情链接

http://capotej.com/blog/2013/07/28/playing-with-groupcache/

 

 

 

阅读全文
0 0