Obtenga más información sobre Redis Cluster: cree un clúster de Redis basado en Docker y DockerCompose, maneje fallas y amplíe la capacidad.

Tabla de contenido

1. Cree un clúster de Redis basado en Docker y DockerCompose

1.1 Prefacio

1.2 Escribir script de shell

1.3 Ejecute el script de shell y cree el archivo de configuración del clúster

1.4 Escriba el archivo docker-compose.yml

1.5 Iniciar el contenedor

1.6 Construir un clúster

1.7 Uso de clústeres

1.8 ¿Qué debo hacer si falla un nodo del clúster?

2. Procesamiento de expansión y falla del clúster

2.1 Manejo de fallas del clúster

a) Determinación de fallos

b) Conmutación por error

2.2 Tiempo de inactividad del clúster

2.3 Expansión del cluster

a) Análisis

b) Agregue el nuevo nodo maestro 110 al clúster

c) Reasignar espacios

Pregunta: ¿Puede el cliente acceder al clúster de Redis durante el proceso de mover ranuras/claves?


1. Cree un clúster de Redis basado en Docker y DockerCompose


1.1 Prefacio

En la etapa actual, dado que solo tengo un servidor en la nube, es más problemático construir un sistema distribuido. En el trabajo real, los clústeres generalmente se construyen utilizando varios hosts.

Entonces, aquí construiré un clúster de Redis basado en Docker y Docker-Compose (orquestación de contenedores).

Ps: antes de configurar, asegúrese de detener el contenedor redis iniciado anteriormente.

1.2 Escribir script de shell

En Linux, los archivos con el sufijo .sh se denominan "scripts de shell", a través de este archivo podemos ejecutar por lotes instrucciones que normalmente se ejecutan en Linux, al mismo tiempo, también podemos agregar condiciones, bucles, funciones y otros mecanismos. .

Aquí creamos 11 nodos de Redis. El contenido de estos archivos de configuración de Redis es similar, por lo que usamos un script para generarlos en lotes (también puede cambiarlos uno por uno manualmente sin usar un script).

for port in $(seq 1 9); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.10${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done

# 注意 cluster-announce-ip 的值有变化,和上面分开写也是因为这个原因

for port in $(seq 10 11); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done

para puerto en $(seq 1 9): representa un bucle, seq es un comando de Linux, genera números [1, 9] y los asigna a la variable puerto por turno.

do, done: en el shell, {} se usa para representar variables, no bloques de código, porque for, do y done se usan para representar el principio y el final de un bloque de código (así era como eran los lenguajes de programación en la antigüedad). ).

\: indica el carácter de continuación, lo que significa fusionar el contenido de la línea siguiente y la línea actual en una línea. De forma predeterminada, el shell requiere que todos los códigos se escriban en una línea, pero puede usar el carácter de continuación para dividir la línea. y seguir añadiendo.

El contenido del primer cuerpo del bucle (el segundo cuerpo del bucle tiene la misma idea): cree 9 carpetas llamadas redis1, redis2, redis3... a través de mkdir, y luego toque redis${port} Debajo de cada carpeta, cree un redis.conf archivo El contenido del archivo (comenzando desde EOF y terminando con EOF) se escribe en cada archivo redis.conf a través de cat.

Empalme de cadenas: en el shell, el empalme de cadenas se escribe directamente juntos, sin usar +.

habilitado para clúster sí: habilita el clúster

cluster-config-file: una vez iniciado el nodo, el archivo de configuración del nodo generado automáticamente configurará parte de la información del clúster de Redis.

cluster-node-timeout 5000: el período de tiempo de espera del paquete de latidos se establece en 5000 ms.

cluster-announce-ip: indica la dirección IP del host donde se encuentra el nodo redis actual (actualmente es un host simulado usando un contenedor acoplable, por lo que debe ser la IP del contenedor acoplable).

