您的位置:首页 > 编程语言 > Go语言

Golang使用QConf教程

2017-09-27 21:32 309 查看

Golang使用QConf教程

QConf 是一个分布式配置管理工具。 用来替代传统的配置文件,使得配置信息和程序代码分离,同时配置变化能够实时同步到客户端,而且保证用户高效读取配置,这使的工程师从琐碎的配置修改、代码提交、配置上线流程中解放出来,极大地简化了配置管理工作。

关于QConf的详细介绍可以看这里github.com/Qihoo360/QConf

特点

一处修改,所有机器实时同步更新

高效读取配置

安装部署方便,使用简单

服务器宕机、网络中断、集群迁移等异常情况对用户透明

支持c/c++、shell、php、python、lua、java、go、node 等语言

架构



所有客户端通过libqconf,与本机的qconf-agent通过共享内存或消息队列通信。

编译goqconf的时候要使用

#cgo LDFLAGS: -lqconf -lm


如果找不到libqconf,通过查看qconf_agent来看qconf-agent所安装的目录

$ ps aux | grep qconf
root      1098  0.1  1.6 600300 131280 ?       Sl   Sep25   5:39 /usr/local/qconf/bin/qconf_agent


比如我的qconf-agent安装目录在:/usr/local/qconf/下,则在cgo后加条件-L/usr/local/qconf/lib

这样可以编译成功,但是在运行时还可能报错,找不到libqconf.so文件,这时需要在/usr/lib或/usr/lib64下创建libqconf的软连接:

$ sudo ln -s /usr/local/qconf/lib/libqconf.so /usr/lib64/libqconf.so
$ ll /usr/lib64/libqconf.so
lrwxrwxrwx 1 root root 32 Sep 27 13:17 /usr/lib64/libqconf.so -> /usr/local/qconf/lib/libqconf.so


附上golibqconf.go的代码:

package go_qconf

/*
#cgo LDFLAGS: -lqconf -lm
#include <stdlib.h>
#include <stdio.h>
struct string_vector
{
int count;      // the number of services
char **data;    // the array of services
};
typedef struct string_vector string_vector_t;
typedef struct qconf_node
{
char *key;
char *value;
} qconf_node;
typedef struct qconf_batch_nodes
{
int count;
qconf_node *nodes;
} qconf_batch_nodes;
int qconf_init();
int qconf_destroy();
int init_string_vector(string_vector_t *nodes);
int destroy_string_vector(string_vector_t *nodes);
int init_qconf_batch_nodes(qconf_batch_nodes *bnodes);
int destroy_qconf_batch_nodes(qconf_batch_nodes *bnodes);
int qconf_get_conf(const char *path, char *buf, int buf_len, const char *idc);
int qconf_get_allhost(const char *path, string_vector_t *nodes, const char *idc);
int qconf_get_host(const char *path, char *buf, int buf_len, const char *idc);
int qconf_get_batch_conf(const char *path, qconf_batch_nodes *bnodes, const char *idc);
int qconf_get_batch_keys(const char *path, string_vector_t *nodes, const char *idc);
*/
import "C"

import (
"fmt"
"reflect"
"unsafe"
)

type Errno int

func (e Errno) Error() string {
s := errText[e]
if s == "" {
return fmt.Sprintf("unknown errno %d", int(e))
}
return s
}

var errText = map[Errno]string{
-1: "Execute failure!",
1:  "Error parameter!",
2:  "Failed to malloc memory!",
3:  "Failed to set share memory!",
4:  "Failed to get zookeeper host!",
5:  "Failed to get idc!",
6:  "Buffer not enough!",
7:  "Illegal data type!",
8:  "Illegal data format!",
10: "Failed to find key on given idc!",
11: "Failed to open dump file!",
12: "Failed to open tmp dump file!",
13: "Failed to find key in dump!",
14: "Failed to rename dump!",
15: "Failed to write dump!",
16: "Same with the value in share memory!",
20: "Configure item error : out of range!",
21: "Configure item error : not number!",
22: "Configure item error : further characters exists!",
30: "Configure item error : invalid ip!",
31: "Configure item error : invalid port!",
40: "No message exist in message queue!",
41: "Length of message in the queue is too large!",
71: "Error hostname!",
}

