Help us shape the future of Go! Take the 2026 Go Developer Survey

RCache

package
v1.3.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2022 License: GPL-3.0 Imports: 11 Imported by: 0

README

缓存流程图:

1. 本地:
                            是
接收 key --> 检查是否被缓存 -----> 返回缓存值 ⑴
                |  否                          是
                |-----> 是否应当从远程节点获取 -----> 与远程节点交互 --> 返回缓存值 ⑵
                                |  否
                                |-----> 调用`回调函数`,获取值并添加到缓存 --> 返回缓存值 ⑶

2. 分布式:

使用一致性哈希选择节点        是                                    是
    |-----> 是否是远程节点 -----> HTTP 客户端访问远程节点 --> 成功?-----> 服务端返回返回值
                    |  否                                    ↓  否
                    |----------------------------> 回退到本地节点处理。

缓存实现过程

  1. cache 最基础的缓存(非并发安全),采用LRU(双向链表优先级判断)缓存淘汰机制 缓存值类型需要实现Size()方法返回其内存大小
  2. syncCache byteView 封装cache,使其并发安全 返回缓存类型为 ByteView 实现Size()方法,ByteSlice()返回缓存值的二进制副本,String()将缓存值转换为字符串
  3. http 赋予缓存值远程访问的能力
       主要依赖于 HttpPool 结构{
             self        string                 //self 用来记录自己的地址,包括 主机名/ip 和 端口。eg:"http://localhost:9999"
             basePath    string                 //basePath,作为节点间通讯地址的前缀
             mu          sync.RWMutex           //并发安全
             peersMap    *consistenthash.Map    //来根据具体的 key 选择节点。
             httpGetters map[string]*httpGetter //映射远程节点与对应的 httpGetter客户端。每一个远程节点对应一个 httpGetter,因为 httpGetter 与远程节点的地址 baseURL 有关
       }
       //客户端
       type httpGetter struct {
               baseURL string //所对应远程断点的ip地址,端口号和固定前缀,只需要缓存组名和缓存名即可进行通信
       }
  1. consistenthash 一致性哈希算法可以通过key值获取最适合的节点值
  2. peers
    // PeerPicker 对应 HttpPool,其 PickPeer() 方法用于根据传入的 key 选择相应节点 PeerGetter。
   type PeerPicker interface {
        PickPeer(key string) (peer PeerGetter, ok bool)
   }

   // PeerGetter 接口对应 HTTP 客户端 PeerGetter,其 Get() 方法用于从对应 group 查找缓存值
   type PeerGetter interface {
           Get(group string, key string) ([]byte, error)
   }
  1. singleflight 保证同一个查询在同一时刻最多执行一次.防止缓存穿透
  2. RCache 分布式缓存组,对上述内容的最高级封装
type Group struct {
    name      string              //命名
    getter    Getter              //即缓存未命中时获取源数据的回调(callback)
    mainCache syncCache           //缓存
    peers     PeerPicker          //用于与其他节点通信的HttpPool结构
    loader    *singleflight.Group //保证一个请求同一时刻只会执行一次(缓存击破)
}

使用方法:

    func createGroup() *RCache.Group {
        return RCache.NewGroup("scores", 2<<10, RCache.GetterFunc(func(key string) ([]byte, error) {
            //log.Println("[SlowDB] search key", key)
            //if v, ok := db[key]; ok {
            //	return []byte(v), nil
            //}
            ...
            return nil, fmt.Errorf("%s not exist", key)
        }))
    }
    1. 本地使用
    group := createGroup()
        view,err := group.Get("Tom")
        if err != nil {
        return
    }
    fmt.Println(view.String())
    2. 在线使用
    func main() {
        var port int
        var api bool
        flag.IntVar(&port, "port", 8001, "RCache server port")
        flag.BoolVar(&api, "api", false, "Start a api server?")
        flag.Parse()

    apiAddr := "localhost:9999"
    addrMap := map[int]string{
        8001: "localhost:8001",
        8002: "localhost:8002",
        8003: "localhost:8003",
    }
    //创建缓存组
    group := createGroup()
    //开启辅助端口
    if api {
        go group.StartServer(apiAddr, "/api", "key")
    }
    //开启分布式缓存
        group.StartCacheServer(addrMap[port], addrMap)
    }
    测试:
    $ go build -o server
    $ ./server.exe -port=8001 &
      ./server.exe -port=8002 &
      ./server.exe -port=8003 -api=1

    $ curl http://localhost:9999/api?key=Jack
      // 589
    $ curl http://localhost:8001/RCache/scores/Jack
      // 589