cluster-announce-port: indica el puerto vinculado al nodo redis actual (el puerto en el contenedor). Diferentes contenedores pueden tener el mismo puerto dentro. Se realiza el mapeo de puertos posterior y luego los diferentes puertos fuera del contenedor se asignan a los puertos dentro del contenedor.Can.

cluster-announce-bus-port: un servidor puede vincularse a varios números de puerto. Actualmente, esto representa el puerto de administración (el puerto comercial mencionado anteriormente se usa para la comunicación de datos comerciales), que se usa para completar algunas tareas de administración. (Si el nodo maestro de Redis en un determinado fragmento cuelga, el nodo esclavo debe convertirse en el nodo maestro, y esto debe hacerse a través del puerto de administración).

1.3 Ejecute el script de shell y cree el archivo de configuración del clúster

Ejecute el script de shell mediante el siguiente comando

Centos ejecuta el comando del script de shell:

sh generate.sh

Ubuntu ejecuta el comando del script de shell:

bash generate.sh

Después de la ejecución, obtendrá 11 directorios, cada directorio tiene un archivo de configuración y las direcciones IP en los archivos de configuración son diferentes.

1.4 Escriba el archivo docker-compose.yml

En el archivo de configuración, primero debe crear manualmente la red de la red y luego asignar el segmento de red a la IP estática de cada nodo en la creación posterior del clúster de Redis.

Ps: La IP estática (IP fija) se configura aquí para su posterior observación.

version: '3.3'
networks:
  mynet:
    ipam:
      config:
        - subnet: 172.30.0.0/24

Luego cree cada nodo en el clúster de Redis.

services:
  redis1:
    image: 'redis:5.0.9'
    container_name: redis1
    restart: always
    volumes:
      - ./redis1/:/etc/redis/
    ports:
      - 6371:6379
      - 16371:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.101

  redis2:
    image: 'redis:5.0.9'
    container_name: redis2
    restart: always
    volumes:
      - ./redis2/:/etc/redis/
    ports:
      - 6372:6379
      - 16372:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.102

  redis3:
    image: 'redis:5.0.9'
    container_name: redis3
    restart: always
    volumes:
      - ./redis3/:/etc/redis/
    ports:
      - 6373:6379
      - 16373:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.103

  redis4:
    image: 'redis:5.0.9'
    container_name: redis4
    restart: always
    volumes:
      - ./redis4/:/etc/redis/
    ports:
      - 6374:6379
      - 16374:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.104

  redis5:
    image: 'redis:5.0.9'
    container_name: redis5
    restart: always
    volumes:
      - ./redis5/:/etc/redis/
    ports:
      - 6375:6379
      - 16375:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.105

  redis6:
    image: 'redis:5.0.9'
    container_name: redis6
    restart: always
    volumes:
      - ./redis6/:/etc/redis/
    ports:
      - 6376:6379
      - 16376:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.106

  redis7:
    image: 'redis:5.0.9'
    container_name: redis7
    restart: always
    volumes:
      - ./redis7/:/etc/redis/
    ports:
      - 6377:6379
      - 16377:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.107

  redis8:
    image: 'redis:5.0.9'
    container_name: redis8
    restart: always
    volumes:
      - ./redis8/:/etc/redis/
    ports:
      - 6378:6379
      - 16378:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.108
 
  redis9:
    image: 'redis:5.0.9'
    container_name: redis9
    restart: always
    volumes:
      - ./redis9/:/etc/redis/
    ports:
      - 6379:6379
      - 16379:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.109

  redis10:
    image: 'redis:5.0.9'
    container_name: redis10
    restart: always
    volumes:
      - ./redis10/:/etc/redis/
    ports:
      - 6380:6379
      - 16380:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.110
 
  redis11:
    image: 'redis:5.0.9'
    container_name: redis11
    restart: always
    volumes:
      - ./redis11/:/etc/redis/
    ports:
      - 6381:6379
      - 16381:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.111