var (
ErrOther               error = Errno(-1)
ErrQconfParam          error = Errno(1)
ErrQconfMem            error = Errno(2)
ErrQconfTblSet         error = Errno(3)
ErrQconfGetHost        error = Errno(4)
ErrQconfGetIdc         error = Errno(5)
ErrQconfBufNotEnough   error = Errno(6)
ErrQconfDataType       error = Errno(7)
ErrQconfDataFormat     error = Errno(8)
ErrQconfNotFound       error = Errno(10)
ErrQconfOpenDump       error = Errno(11)
ErrQconfOpenTmpDump    error = Errno(12)
ErrQconfNotInDump      error = Errno(13)
ErrQconfRenameDump     error = Errno(14)
ErrQconfWriteDump      error = Errno(15)
ErrQconfSameValue      error = Errno(16)
ErrQconfOutOfRange     error = Errno(20)
ErrQconfNotNumber      error = Errno(21)
ErrQconfOtherCharacter error = Errno(22)
ErrQconfInvalidIp      error = Errno(30)
ErrQconfInvalidPort    error = Errno(31)
ErrQconfNoMessage      error = Errno(40)
ErrQconfE2Big          error = Errno(41)
ErrQconfHostname       error = Errno(71)
)

const (
QCONF_DRIVER_GO_VERSION     = "1.2.2"
QCONF_CONF_BUF_INIT_MAX_LEN = 2 * 1024
QCONF_CONF_BUF_MAX_LEN      = 1024 * 1024
QCONF_CONF_BUF_MULTIPLE     = 8
QCONF_HOST_BUF_MAX_LEN      = 256

QCONF_OK                 = 0
QCONF_ERR_BUF_NOT_ENOUGH = 6
)

func init() {
ret := C.qconf_init()
if QCONF_OK != ret {
panic(ret)
}
}

func convertToGoSlice(nodes *C.string_vector_t) []string {
length := int((*nodes).count)
hdr := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer((*nodes).data)),
Len:  length,
Cap:  length,
}
charp_nodes := *(*[]*C.char)(unsafe.Pointer(&hdr))
go_nodes := []string{}
for i := 0; i < length; i++ {
go_host := C.GoString(charp_nodes[i])
go_nodes = append(go_nodes, go_host)
}
return go_nodes
}

func convertToGoMap(bnodes *C.qconf_batch_nodes) map[string]string {
length := int((*bnodes).count)
hdr := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer((*bnodes).nodes)),
Len:  length,
Cap:  length,
}
qconf_nodes := *(*[]C.qconf_node)(unsafe.Pointer(&hdr))
go_nodes := map[string]string{}
for i := 0; i < length; i++ {
go_key := C.GoString(qconf_nodes[i].key)
go_value := C.GoString(qconf_nodes[i].value)
go_nodes[go_key] = go_value
}
return go_nodes
}

func GetConf(key string, idc string) (string, error) {
c_key := C.CString(key)
defer C.free(unsafe.Pointer(c_key))
var ret int
var c_ptr_value *C.char
slice_length := QCONF_CONF_BUF_INIT_MAX_LEN

for ret = QCONF_ERR_BUF_NOT_ENOUGH; ret == QCONF_ERR_BUF_NOT_ENOUGH && slice_length <= QCONF_CONF_BUF_MAX_LEN; slice_length *= QCONF_CONF_BUF_MULTIPLE {
c_value := make([]C.char, slice_length)
c_ptr_value = (*C.char)(unsafe.Pointer(&(c_value[0])))

if idc == "" {
ret = int(C.qconf_get_conf(c_key, c_ptr_value, C.int(slice_length), nil))
} else {
c_idc := C.CString(idc)
defer C.free(unsafe.Pointer(c_idc))
ret = int(C.qconf_get_conf(c_key, c_ptr_value, C.int(slice_length), c_idc))
}
}
if QCONF_OK != ret {
cur_err := Errno(ret)
return "", cur_err
}
go_value := C.GoString(c_ptr_value)
return go_value, nil
}

