Control de Concurrencia Distribuida


He estado trabajando en esto durante unos días, y he encontrado varias soluciones, pero ninguna de ellas increíblemente simple o liviana. El problema es básicamente este: Tenemos un grupo de 10 máquinas, cada una de las cuales está ejecutando el mismo software en una plataforma ESB multiproceso. Puedo lidiar con problemas de concurrencia entre subprocesos en la misma máquina con bastante facilidad, pero ¿qué pasa con la concurrencia en los mismos datos en diferentes máquinas?

Esencialmente, el software recibe solicitudes para alimentar los datos de un cliente de una empresa a otra a través de servicios web. Sin embargo, el cliente puede o no existir todavía en el otro sistema. Si no lo hace, lo creamos a través de un método de servicio web. Así que requiere una especie de prueba y puesta en marcha, pero necesito un semáforo de algún tipo para evitar que las otras máquinas causen condiciones de carrera. He tenido situaciones antes en las que un cliente remoto se creó dos veces para un solo cliente local, lo cual no es realmente deseable.

Soluciones con las que he jugado conceptualmente son:

  1. Usando nuestro sistema de archivos compartidos tolerantes a fallos para crear archivos de "bloqueo" que serán comprobados por cada máquina dependiendo del cliente

  2. Usando una tabla especial en nuestra base de datos, y bloqueando toda la tabla para hacer un "test-and-set" para un registro de bloqueo.

  3. Utilizando Terracotta, un software de servidor de código abierto que ayuda a escalar, pero utiliza un modelo de concentrador y radio.

  4. Uso de EHCache para síncronos replicación de mis cerraduras "in-memory"."

No puedo imaginar que soy la única persona que ha tenido este tipo de problema. ¿Cómo lo resolviste? ¿Cocinaste algo en casa o tienes un producto favorito de 3rd-party?

Author: Anony-Mousse, 2008-09-18

13 answers

Es posible que desee considerar el uso de Hazelcast bloqueos distribuidos. Super lite y fácil.

java.util.concurrent.locks.Lock lock = Hazelcast.getLock ("mymonitor");
lock.lock ();
try {
// do your stuff
}finally {
   lock.unlock();
}

Hazelcast-Cola distribuida, Map, Set, List, Lock

 34
Author: ROMANIA_engineer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-23 12:11:49

Usamos Terracota, así que me gustaría votar a favor.

He estado siguiendo Hazelcast y parece otra tecnología prometedora, pero no puedo votar por ella ya que no la he utilizado, y sabiendo que utiliza un sistema basado en P2P en su oído, realmente no confiaría en él para grandes necesidades de escala.

Pero también he oído hablar de Zookeeper, que salió de Yahoo, y se está moviendo bajo el paraguas de Hadoop. Si eres aventurero probando alguna nueva tecnología, esto realmente tiene un montón de promételo ya que es muy delgado y mezquino, centrándose solo en la coordinación. Me gusta la visión y la promesa, aunque podría ser demasiado verde todavía.

 13
Author: fern,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-17 03:17:08

Terracotta está más cerca de un modelo "estratificado": todas las aplicaciones cliente hablan con una matriz de servidores Terracotta (y lo más importante para la escala, no se hablan entre sí). El Array Terracotta Server es capaz de ser agrupado tanto para la escala como para la disponibilidad (mirrored, para la disponibilidad, y striped, para la escala).

En cualquier caso, como probablemente sepa, Terracotta le da la capacidad de expresar concurrencia a través del clúster de la misma manera que lo hace en una sola JVM mediante el uso de POJO sincronizado / esperar / notificar o utilizando cualquiera de los java.útil.primitivas concurrentes como ReentrantReadWriteLock, CyclicBarrier, AtomicLong, FutureTask y así sucesivamente.

Hay muchas recetas simples que demuestran el uso de estas primitivas en el Libro de cocina de Terracota.

