Memcached support

This commit is contained in:
Denis Zheleztsov 2017-06-22 17:06:39 +03:00
parent d14ad459dd
commit 1641bbfbab
5 changed files with 150 additions and 15 deletions

View File

@ -36,12 +36,20 @@ Zookeeper HTTP rest API
Usage of ./zoorest: Usage of ./zoorest:
-listen string -listen string
Address to listen (default "127.0.0.1:8889") Address to listen (default "127.0.0.1:8889")
-mc
Enable memcached support
-mchosts string
Memcached servers. Comma separated (default "127.0.0.1:11211")
-mcprefix string
Memcached key prefix (default "zoorest")
-path string -path string
Zk root path (default "/") Zk root path (default "/")
-zk string -zk string
Zk servers. Comma separated (default "127.0.0.1:2181") Zk servers. Comma separated (default "127.0.0.1:2181")
``` ```
NOTE: If memcached support is enabled zkStat metrics will not be returned.
## API ## API
### List node childrens ### List node childrens

View File

@ -16,7 +16,7 @@ ENTRYPOINT go build -ldflags "-linkmode external -extldflags -static" && mv zoor
EOF EOF
# Build builder # Build builder
docker build -t zoorest_builder -f Dockerfile.builder . docker build --no-cache -t zoorest_builder -f Dockerfile.builder .
# Build bin # Build bin
docker run -v $(pwd)/out:/out zoorest_builder docker run -v $(pwd)/out:/out zoorest_builder

30
main.go
View File

@ -10,6 +10,9 @@ var (
zk string zk string
listen string listen string
path string path string
mc bool
mcHosts string
mcPrefix string
) )
// init ... // init ...
@ -17,24 +20,39 @@ func init() {
flag.StringVar(&zk, "zk", "127.0.0.1:2181", "Zk servers. Comma separated") flag.StringVar(&zk, "zk", "127.0.0.1:2181", "Zk servers. Comma separated")
flag.StringVar(&listen, "listen", "127.0.0.1:8889", "Address to listen") flag.StringVar(&listen, "listen", "127.0.0.1:8889", "Address to listen")
flag.StringVar(&path, "path", "/", "Zk root path") flag.StringVar(&path, "path", "/", "Zk root path")
flag.BoolVar(&mc, "mc", false, "Enable memcached support")
flag.StringVar(&mcHosts, "mchosts", "127.0.0.1:11211", "Memcached servers. Comma separated")
flag.StringVar(&mcPrefix, "mcprefix", "zoorest", "Memcached key prefix")
flag.Parse() flag.Parse()
} }
// main ... // main ...
func main() { func main() {
var z rest.Zk var z rest.Zk
hosts := strings.Split(zk, ",") hosts := getSlice(zk, ",")
z.Hosts = hosts z.Hosts = hosts
conn, err := z.InitConnection() conn, err := z.InitConnection()
if err != nil { if err != nil {
panic(err) panic(err)
} }
zoo := rest.ZooNode{ var zoo rest.ZooNode
path, zoo.Path = path
conn, zoo.Conn = conn
z, zoo.Zoo = z
}
var MC rest.MC
MC.Hosts = getSlice(mcHosts, ",")
MC.Prefix = mcPrefix
MC.Enabled = mc
MC.Client = MC.InitConnection()
zoo.MC = MC
rest.Serve(listen, zoo) rest.Serve(listen, zoo)
} }
// getSlice returm slice
func getSlice(s string, delimeter string) []string {
return strings.Split(s, ",")
}

58
rest/cache.go Normal file
View File

@ -0,0 +1,58 @@
package rest
import (
"crypto/md5"
"github.com/bradfitz/gomemcache/memcache"
"strings"
)
// Memcached connection settings
type MC struct {
Enabled bool `json:"enabled"`
Hosts []string `json:"hosts"`
Prefix string `json:"prefix"`
Client *memcache.Client
}
// InitConnection to memcached cluster
func (mc MC) InitConnection() *memcache.Client {
client := memcache.New(mc.Hosts...)
return client
}
// StoreToCache save data to memecache
func (mc MC) StoreToCache(key string, data []byte) error {
prefixed_key := strings.Join([]string{mc.Prefix, key}, "_")
var item memcache.Item
// item.Key = hashKey(prefixed_key)
item.Key = prefixed_key
item.Value = data
// store
err := mc.Client.Set(&item)
return err
}
// (mc MC) GetFromCache ...
func (mc MC) GetFromCache(key string) ([]byte, error) {
var data *memcache.Item
prefixed_key := strings.Join([]string{mc.Prefix, key}, "_")
// data, err := mc.Client.Get(hashKey(prefixed_key))
data, err := mc.Client.Get(prefixed_key)
if err != nil {
return []byte(""), err
}
return data.Value, err
}
// hashKey return md5sum of prefixed_key
func hashKey(key string) string {
h := md5.New()
sum := h.Sum([]byte(key))
return string(sum)
}

