Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Teach you to write service discovery using zookeeper with your bare hands

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)06/01 Report--

Zookeeper is a strongly consistent [lax] distributed database, which consists of multiple nodes to form a distributed cluster. If any node is hung up, the database can still work normally, and the client does not perceive failover. The client writes data to any node, and the other nodes can see the latest data immediately.

The interior of zookeeper is a key/value storage engine. Key forms a multi-level hierarchical structure in the form of a tree. Each node can not only store data, but also store the next level of child nodes as a directory.

Zookeeper provides api for creating / modifying / deleting nodes. If the parent node is not created, the word node creation will fail. If the parent node has children, the parent node cannot be deleted.

The two-way communication between the zookeeper and the client is in the form of socket. The client can actively call the api provided by the server, and the server can actively push events to the client. There are a variety of events that can be watch, such as node additions and deletions, child nodes' additions and deletions, session state changes, etc.

Zookeeper events have a transmission mechanism, the events triggered by the addition, deletion and modification of the word node will be propagated to the upper layer in turn, and all the parent nodes can receive the data change event of the word node, so if the level is too deep / there are too many children, it will bring pressure to the event system of the server, and the node allocation should be carefully planned.

Zookeeper satisfies the partition tolerance P and strong consistency C of CAP theorem at the expense of high performance A [availability implication performance]. The storage capacity of zookeeper is limited, when the node level is too deep / there are too many child nodes / the node data is too large, it will affect the stability of the database. So zookeeper is not a high-concurrency and high-performance database, zookeeper is generally only used to store configuration information.

The read performance of zookeeper can increase with the increase of the number of nodes, but the write performance will decrease with the increase of the number of nodes, so the number of nodes should not be too large, generally configured as 3 or 5.

As can be seen in the figure, as the number of server nodes increases, the complexity increases. Because there is a P2P connection between each node and other nodes. 3 nodes can tolerate 1 node and 5 nodes can tolerate 2 nodes.

When the client connects to the zookeeper, any node will be selected to maintain a long link, and subsequent communications will be read and written through this node. If the node dies, the client will try to connect to another node.

The server maintains a session object for each client connection, and the ID of the session is saved on the client. The session object is also distributed, which means that when a node dies and the client uses the original session ID to connect to other nodes, the session object maintained by the server continues to exist and there is no need to recreate a new session.

If the client actively sends a session close message, the session object of the server is deleted immediately. If the client accidentally collapses and does not send a shutdown message, the server's session object will continue to exist for some time. This time is the expiration time of the session, which is provided by the client when the session is created, usually 10 to 30 seconds.

You may ask that the connection is disconnected and the server is aware of it, so why do you need the client to actively send a shutdown message?

Because the server has to consider the network jitter, the connection may only be temporarily disconnected. In order to avoid repeatedly creating and destroying complex session objects and a series of event initialization operations after creating a session, the server will try its best to extend the lifetime of the session.

The nodes of a zookeeper can be Persistent or Ephermeral. The so-called temporary node is that all temporary nodes created during the session will disappear immediately after the session is closed. It is generally used in the service discovery system, which binds the life cycle of the service process with the life cycle of the zookeeper child node, which has the effect of real-time monitoring the survival of the service process.

Zookeeper also provides sequential nodes. Similar to the auto_increment attribute in mysql. The server automatically adds a self-increasing unique suffix after the sequential node name to maintain the uniqueness and sequence of the node name.

There is another type of node called Protected node. This node is very special, but it is not often used. In the case of application service discovery, after the client creates a temporary node, the server node dies, the connection is disconnected, and then the client reconnects to another node. Because the session is not closed, the previously created temporary node still exists, but at this time, the client cannot recognize whether the temporary node is created by itself, because the session ID field is not stored inside the node. So the client adds a GUID prefix to the node name, which is saved on the client so that it can identify which temporary node was created before it was reconnected.

Next, we use the go language to implement the registration and discovery functions of service discovery.

As shown in the figure, we need to provide services such as api.user, which has three nodes, each with a different service address. Each of these three nodes registers their own services into zk, and then consumers read zk to get the service address of api.user, and choose a node address for service invocation. For simplicity, no weight parameters are provided here. In a formal service discovery, there are generally weight parameters, which are used to adjust the traffic distribution between service nodes.

Go get github.com/samuel/go-zookeeper/zk

First, we define a ServiceNode structure, which data is stored in the node's data to represent the address information of service discovery.

Type ServiceNode struct {Name string `json: "name" `/ / service name. Here is user Host string `name: "host" `Port int `json: "port"`

}

In defining a client structure for service discovery, SdClient.

Type SdClient struct {zkServers [] string / / multiple node addresses zkRoot string / / service root node, here is the client connection of / api conn * zk.Conn / / zk

}