- subred: 172.30.0.0/24: Aquí 172.30.0 es el número de red y la IP es la IP de la red interna. Esto requiere que no pueda entrar en conflicto con otros segmentos de red existentes en su host actual (el segmento de red existente de todos en el host). ) párrafo, los detalles pueden no ser los mismos).

ipv4_address: 172.30.0.101: Configure la IP estática aquí. Tenga en cuenta que la parte del número de red debe ser coherente con la red anterior. La parte del número de host se puede configurar arbitrariamente entre 1 y 255, siempre que no se repita. Sin embargo, aquí debemos corresponder a la IP de anuncio de clúster escrita en el archivo de configuración antes de on, como se muestra a continuación

1.5 Iniciar el contenedor

Inicie todos los contenedores configurados en yml mediante docker-compose up -d.

1.6 Construir un clúster

Aquí, los primeros 9 hosts están integrados en un clúster, 3 maestros y 6 esclavos, y los últimos 2 hosts no se utilizan temporalmente.

Simplemente compílelo con el siguiente comando

redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379  --cluster-replicas 2

--cluster create: Indica la creación de un clúster, complete la IP y la dirección de cada nodo (asegúrese de que la IP de este comando sea consistente con el entorno real).

--cluster-replicas 2: indica que cada nodo maestro requiere dos copias de seguridad del nodo esclavo. Después de establecer esta configuración, redis sabrá que hay 3 nodos en un grupo (en un fragmento), un total de 9 nodos, un total de 3 fragmentos.

Después de ingresar sí, de la siguiente manera

1.7 Uso de clústeres

Ahora hay nueve nodos del 101 al 109, que es un clúster. Usar un cliente para conectarse a cualquier nodo es esencialmente equivalente (cada clúster almacena una parte de los datos del "conjunto completo", y cuando se conecta a cualquier cliente con -c opción, se puede acceder a todo el conjunto de datos ).

Después de establecer el clúster, puede conectarse al cliente a través de -h -p, -h, o conectarse directamente al puerto externo a través de -p, de la siguiente manera (todos los siguientes están conectados a 172.30.0.103:6379):

Vea la información actual del clúster a través de los nodos del clúster.

Almacenar datos en el clúster.

El motivo del error en la imagen de arriba es que después del cálculo hash de la clave k1, la ranura es 12706. Este número de ranura pertenece al fragmento número 3 en la información del clúster que acabamos de ver.

 El mensaje de error nos solicita que reenviemos la solicitud del cliente al nodo 103.

¿No sería esto problemático?

De hecho, podemos agregar la opción -c al iniciar redis-cli. En este momento, el cliente redis encontrará automáticamente el host de fragmento coincidente según el número de ranura calculado por la clave actual y completará aún más la operación.

Preste atención a la imagen de arriba: después de la redirección, el cliente conectado a redis también cambiará.

Además, si intenta escribir operaciones en el nodo esclavo, también será redirigido automáticamente al nodo maestro especificado.

Ps: De hecho, los comandos relacionados con Redis mencionados anteriormente son básicamente aplicables (excepto algunos, como mset, mget ... que pueden operar varias claves, no están disponibles porque las claves pueden estar dispersas en diferentes fragmentos).

1.8 ¿Qué debo hacer si falla un nodo del clúster?

¿Qué pasa si el nodo caído es un nodo esclavo? Está bien ~

¿Qué sucede si el nodo principal falla? ¡La operación de escritura no se puede realizar! En este momento, el trabajo realizado por el clúster es algo similar al realizado por el centinela: automáticamente seleccionará uno de los nodos esclavos debajo del nodo maestro y lo promoverá al nodo maestro.

Aquí dejo que el nodo principal redis1 cuelgue.

docker stop redis1

Antes de que redis1 cuelgue, la información del clúster es la siguiente:

Después de que redis1 cuelga, la información del clúster es la siguiente:

