directory

For Windows, the ZK version is ZooKeeper-3.4.14

  • 1. Single-node mode: Deploy it on one server
  • 2. Single-ip multi-node (pseudo cluster) : Multiple nodes with their own ports are deployed on the same IP address
  • 3. Multi-ip multi-node: Deployed on different IP addresses, each with its own port (not tested)

1. Zookeeper Installation (Single-node Deployment)

  • Single-node mode: Deploy it on one server

1. Download address:

D:\ zookeeper-3.4.14.tar.gz Extract code: l77V D:\zookeeper-3.4.14

2. Add the TMP folder

Add TMP folder – used to store logs and data under D:\zookeeper-3.4.14\

Add the data and log folders under TMP

3, open D:\zookeeper-3.4.14\conf

Rename the zoo_sample. CFG file to zoo.cfg

CFG: note that it is best not to copy the Chinese annotations in, prone to flash back, there is a flash back solution below.

tickTime=2000
initLimit=10
syncLimit=5
# configure the location where the data is stored
dataDir=D:\\zookeeper3.414.\\tmp\\data  
Create a folder where logs are stored
dataLogDir=D:\\zookeeper3.414.\\tmp\\log   
# disconnect port 2181 by default
clientPort=2182   

Copy the code

Ps: Parameter description

  • TickTime: indicates the heartbeat interval. This interval is used as the interval between the ZooKeeper server or the ZooKeeper server and the client server to maintain the heartbeat. That is, every tickTime, a heartbeat is sent
  • InitLimit: This configuration item is used to configure the Zookeeper accept client (not the client through which the user connects to the Zookeeper server, It is the maximum heartbeat interval that the Follower server connected to the Leader in the Zookeeper cluster can endure during initial connection. If the Zookeeper server does not receive any message from the client after the tickTime period exceeds five heartbeats, the connection to the client fails. The total length of time is 52000 = 10 seconds
  • SyncLimit: This configuration item indicates the duration of sending messages, requests, and requests between the Leader and followers. The maximum length of the request cannot exceed the number of Ticktimes. The total duration is 22000 = 4 seconds
  • DataDir: indicates the directory where ZooKeeper data is stored. Zookeeper logs are also saved to this directory by default
  • ClientPort: port number used by the client to connect to ZooKeeper
  • Server. A=B: C: D: where A is an integer indicating the server subscript. B is the IP address of the server; C represents the port through which the server exchanges information with the Leader server in the cluster. D indicates that in case the Leader server in the cluster fails, a port is needed to re-elect a new Leader, and this port is used to communicate with each other during the election. In the pseudo-cluster configuration mode, different Zookeeper instances cannot communicate with the same port number because B is the same. Therefore, they need to be assigned different port numbers.

4. Start ZooKeeper

Enter the D: \ zookeeper – 3.4.14 \ bin

Double-click zkServer. CMD, or right click zkServer. CMD – Send to – desktop shortcut, you can start from desktop later

Binding to port 0.0.0.0/0.0.0.0:2182

In this case, you can modify the contents of the zkserver. CMD file by adding pause at the end of the command. After restarting the CMD window, the file does not blink and you can see exceptions thrown during startup

5, Test whether ZooKeeper is available:

5.1 Add the following dependencies to the Maven project pom.xml

<! --zookeeper-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.9</version>
</dependency>
Copy the code

5.2 The most basic example program

package com.dist.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;

/ * * *@author [email protected]
 * @data2019/8/21 15:21 * /
public class ZooKeeperHello {

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {<! Run the CMD ipconfig command to check IP--> ZooKeeper zk =new ZooKeeper("192.168.2.113:2182".300000.new DemoWatcher());// Connect to zK Server
        String node = "/app1";
        Stat stat = zk.exists(node, false);// Check whether /app1 exists
        if (stat == null) {
            // Create a node
            String createResult = zk.create(node, "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println(createResult);
        }
        // Get the value of the node
        byte[] b = zk.getData(node, false, stat);
        System.out.println(new String(b));
        zk.close();
    }

    static class DemoWatcher implements Watcher {
        @Override
        public void process(WatchedEvent event) {
            System.out.println("-- -- -- -- -- -- -- -- -- -- - >");
            System.out.println("path:" + event.getPath());
            System.out.println("type:" + event.getType());
            System.out.println("stat:" + event.getState());
            System.out.println("< -- -- -- -- -- -- -- -- -- -- -"); }}}Copy the code

Console printing effect:

----------->
path:null
type:None
stat: SyncConnected < -- -- -- -- -- -- -- -- -- -- - 15:24:45. 503 [main - SendThread (192.168.2.113:2182)] the DEBUG org. Apache. The zookeeper. ClientCnxn - Reading reply sessionid:0x100015c2c980002, packet:: clientPath:null serverPath:null finished:falseHeader:: 1 3 replyHeader:: 1,21,0 request::'/app1,T response:: S 17,17,1566372182125,1566372182125,0,0,0,0,4,0,17} {15:24:45. 510 [main - SendThread (192.168.2.113:2182)] the DEBUG org.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x100015c2c980002, packet:: ClientPath :null serverPath:null finished:false header:: 2,4 replyHeader:: 2,21,0 request:: '/app1,F  response:: # 74657374, s 17,17,1566372182125,1566372182125,0,0,0,0,4,0,17 {}
test
Copy the code

Single-node deployment is complete. Tests are successful. This version of ZK is remote connection support, do not need to configure the local IP address, also can let others connect!

Pseudo-distributed Installation of Zookeeper (Cluster)

  • Single-ip multi-node (pseudo cluster) : Multiple nodes with their own ports are deployed on the same IP address.

  • Pseudo-distributed installation refers to the installation on the same PC, using the same ZooKeeper package, and configuring multiple configuration files as different ports. Due to the limited number of machines, a pseudo-distributed configuration is used to simulate the cluster configuration.

Zk version: On Windows, the ZK version is zookeeper-3.4.14. Download link: Zookeeper-3.4.14.tar. gz Extract code: L77V

1. Decompressed directory

D:\ Zookeeper-3.4.14

2. Modify the configuration

CFG file in the conf directory, rename the zoo_sample. CFG file to zoo. CFG, and modify the configuration as follows: Do not copy Chinese annotations to the file

tickTime=2000
initLimit=10
syncLimit=5
# configure the location where the data is storedDataDir = D: \ \ zookeeper - 3.4.14 \ \ TMP \ \ dataCreate a folder where logs are storedDataLogDir = D: \ \ zookeeper - 3.4.14 \ \ TMP \ \log 
# disconnect port 2181 by default
clientPort=2182   
Copy the code
Add TMP folder

Add TMP folder under D:\zookeeper-3.4.14\ : D:\zookeeper-3.4.14\ TMP

D:\zookeeper-3.4.14\ TMP \data, D:\zookeeper-3.4.14\ TMP \log

3. Start the ZooKeeper service:

Go to D:\zookeeper-3.4.14\bin and double-click zkserver. CMD to start the ZooKeeper service. Close the zkServer window

4. Pseudo-distributed installation

Pseudo-distributed installation refers to the installation on the same PC, using the same ZooKeeper package, and configuring multiple configuration files as different ports. I’m configuring three pseudo services here.

1.) D: \ zookeeper – 3.4.14 \ conf \ the zoo CFG copying the files separately zoo1. CFG, zoo2. CFG, zoo3. Three CFG file, and modify configuration respectively as follows:

CFG. Do not copy Chinese comments to the zoo1. CFG file. Otherwise, flash rollback may occur

tickTime=2000
initLimit=10
syncLimit=5

Create a directory for storing data
dataDir=D:\\zookeeper3.414.\\tmp\\data\\1     
Create a directory for storing logs
dataLogDir=D:\\zookeeper3.414.\\tmp\\log\\1   
# disconnect port 2181 by default
clientPort=2182   

server1.=localhost:2887:3887
server2.=localhost:2888:3888
server3.=localhost:2889:3889

Copy the code

zoo2.cfg

tickTime=2000
initLimit=10
syncLimit=5

dataDir=D:\\zookeeper3.414.\\tmp\\data\\2   
dataLogDir=D:\\zookeeper3.414.\\tmp\\log\\2
clientPort=2182 

server1.=localhost:2887:3887
server2.=localhost:2888:3888
server3.=localhost:2889:3889

Copy the code

zoo3.cfg

tickTime=2000
initLimit=10
syncLimit=5

dataDir=D:\\zookeeper3.414.\\tmp\\data\\3    
dataLogDir=D:\\zookeeper3.414.\\tmp\\log\\3   
clientPort=2184   

server1.=localhost:2887:3887
server2.=localhost:2888:3888
server3.=localhost:2889:3889

Copy the code

Note: Assume that the configuration file is zoo{num}. CFG, server.{num}= IP /domain:Port1:Port2 Where num: indicates the number of the server. IP /domain: indicates the domain name or IP address of the server. Port1: indicates the port on which the server exchanges information with the Leader server in the cluster. Port2: in the event that the Leader server in the cluster fails, a port is required to elect a new Leader. This port is used for communication between the servers during the election. A=B: C: D: where A is an integer representing the server subscript, which is consistent with the id in the myID file. B is the IP address of the server; C represents the port through which the server exchanges information with the Leader server in the cluster. D indicates that in case the Leader server in the cluster fails, a port is needed to re-elect a new Leader, and this port is used to communicate with each other during the election. In the pseudo-cluster configuration mode, different Zookeeper instances cannot communicate with the same port number because B is the same. Therefore, they need to be assigned different port numbers.


Create a directory

Create subdirectory to store data: D:\zookeeper-3.4.14\ TMP \data\1, D:\zookeeper-3.4.14\ TMP \data\2, D:\zookeeper-3.4.14\ TMP \data\3

Create myID files in the following three files: 1, 2, and 3

Create a subdirectory for storing log logs: D:\zookeeper-3.4.14\ TMP \log\1, D:\zookeeper-3.4.14\ TMP \log\2, D:\zookeeper-3.4.14\ TMP \log\3

Modify zkserver.cmd

Go to D:\zookeeper-3.4.14\bin and copy the zkserver. CMD file to zkserver-1. CMD, zkserver-2. CMD, zkserver-3. CMD

5.1 Modifying zkServer-1. CMD:

setlocal
call "%~dp0zkEnv.cmd"

set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain
set ZOOCFG=D:\\zookeeper-3.4.14\\conf\\zoo3.cfg
echo on
call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*

endlocal
Copy the code

5.2 Modifying zkserver-2. CMD:

setlocal
call "%~dp0zkEnv.cmd"

set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain
REM Adds configuration path ZOOCFG
set ZOOCFG=D:\\zookeeper-3.4.14\\conf\\zoo3.cfg
echo on
call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*

endlocal
Copy the code

5.3 Modifying zkServer-3. CMD:

setlocal
call "%~dp0zkEnv.cmd"

set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain
set ZOOCFG=D:\\zookeeper-3.4.14\\conf\\zoo3.cfg
echo on
call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*

endlocal
Copy the code

6. Start the zkServer

Start zkserver-1. CMD, zkserver-2. CMD, and zkserver-3. CMD respectively

Enter the directory: CMD, zkserver-1. CMD, zkserver-2. CMD, zkserver-3. CMD to start the pseudo-distributed Zookeeper cluster. It is normal if the first two started service accounts are abnormal. No exception occurs until all three ZKServer-X. CMC md are started.

Enter CMD to execute command: netstat -ano # check port status until this zK pseudo-distributed cluster configuration is complete!

Note:

When building a cluster with multiple nodes on the same IP address, you must pay attention to the port problem. The ports must be inconsistent.

When creating multiple node clusters, you must create the myID file in the dataDir directory. The myID file is used to verify the serial number of the ZooKeeper server. The myID file is a one-line file and contains the serial number of the current server. Server2’s myID is 2, etc.

server.A=B:C:D; Where A is A number, indicating the server number; B is the IP address of the server; C represents the port through which the server exchanges information with the Leader server in the cluster. D indicates that in case the Leader server in the cluster fails, a port is needed to re-elect a new Leader, and this port is used to communicate with each other during the election. In the pseudo-cluster configuration mode, different Zookeeper instances cannot communicate with the same port number because B is the same. Therefore, they need to be assigned different port numbers.


7. Problems and solutions in configuration:

  • 1. When zkserver. CMD is started, the CMD window blinks

    At this time, you can modify the content of zkServer. CMD file, add pause keyword at the end, and then start CMD window will not blink back, and you can see the startup of the exception thrown, you can proceed according to the exception description, my exception – Annotation Chinese garble

  • 2. Have myid has an error under Caused by: Java. Lang. IllegalArgumentException: myid file is missing

    Solution: Delete the suffix myid. TXT and retain only the myID file name

  • The above two exceptions are only problems I encountered during the installation process. There may be other exceptions I haven’t encountered. The following are the exceptions recorded by others

  • Error: JAVA_HOME is INCORRECTLY set: Missing JDK or JDK version does not match

  • 4.java.net.bindexception Address already: The port number is occupied

  • 5. Java. Lang. A numberformatexception: digital conversion is unusual, appear the reason may be myid file content, or when using the command start in zkServer. CMD many other content, using the command as shown in the above option when starting to zkServer. The CMD can, You don’t need anything after that


3. Zookeeper Real Distributed cluster (not tested)

Multiple IP addresses, multiple nodes: Deployed on different IP addresses and each node has its own port (not tested). Multiple IP addresses, multiple nodes: Copy ZooKeeper to each node. The multi-IP, multi-node setup process is basically the same as the single-IP, multi-node setup process. The above process is not repeated, but only one point is highlighted: the IP address and port of the server are real.

Note: It is best to have a base number of ZK deployments. The mechanism of a ZK cluster is that as long as more than half of the nodes are OK, the cluster can provide services normally. The cluster fails only if there are too many ZK nodes hanging and only half or less of them are working.

1. In Dubbo, ZooKeeper serves as the registry. If all registry clusters fail, can publishers and subscribers communicate with each other?

When dubbo is started, the consumer will pull data such as the address interface of the registered producer from ZK and cache it locally. Each invocation is made according to the address of the local store. However, adding a new provider after the registry has all died cannot be detected by consumers:

Health of sex

  • The breakdown of the monitoring center does not affect the use of the system, but only the loss of some sample data
  • After the database goes down, the registry can still provide a list of services query through the cache, but it cannot register new services
  • If one of the registry peer clusters fails, it will automatically switch to the other one
  • After all registries go down, service providers and service consumers can still communicate through local caches
  • The service provider is stateless. If any service provider breaks down, the service is not affected
  • When all service providers go down, the service consumer application becomes unavailable and reconnects indefinitely waiting for the service provider to recover

Dubbo default cache local path: C:\Users\Administrator\. Dubbo therefore, access to the project can continue even if the ZK service is turned off.

4. Verify the server

Using zKTools visual tools download address: ZkTools visual extraction code: zV2F

Usage: start ZK first, then use ** zkTools visualization ** connect to the specified IP: port

In Dubbo, Zookeeper acts as the registry. If the registry clusters are all down, can publishers and subscribers communicate?

When dubbo is started, the consumer will pull data such as the address interface of the registered producer from ZK and cache it locally. Each invocation is made according to the address of the local store. However, adding a new provider after the registry has all died cannot be detected by consumers:

Health of sex

  • The breakdown of the monitoring center does not affect the use of the system, but only the loss of some sample data
  • After the database goes down, the registry can still provide a list of services query through the cache, but it cannot register new services
  • If one of the registry peer clusters fails, it will automatically switch to the other one
  • After all registries go down, service providers and service consumers can still communicate through local caches
  • The service provider is stateless. If any service provider breaks down, the service is not affected
  • When all service providers go down, the service consumer application becomes unavailable and reconnects indefinitely waiting for the service provider to recover

Springboot Zookeeperk Dubbo

Here is only how to configure, but more details on how to build the project and detailed code. Port 2183, port 2184, port 2185 in pseudo-distributed installation (cluster) configuration

1. Zk connection test

This is just a ZK test, there is no need to build a Dubbo + ZK sub-deployment project.

Pom. XML dependency
<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>
Copy the code
Test whether the cluster is set up successfully:

The test class ZooKeeperHello. Java

package com.dist.zk;

import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;

import java.io.IOException;

/ * * *@author [email protected]
 * @data2019/8/21 15:21 * /
public class ZooKeeperHello {

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        ZooKeeper zk = new ZooKeeper("192.168.2.113:2183".300000.new DemoWatcher());// Connect to zK Server
        String node = "/app1";
        Stat stat = zk.exists(node, false);// Check whether /app1 exists
        if (stat == null) {
            // Create a node
            String createResult = zk.create(node, "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println(createResult);
        }
        // Get the value of the node
        byte[] b = zk.getData(node, false, stat);
        System.out.println(new String(b));
        zk.close();
    }

    static class DemoWatcher implements Watcher {
        @Override
        public void process(WatchedEvent event) {
            System.out.println("-- -- -- -- -- -- -- -- -- -- - >");
            System.out.println("path:" + event.getPath());
            System.out.println("type:" + event.getType());
            System.out.println("stat:" + event.getState());
            System.out.println("< -- -- -- -- -- -- -- -- -- -- -"); }}/**Spring Boot2.0 integrated Zookeeper cluster * common connection: */
    @Test
    public void testZkClient(a){
        String connection = "192.168.2.113:2183192168 2.113:2184192168 2.113:2185";
        ZkClient zkClient = new ZkClient(connection);
        zkClient.createPersistent("/toov5_01");  // Add a nodezkClient.close(); }}Copy the code

After the test is executed, use the ZkTools visual tool to check whether the test is successful.

Download address: ZkTools Visual extraction code: zV2F

Usage: start ZK first, then use ** zkTools visualization ** connect to the specified IP: port

Test: ZK port 2183:

Zk port 2184:

If a node is added to zK port 2185, the cluster is successfully set up.

2. Standalone test — Distributed (DuBBO)

The Springboot + ZooKeeper + Dubbo distributed test project needs to be set up

Web layer (consumer) configuration
1).Web layer (consumer)- Introduce dependency pom.xml
<! - dubbo dependence - >
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>3.0.1</version>
</dependency>
<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Copy the code
2).web layer (consumer)- *.yml file
# dubbo configuration
dubbo:
  application:
    name: consumer The consumer application name is used to calculate dependencies, not the same as the provider
  registry:
    protocol: zookeeper   # dubbo/zookeeper agreement
    #address: 127.0.0.1:2183 # ZooKeeper protocol configurationAddress: 192.168.2.113:2183# Zookeeper protocol configuration test IP connection, zK support remote callInterface: version 1.0.0# Interface version number
  annotation:
    package: com.dist  # dubbo annotation scan package, pay attention to successfully change your project Java file path, otherwise you will not register the service
  consumer:
    timeout: 50000  # timeout
    check: false   # check: Disable startup check for all servicesVersion: 1.0.0# dubbo Default version number, displayed in the URL as default.version= XXX
Copy the code
3). Web layer (consumer)- spring-dubo-consumer.xml

