マイクロサービス アーキテクチャでは、サービスの登録と検出は非常に重要な問題です。この問題を解決するには、ZooKeeper をサービス登録センターとして使用します。この記事では、Beego フレームワークで ZooKeeper を使用してサービスの登録と検出を実装する方法を紹介します。
1. ZooKeeper の概要
ZooKeeper は、オープンソースの分散調整サービスであり、Apache Hadoop のサブプロジェクトの 1 つです。 ZooKeeper の主な役割は、分散アプリケーションを調整し、分散ロック、ネーミング サービス、構成管理、分散同期などの機能を提供することです。マイクロサービス アーキテクチャでは、ZooKeeper がサービス レジストリとしてよく使用されます。
2. ZooKeeper のインストールと構成
ZooKeeper のインストールと構成については、公式 Web サイトのドキュメントを参照してください: https://zookeeper.apache.org/doc/r3.6.3/インデックス.html。ここでは、一般的に使用されるいくつかの設定項目のみを紹介します。 ZooKeeper は、ZooKeeper 設定ファイルzoo.cfgで設定できます。
以下は重要な設定項目の一部です:
3. Beego フレームワークは ZooKeeper を統合します
Beego フレームワークで ZooKeeper を使用するには、ZooKeeper を導入する必要がありますクライアントライブラリ。 Go Zookeeper クライアント ライブラリ zk を使用して、ZooKeeper クライアント操作を実装できます。
次のコマンドを使用してインストールできます:
go get github.com/samuel/go-zookeeper/zk
Beego フレームワークでは、ZooKeeper でのサービス登録および検出操作のために ZooKeeper クライアント オブジェクトをカプセル化できます。
以下は、ZooKeeper クライアントのサンプル コードです。
package zk import ( "encoding/json" "fmt" "strings" "time" "github.com/samuel/go-zookeeper/zk" ) type Server struct { Host string `json:"host"` Port int `json:"port"` } type ZkClient struct { hosts []string conn *zk.Conn serversPath string sessionTimeout time.Duration } func NewZkClient(hosts []string, serversPath string, sessionTimeout int) (*ZkClient, error) { // 链接zk,创建授权节点 /servers c, _, err := zk.Connect(hosts, time.Duration(sessionTimeout)*time.Second) if err != nil { return nil, err } if exists, _, err := c.Exists(serversPath); err != nil { return nil, err } else if !exists { if _, err := c.Create(serversPath, nil, 0, zk.WorldACL(zk.PermAll)); err != nil { return nil, fmt.Errorf("create znode error(%v)", err) } } return &ZkClient{ hosts: hosts, conn: c, serversPath: serversPath, sessionTimeout: time.Duration(sessionTimeout) * time.Second, }, nil } func (zk *ZkClient) Close() { zk.conn.Close() } // 检测授权节点是否存在 func (zk *ZkClient) ensureServerPath() error { exists, _, err := zk.conn.Exists(zk.serversPath) if err != nil { return err } if !exists { _, err = zk.conn.Create(zk.serversPath, []byte(""), 0, zk.WorldACL(zk.PermAll)) } return err } func (zk *ZkClient) Register(server *Server) error { if err := zk.ensureServerPath(); err != nil { return fmt.Errorf("register: ensureServerPath error(%v)", err) } //在 /servers 节点下创建一个临时性节点,节点名为 IP:Port。 path := fmt.Sprintf("%s/%s:%d", zk.serversPath, server.Host, server.Port) if _, err := zk.conn.Create(path, []byte(""), zk.FlagEphemeral, zk.WorldACL(zk.PermAll)); err != nil { return fmt.Errorf("register: create error(%v)", err) } return nil } // 获取所有服务器列表 func (zk *ZkClient) GetServers() ([]Server, error) { list, _, err := zk.conn.Children(zk.serversPath) if err != nil { return nil, err } servers := make([]Server, 0, len(list)) for _, node := range list { data, _, err := zk.conn.Get(zk.serversPath + "/" + node) if err != nil { continue } arr := strings.Split(node, ":") servers = append(servers, Server{ Host: arr[0], Port: str2Int(arr[1]), }) } return servers, nil } func (zk *ZkClient) WatchServers() ([]Server, <-chan zk.Event, error) { list, _, ch, err := zk.conn.ChildrenW(zk.serversPath) if err != nil { return nil, nil, err } servers := make([]Server, 0, len(list)) for _, node := range list { data, _, err := zk.conn.Get(zk.serversPath + "/" + node) if err != nil { continue } arr := strings.Split(node, ":") servers = append(servers, Server{ Host: arr[0], Port: str2Int(arr[1]), }) } return servers, ch, nil } // 删除授权节点 func (zk *ZkClient) Remove(server *Server) error { path := fmt.Sprintf("%s/%s:%d", zk.serversPath, server.Host, server.Port) return zk.conn.Delete(path, -1) } func str2Int(str string) int { var ( num int err error ) if num, err = strconv.Atoi(str); err != nil { panic(err) } return num }
ZooKeeper クライアント オブジェクトを実装した後、そのオブジェクトを使用してサービスを登録し、呼び出すことができます。
Beego フレームワークでは、初期化関数で ZooKeeper クライアント オブジェクトを作成できます。同時に、API リクエスト処理では、このオブジェクトを使用してサービスを検出し、呼び出すことができます。
次は、ZooKeeper を使用してサービスを登録および呼び出すためのサンプル コードです:
package controllers import ( "encoding/json" "fmt" "log" "github.com/astaxie/beego" "github.com/my/go-zk" ) type MyController struct { beego.Controller zkCli *zk.ZkClient } func (c *MyController) Prepare() { var ( err error ) // 初始化ZooKeeper客户端 servers := []string{"localhost:2181"} serversPath := "/myapp/servers" sessionTimeout := 30 c.zkCli, err = zk.NewZkClient(servers, serversPath, sessionTimeout) if err != nil { log.Fatal(err) } } func (c *MyController) Get() { // 查询服务列表 servers, _, err := c.zkCli.WatchServers() if err != nil { c.Data["json"] = map[string]interface{}{ "code": 1001, "message": fmt.Sprintf("get servers error(%v)", err), } c.ServeJSON() return } // 随机调用一个服务 if len(servers) == 0 { c.Data["json"] = map[string]interface{}{ "code": 1002, "message": "no available servers", } c.ServeJSON() return } server := servers[rand.Intn(len(servers))] url := fmt.Sprintf("http://%s:%d/hello", server.Host, server.Port) resp, err := http.Get(url) if err != nil { c.Data["json"] = map[string]interface{}{ "code": 1003, "message": fmt.Sprintf("call server error(%v)", err), } c.ServeJSON() return } defer resp.Body.Close() result, err := ioutil.ReadAll(resp.Body) if err != nil { c.Data["json"] = map[string]interface{}{ "code": 1004, "message": fmt.Sprintf("read response error(%v)", err), } c.ServeJSON() return } var respData struct { Code int `json:"code"` Msg string `json:"msg"` } if err = json.Unmarshal(result, &respData); err != nil { c.Data["json"] = map[string]interface{}{ "code": 1005, "message": fmt.Sprintf("parse response error(%v)", err), } c.ServeJSON() return } c.Data["json"] = respData c.ServeJSON() } func (c *MyController) Delete() { var ( server zk.Server err error ) // 解析请求数据 if err = json.Unmarshal(c.Ctx.Input.RequestBody, &server); err != nil { c.Data["json"] = map[string]interface{}{ "code": 1001, "message": "invalid parameters", } c.ServeJSON() return } // 删除ZooKeeper中保存的服务节点 if err = c.zkCli.Remove(&server); err != nil { c.Data["json"] = map[string]interface{}{ "code": 1001, "message": fmt.Sprintf("delete server error(%v)", err), } c.ServeJSON() return } c.Data["json"] = map[string]interface{}{ "code": 200, "message": "success", } c.ServeJSON() } func (c *MyController) Post() { var ( server zk.Server err error ) // 解析请求数据 if err = json.Unmarshal(c.Ctx.Input.RequestBody, &server); err != nil { c.Data["json"] = map[string]interface{}{ "code": 1001, "message": "invalid parameters", } c.ServeJSON() return } // 注册服务到ZooKeeper if err = c.zkCli.Register(&server); err != nil { c.Data["json"] = map[string]interface{}{ "code": 1001, "message": fmt.Sprintf("register server error(%v)", err), } c.ServeJSON() return } c.Data["json"] = map[string]interface{}{ "code": 200, "message": "success", } c.ServeJSON() } func (c *MyController) Finish() { // 关闭ZooKeeper客户端 c.zkCli.Close() }
4. 概要
この記事では、Beego フレームワークで ZooKeeper を使用する方法を紹介しました。 . サービスの登録と検出。最初に ZooKeeper のインストールと構成について紹介し、次に ZooKeeper クライアントをカプセル化するサンプル コードを作成しました。最後に、Beego フレームワークを使用して、このサンプル コードを使用してサービスの登録と検出を実装する方法を示しました。この記事が皆さんのお役に立てば幸いです。
以上がZooKeeper を使用して Beego でサービスの登録と検出を実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。