造轮子系列-GO实现分布式缓存:2.缓存主模块

上一节中实现了LRU淘汰算法,这里完成淘汰算法的抽象层:
GOCache\Cache\Cache.go

package Cache

import (
	"GOCache/Cache/CacheAlgorithm"
	"sync"
)

//cache.go的实现非常简单,实例化 lru(或者其他算法),封装 get 和 put 方法,并添加互斥锁 mu。
type Cache struct {
	lock       sync.Mutex                     //互斥锁
	CacheImpl  CacheAlgorithm.ICacheAlgorithm //实现了ICacheAlgorithm的算法,现在只有LRU
	algorithm  string                         //使用的底层算法 例如"LRU"
	cacheBytes uint64                         //最大可存储的比特大小
}

func (c *Cache) newCache(algorithm string) CacheAlgorithm.ICacheAlgorithm {
	switch c.algorithm {
	case "lru": //执行实例化  可添加其他算法
		return CacheAlgorithm.NewLRUCache(c.cacheBytes)
	default:
		return CacheAlgorithm.NewLRUCache(c.cacheBytes)
	}
}

func (c *Cache) put(key string, value ByteView) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.CacheImpl == nil { //延迟初始化
		c.CacheImpl = c.newCache(c.algorithm)
	}
	c.CacheImpl.Put(key, value)
}

func (c *Cache) get(key string) (value ByteView, ok bool) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.CacheImpl == nil { //延迟初始化
		c.CacheImpl = c.newCache(c.algorithm)
	}
	if v, ok := c.CacheImpl.Get(key); ok {
		return v.(ByteView), ok
	}

	return
}

抽象了一个只读数据结构 ByteView 用来表示缓存值,ByteView是byte数组的包装类,可以存储真实字节,图片等
GOCache\Cache\byteview.go

package Cache

//抽象了一个只读数据结构 ByteView 用来表示缓存值
type ByteView struct {
	Bytes []byte //存储真实字节 可存图片等
}

// 实现了Len方法,ByteView是value的实现类,可以作为缓存的val
func (v ByteView) Len() int {
	return len(v.Bytes)
}

// ByteSlice 返回一个比特切片的拷贝
func (v ByteView) ByteSlice() []byte {
	return cloneBytes(v.Bytes)
}

// byte[]转为string的方法
func (v ByteView) String() string {
	return string(v.Bytes)
}

func cloneBytes(b []byte) []byte {
	c := make([]byte, len(b))
	copy(c, b)
	return c
}

接下来完成Group结构,类似于一个数据库,目前是一个数据库对应一个cache结构,每个数据库有唯一id,默认实例化了一个id为1的group。
GOCache\Cache\group.go

package Cache

import (
	"GOCache/conf"
	"fmt"
	"log"
	"sync"
)

type Group struct { //一个group可类似于一个数据库
	GroupID int
	mainCache Cache //实现的并发缓存
}

var ( //全局变量
	mu     sync.RWMutex
	groups = make(map[int]*Group)
	group1 = NewGroup(0) //实例化一个group全局可用
)


func NewGroup(id int) *Group {
	mu.Lock()
	defer mu.Unlock()
	g := &Group{
		GroupID: id,
		//getter:    getter,
		mainCache: Cache{cacheBytes: conf.Config.MaxBytes, algorithm: conf.Config.CacheAlgorithm},
	}
	groups[id] = g
	return g
}
//根据id返回实例指针
func GetGroup(groupID int) *Group {
	mu.RLock()
	g := groups[groupID]
	mu.RUnlock()
	return g
}
//包装get方法
func (g *Group) Get(key string) (ByteView, error) {
	if key == "" {
		return ByteView{}, fmt.Errorf("key is required")
	}

	if v, ok := g.mainCache.get(key); ok {
		log.Println("[GOCache] hit")
		return v, nil
	}
	return ByteView{}, fmt.Errorf("[" + key + "]key Not Found!")
}
//包装put方法
func (g *Group) Put(key string, value ByteView) {
	g.mainCache.put(key, value)
}

至此,GoCache的最核心部分已完成,接下来完成客户端和服务端,但在这之前,需要编写一个读取用户配置类的模块以便用户自定义一些参数。

3.用户配置类

GOCache\conf\GlobalConfig.go

package conf

import (
	"encoding/json"
	"io/ioutil"
)

//实例化一个全部配置类,这个配置类会读取外部json文件
var Config *GlobalConfig

type GlobalConfig struct {
	MaxBytes       uint64 //最大存储比特数
	CacheAlgorithm string //使用的淘汰算法
	Host           string //绑定监听ip
	TcpPort        int    //绑定监听端口
	Name           string //该服务器实例的名字
	Version        string //版本号
	MaxConn        int    //最大连接数
	PassWord       string //密码 一个服务器对应一个密码
	//MaxPackageSize   uint32
	//WorkerPoolSize   uint32
	//MaxWorkerTaskLen uint32 //能排队的最大值
}

func (g *GlobalConfig) Load() {

	data, err := ioutil.ReadFile("./GOCache.json")

	if err != nil { //不存在文件
		return
	}
	err = json.Unmarshal(data, &Config)
	if err != nil {
		panic(err)
	}
}

func init() {
	Config = &GlobalConfig{
		PassWord:       "8035aaaa",
		MaxBytes:       2147483648,
		Host:           "0.0.0.0",
		TcpPort:        9999,
		Name:           "GOCacheServer",
		Version:        "v0.3",
		MaxConn:        10,
		CacheAlgorithm: "lru",
		//MaxPackageSize:   4096,
		//WorkerPoolSize:   10,
		//MaxWorkerTaskLen: 1024,
	}
	Config.Load()

}

暂时在相对目录上没弄好,应该是要把json放到执行文件的同级文件上才行,这里暂时先放到包内。
GOCache\conf\GOCache.json

{
  "maxBytes":4096,
  "Host":             "0.0.0.0",
  "TcpPort":          9999,
  "Name":             "GOCacheServer",
  "Version":          "v0.3",
  "MaxConn":          10,
  "MaxPackageSize":   4096,
  "WorkerPoolSize":   10,
  "PassWord":       "8035aaaa",
  "MaxWorkerTaskLen": 1024
}

4.缓存服务端

如果是以简单或通用性为上,应采用http协议,这里先给出基于TCP的应用层协议 RESP (REdis Serialization Protocol) ,即Redis的应用层通信协议,比HTTP要更加高效,无需HTTP的很多冗余信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值