Write a constructor to create the root node

Func NewClient (zkServers [] string, zkRoot string, timeout int) (* SdClient, error) {client: = new (SdClient) client.zkServers = zkServers client.zkRoot = zkRoot / / connection server conn, _, err: = zk.Connect (zkServers, time.Duration (timeout) * time.Second) if err! = nil {return nil Err} client.conn = conn / / create the service root node if err: = client.ensureRoot () Err! = nil {client.Close () return nil, err} return client, nil} / / close the connection and release the temporary node func (s * SdClient) Close () {s.conn.Close ()

}

Func (s * SdClient) ensureRoot () error {exists, _, err: = s.conn.Exists (s.zkRoot) if err! = nil {return err} if! exists {_, err: = s.conn.Create (s.zkRoot, [] byte ("), 0 Zk.WorldACL (zk.PermAll) if err! = nil & & err! = zk.ErrNodeExists {return err}} return nil

}

It is worth noting that the Create call in the code may return that the node already has an error, which is normal because it is possible for multiple processes to create the node at the same time. If there is an error in creating the root node, you also need to close the connection in time. We don't care about the permission control of the node, so we use zk.WorldACL (zk.PermAll) to indicate that the node has no permission restrictions. The flag=0 in the Create parameter indicates that this is a persistent normal node.

Next, we write the service registration method.

Func (s * SdClient) Register (node * ServiceNode) error {if err: = s.ensureName (node.Name) Err! = nil {return err} path: = s.zkRoot + "/" + node.Name + "/ n" data, err: = json.Marshal (node) if err! = nil {return err} _, err = s.conn.CreateProtectedEphemeralSequential (path, data) Zk.WorldACL (zk.PermAll) if err! = nil {return err} return nil} func (s * SdClient) ensureName (name string) error {path: = s.zkRoot + "/" + name exists, _, err: = s.conn.Exists (path) if err! = nil {return err} if! exists {_ Err: = s.conn.Create (path, [] byte (""), 0, zk.WorldACL (zk.PermAll)) if err! = nil & & err! = zk.ErrNodeExists {return err}} return nil

}

The first step is to create the / api/user node as the parent node of the service list. Then create a protection order temporary (ProtectedEphemeralSequential) child node and store the address information in the node. What is a protection order temporary node? first of all, it is a temporary node, and the node disappears automatically when the session is closed. Otherwise, it is a sequential node, and zookeeper automatically adds a self-increasing suffix to the name to ensure the uniqueness of the node name. It is also a protective node with a GUID field added to the node prefix to ensure that the temporary node can be docked with the client state after disconnection and reconnection.

Next, we implement the consumer access service list method.

Func (s * SdClient) GetNodes (name string) ([] * ServiceNode, error) {path: = s.zkRoot + "/" + name / / get the word node name childs, _, err: = s.conn.Children (path) if err! = nil {if err = = zk.ErrNoNode {return [] * ServiceNode {} Nil} return nil, err} nodes: = [] * ServiceNode {} for _, child: = range childs {fullPath: = path + "/" + child data, _ Err: = s.conn.Get (fullPath) if err! = nil {if err = = zk.ErrNoNode {continue} return nil, err} node: = new (ServiceNode) err = json.Unmarshal (data Node) if err! = nil {return nil, err} nodes = append (nodes, node)} return nodes, nil

}

When we get the list of service nodes, we first get the name list of word nodes, and then read the content in turn to get the service address. Because getting the word node name and getting the word node content is not an atomic operation, it is normal that the node does not have an error when calling Get to get the content.

Put the above code together and a simple service discovery wrapper is implemented.

Finally, let's see if we use the above code, for convenience, we will write multiple service providers and consumers in a main method.

Func main () {/ / Server address list servers: = [] string {"192.168.0.101VR 2118", "192.168.0.102string 2118", "192.168.0.103 string 2118"} client, err: = NewClient (servers, "/ server") 10) if err! = nil {panic (err)} defer client.Close () node1: = & ServiceNode {"user", "127.0.0.1", 4000} node2: = & ServiceNode {"user", "127.0.0.1", 4001} node3: = & ServiceNode {"user", "127.0.0.1" 4002} if err: = client.Register (node1) Err! = nil {panic (err)} if err: = client.Register (node2); err! = nil {panic (err)} if err: = client.Register (node3) Err! = nil {panic (err)} nodes, err: = client.GetNodes ("user") if err! = nil {panic (err)} for _, node: = range nodes {fmt.Println (node.Host, node.Port)}

}

It is worth noting that the Close method must be called before the process exits, otherwise the session of zookeeper will not be closed immediately and the temporary nodes created by the server will not disappear immediately, but the server will not clean up until after timeout.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report