Se puede ver que el mecanismo del clúster también puede manejar la conmutación por error.

2. Procesamiento de expansión y falla del clúster


2.1 Manejo de fallas del clúster

a) Determinación de fallos

1. Cada nodo, cada segundo, enviará paquetes de ping a algunos nodos aleatorios (esto incluye información de configuración del clúster, como ID, a qué fragmento pertenece, si es un nodo maestro o esclavo y qué ranuras tiene). . ....), el nodo recibido devolverá un paquete pong. Los paquetes ping aquí no se envían todos una vez. Esta configuración es para evitar que cuando hay muchos nodos, también haya muchos paquetes de latidos, lo que consume seriamente ancho de banda de la red.

2. Cuando el nodo A envía un paquete de ping al nodo B y B no puede responder como se esperaba, A restablecerá la conexión TCP con B. Si la reconexión falla, A configurará B en PFAIL (equivalente a subjetivo fuera de línea).

3. Después de que A determine que B es PFAIL, se comunicará con otros nodos a través del protocolo Gossip incorporado de redis y confirmará el estado de B con otros nodos.

4. Si A descubre que hay muchos otros nodos que también piensan que B es PFAIL y el número excede el número de clústeres, entonces A marcará B como FAIL (equivalente al objetivo fuera de línea) y sincronizará este mensaje con otros nodos. deje que otros nodos también marquen B como FALLO.

b) Conmutación por error

Primero habrá un juicio:

  • Si B es un nodo esclavo, no hay necesidad de conmutación por error.
  • Si B es el nodo maestro, entonces los nodos esclavos de B (como C y D) activarán la conmutación por error.

concreto:

1. El nodo esclavo determina si está calificado para participar en la elección. Si el nodo esclavo no se ha comunicado con el nodo maestro durante demasiado tiempo (sin sincronización de datos durante demasiado tiempo, la diferencia es demasiado grande), perderá la calificación. correr.

2. Los nodos calificados, como C y D, dormirán primero durante un cierto período de tiempo. Tiempo de suspensión = 500 ms de tiempo básico + [0, 500 ms] tiempo aleatorio + clasificación * 1000 ms. Cuanto mayor sea el valor de compensación (lo que indica que los datos Cuanto más cerca esté el nodo maestro), mayor será la clasificación (más corto será el tiempo de sueño), es decir, el tiempo de sueño depende principalmente de la clasificación .

3. Si el tiempo de inactividad de C se agota en este momento, C sondeará los votos de todos los nodos del clúster, pero solo el nodo maestro es elegible para votar (quien tenga un tiempo de inactividad más corto probablemente será el nuevo nodo maestro).

4. El nodo maestro votará por C (cada nodo maestro tiene solo 1 voto). Cuando el número de votos recibidos por C exceda la mitad del número de nodos maestros, C será promovido a convertirse en el nodo maestro (C ejecuta esclavo de no uno por sí mismo, y deje que D ejecute el esclavo de C).

5. Al mismo tiempo, C también sincronizará la noticia de que se ha convertido en el nodo maestro con otros nodos del clúster y todos actualizarán la información de la estructura del clúster guardada.

6. Finalmente, si se restaura el punto host previamente caído, se convertirá en un nodo esclavo y se conectará al clúster.

2.2 Tiempo de inactividad del clúster

El tiempo de inactividad del clúster se producirá en las siguientes tres situaciones:

Para un determinado fragmento, todos los nodos maestros y esclavos están inactivos y, en este momento, el fragmento no puede proporcionar servicios de datos.

Para un determinado fragmento, el nodo maestro está inactivo, pero no hay nodos esclavos y no se pueden proporcionar servicios de datos.

Si más de la mitad de los nodos maestros están inactivos, significa que el clúster ha encontrado una situación muy grave y es necesario detenerse y verificar si hay algún problema.

Ps: si un nodo en el clúster está inactivo, no importa qué nodo sea, nuestros programadores deben manejarlo lo antes posible (a más tardar, debe manejarse antes de ir a trabajar al día siguiente).

