Análisis diez del código fuente de Dubbo: explicación detallada de ZooKeeper y el curador del marco del cliente

Inserte la descripción de la imagen aquí

Introducción a Zookeeper

El modelo de datos de zookeeper es similar al sistema de archivos. Cada nodo se llama znode, que es la unidad de datos más pequeña en zookeeper. Cada znode puede informar datos y montar nodos secundarios para formar una estructura de atributos jerárquica.

Zookeeper puede crear los siguientes tipos de nodos

Tipo de nodo Explicación
Nodo persistente Cree un nodo como un nodo persistente, y los datos siempre se almacenarán en el servidor de zookeeper. Incluso si la sesión entre el cliente y el servidor que creó el nodo está cerrada, el nodo aún no se eliminará
Nodo de secuencia persistente Sobre la base de los nodos persistentes, se agrega el orden de los nodos
Nodo temporal Cree el nodo como un nodo temporal, los datos no siempre se almacenarán en el servidor de zookeeper, cuando se cierre la sesión del cliente que creó el nodo temporal, el nodo se eliminará en el servidor de zookeeper correspondiente
Nodo de secuencia temporal Sobre la base de los nodos temporales, se agrega el orden de los nodos

Demuestre brevemente los comandos de uso común

create [-s] [-e] path data acl

-s: crear nodos secuenciales
-e: crear nodos temporales
ruta: ruta
datos: datos
acl: permisos

Crear crea un nodo persistente de forma predeterminada

