Redis - 11. Clúster (Clúster)

1. Problemas existentes

La capacidad de un solo redis es limitada, ¿cómo ampliar? ¿Continuar agregando memoria y hardware?
El volumen de escritura simultánea de un solo redis es demasiado grande y hay un cuello de botella en el rendimiento. ¿Cómo resolverlo?
Se proporcionan clústeres en redis 3.0 para resolver estos problemas.

2. ¿Qué es un clúster?

El clúster de redis es la expansión horizontal de redis, es decir, inicia N nodos de redis, distribuye y almacena todos los datos en estos N nodos, y cada nodo almacena 1/N de los datos totales.

Como se muestra en la siguiente figura: un clúster redis compuesto por 3 maestros y 3 esclavos, cada maestro asume un tercio de los datos solicitados y escritos por el cliente, cuando el maestro cuelga, el esclavo reemplazará automáticamente al maestro para lograr un alto disponibilidad.

3. ¿Cómo configurar el clúster?

3.1. Requisitos: configurar 3 clústeres maestros 3 esclavos

A continuación, configuremos un clúster con 3 maestros y 3 esclavos. Se cuelga un esclavo debajo de cada maestro. Después de que el maestro cuelgue, el esclavo será ascendido a maestro.

Para mayor comodidad, simulamos en una máquina, la ip de mi máquina es: 192.168.200.129, se distinguen 6 nodos diferentes por puerto, la información de configuración es la siguiente

3.2 Crear un directorio de trabajo de casos: clúster

Ejecute el siguiente comando para crear el directorio /opt/cluster.Todas las operaciones esta vez se realizan en el directorio del clúster.

# 方便演示,停止所有的redis
ps -ef | grep redis | awk -F" " '{print $2;}' | xargs kill -9
mkdir /opt/cluster
cd /opt/cluster/

3.3 Copie redis.conf en el directorio del clúster

redis.conf es el archivo de configuración predeterminado de redis

cp /opt/redis-6.2.1/redis.conf /opt/cluster/

3.4 Crear el archivo de configuración de master1: redis-6379.conf

Cree un archivo redis-6379.conf en el directorio /opt/cluster, el contenido es el siguiente, tenga en cuenta que 192.168.200.129 es la IP de la máquina de prueba, debe reemplazarla por la suya

include /opt/cluster/redis.conf
daemonize yes
bind 192.168.200.129
dir /opt/cluster/

port 6379
dbfilename dump_6379.rdb
pidfile /var/run/redis_6379.pid
logfile "./6379.log"

# 开启集群设置
cluster-enabled yes
# 设置节点配置文件
cluster-config-file node-6379.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000

3.5 Crear el archivo de configuración de master2: redis-6380.conf

Cree un archivo redis-6380.conf en el directorio /opt/cluster, el contenido es el siguiente, similar al maestro anterior, simplemente reemplace 6379 con 6380

include /opt/cluster/redis.conf
daemonize yes
bind 192.168.200.129
dir /opt/cluster/

port 6380
dbfilename dump_6380.rdb
pidfile /var/run/redis_6380.pid
logfile "./6380.log"

# 开启集群设置
cluster-enabled yes
# 设置节点配置文件
cluster-config-file node-6380.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000

3.6 Cree un archivo de configuración master3: redis-6381.conf

Cree un archivo redis-6381.conf en el directorio /opt/cluster con el siguiente contenido

include /opt/cluster/redis.conf
daemonize yes
bind 192.168.200.129
dir /opt/cluster/

port 6381
dbfilename dump_6381.rdb
pidfile /var/run/redis_6381.pid
logfile "./6381.log"

# 开启集群设置
cluster-enabled yes
# 设置节点配置文件
cluster-config-file node-6381.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000

3.7 Cree un archivo de configuración para slave1: redis-6389.conf

Cree un archivo redis-6389.conf en el directorio /opt/cluster con el siguiente contenido

include /opt/cluster/redis.conf
daemonize yes
bind 192.168.200.129
dir /opt/cluster/

port 6389
dbfilename dump_6389.rdb
pidfile /var/run/redis_6389.pid
logfile "./6389.log"

# 开启集群设置
cluster-enabled yes
# 设置节点配置文件
cluster-config-file node-6389.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000

3.8 Cree un archivo de configuración para slave2: redis-6390.conf

Cree un archivo redis-6390.conf en el directorio /opt/cluster con el siguiente contenido

include /opt/cluster/redis.conf
daemonize yes
bind 192.168.200.129
dir /opt/cluster/

