Golang学习--GroupCache的使用
groupcache 是 Brad Fitzpatrick 最新的作品,目标在于取代一部分memcached的功能。以官方的说明是:groupcache is a caching and cache-filling library, intended as a replacement for memcached in many cases. 另外一篇介绍文是「Playing With Groupcache」。跟memcached 差异最大的地方在于「没有更改与删除的功能」,一旦写进去后就不会变动。在放弃update/delete 的特性后,换来的是: >> 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,实现的基本结构如下所示:
该软件结构图实现了一种只读型静态网站的分布式实现。主要包括三个服务器,其中DB Server是数据库,主要对外提供数据,在实际的场景中可以是NoSql数据库也可能是关系数据库。可对该数据库进行插入、新增数据。缓存服务器,分为前端和GroupCache Server,实际上将Cache Server包含在了业务代码中,其中前端是提供操作的相关接口,而后端部分通常作为业务服务器的一部分,缓存数据可直接被服务器使用。Cli部分主要是用于操作数据量和groupcache server交互。这部分代码可参考https://github.com/capotej/groupcache-db-experiment。这部分代码主要分析了缓存部分的实现,代码如下:
点击(此处)折叠或打开
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 groupcachen", 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("http://localhost:" + *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 dbservern", key)
dest.SetBytes([]byte(result))
return nil
})) //创建一个Group
peers.Set("http://localhost:8001", "http://localhost:8002", "http://localhost: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的基本过程如下所示: >> 首先创建一个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的代码进行进一步的分析。
- R语言的数据导入与导出(write.table,CAT)
- gqlplus的简单使用(r6笔记第43天)
- Java基础-21(01)总结字符流,IO流编码问题,实用案例必做一遍
- zabbix中配置dg的监控(r6笔记第62天)
- Apache ActiveMQ 远程代码执行漏洞 (CVE-2016-3088)分析
- mysql5.5与mysq 5.6中禁用innodb引擎的方法
- 缓慢的update语句性能分析(r6笔记第61天)
- 一个dg警告发现的硬件问题 (r6笔记第60天)
- mysql几种存储引擎介绍
- Java基础-21(02)总结字符流,IO流编码问题,实用案例必做一遍
- DeDeCMS v5.7 密码修改漏洞分析
- Java基础-20(01)总结,递归,IO流
- 一个Oracle bug的手工修复(r6笔记第59天)
- 由drop datafile导致的oracle bug(r6笔记第56天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于TypeScript封装Axios笔记(八)
- springmvc之HttpMessageConverter<T>
- django-模板之静态文件加载(十四)
- springmvc之使用JstlView
- django-模板之include标签(十五)
- 【pytorch】改造mobilenet_v2进行multi-class classification(多标签分类)
- 走进STL - heap,小树芽
- 走进STL - 序列式容器(常用篇)
- springmvc之RequestMapping中的请求方式
- 拥抱STL - union,天作之秀
- 拥抱STL -typename该怎么理解
- 走近STL - map,只愿一键对一值
- springmvc之使用servlet原生API作为参数
- 走近STL - 填上list删除的大坑
- springmvc之RequestMapping中的请求参数和请求头