Put spring-Dubo-consumer.xml under Resources /config

<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <! Application *.yml -->
    <context:property-placeholder location="classpath:application*.yml" ignore-unresolvable="true"/>
    <! -- Consumer application name, used to calculate dependencies, not matching conditions, not the same as provider -->
    <dubbo:application name="${dubbo.application.name}"/>
    <! -- ZK registry exposed service address, protocol -->
    <dubbo:registry id="zk" address="${dubbo.registry.address}" protocol="${dubbo.registry.protocol}"/>
    <! -- Dubbo scan package location -->
    <dubbo:annotation package="${dubbo.annotation.package}"/>
    <! -- Dubbo version, timeout, check: turn off startup check for all services -->
    <dubbo:consumer version="${dubbo.consumer.version}" timeout="${dubbo.consumer.timeout}" check="${dubbo.consumer.check}"/>
</beans>
Copy the code
4). Web layer (consumer)- Need to introduce API layer (public interface) dependency JAR

Add in pom. The XML

<! --> <dependency> <groupId>com.dist</groupId> <artifactId>springboot-test-api</artifactId> < version > 1.0 - the SNAPSHOT < / version > < / dependency >Copy the code
5). Web Layer (Consumer)- Test code:

Create the DubboTestService.java interface

public interface DubboTestService {
	String getData(String data);
}
Copy the code
Service layer (provider) configuration
1).service layer (provider) -pom.xml
<! --dubbo-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>3.0.1</version>
</dependency>
<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<! --dubbo-zk-curator-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.0.1</version>
</dependency>
Copy the code
2).service layer (provider)- *.yml file configuration
# dubbo configuration
dubbo:
  application:
    name: provider  Provide the name of the application used to calculate dependencies, not the same as the consumer
  registry:
    protocol: zookeeper  # dubbo/zookeeper agreement
    address: 127.0. 01.: 2183  Configuration mode of the ZooKeeper protocol
    The zookeeper protocol is configured to test whether zK supports remote calls
    # address: zookeeper: / / 127.0.0.1:2183 # dubbo protocol configuration
  protocol:
    port: 30103  Dubbo protocol default port 20880, multiple providers will conflict
  annotation:
    package: com.dist.server  # dubbo annotation scan package, pay attention to successfully change your project Java file path, otherwise you will not register the service
  provider:
    version: 1.0. 0 #dubbo Default version number, displayed in the URL as default.version= XXX