create /level-1 123
create /level-1/level-1-2 456
get /level-1(获取节点level-1的值,输出123)
ls /level-1 (获取节点level-1的子节点,输出[level-1-2]// 创建一个顺序节点
create -s /nodes 123(输出nodes0000000003)
create -s /nodes 456(输出nodes0000000004)

Después de ejecutar el comando anterior, la estructura de datos es la siguiente

Inserte la descripción de la imagen aquí
Aquí hay una breve charla sobre las características de los nodos secuenciales. Cada vez que se crea un nodo secuencial, zk agregará automáticamente un número de 10 dígitos (contador) después de la ruta, como <ruta> 0000000001, <ruta> 0000000002, ... Se puede garantizar que este contador sea único bajo el mismo nodo padre. Se utiliza un entero de 4 bytes con signo dentro de zk para representar este contador, lo que significa que cuando el tamaño del contador excede 2147483647, se producirá un desbordamiento. Cada vez que se crea un nodo temporal bajo el nodo principal, el tamaño aumenta en 1 .3 a 4 en la imagen de arriba

Uso de curador

Curator es un conjunto de cliente zookeeper de código abierto de la empresa netflix. Puede ayudarnos a simplificar la operación del guardián del zoológico. Se resolvieron muchos problemas subyacentes, como la reconexión, el registro repetido de Watcher y NodeExistsException, etc.

Además, Curator también proporciona varios escenarios de aplicación de Zookeeper: Receta, servicio de bloqueo compartido, mecanismo de elección maestra y contadores distribuidos, etc.

Curator se divide en los siguientes módulos. Los
Inserte la descripción de la imagen aquí
más utilizados son curator-framework (encapsulación de la api de zookeeper, como agregar administración de conexiones, mecanismo de reintento, etc.) y curator-recetas (implementación de escenarios de aplicación típicos de zookeeper), curator -cliente (paquete de cliente zookeeper)

Cuando lo usamos, solo necesitamos agregar las siguientes dependencias

<dependency>
  <groupId>org.apache.curator</groupId>
  <artifactId>curator-recipes</artifactId>
  <version>4.0.1</version>
</dependency>

Demuestre el uso básico de Curator Api

@Slf4j
public class ApiDemo {
    
    

    private CuratorFramework client;

    /**
     * RetryPolicy 是重试策略接口
     * https://www.cnblogs.com/qingyunzong/p/8666288.html
     */
    @Test
    @Before
    public void connect() {
    
    
        String connectString = "myhost:2181";
        // 重试3次,每次间隔1000ms
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.newClient(connectString, retryPolicy);
        client.start();
    }

    /**
     * 创建一个持久节点
     */
    @Test
    public void createPersistent() throws Exception {
    
    
        // 创建一个内容为空的节点
        client.create().forPath("/persistent");
        // 创建包含内容的节点
        client.create().forPath("/persistentContent", "我是内容".getBytes());
    }

    /**
     * 创建临时节点
     */
    @Test
    public void createEphemeral() throws Exception {
    
    
        // 创建一个内容为空的节点
        client.create().withMode(CreateMode.EPHEMERAL).forPath("Ephemeral");
        // 创建包含内容的节点
        client.create().withMode(CreateMode.EPHEMERAL).forPath("/ephemeralContent", "我是内容".getBytes());
    }

    /**
     * 获取值
     */
    @Test
    public void getData() throws Exception {
    
    
        client.getData().forPath("/persistentContent");
    }

    /**
     * 更新值
     */
    @Test
    public void setData() throws Exception {
    
    
        client.setData().forPath("/persistentContent", "新内容".getBytes());
    }

    /**
     * 删除
     */
    @Test
    public void delete() throws Exception {
    
    
        client.delete().forPath("/persistent");
    }
}

Evento detallado

Zookeeper proporciona publicación / suscripción de datos distribuidos, lo que permite al cliente registrar un observador en el servidor.Cuando algunos eventos específicos en el servidor activan al observador, se enviará una notificación de evento al cliente especificado para realizar la función de notificación distribuida.

Zookeeper define la interfaz Watcher para representar un controlador de eventos estándar y contiene
dos clases de enumeración KeeperState y EventType para representar el estado de notificación y el tipo de evento.

La relación entre KeeperState y EventType es la siguiente
Inserte la descripción de la imagen aquí
: Monitorear eventos en el servidor es una tarea importante para que el cliente opere el servidor. En la api de curator, hay dos modos de monitoreo de eventos

  1. El modo de observación estándar solo se puede monitorear una vez (es decir, la interfaz Watcher en Zookeeper. Para lanzar una excepción, el curador redefine una interfaz CuratorWatcher)
  2. Modo de monitor de caché, puede monitorizar varias veces

El modo de monitoreo de caché puede entenderse como el proceso de comparación entre la vista de caché local y la vista de guardián del zoológico remoto.Cuando se detecta el cambio de estado de znode del clúster zk, se activarán eventos y los oyentes registrados procesarán estos eventos.

Hay tres tipos de monitoreo de caché

Tipo de monitor Explicación
Caché de nodo Monitorear el nodo ZNode
Caché de ruta Supervisar los nodos secundarios de ZNode
Caché de árbol Supervisar el nodo ZNode y sus hijos

Sigue yendo directamente al ejemplo

@Test
public void watcher() throws Exception {
    
    
    Watcher watcher = new Watcher() {
    
    
        @Override
        public void process(WatchedEvent event) {
    
    
            // 只输出一次
            // /watchDemo SyncConnected NodeDataChanged
            System.out.println(event.getPath() + " " + event.getState() + " " + event.getType());
        }
    };

    String path = "/watchDemo";
    if (client.checkExists().forPath(path) == null) {
    
    
        client.create().forPath(path);
    }
    client.getData().usingWatcher(watcher).forPath(path);

    client.setData().forPath(path, "第一个变更的内容".getBytes());
    client.setData().forPath(path, "第二个变更的内容".getBytes());

    TimeUnit.SECONDS.sleep(3);
}
@Test
public void curatorWatcher() throws Exception {
    
    
    CuratorWatcher watcher = new CuratorWatcher() {
    
    
        @Override
        public void process(WatchedEvent event) throws Exception {
    
    
            // 只输出一次
            // /watchDemo SyncConnected NodeDataChanged
            System.out.println(event.getPath() + " " + event.getState() + " " + event.getType());
        }
    };

    String path = "/watchDemo";
    if (client.checkExists().forPath(path) == null) {
    
    
        client.create().forPath(path);
    }
    client.getData().usingWatcher(watcher).forPath(path);

    client.setData().forPath(path, "第一个变更的内容".getBytes());
    client.setData().forPath(path, "第二个变更的内容".getBytes());

    TimeUnit.SECONDS.sleep(3);
}

Puede ver que ya sea la interfaz de Watcher en zookeeper o la interfaz de CuratorWatcher en curator, el evento solo se puede monitorear una vez

@Test
public void treeCacheListener() throws Exception {
    
    

    String bossPath = "/treeCache";
    String workerPath = "/treeCache/id-";

    if (client.checkExists().forPath(bossPath) == null) {
    
    
        client.create().forPath(bossPath);
    }

    TreeCache treeCache = new TreeCache(client, bossPath);
    TreeCacheListener listener = ((CuratorFramework client, TreeCacheEvent event) -> {
    
    
        String path = null;
        String content = null;
        switch (event.getType()) {
    
    
            case NODE_ADDED:
                log.info("节点增加");
                path = event.getData().getPath();
                content = new String(event.getData().getData());
                break;
            case NODE_UPDATED:
                log.info("节点更新");
                path = event.getData().getPath();
                content = new String(event.getData().getData());
                break;
            case NODE_REMOVED:
                log.info("节点移除");
                path = event.getData().getPath();
                content = new String(event.getData().getData());
                break;
            default:
                break;
        }
        // 事件类型为: NODE_ADDED, 路径为: /treeCache, 内容为: 192.168.97.69
        // 事件类型为: INITIALIZED, 路径为: null, 内容为: null
        // 事件类型为: NODE_ADDED, 路径为: /treeCache/id-0, 内容为: 0
        // 事件类型为: NODE_ADDED, 路径为: /treeCache/id-1, 内容为: 1
        // 事件类型为: NODE_REMOVED, 路径为: /treeCache/id-0, 内容为: 0
        // 事件类型为: NODE_REMOVED, 路径为: /treeCache/id-1, 内容为: 1
        // 事件类型为: NODE_REMOVED, 路径为: /treeCache, 内容为: 192.168.97.69
        log.info("事件类型为: {}, 路径为: {}, 内容为: {}", event.getType(), path, content);
    });
    treeCache.getListenable().addListener(listener);
    treeCache.start();

    // 创建2个子节点
    for (int i = 0; i < 2; i++) {
    
    
        client.create().forPath(workerPath + i, String.valueOf(i).getBytes());
    }

    // 删除2个子节点
    for (int i = 0; i < 2; i++) {
    
    
        client.delete().forPath(workerPath + i);
    }

    // 删除当前节点
    client.delete().forPath(bossPath);

    TimeUnit.SECONDS.sleep(3);
}

Como puede ver, el modo de monitoreo de caché se puede registrar repetidamente

El resto del contenido de zookeeper no se introducirá mucho.Después de comprender la api de zookeeper y curator, no hay gran problema al mirar el código relacionado con zookeeper en el módulo de registro de Dubbo.

Blog de referencia

[1] https://www.cnblogs.com/crazymakercircle/p/10228385.html

Supongo que te gusta

Origin blog.csdn.net/zzti_erlie/article/details/109409326
Recomendado
Clasificación