вперед отисходный адрес
1. Цель
Нищенский вариант центра конфигурации самообновления, после обновления конфигурации его можно обновить на каждом сервере
2. Архитектура
3. Роль
- config-web: фон конфигурации, в основном используется для управления конфигурацией, добавления и изменения конфигурации
- config-agent: следите за конфигурацией и автоматически загружайте последний файл на локальный сервер при обнаружении изменений.
- config-sdk: SDK для бизнес-интеграции, используемый для чтения конфигурации.
3.1 фон конфигурации config-web
- Постоянным хранилищем является MySQL, также можно добавить слой кеша Redis, установить уникальный бизнес-ключ, соответствующий ZNode в ZK
- Для операции настройки узла его необходимо в конечном итоге разместить на диске и постоянно хранить в MySQL.
- После успешного создания постоянного хранилища запишите настроенное содержимое в кластер ZK.
Ниже приведен код узла создания, такой же, как и набор, это простая операция.
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 мониторинг агента конфигурации
- Благодаря характеристикам ZK он может поддерживать согласованность кластера и предоставлять механизм мониторинга, который может обеспечивать обратные вызовы при изменении содержимого узла.
- Контролируйте соответствующий бизнес-узел в config-agent
- При мониторинге изменений будут уведомления.Например, при изменении содержимого узла содержимое узла получается, а затем помещается на диск, либо сохраняется в памяти.
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
Есть много способов прочитать конфигурацию, две идеи:
- Непосредственное чтение файлов, прямое чтение бизнес-сторонами, .json, .ini, .toml и т. д.
- SDK можно комбинировать с config-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"
-
Из-за локального теста он не был развёрнут на сервер из-за неполадок, меняем locah_path на "/tmp/zookeeper", "/tmp/zookeeper1", "/tmp/zookeeper2" и запускаем три процесса
-
Подключитесь к серверу zk и измените содержимое узла
set /huodong/conf/huodong-0000000001 '{"num":6.13,"strs":["a","b"]}'
-
Глядя на локальный файл, будет создан соответствующий файл конфигурации.
Столбец:
один,Знакомство с основами зоопарка