Copy the code
3).service layer (provider)- spring-dubbo-provider.xml
<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <! Application *.yml -->
    <context:property-placeholder location="classpath:application*.yml" ignore-unresolvable="true"/>
    <! -- Provider application name, used to calculate dependencies, not matching conditions, not the same as consumer -->
    <dubbo:application name="${dubbo.application.name}"/>
    <! Port ="${dubbo.protocol. Port}-->
    <dubbo:registry address="${dubbo.registry.address}" protocol="${dubbo.registry.protocol}"/>
    <! -- Dubbo version, timeout -->
    <dubbo:provider version="${dubbo.provider.version}" timeout="50000" />
    <! -- Dubbo scan package location -->
    <dubbo:annotation package="${dubbo.annotation.package}"/>
</beans>
Copy the code
4).service layer (provider)- Need to introduce API layer (public interface) dependency JAR

Add in pom. The XML

<! --> <dependency> <groupId>com.dist</groupId> <artifactId>springboot-test-api</artifactId> < version > 1.0 - the SNAPSHOT < / version > < / dependency >Copy the code
5).service layer (provider)- Test code:

DubboTestServiceImpl. Java implementation class

import com.alibaba.dubbo.config.annotation.Service;
@Service
public class DubboTestServiceImpl implements DubboTestService {
	@Override
    public String getData(String data){
        return "Data returned by the service layer :"+data; }}Copy the code
