Explicar la aplicación de mapa de bits de redis en detalle.

Podemos usar el mapa de bits (mapa de bits) de Redis para almacenar datos.

1. ¿Qué es el mapa de bits de Redis?

Es decir: manipular el bit en el desplazamiento especificado de la cadena almacenada en la clave de la estructura de datos String y devolver el valor de la posición original

1.1 Ventajas:
Ahorro de espacio: Se utiliza un bit para indicar el valor o estado correspondiente a un elemento, donde la clave es el valor del elemento correspondiente. De hecho, 8 bits pueden formar un Byte, por lo que ahorra mucho espacio.
Alta eficiencia: la complejidad de tiempo de setbit y getbit es O (1), y otras operaciones de bit también son eficientes.

1.2 Desventajas: En
esencia, solo hay una diferencia entre 0 y 1, por lo que si usa bits para el registro de datos comerciales, no necesita preocuparse por el valor del valor.

2. Comando de mapa de bits de Redis

2.1 El comando setbit
establece o modifica el valor de la compensación (compensación) en la tecla.

Sintaxis: setbit key offset value
Valor de retorno: especifique el valor almacenado original del desplazamiento (desplazamiento).
Nota: Si el desplazamiento es demasiado grande, el
desplazamiento 0 se completará en el medio hasta el máximo de 2 ^ 32-1, luego la cadena más grande es 512M
Inserte la descripción de la imagen aquí
bitmap
comando setkey 2.2 comando getbit para
consultar el valor de cadena almacenado en la clave para obtener el desplazamiento Un poco de cantidad.

Sintaxis: getbit key offset
Valor de retorno: devuelve el desplazamiento en la clave especificada, si la clave no existe, devuelve 0.
El comando getbit de bitmap
2.3 comando bitcount
Calcular el número de bits establecidos en 1 en el valor de cadena de la clave dada

Sintaxis: bitcount key [start] [end]
Valor de retorno: el número de bit 1.
Nota: setbit sirve para establecer o borrar la posición del bit. Este es el recuento del número de veces que aparece la tecla 1.
Tenga en cuenta que: [inicio] [final] (unidad) es en realidad un byte, ¿qué significa esto? Entrar en redis es en realidad multiplicar por 8.