port 6390
dbfilename dump_6390.rdb
pidfile /var/run/redis_6390.pid
logfile "./6390.log"

# 开启集群设置
cluster-enabled yes
# 设置节点配置文件
cluster-config-file node-6390.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000

3.9 Cree un archivo de configuración para slave3: redis-6391.conf

Cree un archivo redis-6391.conf en el directorio /opt/cluster con el siguiente contenido

include /opt/cluster/redis.conf
daemonize yes
bind 192.168.200.129
dir /opt/cluster/

port 6391
dbfilename dump_6391.rdb
pidfile /var/run/redis_6391.pid
logfile "./6391.log"

# 开启集群设置
cluster-enabled yes
# 设置节点配置文件
cluster-config-file node-6391.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000

3.10, iniciar maestro, esclavo1, esclavo2

# 方便演示,停止所有的redis
ps -ef | grep redis | awk -F" " '{print $2;}' | xargs kill -9
# 下面启动6个redis
redis-server /opt/cluster/redis-6379.conf
redis-server /opt/cluster/redis-6380.conf
redis-server /opt/cluster/redis-6381.conf
redis-server /opt/cluster/redis-6389.conf
redis-server /opt/cluster/redis-6390.conf
redis-server /opt/cluster/redis-6391.conf

3.11 Comprobar el estado de inicio de 6 redis

ps -ef | grep redis

3.12 Asegúrese de que el archivo node-xxxx.conf se haya generado normalmente

Más tarde fusionaremos 6 instancias en un clúster. Antes de combinar, debemos asegurarnos de que después de que se inicien las 6 instancias de redis, los archivos nodes-xxxx.conf se generen normalmente, de la siguiente manera, el directorio /opt/cluster se genera correctamente

3.13 Sintetizar 6 nodos en un clúster

Ejecute el siguiente comando para combinar 6 redis

/opt/redis-6.2.1/src/redis-cli --cluster create --cluster-replicas 1192.168.200.129:6379 192.168.200.129:6380 192.168.200.129:6381 192.168.200.129:6389 192.168.200.129:6390 192.168.200.129:6391
  • El comando combinado será seguido por la lista ip:port de todos los nodos, y los múltiplos están separados por espacios.Tenga en cuenta que la ip no debe escribir 127.0.0.1, pero la ip real
  • --cluster-replicas 1: Indica que el clúster está configurado de la manera más simple, es decir, cada maestro está equipado con 1 esclavo y 6 nodos forman 3 maestros y 3 esclavos

 El proceso de ejecución es el siguiente, durante el cual determinaremos si el método de asignación es el mismo, ingrese: sí, y luego espere unos segundos, la integración del clúster es exitosa

[root@hspEdu01 src]# redis-cli --cluster create --cluster-replicas 1 192.168.200.129:6379 192.168.200.129:6380 192.168.200.129:6381 192.168.200.129:6389 192.168.200.129:6390 192.168.200.129:6391
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.200.129:6390 to 192.168.200.129:6379
Adding replica 192.168.200.129:6391 to 192.168.200.129:6380
Adding replica 192.168.200.129:6389 to 192.168.200.129:6381
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: ccf3abb791e026380ad3ad2a166aa788df738437 192.168.200.129:6379
slots:[0-5460] (5461 slots) master
M: 3c372392d5a91dad64a6febadfe9524ea2cbd8c0 192.168.200.129:6380
slots:[5461-10922] (5462 slots) master
M: 2c905be9c975be367bd66c962167beca1ef66af3 192.168.200.129:6381
slots:[10923-16383] (5461 slots) master
S: 4a0f860081b969162767aac26801994de54d80a5 192.168.200.129:6389
replicates ccf3abb791e026380ad3ad2a166aa788df738437
S: 62c9f37a362459c212e8af6dd744b6562f5fe6a7 192.168.200.129:6390
replicates 3c372392d5a91dad64a6febadfe9524ea2cbd8c0
S: a2f89efc09681520f9d9502707b18e1f46a40b90 192.168.200.129:6391
replicates 2c905be9c975be367bd66c962167beca1ef66af3
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 192.168.200.129:6379)
M: ccf3abb791e026380ad3ad2a166aa788df738437 192.168.200.129:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 2c905be9c975be367bd66c962167beca1ef66af3 192.168.200.129:6381
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 62c9f37a362459c212e8af6dd744b6562f5fe6a7 192.168.200.129:6390
slots: (0 slots) slave
replicates 3c372392d5a91dad64a6febadfe9524ea2cbd8c0
M: 3c372392d5a91dad64a6febadfe9524ea2cbd8c0 192.168.200.129:6380
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 4a0f860081b969162767aac26801994de54d80a5 192.168.200.129:6389
slots: (0 slots) slave
replicates ccf3abb791e026380ad3ad2a166aa788df738437
S: a2f89efc09681520f9d9502707b18e1f46a40b90 192.168.200.129:6391
slots: (0 slots) slave
replicates 2c905be9c975be367bd66c962167beca1ef66af3
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