API Layer (Public Interface)

The API layer provides the common interface, the Web layer calls, and the service layer implementation, requiring both to introduce the API layer dependent JAR:

Dubbotestservice. Java public interface

public interface DubboTestService {
	String getData(String data);
}
Copy the code

3. Pseudo-cluster Testing — Distributed (DuBBO)

Change the *.yML configuration on a 2, Standalone test-distributed (Dubbo) basis:

1. Web layer (consumer)- *.yML file configuration: ZooKeeper cluster configuration
# dubbo configuration
dubbo:
  application:
    name: consumer
  registry:
    protocol: zookeeper   # dubbo/zookeeper agreement
    #address: 127.0.0.1:2183 # ZooKeeper protocol configuration
    The zookeeper protocol is configured to test whether zK supports remote calls
    # address: zookeeper: / / 127.0.0.1:2183 # dubbo protocol configuration
    # address: zookeeper: / / 127.0.0.1:2183? Backup = 127.0.0.1:2184127.00 0.1:2185 # dubbo - zk master-slave configuration protocol configuration cluster method
    address: 127.0. 01.: 2183127.00 0.1:2184127.00 0.1:2185  Zk non-master/slave configuration
  interface:
    version: 1.0. 0
  annotation:
    package: com.dist  # scan package
  consumer:
    timeout: 50000
    check: false
    version: 1.0. 0 #dubbo Default version number, displayed in the URL as default.version= XXX
