为游戏服务器设计的多副本强一致sql缓存,sql支持mysql和pgsql
sqlDB
|
-------------------------------------
| |
| raft group |
| |----flypd
| flykv(leader) flykv flykv | |
------------------------------------- |
| |
flygate-----------------------
|
client
数据在sql库中用传统的表格存储。表格包括__key__
,__version__
两个默认字段以及用户自定义的字段。用户自定义字段仅支持int64,uint64,string,float64,blob五种类型。
当记录被访问时,如果记录在本地不存在,被访问的记录将会被载入本地cache。数据库记录到本地cache记录的映射规则如下:
用table:key合成唯一的键,用hash结构存储,表格中的字段作为hash内容。
假如sql中存在一个user表格,有以下记录
__key__ age phone
lili 10 123456
bily 12 434443
chuck 7 34343
在本地被映射为
key=user:lili field:age = 10 field:phone = 123456
key=user:bily field:age = 12 field:phone = 434443
key=user:chuck filed:age = 7 field:phone = 34343
表格元信息存储在table_conf表中,每一行代表一张表格信息,flykv启动时会从数据库中读取元信息。
表格配置规则如下:
字段1:类型:默认值,字段2:类型:默认值,字段3:类型:默认值
例如有如下三张表,table_conf内容如下:
table conf
users1 age:int:0,phone:string:123,name:string:haha
counter c:int:0
blob data:blob:0
对于blob类型会使用0长二进制初始化,所以这里填的默认值0只是占位符,没有实际作用。
//按需获取单条记录的字段
Get(table,key string,fields ...string)
//获取单条记录的所有字段
GetAll(table,key string)
//设置单条记录的字段,如果提供了version字段会进行版本号校验,只有版本号一致才允许设置
Set(table,key string,fields map[string]interface{},version ...int64)
//设置单条记录,只有当记录不存在时才设置成功
SetNx(table,key string,fields map[string]interface{})
//当记录的field内容==oldV时,将其设置为newV,不管设置与否返回field的最新值(除非记录不存在)
CompareAndSet(table,key,field string, oldV ,newV interface{})
//如果记录不存在用默认值创建记录并将field设为newV,否则同CompareAndSet
CompareAndSetNx(table,key,field string, oldV ,newV interface{})
//删除一条记录,如果提供了版本号需要执行版本号校验
Del(table,key string,version ...int64)
//将记录的field字段原子增加value,如果记录不存在用默认值创建记录后执行
IncrBy(table,key,field string,value int64)
//将记录的field字段原子减少value,如果记录不存在用默认值创建记录后执行
DecrBy(table,key,field string,value int64)
//获取同一table多条记录的指定字段,如果fields没有传将获取所有字段。
MGet(table string,keys []string,fields ...string)
//将table中key记录从缓存中踢除,flyfish保证记录回写到数据库之后才踢除
Kick(table, key string)
package main
import (
"encoding/binary"
"fmt"
kclient "github.com/sniperHW/flyfish/client"
"github.com/sniperHW/flyfish/errcode"
"github.com/sniperHW/kendynet/golog"
"os"
)
func main() {
kclient.InitLogger(golog.New("flyfish client", golog.NewOutputLogger("log", "flyfish client", 1024*1024*50)))
services := []string{}
for i := 1; i < len(os.Args); i++ {
services = append(services, os.Args[i])
}
c := kclient.OpenClient(services)
buff := make([]byte, 4)
binary.BigEndian.PutUint32(buff, 100)
fields := map[string]interface{}{}
fields["age"] = 12
fields["blob"] = buff
fields["name"] = "sniperHW"
r2 := c.Set("users1", "sniperHW", fields).Exec()
if r2.ErrCode != errcode.ERR_OK {
fmt.Println("Set error:", errcode.GetErrorStr(r2.ErrCode))
return
}
r3 := c.Get("users1", "sniperHW", "name", "phone", "age", "blob").Exec()
fmt.Println(r3.Fields["name"].GetString())
fmt.Println(r3.Fields["phone"].GetString())
fmt.Println(r3.Fields["age"].GetInt())
fmt.Println(binary.BigEndian.Uint32(r3.Fields["blob"].GetBlob()))
fmt.Println(r3.Version)
}