func GetHost(key string, idc string) (string, error) {
c_key := C.CString(key)
defer C.free(unsafe.Pointer(c_key))
var c_host [QCONF_HOST_BUF_MAX_LEN]C.char
c_ptr_host := (*C.char)(unsafe.Pointer(&(c_host[0])))

var ret int
if idc == "" {
ret = int(C.qconf_get_host(c_key, c_ptr_host, QCONF_HOST_BUF_MAX_LEN, nil))
} else {
c_idc := C.CString(idc)
defer C.free(unsafe.Pointer(c_idc))
ret = int(C.qconf_get_host(c_key, c_ptr_host, QCONF_HOST_BUF_MAX_LEN, c_idc))
}
if QCONF_OK != ret {
cur_err := Errno(ret)
return "", cur_err
}
go_host := C.GoString(c_ptr_host)
return go_host, nil
}

func GetAllHost(key string, idc string) ([]string, error) {
c_key := C.CString(key)
defer C.free(unsafe.Pointer(c_key))
var nodes C.string_vector_t
init_ret := C.init_string_vector(&nodes)
if QCONF_OK != init_ret {
cur_err := Errno(init_ret)
return nil, cur_err
}
defer C.destroy_string_vector(&nodes)

var ret int
if idc == "" {
ret = int(C.qconf_get_allhost(c_key, &nodes, nil))
} else {
c_idc := C.CString(idc)
defer C.free(unsafe.Pointer(c_idc))
ret = int(C.qconf_get_allhost(c_key, &nodes, c_idc))
}
if QCONF_OK != ret {
cur_err := Errno(ret)
return nil, cur_err
}

go_nodes := convertToGoSlice(&nodes)
return go_nodes, nil
}

func GetBatchConf(key string, idc string) (map[string]string, error) {
c_key := C.CString(key)
defer C.free(unsafe.Pointer(c_key))
var bnodes C.qconf_batch_nodes
init_ret := C.init_qconf_batch_nodes(&bnodes)
if QCONF_OK != init_ret {
cur_err := Errno(init_ret)
return nil, cur_err
}
defer C.destroy_qconf_batch_nodes(&bnodes)

var ret int
if idc == "" {
ret = int(C.qconf_get_batch_conf(c_key, &bnodes, nil))
} else {
c_idc := C.CString(idc)
defer C.free(unsafe.Pointer(c_idc))
ret = int(C.qconf_get_batch_conf(c_key, &bnodes, c_idc))
}
if QCONF_OK != ret {
cur_err := Errno(ret)
return nil, cur_err
}

go_nodes := convertToGoMap(&bnodes)
return go_nodes, nil
}

func GetBatchKeys(key string, idc string) ([]string, error) {
c_key := C.CString(key)
defer C.free(unsafe.Pointer(c_key))
var nodes C.string_vector_t
init_ret := C.init_string_vector(&nodes)
if QCONF_OK != init_ret {
cur_err := Errno(init_ret)
return nil, cur_err
}
defer C.destroy_string_vector(&nodes)

var ret int
if idc == "" {
ret = int(C.qconf_get_batch_keys(c_key, &nodes, nil))
} else {
c_idc := C.CString(idc)
defer C.free(unsafe.Pointer(c_idc))
ret = int(C.qconf_get_batch_keys(c_key, &nodes, c_idc))
}
if QCONF_OK != ret {
cur_err := Errno(ret)
return nil, cur_err
}

go_nodes := convertToGoSlice(&nodes)
return go_nodes, nil
}

func Version() (string, error) {
return QCONF_DRIVER_GO_VERSION, nil
}


goqconf_demo.go代码

package main

import (
"fmt"
"flag"
"os"

"./go_qconf"
)

func main() {
idc := "test" //"corp"

key := flag.String("k", "", "key of witch you get")
reqVer := flag.Bool("v", false, "show version")
flag.Parse()

if *reqVer {
ver,_ := go_qconf.Version()
fmt.Println("qconf version: ", ver)
return
}

if len(*key) > 0 {
value, e := go_qconf.GetConf(*key, idc)
if e != nil {
fmt.Println("get error:", e)
e = new(Error)
} else {
fmt.Println("key=", *key, "val=", value)
}
} else {
fmt.Println("Usage: ", os.Args[0] , " -k $key")
fmt.Println("like: ", os.Args[0], "-k /dev/mykeyOfMyConf")
}

}


编译执行:

$ go build goqconf_demo.go
./goqconf_demo -k '/dev/mykeyOfMyConf'
key= /dev/mykeyOfMyConf val= http://xxx.xxx/api[/code] 
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  golang 配置管理 qconf