Como ejemplo, publicaré el ejemplo ReentrantReadWriteLock (tenga en cuenta que no hay una versión "Terracota" del bloqueo, solo use Java ReentrantReadWriteLock normal)

import java.util.concurrent.locks.*;

public class Main
{
    public static final Main instance = new Main();
    private int counter = 0;
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(true);

    public void read()
    {
        while (true) {
            rwl.readLock().lock();
                try {
                System.out.println("Counter is " + counter);
            } finally {
                rwl.readLock().unlock();
            }
            try { Thread.currentThread().sleep(1000); } catch (InterruptedException ie) {  }
        }
    }

    public void write()
    {
        while (true) {
            rwl.writeLock().lock();
            try {
               counter++;
               System.out.println("Incrementing counter.  Counter is " + counter);
            } finally {
                 rwl.writeLock().unlock();
            }
            try { Thread.currentThread().sleep(3000); } catch (InterruptedException ie) {  }
        }
    }

    public static void main(String[] args)
    {
        if (args.length > 0)  {
            // args --> Writer
            instance.write();
        } else {
            // no args --> Reader
            instance.read();
        }
    }
}
 4
Author: Taylor Gautier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-19 21:03:51

Recomiendo usar Redisson. Implementa más de 30 estructuras y servicios de datos distribuidos, incluyendo java.util.Lock. Ejemplo de uso:

Config config = new Config();
config.addAddress("some.server.com:8291");
Redisson redisson = Redisson.create(config);

Lock lock = redisson.getLock("anyLock");
lock.lock();
try {
    ...
} finally {
   lock.unlock();
}

redisson.shutdown();
 3
Author: Nikita Koksharov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-19 18:56:00

Iba a aconsejar sobre el uso de memcached como un almacenamiento RAM muy rápido y distribuido para mantener registros; pero parece que EHCache es un proyecto similar pero más centrado en java.

Cualquiera de los dos es el camino a seguir, siempre y cuando esté seguro de usar actualizaciones atómicas (memcached las soporta, no sabe sobre EHCache). Es, con mucho, la solución más escalable.

Como punto de datos relacionado, Google utiliza 'Chubby', un almacenamiento de bloqueo distribuido rápido basado en RAM como la raíz de varios sistemas, entre ellos BigTable.

 2
Author: Javier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-17 03:36:17

He hecho mucho trabajo con Coherence, lo que permitió varios enfoques para implementar un bloqueo distribuido. El enfoque ingenuo fue solicitar bloquear el mismo objeto lógico en todos los nodos participantes. En términos de coherencia, esto estaba bloqueando una clave en una caché replicada. Este enfoque no escala tan bien porque el tráfico de red aumenta linealmente a medida que agrega nodos. Una forma más inteligente era usar una caché distribuida, donde cada nodo en el clúster es naturalmente responsable de una parte de el espacio de claves, por lo que bloquear una clave en una caché de este tipo siempre implicaba la comunicación con, como máximo, un nodo. Usted podría rodar su propio acercamiento basado en esta idea, o mejor aún, conseguir Coherencia. Realmente es el kit de herramientas de escalabilidad de sus sueños.

Yo añadiría que cualquier mecanismo de bloqueo basado en la red multi-nodo medio decente tendría que ser razonablemente sofisticado para actuar correctamente en el caso de cualquier fallo de la red.

 1
Author: Craig Day,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 13:42:39

¿No está seguro de si entiendo todo el contexto, pero suena como si tuviera 1 base de datos única respaldando esto? ¿Por qué no hacer uso del bloqueo de la base de datos: si la creación del cliente es una sola INSERCIÓN, entonces esta declaración por sí sola puede servir como un bloqueo, ya que la base de datos rechazará una segunda INSERCIÓN que violaría una de sus restricciones (por ejemplo, el hecho de que el nombre del cliente es único, por ejemplo).

