[Golang] groupcache的简单例子

在网上查了挺多groupcache的相关信息,但是搜出来大部分都是copy,实际的例子也没有,所以就看了下源码,也在golang-nuts上问了,github上搜索了一些groupcache的使用例子,在此作个总结,目前对这个缓存库还仅处于了解状态

大概介绍

其实关于groupcache的介绍网上非常的多,搜索出来清一色都是说的介绍,当然也有配图如何部署,但是文字与配图完全不在一个时空,图也是copy国外的一篇博客。它不像其它的一些缓存数据库有个服务端,需要客户端去连接,文档中明确说明了它就是一个程序库,所以没有服务端与客户端这么一说,换句话说,它本没有服务端,又或者是人人都是服务端,食神的感觉油然而生。

主要代码结构

它的代码结构也比较清晰,代码量也不是很大,很适合大家去阅读学习。主要分为了consistenthash(提供一致性哈希算法的支持)lru(提供了LRU方式清楚缓存的算法)singleflight(保证了多次相同请求只去获取值一次,减少了资源消耗),还有一些源文件:byteview.go提供类似于一个数据的容器http.go提供不同地址间的缓存的沟通的实现peers.go节点的定义sinks.go感觉就是一个开辟空间给容器,并和容器交互的一个中间人groupcache.go整个源码里的大当家,其它人都是为它服务的

一个测试例子

在使用这个缓存的时候比较重要的几方面也是我之前犯错的几个地方

  • 需要监听两个地方,一个是监听节点,一个是监听请求
  • 在批量设置节点地址的时候需要在地址前面加上http://,因为一开始我没有加上去,所以缓存信息一直不能再节点之间交互
  • 启动的节点地址要与设置的节点地址一致:数量和地址值。因为我每次少一个就无法在节点间交互。

以上的一些信息可能也有不对的地方,只是我个人的一个测试后的结果。

代码部分

package main

        import (
            "flag"
            "fmt"
            "github.com/golang/groupcache"
            "io/ioutil"
            "log"
            "net/http"
            "os"
            "strconv"
            "strings"
        )
        
        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, "peer index")
        )
        
        func main() {
            flag.Parse()
            peers_addrs := make([]string,102);">3)
            rpc_addrs 3)
            if len(os.Args) > 0 {
                for i := 1; i < 4; i++ {
                    peers_addrs[i-1] = os.Args[i]
                    rpcaddr := strings.Split(os.Args[i],33);">":")[1]
                    port, _ := strconv.Atoi(rpcaddr)
                    rpc_addrs[i1] = ":" + strconv.Itoa(port+1000)
                }
            }
            if *index < 0 || *index >= len(peers_addrs) {
                fmt.Printf("peer_index %d not invalid\n", *index)
                os.Exit(1)
            }
            peers := groupcache.NewHTTPPool(addrToURL(peers_addrs[*index]))
            var stringcache = groupcache.NewGroup("SlowDBCache",102);">64<<20, groupcache.GetterFunc(
                func(ctx groupcache.Context, key dest groupcache.Sink) error {
                    result, err := ioutil.ReadFile(key)
                    if err != nil {
                        log.Fatal(err)
                        return err
                    }
                    fmt.Printf("asking for %s from dbserver\n", key)
                    dest.SetBytes([]byte(result))
                    return nil
                }))
        
            peers.Set(addrsToURLs(peers_addrs)...)
        
            http.HandleFunc("/zk", func(rw http.ResponseWriter, r *http.Request) {
                log.Println(r.URL.Query().Get("key"))
                var data []byte
                k := r.URL.Query().Get("key")
                fmt.Printf("cli asked for %s from groupcache\n", k)
                stringcache.Get(nil, k, groupcache.AllocatingByteSliceSink(&data))
                rw.Write([]byte(data))
            })
            go http.ListenAndServe(rpc_addrs[*index], nil)
            rpcaddr := strings.Split(os.Args[1],102);">1]
            log.Fatal(http.ListenAndServe(":"+rpcaddr, peers))
        }
        
        func addrToURL(addr string) string {
            return "http://" + addr
        }
        
        func addrsToURLs(addrs []string) []string {
            result 0)
            for _, addr := range addrs {
                result = append(result, addrToURL(addr))
            }
            return result
        }

执行方式:./demo 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003

在上面的命令中我们就启动了一个节点,并且设置节点地址个数为3个,这里由于我是默认的index为0,所以在启动其它节点的时候变换下地址的顺序,使第一个地址三次都不一样就好了。(抱歉,这里实现的不是很好),这样同样方法启动三个节点。

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

运行结果:

  • 当我访问:9001时结果

在上面图中,我们像:8001这个节点请求数据,它没有缓存数据,然后会去其它节点中寻找这个key的数据,当都没有的时候就会去数据库中获取(这里我们是一个文件),所以会出现在:8003这个节点中获取数据库数据的操作。

  • 然后我访问:9002

根据上图看到,第一个地址为:8002这个节点直接从缓存里面取值,但是在请求之前这个节点并没有缓存数据,这个也同样是节点间的交互完成的。

我在本地开启了两个虚拟机,在同一个局域网中,测试也能得出相同的结果。这里结果就不再贴上了,当然运行的时候节点地址要做相应的变动,根据每个机子的局域网中的地址。

这篇博客关于groupcache的介绍和源代码的说明部分比较少,主要就是贴出了一个测试的例子,因为我看到网上很少,并且压根就没有给出如何运行或者运行结果(不包括刚才提到的老外的一个博客,他写的还是很好的,我就是看了他的博客才着手自己编写的)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Golang的文档和社区资源:为什么它可以帮助开发人员快速上手?
Golang:AI 开发者的实用工具
Golang的标准库:为什么它可以大幅度提高开发效率?
Golang的部署和运维:如何将应用程序部署到生产环境中?
高性能AI开发:Golang的优势所在
本篇文章和大家了解一下go语言开发优雅得关闭协程的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。1.简介本文将介绍首先为什么需要主...
这篇文章主要介绍了Go关闭goroutine协程的方法,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。1.简介本文将介绍首先为什么需要主动关闭gor...
本篇文章和大家了解一下go关闭GracefulShutdown服务的几种方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。目录Shutdown方法Regi...
这篇文章主要介绍了Go语言如何实现LRU算法的核心思想和实现过程,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。GO实现Redis的LRU例子常
今天小编给大家分享的是Go简单实现多租户数据库隔离的方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会...
这篇“Linux系统中怎么安装NSQ的Go语言客户端”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希
本文小编为大家详细介绍“怎么在Go语言中实现锁机制”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么在Go语言中实现锁机制”文章能帮助大家解决疑惑,下面...
今天小编给大家分享一下Go语言中interface类型怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“怎么以正确的方式替换Go语言程序自身”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希
本文小编为大家详细介绍“Go语言中除法运算的效率怎么提高”,内容详细,步骤清晰,细节处理妥当,希望这篇“Go语言中除法运算的效率怎么提高”文章能帮助大家解...
本文小编为大家详细介绍“Go语言中的next()方法怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Go语言中的next()方法怎么使用”文章能帮助大家解决疑...
这篇文章主要介绍了Go语言中slice的反转方法怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Go语言中slice的反转方法怎...
这篇文章主要介绍“怎么使用Go语言实现数据转发功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用Go语
这篇文章主要讲解了“Go语言中怎么实现代码跳转”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究
这篇文章主要讲解了“Go语言如何多开协程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Go语言如何多开协...