一.groupcache介绍
memcached作者Brad Fitzpatrick用Go开发了前者的替代版,现已在Google多个生产环境(如dl.google.com)中投入使用。本文粗略介绍一下groupcache的实现方式。
memcached的业务架构如下图,memcache的分布式不是服务器端实现,而是通过客户端实现;是客户端根据key自己计算决定memcached实例 。
groupcahe的业务结构如下图,key的存储采用分布式方式,key通过一致性哈希分散在各个实例中,通过任意一个实例皆可得到数据。
二.groupcahe数据结构
1.byteview
byteview对字符串数组和string进行封装,存储何种形式的字符串对用户透明,定义如下
type struct {
b []byte
s string
}
具体的操作函数的实现方式如下
func at(i){
if b!=nil
return b[i]
return s[i]
}
2.singleflight
singleflight保证“同时”多个同参数的get请求只执行一次操作功能,整个流程如下
当Thread3在时间00:01执行Get("太阳")时候,在系统中以key为“太阳”标识正在翻译“太阳”,整个翻译过程需要8秒钟。
当Thread1和Thread2分别与00:02,00:03提交执行Get("太阳")时候,发现系统中存在以key为“太阳”标识的翻译执行,进程阻塞等待Thread3的翻译结果。
在时间00:09,Thread3得到“太阳”的翻译结果,返回给客户,此时Thread1和Thread2执行读取翻译结果返回给客户。
整个过程中,不仅减少Thread1和Thread2的得到结果时间,也减少读取数据库的次数,节约系统资源。
3. consistenthash
consistenthash提供一致性hash功能,将key按照一致性hash分布在各个实例中,主要作用是实例加入离开时不会导致映射关系的重大变化。
consistenthash 由数组和一个存储实例标识和标识key的hashmap实现,结构如下,
consistenthash会将实例标识复制replicas(可以设置)份放到hashmap结构中,选择数据key的时候,选择大于实例key的hash值最近的一个。
eg:如果 hash("太阳")的值为24,选择整数数组中的30(大于24最近的key)作为存储实例的key,从hashmap找到30的实例为192.168.0.1,判断192.168.0.1作为“太阳”的存储实例。
4.lru
lru提供缓存的清除算法,groupcache实现方式无特别之处,再次略过不说。
5.group
group是key-value的容器,每个group都有一个名字,相当于一批key-value的家族标识。
当用户访问某个key时,group现在本地内存中维持的hashmap中查找,如果没有则从远端的peer或者本地的文件系统等地方加载。
Getter定了如何从本地读取数据,这部分需要使用使用groupcache的开发者自己提供实现,group 函数getLocally将会调用。
PickPeer会按照一致性hash选择peer,发起http请求拉取数据,这便是group函数getFromPeer实现。
在getLocally和getFromPeer调用的过程中,用singleflight提供多次同参get请求只执行一次操作。
maincahe 是本地读取的数据的存储容器;hotcahe是从远端peer读取的热数据的存储,现在的热数据完全凭运气,从远端读取的数据有10%的概率会称为热数据。
maincahe和hotcahe的内存用量总和高于此group的cacheBytes限制时,便启用lru进行数据清理。
stats是指标统计,如Gets便是用户请求本实例的计次,cacheHits是命中本地内存maincahe和hotcahe的计次。
group通过key对应的value的伪代码如下:
func get(key){
/*从本地内存中读取*/
if maincache.has(key)
return maincache[key]
if hotcahe.has(key)
return hotcahe [key]
/*从远端peer读取*/
value := PeerPicker.PickPeer(key).get(key)
if value !=nil
if(rand()%10 == 1)
hotcahe[key] = value
return value
/*从本地文件等系统读取*/
value:= getLocally(key)
if value !=nil
maincache[key] = value
return value
}
6.httppool
httppool便是各个peer通讯的封装,开启通讯http,group的getFromPeer便是调用相对应peer的httpool提供的服务。
httppool同时保存了所有的远端peer实例的请求地址,实现pickPeer安装一致性hash取得某key对应的远端peer实例的地址。
三. groupcahe使用
groupcahe是个库,不是一个程序,如果需要使用,需要自己写部分逻辑,在此提供一个简单的例子
package main
import (
"fmt"
"github.com/groupcache"
"io/ioutil"
"log"
"net/http"
"os"
)
var (
peers_addrs = []string{"http://127.0.0.1:8001", "http://127.0.0.1:8002", "http://127.0.0.1:8003"}
)
func main() {
if len(os.Args) != 3 {
fmt.Println("\r\n Usage local_addr \t\n local_addr must in(127.0.0.1:8001,localhost:8002,127.0.0.1:8003)\r\n")
os.Exit(1)
}
local_addr := os.Args[1]
peers := groupcache.NewHTTPPool("http://" + local_addr)
peers.Set(peers_addrs...)
var image_cache = groupcache.NewGroup("image", 8<<30, groupcache.GetterFunc(
func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
result, err := ioutil.ReadFile(key)
if err != nil {
fmt.Printf("read file error %s.\n", err.Error())
return nil
}
fmt.Printf("asking for %s from local file system\n", key)
dest.SetBytes([]byte(result))
return nil
}))
http.HandleFunc("/image", func(rw http.ResponseWriter, r *http.Request) {
var data []byte
k := r.URL.Query().Get("id")
fmt.Printf("user get %s from groupcache\n", k)
image_cache.Get(nil, k, groupcache.AllocatingByteSliceSink(&data))
rw.Write([]byte(data))
})
log.Fatal(http.ListenAndServe(local_addr, nil))
}
使用的时候
src.exe 127.0.0.1:8001 src.exe 127.0.0.1:8002 src.exe 127.0.0.1:8003创建3个peer实例即可
客户端访问http://127.0.0.1:8001/image?id=configure.ini即可得到数据
对源码进行修改打印出来的日志,各位看到的并不是这样,并没有这些日志。
四.最后说几点
groupcahe不提供过期、删除等操作,所有groupcahe只适合与静态不变的数据,不能用于取代memcahe。
一些地方实现比较粗略,如定义热点数据等,现在采用10%随机并不合理;peer节点的删除增加也没有处理。
- 大小: 25.6 KB
- 大小: 26.5 KB
- 大小: 28.3 KB
- 大小: 18.1 KB
- 大小: 16.2 KB
- 大小: 103.6 KB
分享到:
相关推荐
这里我们关注的是三个开源项目:BFS、Cache2Go和Groupcache,它们分别涉及文件系统和缓存解决方案。 首先,BFS(Big File System)通常指的是大文件系统,它可能是为了解决大数据存储和访问效率问题而设计的。在...
groupcache是一个缓存和缓存填充库,在许多情况下都可以替代memcached。 有关API文档和示例,请参见 与memcached的比较 像memcached ,groupcache一样: 通过密钥分片以选择哪个对等方负责该密钥 与memcached...
6. **Concurrency**: Go语言的并发模型使得Groupcache天生支持高并发访问,其内部使用goroutines和channels来处理并发请求,保证了良好的性能。 在实际应用中,Groupcache常用于减轻数据库的压力,尤其是在读取密集...
groupcache是一个分布式缓存和缓存填充库,在许多情况下可用来替代内存缓存节点池。 有关API文档和示例,请参见 与memcached的比较 像memcached ,groupcache一样: 通过密钥分片以选择哪个对等方负责该密钥 ...
groupcache是一个分布式缓存和缓存填充库,在许多情况下都可用来替代内存缓存节点池。 有关API文档和示例,请参见 与memcached的比较 像memcached ,groupcache一样: 通过密钥分片以选择哪个对等方负责该密钥...
groupcache总结groupcache是一个分布式缓存和缓存填充库,在许多情况下都可用来替代memcached节点池。 有关API文档和示例,请参见http://godoc.org/github.com/golan groupcache。摘要groupcache是一个...
【描述】提到的"scala-groupcache.zip"是一个使用Scala编程语言实现的GroupCache项目。GroupCache是一个由Google开源的、用于缓存的轻量级库,特别适合于在大规模分布式系统中缓存数据,以减少对远程服务或昂贵计算...
改写MATLAB代码为python代码 HotPotatoFS ...它是使用groupcache和bazil.org保险丝库在go(golang)中编写的: 快速开始 设置走走路径: 安装方式 go get github.com/ryanbressler/HotPotatoFS go ins
httpservecache 这是实验软件。 除非您知道自己在做什么,否则不要使用。 许可证:Affero GPL 3。
在这个场景中,我们讨论的是使用Golang语言实现的RTMP服务器,这允许开发人员利用Golang的并发性和性能优势来构建高效、可扩展的流媒体服务。 Golang是一种静态类型的编译语言,以其简洁的语法、高效的性能以及内置...
将ggfetch和ggfetch.yml复制到目标计算机,然后根据使用情况调整ggfetch.yml 。 您可以键入ggfetch -h来了解标志。 当部署为群集时,您可以选择一台计算机作为主服务器,并使其他节点连接到该主服务器。 然后,节点...
3. **使用更先进的解决方案**:随着技术的发展,一些新的缓存方案,如Redis或作者新推出的Groupcache(使用Go语言编写),可能更适合某些特定场景的需求。 #### 五、结论 Memcached作为一种成熟的内存缓存技术,在...
`Gogroupache`的核心理念是通过将数据分发到多个缓存节点来实现高可用性和负载均衡。它利用了Go语言的goroutine和channel特性,使得在并发环境中高效地读写数据成为可能。此外,它的设计允许开发者自定义缓存策略,...
类似groupcache的分布式缓存?或者一个简单的Python解释器?希望这个仓库能给你答案。推荐先阅读,这篇文章了解Go的基本语法,并发编程,依赖管理等内容。推荐,加深对Go语言的理解。推荐(),写出高级的Go代码。...
图像处理Web服务。0.2版更改: 阿尔法与面膜混合。它用: 用于图像处理。 作为存储后端。 提供内容。现在它可以: 缩放图像裁剪图像转换格式(jpg,png) 混合... 使用静态链接的OpenCV库有两种方法来构建它,这些库
3. **缓存策略**:实现LRU策略,可以使用第三方库如`github.com/golang/groupcache/lru`。 4. **数据迁移**:监控内存使用情况,当达到预设阈值时,将LRU淘汰的数据写入磁盘,并在需要时读取。 5. **持久化**:...
在weather-app中,开发者会使用这个库来构造一个GET请求,附带上API密钥和其他必要的参数,如城市名或地理坐标。收到API的响应后,程序会解析返回的JSON或XML格式的数据,提取出温度、湿度、风速等天气信息,并将...
这提供了lru包,该包实现了固定大小的线程安全LRU缓存。 它基于Groupcache中的缓存。 文献资料 完整文档可在上 例子 使用LRU非常简单: l , _ := New ( 128 ) for i := 0 ; i < 256 ; i ++ { l . Add ( i , nil...