Documentation

Index

Constants

View Source
const (
	// DefBasePath 默认路由前缀
	DefBasePath = "/RCache/"
	// DefReplicas 默认虚拟节点倍率
	DefReplicas = 50
	// DefHTTP 默认前缀
	DefHTTP = "http://"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ByteView

type ByteView struct {
	// contains filtered or unexported fields
}

ByteView 一个只读数据结构,用来表示缓存值

func (ByteView) ByteSlice

func (v ByteView) ByteSlice() []byte

ByteSlice 返回缓存值副本,防止被外界修改

func (ByteView) Size

func (v ByteView) Size() int

Size 返回缓存长度

func (ByteView) String

func (v ByteView) String() string

将缓存值转为字符串,有必要时进行备份

type Getter

type Getter interface {
	Get(key string) ([]byte, error)
}

Getter 自行实现调用数据库函数

type GetterFunc

type GetterFunc func(key string) ([]byte, error)

func (GetterFunc) Get

func (f GetterFunc) Get(key string) ([]byte, error)

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group 分布式缓存组

func GetGroup

func GetGroup(name string) *Group

GetGroup 获取指定name的缓存组

func NewGroup

func NewGroup(name string, cacheBytes int, getter Getter) *Group

NewGroup 缓存,name:命名空间,cacheBytes:最大缓存字节数,getter:回调函数

func (*Group) Get

func (g *Group) Get(key string) (ByteView, error)

Get 获取缓存

func (*Group) RegisterPeers

func (g *Group) RegisterPeers(peers PeerPicker)

RegisterPeers 方法,将 实现了 PeerPicker 接口的 HTTPPool 注入到 Group 中。

func (*Group) Set

func (g *Group) Set(key string, value ByteView)

func (*Group) StartCacheServer

func (g *Group) StartCacheServer(addr string, addressMap map[int]string)

StartCacheServer 开启分布式缓存 addr 当前主机ip及端口,address 所有主机ip及端口

func (*Group) StartServer

func (g *Group) StartServer(apiAddr, prefix, key string)

StartServer StartAPIServer 启动辅助服务

type HttpPool

type HttpPool struct {
	// contains filtered or unexported fields
}

HttpPool 节点间 HTTP 通信的核心数据结构

func NewHTTPPool

func NewHTTPPool(self string) *HttpPool

func (*HttpPool) Log

func (hp *HttpPool) Log(format string, v ...interface{})

func (*HttpPool) PickPeer

func (hp *HttpPool) PickPeer(key string) (PeerGetter, bool)

PickPeer 为 key 选择一个节点

func (*HttpPool) ServeHTTP

func (hp *HttpPool) ServeHTTP(w http.ResponseWriter, r *http.Request)

回应远程请求

func (*HttpPool) Set

func (hp *HttpPool) Set(peers ...string)

Set 存储其他节点

type PeerGetter

type PeerGetter interface {
	Get(group string, key string) ([]byte, error)
}

PeerGetter 接口对应 HTTP 客户端 PeerGetter,其 Get() 方法用于从对应 group 查找缓存值

type PeerPicker

type PeerPicker interface {
	PickPeer(key string) (peer PeerGetter, ok bool)
}

PeerPicker 对应 HttpPool,其 PickPeer() 方法用于根据传入的 key 选择相应节点 PeerGetter。

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL