1 conejo MQ
1.1 Introducción
1.1.1 Conceptos básicos
-
Broker: En pocas palabras, es la entidad del servidor de cola de mensajes.
-
Vinculante: vinculante, su función es vincular el intercambio y la cola de acuerdo con las reglas de enrutamiento.
-
Clave de enrutamiento: clave de enrutamiento, el intercambio entrega mensajes de acuerdo con esta clave.
-
vhost: host virtual, se pueden configurar múltiples vhosts en un intermediario para separar los permisos de diferentes usuarios.
-
productor: El productor de mensajes es el programa que entrega el mensaje.
-
Consumidor: El consumidor de mensajes es el programa que recibe el mensaje.
-
canal: Canal de mensajes En cada conexión de cliente se pueden establecer múltiples canales y cada canal representa una tarea de sesión.
1.1.2 Tres tipos de intercambio
-
directo: el
mensaje se enruta a una cola específica mediante la clave de enrutamiento Hay un intercambio predeterminado en el sistema
, el nombre es una cadena vacía y el mensaje se enruta de acuerdo con la clave de enrutamiento. -
tema: coincidir con comodines de * y #, * (asterisco) puede sustituir exactamente una
palabra, # (hash) puede sustituir a cero o más palabras. -
fanout: envía mensajes a todas las colas, ignorando routing_key
1.1.3 Alta disponibilidad del clúster
Para garantizar la alta disponibilidad del clúster, generalmente se utilizan colas duplicadas. La cola duplicada se compone de un maestro y varios esclavos. Hay tres tipos de modo ha:
-
all: espejo para todos los nodos
-
exactamente: reflejado en el número especificado de nodos
-
nodos: espejo del nodo especificado
1.2 Uso
Las versiones utilizadas por RabbitMQ son las siguientes:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.2.0</version>
</dependency>
1.2.1 Crear conexión TCP
ConnectionFactory factory = new ConnectionFactory();
connectionFactory.setAutomaticRecoveryEnabled(true);// 故障自动重连
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
ThreadPoolExecutor executor=xxx;//用于执行consumer的线程池
Connection conn = factory.newConnection(executor);
1.2.2 Producción
Channel channel = conn.createChannel();
channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments);
//durable-持久 ,exclusive-无连接自动删除队列 ,autoDelete-不使用自动删除队列
channel.confirmSelect() //设置确认机制
BasicProperties props = queueConfig.isDurable() ? MessageProperties.MINIMAL_PERSISTENT_BASIC: MessageProperties.MINIMAL_BASIC
channel.basicPublish(String exchange, String routingKey,BasicProperties props, byte[] body);//发送消息
channel.waitForConfirms(long timeout)// 等待队列发送确认
1.2.3 Consumo
Channel channel = conn.createChannel();
channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments);
channel.basicQos() //流控
channel.basicConsume(queueName, autoAck, "myConsumerTag", //autoAck=false queue等consumer 发送确认才删除消息
new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException
{
String routingKey = envelope.getRoutingKey();
String contentType = properties.getContentType();
long deliveryTag = envelope.getDeliveryTag();
// (process the message components here ...)
channel.basicAck(deliveryTag, false); //void basicAck(long deliveryTag, boolean multiple) throws IOException; multiple表示是否一次确认多个
}
});
1.2.4 Asuntos que requieren atención
-
El canal se puede almacenar en caché para garantizar el rendimiento
-
La concurrencia de consumidores está determinada por el número de canales y el menor número de subprocesos en el grupo de subprocesos.
-
queueDeclare se puede llamar repetidamente y la existencia de la cola está garantizada
-
Cuando falla el consumo de mensajes, existen las siguientes estrategias de procesamiento
basicNack(deliveryTag, false, true)
队列中的消息会被派发到别的consumer,做出此响应的consumer仍然可以收到消息,直到所有消息完成
basicNack(deliveryTag, false, false)
做出此响应的consumer仍然可以收到消息,直到所有消息完成,但是失败的消息不会再出现在队列
无动作
消息处于没确定状态(对队列来讲),消息不会被派发给别的消费者(当该consumer被取消注册以后,消息被派发给别的consumer)
2 Redis
Versión 2.1
Redis generalmente usa el cliente Jedis e introduce dependencias de la siguiente manera:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
2.2 Cómo utilizar
Hay muchas formas de usar Redis, y el método de operación específico se puede encontrar en https://redis.io/commands.
Los códigos de muestra se pueden encontrar en
https://github.com/xetorthio/jedis/tree/master/src/test/java/redis/clients/jedis/tests
.
2.2.1 Nodo único
//初始化链接
HostAndPort hnp = xxx ;
Jedis jedis = new Jedis(hnp.getHost(), hnp.getPort(), 500);
jedis.connect();
jedis.auth("xxx");
//操作
String status = jedis.set("foo", "bar");
assertEquals("OK", status);
//关闭链接
jedis.disconnect();
-
new Jedis(hnp.getHost(), hnp.getPort(), 500)
Usado para inicializar el objeto jedis, existen múltiples métodos sobrecargados, principalmente usados para establecer parámetros de tiempo de espera de TCP -
jedis.connect()
Se utiliza para mostrar el establecimiento del enlace TCP, y es posible que la llamada no se muestre, y el establecimiento de TCP estará garantizado cuando se envíen comandos internos. -
Las siguientes operaciones de Redis están usando
Jedis
objetos y se realizaJedis
una capa de encapsulación.
Si desea utilizar Pool para administrar la conexión, puede hacerlo.
JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000);
Jedis jedis = pool.getResource();
jedis.close();
pool.close();
2.2.2 Hash consistente
//初始化
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(2);
JedisShardInfo shard1 = new JedisShardInfo(redis1.getHost(), redis1.getPort());
shard1.setPassword("foobared");
shards.add(shard1);
JedisShardInfo shard2 = new JedisShardInfo(redis2.getHost(), redis2.getPort());
shard2.setPassword("foobared");
shards.add(shard2);
ShardedJedis jedis = new ShardedJedis(shards);
//操作
String status = jedis.set("foo", "bar");
assertEquals("OK", status);
//关闭链接
jedis.close();
-
JedisShardInfo
Información diversa utilizada para especificar fragmentos -
ShardedJedis(List<JedisShardInfo> shards, Hashing algo)
Se puede especificar el algoritmo hash
Si desea utilizar Pool para administrar la conexión, puede hacerlo.
List<JedisShardInfo> shards = xxx;
ShardedJedisPool pool = new ShardedJedisPool(new GenericObjectPoolConfig(), shards);
ShardedJedis jedis = pool.getResource();
Jedis jedis = pool.getResource();
jedis.close();
pool.close();
2.2.3 Centinela
// 初始化
HostAndPort sentinel1 = xxx;
HostAndPort sentinel2 = xxx;
Set<String> sentinels = new HashSet<String>();
sentinels.add(sentinel1.toString());
sentinels.add(sentinel2.toString());
JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels,
new GenericObjectPoolConfig(), 2000, "foobared", 2);
// 获取Jedis
Jedis borrowed = pool.getResource();
borrowed.set("foo", "bar");
borrowed.close();
// 释放资源
pool.close();
3 Guardián del zoológico
3.1 Introducción
Zookeeper es un pequeño sistema de archivos distribuido y está diseñado para una alta disponibilidad. Los puntos únicos de falla se pueden evitar mediante algoritmos de elección y replicación de clústeres. Por lo general, Zookeeper consta de 2n + 1 servidores, y cada servidor conoce la existencia de los demás. Cada servidor mantiene la duplicación del estado de la memoria y el almacenamiento persistente de los registros de transacciones y las instantáneas.
3.1.1 Modelo de datos
Zookeeper tiene un espacio de nombres jerárquico, que es muy similar a un sistema de archivos distribuido. La diferencia es el Znode en el espacio de nombres de ZooKeeper, que tiene características de archivo y directorio. No solo mantiene estructuras de datos como datos, metainformación, ACL y marca de tiempo como un archivo, sino que también se puede usar como parte de la identificación de ruta como un directorio y puede tener subznodes. Los usuarios pueden agregar, eliminar, modificar y verificar znodes.
Cada nodo del árbol de directorios de ZooKeeper corresponde a un Znode. Cada Znode mantiene una estructura de atributos, que contiene información de estado, como el número de versión (dataVersion), la marca de tiempo (ctime, mtime), etc.
3.1.2 Rol
-
Líder, responsable del inicio y resolución de la votación, y actualizar el estado del sistema.
-
Alumno, incluidos seguidores y observadores,
-
Seguidor, utilizado para aceptar solicitudes de clientes y devolver resultados al cliente, participar en la votación en el proceso de elección del maestro.
-
El observador puede aceptar solicitudes de clientes y enviar solicitudes de escritura al líder, pero el observador no participa en el proceso de votación y solo sincroniza el estado del líder. El propósito del observador es expandir el sistema y mejorar la velocidad de lectura.
-
Cliente, iniciador de solicitudes
3.2 API básica
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
Todos los códigos de muestra se pueden encontrar en
https://github.com/apache/curator/tree/master/curator-framework/src/test/java/org/apache/curator/framework/imps
.
3.2.1 Crear sesión
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3)
CuratorFramework client =
CuratorFrameworkFactory.builder()
.connectString(connectionInfo)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
client.start();
3.2.2 Crear nodo
Modo de creación de nodos de Zookeeper
PERSISTENT: persistente
PERSISTENT_SEQUENTIAL: persistente con número de serie
EPHEMERAL: temporal
EPHEMERAL_SEQUENTIAL: temporal con número de serie
client.create().forPath("/my/path", myData)
client.create().creatingParentsIfNeeded().forPath("/my/path", myData);//递归创建
client.create().withMode(CreateMode.EPHEMERAL).forPath("path");
3.2.3 Eliminar nodo
client.delete().forPath("/my/path"); //只删除叶子节点
client.delete().deletingChildrenIfNeeded().forPath("path"); //递归删除其所有的子节点
3.2.4 Obtener nodos secundarios
client.getChildren().forPath("/")
3.2.5 Leer datos
client.getData().forPath("path");//此方法返的返回值是byte[];
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath("path");//读取一个节点的数据内容,同时获取到该节点的stat
3.2.6 Actualizar datos
client.setData().forPath("path","data".getBytes());
3.2.7 Verifique si el nodo existe
client.checkExists().forPath("path");
3.2.8 Ejecución asincrónica
Si el inBackground()
método no especifica un ejecutor, el EventThread de Curator se utilizará de forma predeterminada para el procesamiento asincrónico.
Executor executor = Executors.newFixedThreadPool(2);
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.inBackground((curatorFramework, curatorEvent) -> {
System.out.println(String.format("eventType:%s,resultCode:%s",curatorEvent.getType(),curatorEvent.getResultCode()));
},executor)
.forPath("path");
3.3 API avanzada
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
Todos los códigos de muestra se pueden encontrar en
https://github.com/apache/curator/tree/master/curator-recipes/src/test/java/org/apache/curator/framework/recipes
.
3.3.1 Seguimiento
3.3.1.1 PathChildrenCache
Cuando se agrega, actualiza o elimina un nodo secundario, Path Cache cambiará su estado,
incluido el último nodo secundario,
los datos y el estado del nodo secundario, y el cambio de estado se notificará a través de PathChildrenCacheListener.
Timing timing = new Timing();
CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), new RetryOneTime(1));
PathChildrenCache cache = new PathChildrenCache(client, "/a/b/test", true);
try
{
client.start();
final BlockingQueue<PathChildrenCacheEvent.Type> events = Queues.newLinkedBlockingQueue();
PathChildrenCacheListener listener = new PathChildrenCacheListener()
{
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception
{
events.add(event.getType());
}
};
cache.getListenable().addListener(listener);
cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.CONNECTION_RECONNECTED);
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.INITIALIZED);
client.create().forPath("/a/b/test/one");
client.create().forPath("/a/b/test/two");
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.CHILD_ADDED);
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.CHILD_ADDED);
client.delete().forPath("/a/b/test/one");
client.delete().forPath("/a/b/test/two");
client.delete().forPath("/a/b/test");
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.CHILD_REMOVED);
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.CHILD_REMOVED);
timing.sleepABit();
client.create().creatingParentContainersIfNeeded().forPath("/a/b/test/new");
Assert.assertEquals(events.poll(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS), PathChildrenCacheEvent.Type.CHILD_ADDED);
}
finally
{
CloseableUtils.closeQuietly(cache);
CloseableUtils.closeQuietly(client);
}
3.3.1.2 NodeCache
Node Cache solo monitorea un nodo específico.
NodeCache cache = null;
Timing timing = new Timing();
CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
client.start();
try
{
client.create().forPath("/test");
cache = new NodeCache(client, "/test/node");
cache.start(true);
final Semaphore semaphore = new Semaphore(0);
cache.getListenable().addListener
(
new NodeCacheListener()
{
@Override
public void nodeChanged() throws Exception
{
semaphore.release();
}
}
);
Assert.assertNull(cache.getCurrentData());
client.create().forPath("/test/node", "a".getBytes());
Assert.assertTrue(timing.acquireSemaphore(semaphore));
Assert.assertEquals(cache.getCurrentData().getData(), "a".getBytes());
client.setData().forPath("/test/node", "b".getBytes());
Assert.assertTrue(timing.acquireSemaphore(semaphore));
Assert.assertEquals(cache.getCurrentData().getData(), "b".getBytes());
client.delete().forPath("/test/node");
Assert.assertTrue(timing.acquireSemaphore(semaphore));
Assert.assertNull(cache.getCurrentData());
}
finally
{
CloseableUtils.closeQuietly(cache);
TestCleanState.closeAndTestClean(client);
}
3.3.1.3 TreeCache
Tree Cache puede monitorear todos los nodos en todo el árbol, similar a la combinación de PathCache y NodeCache.
3.3.2 Elección de líder
3.3.2.1 LeaderLatch
El constructor es el siguiente:
public LeaderLatch(CuratorFramework client, String latchPath)
public LeaderLatch(CuratorFramework client, String latchPath, String id)
El método principal ::
start()
iniciar la elección
hasLeadership()
: determinar si actualmente es líder
await()
: no regresar hasta convertirse en líder
close()
: liberar LeaderShip
Manejo de excepciones: la
instancia de LeaderLatch puede agregar ConnectionStateListener para monitorear los problemas de conexión de red. Cuando está SUSPENDIDO
o PERDIDO, el
líder ya no piensa que sigue siendo el líder. Cuando la conexión después de LOST se vuelve a conectar y se vuelve a conectar, LeaderLatch eliminará el ZNode anterior y creará uno nuevo.
Vea el código de muestra:
TestLeaderLatch
3.3.2.2 LeaderSelector
El constructor es el siguiente:
public LeaderSelector(CuratorFramework client, String mutexPath,LeaderSelectorListener listener)
public LeaderSelector(CuratorFramework client, String mutexPath, ThreadFactory threadFactory, Executor executor, LeaderSelectorListener listener)
Métodos principales:
start()
Iniciar elección
takeLeadership()
: se llama cuando la instancia obtiene el liderazgo y libera el liderazgo cuando regresa
autoRequeue()
: la llamada al método garantiza que la instancia también puede obtener el liderazgo después de que se libera el liderazgo.
close()
: Lanzamiento LeaderShip
Manejo de excepciones: la
clase LeaderSelectorListener hereda ConnectionStateListener . LeaderSelector debe tener cuidado con los
cambios en el estado de la conexión . Si la instancia se convierte en el líder, debe corresponder a SUSPENDED o LOST. Cuando aparece el estado SUSPENDED, la
instancia debe asumir que ya no puede ser el líder antes de que la reconexión sea exitosa. Si aparece el estado PERDIDO, la
instancia ya no es el líder y el método takeLeadership regresa.
Vea el código de muestra:
TestLeaderSelector
3.3.3 Barrera
La clase DistributedBarrier implementa la función de una valla. Su constructor es el siguiente:
public DistributedBarrier(CuratorFramework client, String barrierPath)
client - client
barrierPath - path to use as the barrier
El método principal:
setBarrier()
Coloque la cerca, bloqueará los hilos que
waitOnBarrier()
esperan en ella : Espere la condición de liberación
removeBarrier()
: Retire la cerca, todos los hilos en espera continuarán ejecutándose
Manejo de excepciones:
DistributedBarrier monitoreará el estado de la conexión y el método waitOnBarrier () lanzará una excepción cuando la conexión se desconecte.
Ver código de muestra:
TestDistributedBarrier
Double Barrier
permite al cliente sincronizar al principio y al final del cálculo. Cuando se agrega suficiente progreso a la valla doble, el progreso comienza a contar, y
cuando se completa el cálculo, abandone la valla.
Vea el código de muestra:
TestDistributedDoubleBarrier
3.3.4 Contador
DistributedAtomicLong intenta configurar el contador utilizando un bloqueo optimista.
Métodos principales:
get()
Obtener el valor actual
increment()
: Sumar uno
decrement()
: Restar uno
add()
: Aumentar un valor específico
subtract()
: Restar un valor específico
trySet()
: Intentar establecer el valor de recuento
forceSet()
: Forzar el valor de recuento
Debes marcar el Successeded () que devuelve el resultado, que representa si la operación fue exitosa. Si la operación es exitosa,
preValue () representa el valor antes de la operación y postValue () representa el valor después de la operación.
Para obtener un código de muestra, consulte:
TestDistributedAtomicLong
3.3.5 Bloqueo
3.3.5.1 Bloqueo reentrante
Constructor:
public InterProcessMutex(CuratorFramework client, String path)
El método principal :: acquire()
Adquirir el bloqueo release()
: liberar el bloqueo no debe estar en
Manejo de excepciones:
use ConnectionStateListener para manejar el cambio de estado de conexión. Ya no eres dueño de la cerradura cuando te conectas a LOST.
3.3.5.2 Bloqueo no reentrante
Constructor:
public InterProcessSemaphoreMutex(CuratorFramework client, String path)