Con el cliente de cónsul OrbitzWorld de Java, estoy tratando de sincronizar varias instancias de mi aplicación de Java a través del método acquireLock.

Mi código hasta ahora:
Aplicación de registro como servicio de cónsul:

private void registerService(Config config) {
        String serviceId = config.getService().getId();
        String serviceName = config.getService().getName();
        long ttl = config.getService().getTtl();
        AgentClient agentClient = client.agentClient();
        Registration service = ImmutableRegistration.builder()
                .id(serviceId)
                .name(serviceName)
                .check(Registration.RegCheck.ttl(ttl))
                .build();
        agentClient.register(service);
        new HeartBeater(agentClient, serviceId, ttl).start();
    }

HeartBeater:

@Override
    public void run() {
        while(true) {
            try {
                client.pass(serviceId);
                Thread.sleep((Math.max(ttl / 2, 1)));
            } catch (NotRegisteredException | InterruptedException e) {}
        }
    }

El código anterior funciona y el servicio se actualiza con éxito en el cónsul.
Ahora me pregunto sobre la implementación del bloqueo.

Lo que he escrito hasta ahora:

public boolean amILeader() {
    // return if current java app is leader
}

private String createSession() {
    final Session session = ImmutableSession.builder().name(config.getService().getName()).build();
    return client.sessionClient().createSession(session).getId();
}

private void watchLeaderLockStateChange() {
    KeyValueClient keyValueClient = client.keyValueClient();
    KVCache kvCache = KVCache.newCache(keyValueClient, Constants.LEADER_LOCK_KEY, config.getService().getWatchKey());
    kvCache.addListener(map -> {
        Value value = map.get(Constants.LEADER_LOCK_KEY);
        if(!value.getSession().isPresent()) {
            keyValueClient.acquireLock(Constants.LEADER_LOCK_KEY, ???); //create new session here ???
        }
    });
    kvCache.start();
}

Estoy atrapado aquí porque no entiendo la teoría y no he encontrado nada útil en la documentación.

Mis preguntas:

  • ¿es necesaria la sesión para sincronizar mediante el método acquireLock?
  • Si es así, ¿cuándo y cómo se debe crear / sincronizar la sesión?
  • ¿La invalidación de sesión es algo común? Según la documentación, sucede si uno de los servicios no envía ttl, lo que puede ocurrir con mucha frecuencia.
  • ¿Cómo se sincronizan los servicios vivos para crear una nueva sesión?
  • ¿Cómo se sincronizan los servicios a través del bloqueo?

¿Puede proporcionar algunos ejemplos de código o completar mi implementación? Gracias por cualquier respuesta:]

0
milkamar 21 feb. 2020 a las 17:09

2 respuestas

La mejor respuesta

Creo que lo entiendo ahora.

La teoría es así:

  • La sesión de cónsul representa una conexión de un solo servicio a cónsul. En mi caso, representa una conexión entre una de mis instancias de la aplicación Java y el Cónsul
  • la sesión se usa para adquirir el bloqueo. Cuando el cliente acude al Cónsul y desea adquirir el bloqueo, el Cónsul verificará si hay alguna ID de sesión asociada. Si no lo hay, Consul le da un bloqueo al cliente y asocia a los clientes sessionId con el bloqueo.
  • La cerradura no es nada lujoso. Es solo una clave en el mapa KV guardado en el nodo Consul.
  • puede verificar el bloqueo y, si hay algún sessionId asociado, así:
    public class SessionFacade {
        private String leaderLock;
        private String sessionId;
        private Consul client;
        private Config config;

        public SessionFacade(Consul client, Config config) {
            this.client = client;
            this.config = config;
            this.leaderLock = "service/" + config.getService().getName() + "/leader";
            this.sessionId = createSession();
            new SessionHeartBeater(client, sessionId, config.getService().getSessionTtl()).start();
            watchLeaderLockStateChange(sessionId);
            client.keyValueClient().acquireLock(leaderLock, sessionId);
        }

        public boolean doIPossesLeaderLock() {
            Optional<Value> leaderValue = client.keyValueClient().getValue(leaderLock);
            if(leaderValue.isPresent()) {
                Optional<String> session = leaderValue.get().getSession();
                return session.isPresent() && session.get().equals(sessionId);
            }
            return false;
        }

        private String createSession() {
            int sessionTtl = config.getService().getSessionTtl();
            final Session session = ImmutableSession.builder()
                    .name(config.getService().getName())
                    .ttl(sessionTtl + "s")
                    .build();
            return client.sessionClient().createSession(session).getId();
        }

        private void watchLeaderLockStateChange(String sessionId) {
            KeyValueClient keyValueClient = client.keyValueClient();
            KVCache kvCache = KVCache.newCache(keyValueClient, leaderLock, config.getService().getWatchLockEach());
            kvCache.addListener(map -> {
                Value value = map.get(leaderLock);
                if(!value.getSession().isPresent()) {
                    keyValueClient.acquireLock(leaderLock, sessionId);
                }
            });
            kvCache.start();
        }
    }

Tenga en cuenta que el código probablemente tenga errores, ya que aún no lo he probado completamente.

0
milkamar 21 feb. 2020 a las 16:58

¿Ha leído https://learn.hashicorp.com/consul/developer-configuration/ elecciones todavía? Recorre este escenario en el nivel de una aplicación que utiliza Cónsul para las elecciones de líderes.

0
chucky_z 23 feb. 2020 a las 07:35