// 计算长度为 count 的二进制数组指针 s 被设置为 1 的位数量
// 这个函数只能在最大为 512 MB 的字符串上使用
size_t redisPopcount(void *s, long count) {
    
    
    size_t bits = 0;
    unsigned char *p = s;
    uint32_t *p4;
    // 通过查表来计算,对于 1 字节所能表示的值来说
    // 这些值的二进制表示所带有的 1 的数量
    // 比如整数 3 的二进制表示 0011 ,带有两个 1
    // 正好是查表 bitsinbyte[3] == 2
    
    static const unsigned char bitsinbyte[256] = {
    
    0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};

    /* Count initial bytes not aligned to 32 bit. */
    while((unsigned long)p & 3 && count) {
        bits += bitsinbyte[*p++];
        count--;
    }

    /* Count bits 16 bytes at a time */
    // 每次统计 16 字节
    // 关于这里所使用的优化算法,可以参考:
    // http://yesteapea.wordpress.com/2013/03/03/counting-the-number-of-set-bits-in-an-integer/
    p4 = (uint32_t*)p;
    while(count>=16) {
        uint32_t aux1, aux2, aux3, aux4;

        aux1 = *p4++;
        aux2 = *p4++;
        aux3 = *p4++;
        aux4 = *p4++;
        count -= 16;

        aux1 = aux1 - ((aux1 >> 1) & 0x55555555);
        aux1 = (aux1 & 0x33333333) + ((aux1 >> 2) & 0x33333333);
        aux2 = aux2 - ((aux2 >> 1) & 0x55555555);
        aux2 = (aux2 & 0x33333333) + ((aux2 >> 2) & 0x33333333);
        aux3 = aux3 - ((aux3 >> 1) & 0x55555555);
        aux3 = (aux3 & 0x33333333) + ((aux3 >> 2) & 0x33333333);
        aux4 = aux4 - ((aux4 >> 1) & 0x55555555);
        aux4 = (aux4 & 0x33333333) + ((aux4 >> 2) & 0x33333333);
        bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
                ((((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
                ((((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
                ((((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
    }

    /* Count the remaining bytes. */
    // 不足 16 字节的,剩下的每个字节通过查表来完成
    p = (unsigned char*)p4;
    while(count--) bits += bitsinbyte[*p++];
    return bits;
}

Uso de la instrucción bitcount
2.4 comando bitop
Realice una metaoperación en una o más claves de cadena binaria y guarde el resultado en destkey.

Sintaxis: la operación puede ser una de and, or, not y xor.
bitop and destkey key [key...], Combine lógicamente una o más claves y guarde el resultado en destkey.
bitop or destkey key [key...], OR lógico para una o más claves, y guarde el resultado en destkey.
bitop xor destkey key [key...], Lógicamente XOR una o más claves, y guarde el resultado en destkey.
bitop xor destkey key, Para la negación lógica de una o más claves, el resultado se guarda en destkey.
Además de NOT, la mayoría de las demás operaciones pueden aceptar una o más teclas como entrada.

(Golpeando la pizarra, destacando los puntos clave) La complejidad de tiempo de BITOP es O (N). Cuando se trata de matrices grandes o grandes cantidades de estadísticas de datos, es mejor asignar tareas a los nodos esclavos para evitar bloquear el nodo principal.

Ventaja
1. El almacenamiento se basa en la unidad de bits más pequeña, por lo que ahorra mucho espacio.
2. La complejidad temporal del ajuste es O (1), la complejidad temporal de la lectura es O (1) y la operación es muy rápida.
3. El almacenamiento de datos binarios es muy rápido cuando se realizan cálculos relacionados.
4. Ampliación conveniente

La limitación de la
asignación de bits en redis está limitada a 512 MB, por lo que el máximo es 2 ^ 32 bits.

3. Escenarios de uso de mapa de bits

Hay muchas formas de utilizarlos, según las distintas necesidades del negocio, pero en general hay dos tipos, tomando al usuario como ejemplo:

1. Una es la expansión horizontal de un determinado usuario, es decir, los diversos valores de estado del usuario actual se registran en este valor clave, lo que permite una expansión ilimitada (dentro de 2 ^ 32)

Comentario: Este uso se usa básicamente con poca frecuencia, porque cada clave lleva información de uid. Si el espacio de la clave almacenada es mayor que el valor, hay un cierto espacio de optimización desde la perspectiva del espacio. Si es para registrar la cola larga, se puede considerar.

2. Una es la expansión vertical de un usuario, es decir, cada clave solo registra el estado del atributo comercial actual, y cada uid se usa como un bit para registrar información (los usuarios que excedan 2 ^ 32 deben almacenarse en fragmentos)

Comentario: Básicamente, las escenas utilizadas en el proyecto se basan en este método. Es conveniente reciclar los recursos según el negocio. Solo hay un valor clave. El almacenamiento de uid se convierte en almacenamiento de bits. Se puede encontrar el valor correspondiente por uid muy inteligentemente La principal capacidad de almacenamiento es el valor, que está en línea con las expectativas.

1.视频属性的无限延伸

análisis de demanda:

Una aplicación de video corta con miles de millones de volumen de datos, el video tiene varios atributos (ya sea bloqueado, efectos especiales, etc.) y debe marcarse.

Soluciones posibles:

1. Almacenado en mysql, definitivamente no. Uno es que los atributos siguen aumentando con el crecimiento del negocio y hay atributos por tiempo limitado. No es razonable agregar y restar campos directamente a la base de datos. Incluso si hay un campo con tecnología de compresión como json, existe un problema de eficiencia de lectura y, para cientos de millones de datos, es muy problemático reciclar los campos descartados.

2. Registre directamente en redis y guárdelo de acuerdo con el atributo comercial + uid como clave. No hay nada de malo en la eficiencia de lectura y escritura, pero desde la perspectiva del almacenamiento, la cantidad de datos en la clave es mayor que el valor, lo que consume demasiado espacio. Incluso si se almacena utilizando tecnologías de compresión como json. También hay problemas, la descompresión lleva tiempo y la recuperación de datos de cientos de millones también es un problema.

Diseño:

Utilice el mapa de bits de redis para el almacenamiento.
La clave se compone de ID de atributo + ID de segmento de video. El valor modula el rango de segmentación de acuerdo con la identificación de video para determinar el desplazamiento de compensación. Mil millones de videos con un atributo de aproximadamente 120 m es bastante rentable.

Código falso:

function set($business_id , $media_id , $switch_status=1){
    
    
    $switch_status = $switch_status ? 1 : 0;
    $key = $this->_getKey($business_id, $media_id);
    $offset = $this->_getOffset($media_id);
    return $this->redis->setBit($key, $offse, $switch_status);
}

function get($business_id , $media_id){
    
    
    $key = $this->_getKey($business_id,$media_id);
    $offset = $this->_getOffset($media_id);
    return $this->redis->getBit($key , $offset);
}

function _getKey($business_id, $media_id){
    
    
        return 'm:'.$business_id.':'.intval($media_id/10000);
}

function _getOffset($media_id){
    
    
    return $media_id % 10000;
}

Básicamente, esto realiza el almacenamiento de atributos, y la posterior adición de nuevos atributos es solo otro valor para business_id.

¿En cuanto a por qué la fragmentación? ¿Cómo medir la granularidad de la fragmentación?

Hay dos razones para la fragmentación: 1. En la distribución no intensiva, la longitud es demasiado larga, habrá una gran cantidad de 0 valores inútiles ocupando recursos de memoria 2. El mapa de bits tiene un límite de longitud de 2 ^ 32 .

Cómo medir la granularidad de la fragmentación: 1. Si hay una falla en la identificación de la clave principal, elija la granularidad en la medida de lo posible para evitar el rango de identificación de este segmento y evitar el desperdicio de espacio. Porque hay un 00000 ... 9999 0 ... 01, entonces debido al almacenamiento de un atributo. Si lo guarda todo, se desperdicia. 2. La granularidad de la fragmentación se puede juzgar haciendo referencia al valor de crecimiento de una determinada unidad de tiempo, que también conduce a la cantidad de espacio que ocupa el presupuesto, aunque el espacio no ocupará mucho.

2.用户在线状态

análisis de demanda:

¿Necesita proporcionar una interfaz al subproyecto para indicar si un usuario está en línea?

Diseño:

El uso de mapa de bits es un método eficiente y que ahorra espacio. Solo necesita una clave y el ID de usuario es el desplazamiento de compensación. Si está en línea, se establece en 1 y se establece en 0 si está fuera de línea. 300 millones los usuarios solo necesitan 36 MB de espacio.

Código falso:

$status = 1;
$redis->setBit('online', $uid, $status);
$redis->getBit('online', $uid);

Es necesario agregar el mismo método de fragmentación que en el Ejemplo 1. Mil millones es realmente demasiado. 10w divididos en una sola pieza.

3.统计活跃用户

análisis de demanda:

Necesidad de calcular la situación de los datos de los usuarios activos.

Diseño:

Use el tiempo como clave para el caché, y luego la identificación del usuario se compensa y se establece en 1 si ha estado activo ese día. Posteriormente, se realizan cálculos binarios a través de bitOp para calcular la actividad del usuario en un período de tiempo determinado.

Código falso:

$status = 1;
$redis->setBit('active_20170708', $uid, $status);
$redis->setBit('active_20170709', $uid, $status);
$redis->bitOp('AND', 'active', 'active_20170708', 'active_20170709'); 

Cientos de millones de usuarios necesitan agregar fragmentación como en el Ejemplo 1. Si son cientos de miles o menos, no es necesario dividir el negocio para ahorrar complejidad.
Otras situaciones similares:
clave: fecha;
desplazamiento: id de usuario [número o binario];
valor: si iniciar sesión / realizar alguna operación;
generar un mapa de bits por fecha

Cálculo 月活: todos los mapas de bits de 30 días se pueden calcular mediante OR, y se realiza el cálculo del recuento de bits;
cálculo 留存率: ayer retenido = el número de personas que iniciaron sesión continuamente ayer y hoy / el número de personas que iniciaron sesión ayer, es decir, ayer El mapa de bits y el mapa de bits de hoy se calculan y se dividen por el número de bitcount ayer.

4.用户签到

análisis de demanda:

El usuario debe iniciar sesión y los datos de inicio de sesión deben analizarse y la estrategia de operación correspondiente.

Diseño:

Utilizando redis bitmap, por ser un registro de cola larga, la clave está compuesta principalmente por uid y se establece una hora inicial, luego, si no se suma un día, corresponde a la posición del offset en el valor.

Código falso:

$start_date = '20170708';
$end_date = '20170709';
$offset = floor((strtotime($start_date) - strtotime($end_date)) / 86400);
$redis->setBit('sign_123456', $offset, 1);

//算活跃天数
$redis->bitCount('sign_123456', 0, -1)

No se requiere fragmentación. Durante los 365 días del año, 300 millones de usuarios representan aproximadamente 300000000 * 365/8/1000/1000/1000 = 13,68 g. ¿El costo de almacenamiento es muy bajo?

使用bitmap过程中可能会遇到的坑

1. La trampa de bitcout
Si lee el uso anterior con atención, encontrará que hay una nota como "devolver el número de bits en una clave especificada con un valor de 1 (en bytes, no bits)", aquí es donde el hoyo es.

Hay imágenes y la verdad:
Inserte la descripción de la imagen aquí
así que cuenta de bits 0 0, entonces debería ser el número 1 en el primer byte. Tenga en cuenta que es un byte. El primer byte es 0,1,2,3,4,5,6, 7 estas ocho posiciones.

4. Comparación del uso de almacenamiento establecido y BitMap,

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

A través de la comparación anterior, podemos ver que si hay muchos usuarios independientes, usar BitMap es obviamente más ventajoso y puede ahorrar mucha memoria. Sin embargo, si la cantidad de usuarios independientes es pequeña, se recomienda utilizar el almacenamiento establecido, ya que BitMap generará una sobrecarga de almacenamiento redundante.

Utilice el
tipo de experiencia = cadena, BitMap es un tipo de picadura, el máximo es 512 MB.
Preste atención al desplazamiento durante el setbit, que puede llevar mucho tiempo
, ya que el mapa de bits no es absolutamente bueno.

Supongo que te gusta

Origin blog.csdn.net/qq_26249609/article/details/103563391
Recomendado
Clasificación