一、目标

一个乞丐版自更新配置中心,更新配置后,能在各个服务器实现更新

二、架构

三、角色

  • config-web: 配置后台,主要用于管理配置,增改配置
  • config-agent: 监听配置,遇到变动后,自动拉取最新文件到本地
  • config-sdk: 业务集成该sdk,用于读取配置

3.1 config-web 配置后台

  1. 持久存储为MySQL,也可以加一层缓存Redis,设置一个唯一的业务KEY,对应的ZK里的ZNode

    • 对于配置节点的操作,最终必须落盘,持久化存储于MySQL
  2. 持久存储成功后,将配置的内容写入ZK集群中

以下是create节点的代码,set的同,这是简单的操作

package main

import (
"fmt"
. "go-zk/connect" "github.com/samuel/go-zookeeper/zk"
) func main() {
conn := Connect()
defer conn.Close() flags := int32(zk.FlagSequence)
acl := zk.WorldACL(zk.PermAll) // create node
path := PathConfig.ZNodePath +"/"+ "huodong-"
data := []byte(`{"num":6.13,"strs":["a","b"]}`)
createPath, err := conn.Create(path, data, flags, acl)
if err != nil {
panic(err)
}
} 复制代码

3.2 config-agent 监控

  1. 由于ZK的特性,能保持集群的一致性,以及提供了监听机制,在节点内容被改变时能提供回调
  2. 在config-agent监听对应的业务节点
  3. 监听的变动时,会有通知,例如,更改节点内容时,获取节点的内容,然后进行落盘,或者存到内存中都
package main