3.14 Conéctese a los nodos del clúster y vea la información del clúster: nodos del clúster

Debe usar el comando redis-cli -c para conectarse a cualquiera de los 6 nodos en el clúster. Tenga en cuenta que es un poco diferente de los parámetros de conexión anteriores. Hay un parámetro -c adicional después del comando redis-cli, lo que significa que el clúster se usa para conectarse. Más tarde, use clusternodes para ver la información del nodo del clúster, de la siguiente manera

192.168.200.129:6379> cluster nodes
2c905be9c975be367bd66c962167beca1ef66af3 192.168.200.129:6381@16381 master - 0
1650194157604 3 connected 10923-16383
62c9f37a362459c212e8af6dd744b6562f5fe6a7 192.168.200.129:6390@16390 slave
3c372392d5a91dad64a6febadfe9524ea2cbd8c0 0 1650194158611 2 connected
3c372392d5a91dad64a6febadfe9524ea2cbd8c0 192.168.200.129:6380@16380 master - 0
1650194158000 2 connected 5461-10922
4a0f860081b969162767aac26801994de54d80a5 192.168.200.129:6389@16389 slave
ccf3abb791e026380ad3ad2a166aa788df738437 0 1650194156000 1 connected
ccf3abb791e026380ad3ad2a166aa788df738437 192.168.200.129:6379@16379
myself,master - 0 1650194157000 1 connected 0-5460
a2f89efc09681520f9d9502707b18e1f46a40b90 192.168.200.129:6391@16391 slave
2c905be9c975be367bd66c962167beca1ef66af3 0 1650194159617 3 connected
192.168.200.129:6379>

Como se muestra en la siguiente figura, explique los resultados de los nodos del clúster. Primero, mire las notas en rojo. Cada nodo del clúster generará una ID, y esta información de ID se escribirá en el archivo node-xxxx.conf. ¿Por qué? generar una identificación? ?

Porque la ip y el puerto del nodo pueden cambiar, pero la ID del nodo no cambiará, y otros nodos pueden reconocer cada nodo a través de la ID de otros nodos.

3.15 Verificar las operaciones de lectura y escritura de los datos del clúster

De la siguiente manera, conectamos el nodo 6379 y luego realizamos una operación de configuración, el efecto es el siguiente, la escritura es exitosa

[root@hspEdu01 cluster]# redis-cli -c -h 192.168.200.129 -p 6379
192.168.200.129:6379> set name ready
-> Redirected to slot [5798] located at 192.168.200.129:6380
OK
192.168.200.129:6380>

Es posible que haya notado que obviamente estamos operando en 6379, pero la solicitud se envía al nodo 6380 para su procesamiento. Aquí está el conocimiento de la ranura de la que hablaremos más adelante, primero miremos hacia atrás.

4. ¿Cómo asigna el clúster de redis estos 6 nodos?

Un clúster tiene al menos 3 nodos maestros, porque la elección de un nuevo maestro requiere el consentimiento de más de la mitad de los nodos maestros del clúster para ser elegido correctamente, si solo hay dos nodos maestros y uno de ellos cuelga, las condiciones para la elección de un nuevo maestro no se puede cumplir.

La opción --cluster-replicas 1 indica que queremos crear un nodo esclavo para cada nodo maestro en el clúster.

El principio de asignación trata de garantizar que cada biblioteca maestra se ejecute en una IP diferente, y que cada biblioteca maestra y biblioteca esclava no estén en la misma IP, para lograr una alta disponibilidad.

5. ¿Qué son las tragamonedas (slots)?

Como se muestra en la figura a continuación, echemos un vistazo a algunos resultados de información durante el proceso de fusión de clústeres.

 El clúster de Redis divide internamente 16384 ranuras (slots). Al fusionarse, cada ranura se asignará a un maestro. Por ejemplo, la relación entre los tres maestros anteriores y las ranuras es la siguiente:

