Golang使用QConf教程

前端之家收集整理的这篇文章主要介绍了Golang使用QConf教程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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,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,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)),}
    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_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,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_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,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,cur_err
    }

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

func GetBatchKeys(key string,cur_err
    }
    defer C.destroy_string_vector(&nodes)

    var ret int
    if idc == "" {
        ret = int(C.qconf_get_batch_keys(c_key,nil))
    } else {
        c_idc := C.CString(idc)
        defer C.free(unsafe.Pointer(c_idc))
        ret = int(C.qconf_get_batch_keys(c_key,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: ","-k /dev/mykeyOfMyConf")
    }   

}

编译执行:

$ go build goqconf_demo.go
./goqconf_demo -k '/dev/mykeyOfMyConf'
key= /dev/mykeyOfMyConf val= http://xxx.xxx/api

猜你在找的Go相关文章