import (
"fmt"
"github.com/samuel/go-zookeeper/zk"
. "go-zk/connect"
"os"
"sync"
)
type Watch struct { } func (this *Watch)ZkChildrenWatch(c *zk.Conn, path string) {
for {
v, _, get_ch, err := c.ChildrenW(path)
if err != nil {
fmt.Println(err)
} fmt.Printf("value of path[%s]=[%s].\n", path, v) for {
select {
case ch_event := <-get_ch:
{
fmt.Printf("%+v\n", ch_event) if ch_event.Type == zk.EventNodeCreated {
fmt.Printf("has new node[%d] create\n", ch_event.Path)
} else if ch_event.Type == zk.EventNodeDeleted {
fmt.Printf("has node[%s] detete\n", ch_event.Path)
} else if ch_event.Type == zk.EventNodeDataChanged {
this.Callback(c, ch_event.Path)
} else if ch_event.Type == zk.EventNodeChildrenChanged {
fmt.Printf("children node change%+v\n", ch_event.Path)
}
}
}
break
}
}
} func (this *Watch)ZkNodeWatch(c *zk.Conn, path string) {
for {
v, _, get_ch, err := c.GetW(path)
if err != nil {
fmt.Println(err)
} fmt.Printf("value of path[%s]=[%s].\n", path, v) for {
select {
case ch_event := <-get_ch:
{
if ch_event.Type == zk.EventNodeCreated {
fmt.Printf("has new node[%d] create\n", ch_event.Path)
} else if ch_event.Type == zk.EventNodeDeleted {
fmt.Printf("has node[%s] detete\n", ch_event.Path)
} else if ch_event.Type == zk.EventNodeDataChanged {
this.Callback(c, ch_event.Path)
}
}
}
break
}
}
} func (this *Watch)Callback(c *zk.Conn, path string) {
data, _, err := c.Get(path)
if err != nil {
fmt.Println(err)
} // create file
fileName := PathConfig.LocalPath + path + ".json"
os.Create(fileName)
f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC, 0600)
defer f.Close()
if err != nil {
fmt.Println(err.Error())
} else {
_,err=f.Write([]byte(data))
fmt.Println(err)
return
} fmt.Print("Write File OK !!!")
} func main() {
conn := Connect() // 监听所有子节点变化
children, _, err := conn.Children(PathConfig.ZNodePath)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", children) w := Watch{} var wg sync.WaitGroup
wg.Add(1)
go func(path string) {
w.ZkChildrenWatch(conn, path)
}(PathConfig.ZNodePath)
wg.Wait() // 监听节点内容变化
//var wg sync.WaitGroup
//wg.Add(len(children))
//
//for _, path := range children{
// path = PathConfig.ZNodePath + "/" + path
// go func(path string) {
// defer wg.Done()
// log.Print("Zookeeper Watcher Starting, ", path)
// w.ZkNodeWatch(conn, path)
// }(path)
//}
//wg.Wait() }
复制代码

3.3 config-sdk 客户端加载配置

读取配置的方式很多样,两种思路:

  1. 直接读取文件,由业务方直接读取,.json 、 .ini 、 .toml等
  2. sdk可以与config-agent结合,如果读取文件加载配置失败,利用agent,重新主动拉一次文件到本地,实现文件的懒加载

四、效果展示

# This is Zookeeper config file.

title = "Zookeeper config file"

[zookeeper]
servers = ["10.00.85.70:2181", "10.00.80.191:2181", "10.00.97.239:2181"]
port = 2181
session_timeout = 500
enabled = true [path]
znode_path = "/huodong/conf"
local_path = "/tmp/zookeeper"
复制代码
  1. 由于在本地测试,嫌麻烦就没有部署到服务器了,将locah_path分别改成"/tmp/zookeeper"、"/tmp/zookeeper1"、"/tmp/zookeeper2",起三个进程

  2. 连接到zk服务器,修改节点的内容 set /huodong/conf/huodong-0000000001 '{"num":6.13,"strs":["a","b"]}'

  3. 看下本地文件就会生成对应的配置文件

作者:知否专栏
链接:https://juejin.im/post/5cdcbf02f265da037129c3c7
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Zookeeper 应用实现-配置中心的更多相关文章

  1. 基于zookeeper实现分布式配置中心(二)

    上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...

  2. 基于zookeeper实现分布式配置中心(一)

    最近在学习zookeeper,发现zk真的是一个优秀的中间件.在分布式环境下,可以高效解决数据管理问题.在学习的过程中,要深入zk的工作原理,并根据其特性做一些简单的分布式环境下数据管理工具.本文首先 ...

  3. zookeeper配置中心实战--solrcloud zookeeper配置中心原理及源码分析

    程序的发展,需要引入集中配置: 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关.参数的配置.服务器的地址…… 并且对配置的期望也越来越高,配置修改后实时生效,灰度发布,分环境.分集群管理配 ...

  4. ZooKeeper系列(2)--基于ZooKeeper实现简单的配置中心

    ZooKeeper节点的类型分为以下几类:  1. 持久节点:节点创建后就一直存在,直到有删除操作来主动删除该节点 2. 临时节点:临时节点的生命周期和创建该节点的客户端会话绑定,即如果客户端会话失效 ...

  5. 基于ZK构建统一配置中心的方案和实践

    背景: 近期使用Zk实现了一个简单的配置管理的小东西,在此开源出来,有兴趣的希望提出您的宝贵意见.如果恰巧您也使用或者接触过类似的东西, 也希望您可以分享下您觉得现在这个项目可以优化和改进的地方. 项 ...

  6. .Net配置中心-简介

    系统简介 最近做了一个.Net配置中心,本质就是将原本放在各个站点下AppSettings中的配置统一管理,可以实现一次更改,自动更新,这里提供了两个版本, 一个是心跳版,一个是zookeeper版. ...

  7. SrpingCloud 之SrpingCloud config分布式配置中心

    Config架构 当一个系统中的配置文件发生改变的时候,我们需要重新启动该服务,才能使得新的配置文件生效,spring cloud config可以实现微服务中的所有系统的配置文件的统一管理,而且还可 ...

  8. ASP.Net Core 中使用Zookeeper搭建分布式环境中的配置中心系列一:使用Zookeeper.Net组件演示基本的操作

    前言:马上要过年了,祝大家新年快乐!在过年回家前分享一篇关于Zookeeper的文章,我们都知道现在微服务盛行,大数据.分布式系统中经常会使用到Zookeeper,它是微服务.分布式系统中必不可少的分 ...

  9. springcloud集成zookeeper,并使用configserver作为服务的配置中心

    1.springcloud集成zookeeper: 做法: 出现问题: 版本不一致导致出现keepError: 解决:服务器的zookeeper要与客户端的zookeeper一致,才可以. 2.使用c ...

随机推荐

  1. java 调用启动远程shell脚本,启动spark

    1 依赖 <!--远程调用shell--> <dependency> <groupId>ch.ethz.ganymed</groupId> <ar ...

  2. 【Spring Boot】java.lang.NoSuchMethodError: org.springframework.web.util.UrlPathHelper.getLookupPathForRequest(Ljavax/servlet/http/HttpServletRequest;Ljava/lang/String;)Ljava/lang/String;

    Digest:今天Spring Boot 应用启动成功,访问接口出现如下错误,不知到导致问题关键所在,记录一下这个问题. 浏览器报500错误 项目代码如下 Controller.java packag ...

  3. (转载)学校搭建使用nginx同时编译rtmp-module进行直播的技术文档

    原文地址:学校搭建使用 nginx 同时编译 rtmp-module 进行直播的技术文档 转载自我的大佬同学 MetalkgLZH.学校有几次需要全校观看网络直播的情况,但是学校的带宽不允许所有的班一 ...

  4. 题解【洛谷】CF134A

    题解 CF134A [Average Numbers] 这题就是简单的模拟. 只不过要优化一下常数什么的 思路: 为了不浪费时间总是取平均数,直接用一个 S 储存总和,每次都减去 a_i​ 再除以 n ...

  5. Python3 下的输出字符控制

    最近在使用 python3 进行爬虫的时候,出现了令人窒息的,只会在 python2 中遇到的,没想到在 python3 还能碰见的输出编码问题,报错如下: UnicodeEncodeError: ' ...

  6. PMD-Java代码静态分析工具使用

    如今,使用代码分析工具来代替人工进行代码审查,已经是大势所趋了.用于Java代码检测的工具中,不乏许许多多的佼佼者,其中PMD就是其中一款.PMD既可以独立运行,也可以以命令行的形式运行,还可以作为插 ...

  7. CSP-S模拟57

    这次的T1是来送温暖的. T2T3挺神的. T1. 不会 T2. 容斥,挺神的 T3. 考场上被卡常卡掉10分让我很难受.....(虽然说$O(n)$过$1e8$本来就不太行) 考场上:疯狂化简式子, ...

  8. Fiddler 原理及iPhone的配置

    原理: 首先Fiddler运行在自己的PC上,Fiddler运行的时候会在PC的8888端口开启一个代理服务,这个服务实际上是一个HTTP/HTTPS的代理. 确保手机和PC在同一个局域网内,我们可以 ...

  9. Windows7下安装Linux双操作系统

    本文链接:https://blog.csdn.net/zh175578809/article/details/78576193 最近正在学习Linux系统的常用操作命令,于是心血来潮,想自己安装一个L ...

  10. Git II: 操作远程Repository基础

    很久之前写过一篇Git: Setup a remote Git repository,留意到有前同事谈论到Git的一些操作,就把Git值得留意的操作补补全吧.这次,主要讲述Git远程Repositor ...