nodo maestro redis Rango de ranura
maestro1 (puerto: 6379) [0-5460], la posición de la ranura comienza desde 0, y 0 significa la primera ranura
maestro2 (puerto: 6380) [5460-10922]
maestro3 (puerto: 6381) [10923-16383]
esclavo1, esclavo2, esclavo3 No hay ranura para el nodo esclavo, y el esclavo se utiliza como sustituto del maestro

Y cada clave en la base de datos pertenece a una de las ranuras 16384. Al leer y escribir datos a través de la clave, redis necesita calcular las ranuras correspondientes a la clave de acuerdo con la clave, y luego encontrar las ranuras correspondientes de acuerdo con la relación de mapeo entre las ranuras y el maestro El nodo redis, los datos correspondientes a la clave están en este nodo.

Utilice la fórmula CRC16(clave)%16384 en el clúster para calcular a qué ranura pertenece la clave

6. Ingrese valores en el clúster

Cada vez que ingrese y consulte el valor de la clave en redis-cli, redis calculará la ranura correspondiente a la clave. Si no es la ranura del nodo actual de redis, redis informará un error y le informará la dirección y el puerto de la instancia de redis. para ir a. El efecto es el siguiente, conectamos La instancia 6379 se utiliza para operar k1. El nodo encuentra que la ranura de k1 está por encima de 6381 y devuelve un mensaje de error. ¿Qué debo hacer?

[root@hspEdu01 cluster]# redis-cli -h 192.168.200.129 -p 6379
192.168.200.129:6379> set k1 v1
(error) MOVED 12706 192.168.200.129:6381

El uso del cliente redis-cli para proporcionar el parámetro -c puede resolver este problema, lo que significa que se ejecuta en un modo de clúster.Cuando el nodo actual no puede manejar el comando al ejecutar el comando, redirigirá automáticamente la solicitud al destino. nodo El efecto es el siguiente, se redirige a 6381

[root@hspEdu01 cluster]# redis-cli -c -h 192.168.200.129 -p 6379
192.168.200.129:6379> set k1 v1
-> Redirected to slot [12706] located at 192.168.200.129:6381
OK
192.168.200.129:6381>

Del mismo modo, se redirigirá la ejecución de get, el efecto es el siguiente

[root@hspEdu01 cluster]# redis-cli -c -h 192.168.200.129 -p 6379
192.168.200.129:6379> get k1
-> Redirected to slot [12706] located at 192.168.200.129:6381
"v1"
192.168.200.129:6381>

Si no está debajo de una ranura, no se pueden usar operaciones de teclas múltiples como mget y mset. El efecto es el siguiente

192.168.200.129:6381> mset k1 v1 k2 v2
(error) CROSSSLOT Keys in request don't hash to the same slot
192.168.200.129:6381> mget k1 k2
(error) CROSSSLOT Keys in request don't hash to the same slot

Puede usar {} para definir el concepto de un grupo, de modo que el mismo valor de clave en {} en la clave se pueda colocar en una ranura, y el efecto es el siguiente

192.168.200.129:6381> mset k1{g1} v1 k2{g1} v2 k3{g1} v3
OK
192.168.200.129:6381> mget k1{g1} k2{g1} k3{g1}
1) "v1"
2) "v2"
3) "v3"

7. Algunos comandos relacionados con la ranura

  • cluster keyslot <key>: Calcular el slot correspondiente a la clave
  • cluster coutkeysinslot <ranura>: Obtener el número de claves en la ranura ranura
  • cluster getkeysinslot <slot> <count> devuelve las claves en las ranuras de conteo
192.168.200.129:6381> cluster keyslot k1{g1}
(integer) 13519
192.168.200.129:6381> cluster countkeysinslot 13519
(integer) 3
192.168.200.129:6381> cluster getkeysinslot 13519 3
1) "k1{g1}"
2) "k2{g1}"
3) "k3{g1}"

8. Recuperación de fallas

Si el nodo maestro se desconecta, ¿se puede promover el nodo esclavo a nodo maestro? Nota: espere 15 segundos.
Intentemos, de la siguiente manera, conectarnos a master1 y luego detener master1.

[root@hspEdu01 cluster]# redis-cli -c -h 192.168.200.129 -p 6379
192.168.200.129:6379> shutdown
not connected>

Ejecute el siguiente comando para conectarse a master1 y ver la información de los nodos del clúster

redis-cli -c -h 192.168.200.129 -p 6380
cluster nodes