Copy the code
2. Service layer (provider)- *.yML configuration: cluster configuration
# dubbo configuration
dubbo:
  application:
    name: provider
  registry:
    protocol: zookeeper  # dubbo/zookeeper agreement
    #address: 127.0.0.1:2183 # ZooKeeper protocol configuration mode
    The zookeeper protocol is configured to test whether zK supports remote calls
    # address: zookeeper: / / 127.0.0.1:2183 # dubbo protocol configuration
    # address: zookeeper: / / 127.0.0.1:2183? Backup = 127.0.0.1:2184127.00 0.1:2185 # dubbo - zk master-slave configuration protocol configuration cluster method
    address: 127.0. 01.: 2183127.00 0.1:2184127.00 0.1:2185  Zk non-master/slave configuration
  protocol:
    port: 30103
  annotation:
    package: com.dist.server
  provider:
    version: 1.0. 0 #dubbo Default version number, displayed in the URL as default.version= XXX
Copy the code

Go here to pseudo cluster test – configuration complete!

Remark:

  • The web layer protocol is the same as the service protocol. The protocol: Dubbo/Zookeeper # protocol can be called if the two protocols are inconsistent


Zookeeper security authentication

1. Why does Zookeeper require security certification?

1). The services are all on the internal network, and the Configuration of the Zookeeper cluster is based on the internal IP address. The external network does not open related ports, so Zookeeper does not need to open to the outside world. However, if services are upgraded, for example, aliyun service is purchased and the Zookeeper service needs to be opened to the outside, security authentication must be performed on Zookeeper.

2). Unauthorized access to Zookeeper (intermediate crisis, 3 places)

2. Introduction to ACL authentication

First, why do WE need acLs

To put it simply: ZooKeeper allows unauthorized access under normal circumstances, so unauthorized access vulnerabilities are exposed in security vulnerability scans. This is not allowed on heavily monitored systems, so acLs are required to control permissions.Copy the code

Since acLs are required to control permissions, what are Zookeeper permissions? The following permissions are available:

CREATE: child nodes can be created READ: node data can be obtained and child nodes can be listed WRITE: node data can be set DELETE: child nodes can be deleted ADMIN: permission can be setCopy the code

Zookeeper provides four authentication modes:

World: indicates that the whole world can access auth: indicates an authenticated user. On the CLI, you can use addauth digest user:pwdThis is the most common IP address in a service system: the user name and password are used for authenticationCopy the code

So much for the basic introduction to ACLs.

3. Perform zooKeeper operations without ACL authentication

Directly on the code: change the server address and port number! pom.xml

<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.8</version>
   <scope>test</scope>
