Redis - 13. Especificación de desarrollo

Este artículo presenta principalmente las especificaciones de desarrollo cuando se usa Redis y lo explica a partir de los siguientes aspectos.

  • diseño de clave-valor

  • uso de comandos

  • uso del cliente

  • herramientas relacionadas

A través de la introducción de este artículo, se pueden reducir los problemas causados ​​por el uso del proceso de Redis.

1. Diseño de clave-valor

1.1 Diseño de nombre clave

1.1.1 Legibilidad y manejabilidad

Prefije el nombre de la empresa (o el nombre de la base de datos) (para evitar conflictos de claves), separados por dos puntos, como nombre de la empresa: nombre de la tabla: id.

ugc:video:1

1.1.2 Simplicidad

Bajo la premisa de asegurar la semántica, controle la longitud de la clave, cuando hay muchas claves, el uso de la memoria no se puede ignorar, por ejemplo:

user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}。

1.1.3, no contienen caracteres especiales

Ejemplo negativo: contiene espacios, saltos de línea, comillas simples y dobles y otros caracteres de escape

1.2, diseño de valor

1.2.1 Rechazar bigkey

Para evitar el tráfico de la tarjeta de red y las consultas lentas, el tipo de cadena debe controlarse dentro de los 10 KB, y la cantidad de elementos hash, list, set y zset no debe exceder los 5000.

Contraejemplo: una lista con 2 millones de elementos.

Para bigkeys que no sean cadenas, no use del para eliminar, use hscan, sscan, zscan para eliminar gradualmente y, al mismo tiempo, preste atención para evitar la eliminación automática del tiempo de caducidad de bigkey (por ejemplo, si se establece un zset de 2 millones para caducar en 1 hora, se activará la operación del, lo que provocará el bloqueo, y la operación no aparecerá en la consulta lenta (se puede verificar la latencia), método de búsqueda y método de eliminación

1.2.2 Seleccione el tipo de datos apropiado

Por ejemplo: tipo de entidad (control razonable y uso de la configuración de optimización de la codificación de la memoria de la estructura de datos, como ziplist, pero también preste atención al equilibrio entre el ahorro de memoria y el rendimiento)

Contador de ejemplo:

set user:1:name tom
set user:1:age 19
set user:1:favor football

Ejemplo positivo:

hmset user:1 name tom age 19 favor football

1.2.3 Controlar el ciclo de vida de la llave

Redis no es un bote de basura. Se recomienda usar expire para establecer el tiempo de vencimiento (el tiempo de vencimiento se puede dividir si las condiciones lo permiten para evitar el vencimiento centralizado), y los datos no vencidos deben centrarse en el tiempo de inactividad.

2. Uso de comandos

2.1, los comandos O(N) se centran en el número de N

Por ejemplo, hgetall, lrange, smembers, zrange, sinter, etc. no son imposibles de usar, pero es necesario especificar el valor de N. Si es necesario atravesar, se pueden usar hscan, sscan y zscan en su lugar.

2.2 Deshabilitar comando

Está prohibido usar claves, flushall, flushdb, etc. en línea, y prohibir comandos a través del mecanismo de cambio de nombre de redis, o usar escaneo para procesar progresivamente.

2.3 Uso razonable de select

La base de datos múltiple de Redis es débil y se usan números para distinguirla. Muchos clientes la admiten de manera deficiente. Al mismo tiempo, las bases de datos múltiples para servicios múltiples en realidad son procesadas por un solo hilo, lo que interferirá.

2.4 Utilice operaciones por lotes para mejorar la eficiencia

  • Comandos nativos: por ejemplo, mget, mset.

  • Comandos no nativos: puede usar canalización para mejorar la eficiencia.

Pero preste atención al control del número de elementos en una operación por lotes  (por ejemplo, dentro de 500, en realidad está relacionado con el número de bytes del elemento).

Tenga en cuenta la diferencia entre los dos:

  • Native es una operación atómica y Pipeline es una operación no atómica.

  • La tubería puede empaquetar diferentes comandos, lo que no se puede hacer de forma nativa.

  • La canalización debe ser compatible tanto con el cliente como con el servidor.

2.5 No se recomienda usar demasiado la función de transacción de Redis

La función de transacción de Redis es débil (no se admite la reversión) y la versión de clúster (autodesarrollada y oficial) requiere que la clave de una operación de transacción esté en una ranura (se puede resolver usando la función de hashtag)

2.6. La versión del clúster de Redis tiene requisitos especiales para usar Lua

1. Todas las claves deben ser pasadas por la matriz KEYS, el comando redis llamado en redis.call/pcall, la posición de la clave debe ser la matriz KEYS, de lo contrario, el error se devolverá directamente, "-ERR bad lua script for redis clúster, todas las claves que usa el script deben pasarse usando la matriz KEYS"

2. Todas las claves deben estar en una ranura, de lo contrario, devolverá directamente el error, "-ERR eval/evalsha las teclas de comando deben estar en la misma ranura"

2.7, control de comando

Cuando use el comando monitor si es necesario, tenga cuidado de no usarlo durante mucho tiempo.

3. Uso del cliente

3.1 Evite usar una instancia de Redis para múltiples aplicaciones

División comercial irrelevante, datos públicos como servicio.

3.2, usar grupo de conexiones

Puede controlar efectivamente la conexión y mejorar la eficiencia al mismo tiempo.El método de uso estándar:

执行命令如下:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    //具体的命令
    jedis.executeCommand()
} catch (Exception e) {
    logger.error("op key {} error: " + e.getMessage(), key, e);
} finally {
    //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
    if (jedis != null)
        jedis.close();
}