El resultado es el siguiente, puede ver que slave1 (6389) se ha convertido en el maestro y su maestro original: master1 (6379) está fuera de línea

A continuación, comencemos 6379 nuevamente y luego veamos cómo se ve el clúster. El comando es el siguiente

[root@hspEdu01 cluster]# redis-server /opt/cluster/redis-6379.conf
[root@hspEdu01 cluster]# redis-cli -c -h 192.168.200.129 -p 6379
192.168.200.129:6379> cluster nodes

Los resultados de la ejecución son los siguientes, 6379 se ha convertido en un esclavo y está colgado bajo 6389

 Si el maestro y el esclavo de una determinada ranura están inactivos, ¿puede continuar el servicio redis?

En este momento, depende del valor del parámetro cluster-require-full-coverage

  • yes (valor predeterminado): todo el clúster no puede proporcionar servicios
  • no: no se pueden usar todos los datos de ranura del tiempo de inactividad, y las otras ranuras son normales

9. SpringBoot integra el clúster redis

9.1 Introducir la configuración maven de redis

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

9.2 Configurar la información del clúster de redis en application.properties

# 集群节点(host:port),多个之间用逗号隔开
spring.redis.cluster.nodes=192.168.200.129:6379,192.168.200.129:6380,192.168.200.129:6381,192.168.200.129:6389,192.168.200.129:6390,192.168.200.129:6391
# 连接超时时间(毫秒)
spring.redis.timeout=60000

9.3 Use la clase de herramienta RedisTemplate para operar redis

RedisTemplate se usa en springboot para operar redis, y este objeto debe inyectarse en nuestro bean. El código es el siguiente:

@Autowired
private RedisTemplate<String, String> redisTemplate;

// 用下面5个对象来操作对应的类型
this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法
this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法
this.redisTemplate.opsForSet(); //提供了操作set的所有方法
this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法
this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法

9.4, código de muestra de RedisTemplate

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @className RedisController
 * @date 2022/6/21
 **/
@RestController
@RequestMapping("/redis")
public class RedisController {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * string测试
     * @return
     */
    @RequestMapping("/stringTest")
    public String stringTest() {
        this.redisTemplate.delete("name");
        this.redisTemplate.opsForValue().set("name", "路人");
        String name = this.redisTemplate.opsForValue().get("name");
        return name;
    }

    /**
     * list测试
     * @return
     */
    @RequestMapping("/listTest")
    public List<String> listTest() {
        this.redisTemplate.delete("names");
        this.redisTemplate.opsForList().rightPushAll("names", "刘德华", "张学友", "郭富城", "黎明");
        List<String> courses = this.redisTemplate.opsForList().range("names", 0, -1);
        return courses;
    }

    /**
     * set类型测试
     * @return
     */
    @RequestMapping("setTest")
    public Set<String> setTest() {
        this.redisTemplate.delete("courses");
        this.redisTemplate.opsForSet().add("courses", "java", "spring", "springboot");
        Set<String> courses = this.redisTemplate.opsForSet().members("courses");
        return courses;
    }

    /**
     * hash类型测试
     * @return
     */
    @RequestMapping("hashTest")
    public Map<Object, Object> hashTest() {
        this.redisTemplate.delete("userMap");
        Map<String, String> map = new HashMap<>();
        map.put("name", "路人");
        map.put("age", "30");
        this.redisTemplate.opsForHash().putAll("userMap", map);
        Map<Object, Object> userMap = this.redisTemplate.opsForHash().entries("userMap");
        return userMap;
    }

    /**
     * zset类型测试
     * @return
     */
    @RequestMapping("zsetTest")
    public Set<String> zsetTest() {
        this.redisTemplate.delete("languages");
        this.redisTemplate.opsForZSet().add("languages", "java", 100d);
        this.redisTemplate.opsForZSet().add("languages", "c", 95d);
        this.redisTemplate.opsForZSet().add("languages", "php", 70);
        Set<String> languages = this.redisTemplate.opsForZSet().range("languages", 0, -1);
        return languages;
    }

    /**
     * 查看redis机器信息
     * @return
     */
    @RequestMapping(value = "/info", produces = MediaType.TEXT_PLAIN_VALUE)
    public String info() {
        return this.redisTemplate.execute((RedisCallback<String>) connection ->
                String.valueOf(connection.execute("info")));
    }

}

Supongo que te gusta

Origin blog.csdn.net/qq_34272760/article/details/125397953
Recomendado
Clasificación