</dependency>
Copy the code
import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class ZkConn {
	 public static void main(String[] args) 
             throws IOException, KeeperException, InterruptedException {
     /** * Create a connection to the server * Parameter 1: server address and port number (the port number is the value of the server allows clients to connect to the port number) * Parameter 2: connection session timeout * parameter 3: observer, which is triggered when the connection is successful. But it only triggers once. * The Watcher gets notifications of various events */
     ZooKeeper zk = new ZooKeeper("node005:4180".60000.new Watcher() {
         // Monitor all events that are triggered
         public void process(WatchedEvent event) {
             System.out.println("Monitor all triggered events :EVENT:"+ event.getType()); }}); System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
     // View the children of the root node
     System.out.println("View the children of the root node :ls / =>" + zk.getChildren("/".true));
     System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
     // Create a directory node
     if (zk.exists("/node".true) = =null) {
         /** * Parameter 1: path address * Parameter 2: data that you want to save needs to be converted to a byte array * Parameter 3: Access control list (ACL), parameter type is ArrayList
      
       , Ids interface provides some default values to call. * OPEN_ACL_UNSAFE This is a completely open ACL, Unsafe * CREATOR_ALL_ACL This ACL gives the * creators authentication ID's all permissions. * This ACL allows those authorized users to have permissions READ_ACL_UNSAFE This ACL gives the world the ability to read. * This ACL gives users read permissions, such as retrieving data. * Parameter 4: Type of the node to be created. Enumeration value CreateMode * PERSISTENT (0, false, false) * PERSISTENT_SEQUENTIAL (2, false, true) * Both types create PERSISTENT_SEQUENTIAL nodes that are not deleted automatically after a call. EPHEMERAL (1, true, false) * EPHEMERAL_SEQUENTIAL (3, true, true) * These two types create temporary type nodes. Automatically deletes after the return call. * The difference is that the second type creates a temporary node name followed by a monotonically increasing value. * Finally, the return value of the create() method is the actual path of the created node */
      
         zk.create("/node"."conan".getBytes(),
                 Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
         System.out.println("Create a directory node: Create/Node Conan");
         /** * View the data of the /node node, and the output should be "Conan" * parameter 1: obtain the path of the node * Parameter 2: indicate whether the node needs to be observed, set to true, and share the default observer * Parameter 3: stat class, save the node information. For example, data version information, creation time, modification time and other information */
         System.out.println(Get /node =>
                 + new String(zk.getData("/node".false.null)));
         /** * View the root node * View the root node value here, which should output the /node node */ created above
         System.out.println("View root node :ls / =>" + zk.getChildren("/".true));
     }
     System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
     // Create a subdirectory node
     if (zk.exists("/node/sub1".true) = =null) {
         zk.create("/node/sub1"."sub1".getBytes(),
                 Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
         System.out.println(Create a subdirectory node :create /node/sub1 sub1);
         // View the node
         System.out.println("View node :ls /node =>"
                 + zk.getChildren("/node".true));
     }
     System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
     /** * Change node data * change data will overwrite the last set of data * setData(). * Parameter 3: Numerical type. The version number of the numeric type that needs to be passed into the interface!! * This information can be obtained from the Stat class or from the command line. * If this value is set to -1, it ignores the version match and directly sets the value saved by the node. * /
     if (zk.exists("/node".true) != null) {
         zk.setData("/node"."changed".getBytes(), -1);
         // View /node data
         System.out.println(Modify node data :get /node =>
                 + new String(zk.getData("/node".false.null)));
     }
     System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
     // Delete a node
     if (zk.exists("/node/sub1".true) != null) {
         zk.delete("/node/sub1", -1);
         zk.delete("/node", -1);
         // Check the root node
         System.out.println("Delete node :ls / =>" + zk.getChildren("/".true));
     }
     // Close the connectionzk.close(); }}Copy the code

Authentication is only for one node

  • Authentication is only for one node

  • ACL [Access Control List] : As a distributed coordination framework, ZooKeeper stores some metadata related to the running state of the distributed system, especially related to some application scenarios such as distributed locks, Master elections and coordination. We need to ensure data security in ZooKeeper. ZooKeeper provides three modes. Permission mode, authorization object, and permission.

  • Permission mode: Scheme. Developers can use the following four permission modes: IP: IP mode Permission control is implemented based on the IP address granularity. For example, if IP is configured, 192.168.1.107 indicates that permission control is implemented for this IP address

    Digest: Digest is the most common permission control mode. It is similar to a permission identifier in the form of username: password for configuring permissions. ZooKeeper encodes formal permission identifiers twice, using sha-1 encryption algorithm and BASE64 encoding respectively

    World: World is the most open permission control mode of all time. This control mode can be thought of as a special Digest, which is just an identifier

    Super: indicates the Super user mode. In this mode, you can perform any operations on ZooKeeper

  • Authorized object: a user or a specified entity, such as an IP address or a machine, to which the permission is granted. The authorization object is different in different modes. This pattern corresponds to the permission object one by one

  • Permissions: Permission refers to the operations that can be performed after passing the permission check. In ZooKeeper, data operation permissions are classified into five categories: CREATE, DELETE, READ, WRITE, and ADMIN


4. Operation test of ZooKeeper with ACL authentication:

pom.xml

<dependency>
         <groupId>org.apache.zookeeper</groupId>
         <artifactId>zookeeper</artifactId>
		<version>3.4.8</version>
         <scope>test</scope>
     </dependency>
Copy the code

Code class :Zookeeper node authorization

package com.dist;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/** Authorization of the Zookeeper node * The authentication mode tested here is digest, which is equivalent to user:pass authentication **@author [email protected]
 * @data 2019/8/22 15:29
 */
public class ZookeeperAuth implements Watcher {

    /** Connection address */
    final static String CONNECT_ADDR = "127.0.0.1:2183";
    /** Test path */
    final static String PATH = "/testAuth";
    final static String PATH_DEL = "/testAuth/delNode";
    /** Authentication type */
    final static String authentication_type = "digest";
    /** Verify the correct method */
    final static String correctAuthentication = "123456";
    /** Authentication error method */
    final static String badAuthentication = "654321";

    static ZooKeeper zk = null;
    /** Timer */
    AtomicInteger seq = new AtomicInteger();
    /** 标识 */
    private static final String LOG_PREFIX_OF_MAIN = "【Main】";

    private CountDownLatch connectedSemaphore = new CountDownLatch(1);

    @Override
    public void process(WatchedEvent event) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (event==null) {
            return;
        }
        // Connection status
        Event.KeeperState keeperState = event.getState();
        // Event type
        Event.EventType eventType = event.getType();
        // Affected path
        String path = event.getPath();

        String logPrefix = "The Watcher -" + this.seq.incrementAndGet() + "】";

        System.out.println(logPrefix + "Received a Watcher notice");
        System.out.println(logPrefix + "Connection Status :\t" + keeperState.toString());
        System.out.println(logPrefix + "Event Type :\t" + eventType.toString());
        if (Event.KeeperState.SyncConnected == keeperState) {
            // Successfully connected to the ZK server
            if (Event.EventType.None == eventType) {
                System.out.println(logPrefix + "Successfully connected to ZK server"); connectedSemaphore.countDown(); }}else if (Event.KeeperState.Disconnected == keeperState) {
            System.out.println(logPrefix + "Disconnected from ZK server");
        } else if (Event.KeeperState.AuthFailed == keeperState) {
            System.out.println(logPrefix + "Permission check failed");
        } else if (Event.KeeperState.Expired == keeperState) {
            System.out.println(logPrefix + "Invalid session");
        }
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
    }
    /** * Create ZK connection **@paramConnectString * ZK server address list *@paramSessionTimeout * Session timeout duration */
    public void createConnection(String connectString, int sessionTimeout) {
        this.releaseConnection();
        try {
            zk = new ZooKeeper(connectString, sessionTimeout, this);
            // Add node authorization
            zk.addAuthInfo(authentication_type,correctAuthentication.getBytes());
            System.out.println(LOG_PREFIX_OF_MAIN + "Start connecting to ZK server");
            // Count down
            connectedSemaphore.await();
        } catch(Exception e) { e.printStackTrace(); }}/** * Close the ZK connection */
    public void releaseConnection(a) {
        if (this.zk! =null) {
            try {
                this.zk.close();
            } catch (InterruptedException e) {
            }
        }
    }

    / * * * * name: < B > method < / B > < B > < BR > * test function summary: < / B > < BR > * test authentication@param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        ZookeeperAuth testAuth = new ZookeeperAuth();
        testAuth.createConnection(CONNECT_ADDR,2000);
        List<ACL> acls = new ArrayList<ACL>(1);
        for (ACL ids_acl : ZooDefs.Ids.CREATOR_ALL_ACL) {
            acls.add(ids_acl);
        }

        try {
            zk.create(PATH, "init content".getBytes(), acls, CreateMode.PERSISTENT);
            System.out.println("Use authorization key:" + correctAuthentication + "Create node:"+ PATH + ", the initial content is: init content");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            zk.create(PATH_DEL, "will be deleted! ".getBytes(), acls, CreateMode.PERSISTENT);
            System.out.println("Use authorization key:" + correctAuthentication + "Create node:"+ PATH_DEL + ", initial content: Will be deleted!);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Get data
        getDataByNoAuthentication();  // Get data: do not use password
        getDataByBadAuthentication(); // Get data: use wrong password
        getDataByCorrectAuthentication();  // Use the correct password

        // Update data
        updateDataByNoAuthentication();  // Update data: do not use password
        updateDataByBadAuthentication();  // Update data: use wrong password
        updateDataByCorrectAuthentication();  // Update data: use the correct password

        // Delete data
        deleteNodeByNoAuthentication();  // Delete the node without password
        deleteNodeByBadAuthentication(); // Use the wrong password to delete the node
        deleteNodeByCorrectAuthentication();  // Delete the node with the correct password
        
        // The thread waits
        Thread.sleep(1000);

        // Delete the parent node with the correct password
        deleteParent();
        
        // Release the connection
        testAuth.releaseConnection();
    }

    /** Get data: use the wrong password */
    static void getDataByBadAuthentication(a) {
        String prefix = "[Using wrong authorization information]";
        try {
            ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000.null);
            / / authorization
            badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
            Thread.sleep(2000);
            System.out.println(prefix + "Get data:" + PATH);
            System.out.println(prefix + "Successful data acquisition:" + badzk.getData(PATH, false.null));
        } catch (Exception e) {
            System.err.println(prefix + "Failed to obtain data, cause:"+ e.getMessage()); }}/** Get data: do not use password */
    static void getDataByNoAuthentication(a) {
        String prefix = "[Do not use any authorized information]";
        try {
            System.out.println(prefix + "Get data:" + PATH);
            ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000.null);
            Thread.sleep(2000);
            System.out.println(prefix + "Successful data acquisition:" + nozk.getData(PATH, false.null));
        } catch (Exception e) {
            System.err.println(prefix + "Failed to obtain data, cause:"+ e.getMessage()); }}/** Use the correct password */
    static void getDataByCorrectAuthentication(a) {
        String prefix = "[Use the correct authorization information]";
        try {
            System.out.println(prefix + "Get data:" + PATH);

            System.out.println(prefix + "Successful data acquisition:" + zk.getData(PATH, false.null));
        } catch (Exception e) {
            System.out.println(prefix + "Failed to obtain data, cause:"+ e.getMessage()); }}/** * Update data: do not use password */
    static void updateDataByNoAuthentication(a) {

        String prefix = "[Do not use any authorized information]";

        System.out.println(prefix + "Update data:" + PATH);
        try {
            ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000.null);
            Thread.sleep(2000);
            Stat stat = nozk.exists(PATH, false);
            if(stat! =null) {
                nozk.setData(PATH, prefix.getBytes(), -1);
                System.out.println(prefix + "Update successful"); }}catch (Exception e) {
            System.err.println(prefix + "Update failed because:"+ e.getMessage()); }}/** * update data: use the wrong password */
    static void updateDataByBadAuthentication(a) {

        String prefix = "[Using wrong authorization information]";

        System.out.println(prefix + "Update data:" + PATH);
        try {
            ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000.null);
            / / authorization
            badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
            Thread.sleep(2000);
            Stat stat = badzk.exists(PATH, false);
            if(stat! =null) {
                badzk.setData(PATH, prefix.getBytes(), -1);
                System.out.println(prefix + "Update successful"); }}catch (Exception e) {
            System.err.println(prefix + "Update failed because:"+ e.getMessage()); }}/** * Update data: use the correct password */
    static void updateDataByCorrectAuthentication(a) {

        String prefix = "[Use the correct authorization information]";

        System.out.println(prefix + "Update data:" + PATH);
        try {
            Stat stat = zk.exists(PATH, false);
            if(stat! =null) {
                zk.setData(PATH, prefix.getBytes(), -1);
                System.out.println(prefix + "Update successful"); }}catch (Exception e) {
            System.err.println(prefix + "Update failed because:"+ e.getMessage()); }}/** * Delete node */ without password
    static void deleteNodeByNoAuthentication(a) throws Exception {

        String prefix = "[Do not use any authorized information]";

        try {
            System.out.println(prefix + "Delete node:" + PATH_DEL);
            ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000.null);
            Thread.sleep(2000);
            Stat stat = nozk.exists(PATH_DEL, false);
            if(stat! =null) {
                nozk.delete(PATH_DEL,-1);
                System.out.println(prefix + "Deleted successfully"); }}catch (Exception e) {
            System.err.println(prefix + "Deletion failed because:"+ e.getMessage()); }}/** * Delete node */ with incorrect password
    static void deleteNodeByBadAuthentication(a) throws Exception {

        String prefix = "[Using wrong authorization information]";

        try {
            System.out.println(prefix + "Delete node:" + PATH_DEL);
            ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000.null);
            / / authorization
            badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
            Thread.sleep(2000);
            Stat stat = badzk.exists(PATH_DEL, false);
            if(stat! =null) {
                badzk.delete(PATH_DEL, -1);
                System.out.println(prefix + "Deleted successfully"); }}catch (Exception e) {
            System.err.println(prefix + "Deletion failed because:"+ e.getMessage()); }}/** * Delete the node */ with the correct password
    static void deleteNodeByCorrectAuthentication(a) throws Exception {

        String prefix = "[Use the correct authorization information]";

        try {
            System.out.println(prefix + "Delete node:" + PATH_DEL);
            Stat stat = zk.exists(PATH_DEL, false);
            if(stat! =null) {
                zk.delete(PATH_DEL, -1);
                System.out.println(prefix + "Deleted successfully"); }}catch (Exception e) {
            System.out.println(prefix + "Deletion failed because:"+ e.getMessage()); }}/** * delete the parent node */ with the correct password
    static void deleteParent(a) throws Exception {
        String prefix = "[Use the correct authorization information]";
        try {
            Stat stat = zk.exists(PATH_DEL, false);
            if (stat == null) {
                zk.delete(PATH, -1); }}catch (Exception e) {
            System.out.println(prefix + "Failed to delete the parent node because:"+ e.getMessage()); e.printStackTrace(); }}}Copy the code

5. Zookeeper Superuser Configuration (Windows/Linux)

  • Zookeeper Configuration Superuser (Windows/Linux)

Zookeeper+Dubbo authentication

  • You can run < dubbo:registry username=”admin” password=”1234″ /> to set the ZooKeeper login information
  • You can run < dubbo: Registry group=”dubbo” /> to set the root node of ZooKeeper. If this parameter is not set, the rootless tree is used

Article 5 of the official website explains that you can set the ZooKeeper login information using the username and password fields.

However, if the ACL is set in Digest mode on Zookeeper and the user and password are configured in Dubbo Registry, the service cannot be registered with Zookeeper and a KeeperErrorCode = NoAuth error is reported. I looked at the code related to the call down and found that the ACL passed when registering the service was configured on dubbo and not found where it was used (if the registry is Zookeeper).Copy the code

However, ZookeeperRegistry related source code did not find the relevant certification, search the whole network rarely ask similar questions, this issue does not seem to be much attention.

Most of the services are deployed on the internal network, and are rarely open to the external network. However, Dubbo’s ZooKeeper user permission authentication does not seem to work. If you want to open to the outside world, you can only use IPtables or firewall for IP Access Control. If it is ali cloud server, the security group is also a good choice