内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuduorui/article/details/78117520
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuduorui/article/details/78117520
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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++ How to Program (5th Edition) (How to Program)
Harvey & Paul) Deitel & Associates / Prentice Hall / 2005-01-05 / USD 98.00
With over 250,000 sold, Harvey and Paul Deitel's C++ How to Program is the world's best-selling introduction to C++ programming. Now, this classic has been thoroughly updated! The Deitels' groundbreak......一起来看看 《C++ How to Program (5th Edition) (How to Program)》 这本书的介绍吧!