Si la operación" inserción de un cliente " no es atómica y es un lote de declaraciones, entonces Introduciría (o usaría) una INSERCIÓN inicial que crea un registro básico simple que identifica a su cliente (con las restricciones de singularidad necesarias) y luego haría todas las otras inserciones/actualizaciones en la misma transacción. Una vez más, la base de datos se encargará de la coherencia y cualquier modificación concurrente resultará en que una de ellas falle.

 1
Author: Boris Terzic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 13:50:31

Hice un servicio RMI simple con dos métodos: bloquear y liberar. ambos métodos toman una clave (mi modelo de datos utiliza UUIDs como pk por lo que también era la clave de bloqueo).

RMI es una buena solución para esto porque está centralizado. no puede hacer esto con EJBs (especialmente en un clúster, ya que no sabe en qué máquina aterrizará su llamada). además, es fácil.

Funcionó para mí.

 0
Author: entzik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 13:33:44

Si puede configurar su equilibrio de carga para que las solicitudes de un solo cliente siempre se asignen al mismo servidor, entonces puede manejar esto a través de la sincronización local. Por ejemplo, tome su ID de cliente mod 10 para encontrar cuál de los 10 nodos usar.

Incluso si no desea hacer esto en el caso general, sus nodos podrían proxy entre sí para este tipo específico de solicitud.

Asumiendo que tus usuarios son lo suficientemente uniformes (es decir, si tienes un montón de ellos) que no esperas puntos calientes para aparecer donde un nodo se sobrecarga, esto aún debería escalar bastante bien.

 0
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-16 07:27:11

También podría considerar Cacheonix para bloqueos distribuidos. A diferencia de cualquier otra cosa mencionada aquí Cacheonix soporta bloqueos ReadWrite con escalado de bloqueo de lectura a escritura cuando sea necesario:

ReadWriteLock rwLock = Cacheonix.getInstance().getCluster().getReadWriteLock();
Lock lock = rwLock.getWriteLock();
try {
  ...
} finally {
  lock.unlock();
}

Divulgación completa: Soy un desarrollador de Cacheonix.

 0
Author: Slava Imeshev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-26 16:54:37

Dado que ya se está conectando a una base de datos, antes de agregar otra pieza infra, eche un vistazo a JdbcSemaphore , es fácil de usar:

JdbcSemaphore semaphore = new JdbcSemaphore(ds, semName, maxReservations);
boolean acq = semaphore.acquire(acquire, 1, TimeUnit.MINUTES);
if (acq) {
 // do stuff
 semaphore.release();
} else {
  throw new TimeoutException();
}

Es parte de la biblioteca spf4j.

 0
Author: user2179737,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-23 01:01:11

Antes, usábamos un "servidor de bloqueo" específico en la red para manejar esto. Bleh.

Su servidor de base de datos puede tener recursos específicamente para hacer este tipo de cosas. MS-SQL Server tiene bloqueos de aplicaciones utilizables a través del sp_getaplock/procedimientos sp_releaseapplock.

 -1
Author: Clinton Pierce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 13:28:14

Hemos estado desarrollando un framework de sincronización distribuida de código abierto, actualmente DistributedReentrantLock y DistributedReentrantReadWrite lock se ha implementado, pero todavía están en fase de prueba y refactorización. En nuestra arquitectura, las teclas de bloqueo se dividen en cubos y cada nodo es resonable para cierto número de cubos. Tan efectivamente para una solicitud de bloqueo exitosa, solo hay una solicitud de red. También estamos utilizando la clase AbstractQueuedSynchronizer como estado de bloqueo local, por lo tanto, todas las solicitudes de bloqueo fallidas se manejan localmente, esto reduce drásticamente el tráfico de red. Estamos usando JGroups ( http://jgroups.org ) para comunicación grupal y Hessian para serialización.

Para obtener más información, consulte http://code.google.com/p/vitrit/.

Por favor envíenme sus valiosos comentarios.

Kamran

 -5
Author: Kamran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-08 08:45:35