2.3 Expansión del cluster

a) Análisis

Las operaciones anteriores han combinado 101 ~ 109 9 hosts en un clúster con 3 maestros y 6 esclavos.

A continuación, para demostrar la expansión, también se agregan 110 y 111 al clúster.

Tome 110 como maestro y 111 como esclavo, y divida los datos de 3 -> 4.

b) Agregue el nuevo nodo maestro 110 al clúster

redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379

add-node: la primera IP y el número de puerto indican el nuevo nodo, y la segunda IP y el número de puerto indican cualquier nodo en el clúster (cualquiera servirá, siempre que sea un nodo en un clúster al que desea unirse) ( eso es todo), indicando a qué cluster se debe agregar el nuevo nodo.

Luego, puede ver a través de los nodos del clúster que el nodo maestro redis10 se ha unido al clúster, pero las ranuras no están asignadas.

c) Reasignar espacios

Saque las ranuras de los tres conjuntos de maestros anteriores y asígnelas al nuevo maestro 

redis-cli --cluster reshard 172.30.0.101:6379

Después de ingresar el comando, se imprimirá el estado de cada máquina en el grupo actual y luego se le pedirá al usuario que ingrese la cantidad de ranuras que se dividirán.

Hay 4 fragmentos, un total de 16384. Divida entre 4 para obtener 4096, así que complete 4096 aquí (los números de ranura 4096 se dividen en redis10).

Inmediatamente después, le preguntará qué nodo recibir, simplemente pegue la identificación del host redis10.

A continuación, le permite elegir de qué nodos diversificar las ranuras:

  1. all: significa hacer clic desde cualquier otro maestro que tenga espacios.
  2. Especifique manualmente mover ranuras de uno o varios nodos (finalizando con listo).

Después de ingresar todo, no se realizará el transporte real, pero primero se dará el plan de transporte.

Después de ingresar "Sí", la transferencia realmente comienza. En este momento, no solo se vuelven a dividir las ranuras, sino que los datos correspondientes en las ranuras también se transferirán al nuevo host . (Esta es una operación relativamente pesada)

d) Agregar nodos esclavos al nuevo nodo maestro

redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave

 

Una vez completada la ejecución, se agrega el nodo esclavo.

 

Pregunta: ¿Puede el cliente acceder al clúster de Redis durante el proceso de mover ranuras/claves?

Hemos aprendido sobre el algoritmo de partición de ranura hash antes y podemos saber que la mayoría de las claves no necesitan moverse. Para estas claves que no se han movido, se puede acceder a ellas normalmente en este momento. Para las claves que se están moviendo, Pueden ocurrir errores de acceso .

Supongamos que el cliente accede a k1, y el k1 obtenido por el clúster a través del algoritmo de fragmentación son los datos del primer fragmento, y será redirigido al nodo del primer fragmento, entonces existe la posibilidad de que después de la redirección, k1 Una vez que se haya movido, naturalmente se volverá inaccesible.

Si desea expandir la capacidad de un entorno de producción, aún debe tomarse su tiempo. Por ejemplo, busque un momento para expandirse en la oscuridad de la noche cuando no hay clientes accediendo al clúster, para que la pérdida pueda minimizarse.

Obviamente, si desea lograr una mayor disponibilidad y hacer que la expansión tenga menos impacto en los usuarios, necesita construir un nuevo conjunto de máquinas, reconstruir el clúster, importar los datos y usar el nuevo clúster para reemplazar el antiguo (pero el costo). es el más alto).

Ps: con respecto a la reducción del clúster, consiste en eliminar algunos nodos y reducir la cantidad de fragmentos.

Sin embargo, generalmente se amplía y rara vez se reduce.

Supongo que te gusta

Origin blog.csdn.net/CYK_byte/article/details/132940548
Recomendado
Clasificación