3.3 Función de fusión

Bajo alta concurrencia, se recomienda que el cliente agregue una función de fusible (como netflix hystrix)

3.4 Cifrado razonable

Establezca una contraseña razonable y utilice el acceso encriptado SSL si es necesario (compatible con Alibaba Cloud Redis)

3.5 Estrategia de eliminación

De acuerdo con su propio tipo de negocio, seleccione maxmemory-policy (política de eliminación de memoria máxima) y configure el tiempo de caducidad.

La estrategia predeterminada es volatile-lru, es decir, después de que se supera la memoria máxima, se usa el algoritmo lru para eliminar las claves de las claves caducadas para garantizar que los datos no caducados no se eliminen, pero pueden ocurrir problemas de OOM.

Otras estrategias son las siguientes:

  • allkeys-lru: elimine claves de acuerdo con el algoritmo LRU, independientemente de si los datos tienen un atributo de tiempo de espera, hasta que haya suficiente espacio disponible.

  • allkeys-random: elimina aleatoriamente todas las claves hasta que haya suficiente espacio.

  • volatile-random: elimine aleatoriamente las claves caducadas hasta que se haga suficiente espacio.

  • volatile-ttl: de acuerdo con el atributo ttl del objeto clave-valor, elimine los datos que caducan recientemente. Si no, recurra a la política de no desalojo.

  • noeviction: no se eliminará ningún dato, se rechazarán todas las operaciones de escritura y se devolverá el mensaje de error del cliente "(error) Comando OOM no permitido cuando se usa la memoria". En este momento, Redis solo responde a las operaciones de lectura.

4. Herramientas relacionadas

4.1 Sincronización de datos

Se puede usar la sincronización de datos entre redis: redis-port

4.2, búsqueda de teclas grandes

herramienta de búsqueda de clave grande redis

4.3 Búsqueda de teclas de acceso rápido

La implementación interna usa monitor, por lo que se recomienda usar redis-faina de facebook por un corto tiempo Aliyun Redis ha resuelto el problema de las teclas de acceso rápido a nivel del kernel

5. Eliminar clave grande

  • Las siguientes operaciones se pueden acelerar mediante la canalización.

  • Redis 4.0 ya admite la eliminación asíncrona de claves, bienvenido a usar.

5.1, eliminación de hash: hscan + hdel

public void delBigHash(String host, int port, String password, String bigHashKey) {
    Jedis jedis = new Jedis(host, port);
    if (password != null && !"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = new ScanParams().count(100);
    String cursor = "0";
    do {
        ScanResult<Entry<String, String>> scanResult = jedis.hscan(bigHashKey, cursor, scanParams);
        List<Entry<String, String>> entryList = scanResult.getResult();
        if (entryList != null && !entryList.isEmpty()) {
            for (Entry<String, String> entry : entryList) {
                jedis.hdel(bigHashKey, entry.getKey());
            }
        }
        cursor = scanResult.getStringCursor();
    } while (!"0".equals(cursor));
    //删除bigkey
    jedis.del(bigHashKey);
}

5.2, Eliminar lista: ltrim

public void delBigList(String host, int port, String password, String bigListKey) {
    Jedis jedis = new Jedis(host, port);
    if (password != null && !"".equals(password)) {
        jedis.auth(password);
    }
    long llen = jedis.llen(bigListKey);
    int counter = 0;
    int left = 100;
    while (counter < llen) {
        //每次从左侧截掉100个
        jedis.ltrim(bigListKey, left, llen);
        counter += left;
    }
    //最终删除key
    jedis.del(bigListKey);
}

5.3, Establecer eliminación: sscan + srem

public void delBigSet(String host, int port, String password, String bigSetKey) {
    Jedis jedis = new Jedis(host, port);
    if (password != null && !"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = new ScanParams().count(100);
    String cursor = "0";
    do {
        ScanResult<String> scanResult = jedis.sscan(bigSetKey, cursor, scanParams);
        List<String> memberList = scanResult.getResult();
        if (memberList != null && !memberList.isEmpty()) {
            for (String member : memberList) {
                jedis.srem(bigSetKey, member);
            }
        }
        cursor = scanResult.getStringCursor();
    } while (!"0".equals(cursor));
    //删除bigkey
    jedis.del(bigSetKey);
}

5.4, ​​SortedSet eliminar: zscan + zrem

public void delBigZset(String host, int port, String password, String bigZsetKey) {
    Jedis jedis = new Jedis(host, port);
    if (password != null && !"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = new ScanParams().count(100);
    String cursor = "0";
    do {
        ScanResult<Tuple> scanResult = jedis.zscan(bigZsetKey, cursor, scanParams);
        List<Tuple> tupleList = scanResult.getResult();
        if (tupleList != null && !tupleList.isEmpty()) {
            for (Tuple tuple : tupleList) {
                jedis.zrem(bigZsetKey, tuple.getElement());
            }
        }
        cursor = scanResult.getStringCursor();
    } while (!"0".equals(cursor));
    //删除bigkey
    jedis.del(bigZsetKey);
}

Supongo que te gusta

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