View File

@ -12,6 +12,7 @@ type ZooNode struct {
Path string Path string
Conn *zk.Conn Conn *zk.Conn
Zoo Zk Zoo Zk
MC MC
} }
//Zk Zookeeper connection settings //Zk Zookeeper connection settings
@ -43,10 +44,23 @@ func (z ZooNode) GetChildrens(path string) Ls {
lsPath = strings.Replace(lsPath, "//", "/", 1) lsPath = strings.Replace(lsPath, "//", "/", 1)
} }
log.Print("ls: ", lsPath) log.Print("V1 LS: ", lsPath)
var l Ls var l Ls
l.State = "OK" l.State = "OK"
l.Path = path
if z.MC.Enabled {
data, err := z.MC.GetFromCache(lsPath)
if err != nil {
log.Print("V1 LS ERROR: ", err.Error())
} else {
log.Print("We are get it from memecache!")
childrens := strings.Split(string(data), ",")
l.Childrens = childrens
return l
}
}
childrens, zkStat, err := z.Conn.Children(lsPath) childrens, zkStat, err := z.Conn.Children(lsPath)
if err != nil { if err != nil {
@ -55,15 +69,22 @@ func (z ZooNode) GetChildrens(path string) Ls {
return l return l
} }
// Store to cache
if z.MC.Enabled {
err := z.MC.StoreToCache(lsPath, []byte(strings.Join(childrens, ",")))
if err != nil {
log.Print("V1 LS: ", err.Error())
}
}
l.Error = "" l.Error = ""
l.Childrens = childrens l.Childrens = childrens
l.Path = path
l.ZkStat = zkStat l.ZkStat = zkStat
return l return l
} }
// GetNode ... // GetNode data
func (z ZooNode) GetNode(path string) Get { func (z ZooNode) GetNode(path string) Get {
var getPath string var getPath string
getPath = strings.Join([]string{z.Path, path}, "") getPath = strings.Join([]string{z.Path, path}, "")
@ -75,10 +96,21 @@ func (z ZooNode) GetNode(path string) Get {
getPath = strings.Replace(getPath, "//", "/", 1) getPath = strings.Replace(getPath, "//", "/", 1)
} }
log.Print("get: ", getPath) log.Print("V1 GET: ", getPath)
var g Get var g Get
g.State = "OK" g.State = "OK"
g.Path = path
// Get data from memcached
if z.MC.Enabled {
if data, err := z.MC.GetFromCache(getPath); err != nil {
log.Print("V1 GET: ", err.Error())
} else {
g.Data = data
return g
}
}
data, zkStat, err := z.Conn.Get(getPath) data, zkStat, err := z.Conn.Get(getPath)
if err != nil { if err != nil {
@ -87,9 +119,16 @@ func (z ZooNode) GetNode(path string) Get {
return g return g
} }
// Store to cache
if z.MC.Enabled {
err := z.MC.StoreToCache(getPath, data)
if err != nil {
log.Print("V1 LS: ", err.Error())
}
}
g.Error = "" g.Error = ""
g.Data = data g.Data = data
g.Path = path
g.ZkStat = zkStat g.ZkStat = zkStat
return g return g
@ -149,6 +188,12 @@ func (z ZooNode) UpdateNode(path string, content []byte) string {
return err.Error() return err.Error()
} }
if z.MC.Enabled {
if err := z.MC.StoreToCache(upPath, content); err != nil {
log.Print("V1 update ERROR: ", err.Error())
}
}
return path return path
} }
@ -167,6 +212,12 @@ func (z ZooNode) CreateChild(path string, content []byte) string {
return err.Error() return err.Error()
} }
if z.MC.Enabled {
if err := z.MC.StoreToCache(crPath, content); err != nil {
log.Print("V1 create ERROR: ", err.Error())
}
}
return path return path
} }