Solución simple para caché de cola de alta concurrencia-redis + almacenamiento por lotes mysql

Análisis de problemas

  • Pregunta 1: Es mejor requerir que los registros se almacenen en la base de datos; sin embargo, mysql no se puede almacenar directamente en la base de datos, y no hay ningún problema en el almacenamiento por lotes, hecho. [La diferencia de rendimiento entre el almacenamiento por lotes y el almacenamiento directo]
  • Problema dos: se requieren colas de mensajes de alta concurrencia para el almacenamiento por lotes y se decide utilizar la simulación de la lista de redis para lograr la reversión.
  • Pregunta tres: Después de todo, la cantidad de registros es grande. Es suficiente para guardar los últimos 30 elementos. Decidí escribir un script de limpieza y estadísticas fuera de línea con php.

1. Diseñar tablas de bases de datos y almacenamiento

  • Teniendo en cuenta que el sistema de registro tiene más rendimiento en la base de datos, la estabilidad y la seguridad no son tan altas 存储引擎自然是只支持select insert 没有索引的archive. Si necesita actualizar, también puede usar myISAM.
  • Teniendo en cuenta que el registro es todos los datos registrados en tiempo real, el número puede ser enorme 主键采用bigint,自增即可.
  • Teniendo en cuenta el sistema de registro 以写为主,统计采用离线计算,字段均不要出现索引, por un lado, puede afectar la eficiencia de la inserción de datos y, además, provocará un punto muerto al leer y afectar la escritura de datos.

En segundo lugar, redis almacena datos para formar una cola de mensajes.

Código de copia
/ ** 
     * Use la cola para generar datos de prueba de reids 
     * Correcto : después de realizar la operación RPUSH, la longitud de la lista devuelta: 8 
     * / 
    public function createRedisList ($ listKey = 'message01') 
    { 
        $ redis = RedisInstance :: MasterInstance (); 
        $ redis -> select (1); 
        $ mensaje = [ 
            'type' => 'say', 
            'userId' => $ redis-> incr ('user_id'), 
            'userName' => 'Tinywan'. mt_rand (100, 9999 ), // Si la grabación 
            'userImage' => '/res/pub/user-default-w.png', // Si la grabación es 
            'openId' => 'openId'. Mt_rand (100000, 9999999999999999), 
            'roomId '=>' openId '. mt_rand (30, 50),
            'createTime' => date ('Ymd H: i: s', time ()),
            'content' => $ redis-> incr ('content') // Si el estado actual de transmisión es 
        ];
        $ rPushResul = $ redis-> rPush ($ listKey, json_encode ($ message)); // Devuelve la longitud de la lista actual después de una ejecución exitosa 9 
        devuelve $ rPushResul; 
    }
Código de copia

Tres, lea los datos en la cola de mensajes de redis, almacenamiento por lotes

La primera idea:

Código de copia
/ ** 
     * 消息 Redis 方法 保存 到 Mysql 数据库
     * @param string $ liveKey 
     * / 
    public function RedisSaveToMysql ($ listKey = 'message01') 
    { 
        if (empty ($ listKey)) { 
            $ result = ["errcode" => 500 , "errmsg" => "¡este parámetro está vacío!"]; 
            exit (json_encode ($ resultado)); 
        } 
        $ redis = RedisInstance :: MasterInstance (); 
        $ redis-> select (1); 
        $ redisInfo = $ redis-> lRange ($ listKey, 0, 5); 
        $ dataLength = $ redis-> lLen ($ listKey); 
        $ modelo = M ("Usuario"); 
        while ($ dataLength> 65970) { 
            pruebe { 
                $ model->
                $ redis-> watch ($ listKey); 
                $ arrList = []; 
                foreach ($ redisInfo como $ key => $ val) { 
                    $ arrList [] = array ( 
                        'username' => json_decode ($ val, true) ['userName'], 
                        'logintime' => json_decode ($ val, true) ['createTime'], 
                        'descripción' => json_decode ($ val, verdadero) ['contenido'], 
                        'pido' => json_decode ($ val, verdadero) ['contenido'] 
                    ); 
                } 
                $ insertResult = $ model-> addAll ($ arrList); 
                Si (! 
                    $ result = array ("errcode" => 500, "errmsg" 
                    exit (json_encode ($ resultado)); 
                } 
                $ modelo-> commit (); 
                $ redis-> lTrim ($ listKey, 6, -1); 
                $ redisInfo = $ redis-> lRange ($ listKey, 0, 5); 
                $ dataLength = $ redis-> lLen ($ listKey); 
            } catch (Exception $ e) { 
                $ model-> rollback (); 
                $ result = array ("errcode" => 500, "errmsg" => "Insertar datos en error!"); 
                exit (json_encode ($ resultado)); 
        $ result = array ("errcode" => 200, "errmsg" => "Insertar datos en el éxito!", 'data' => 'dataLength:'. $ dataLength. 'liveKey: 
        exit (json_encode ($ resultado)); 
    }
Código de copia

La segunda idea (para referencia, no marco) 

Código de copia
<? php 
$ redis_xx = new Redis (); 
$ redis_xx-> connect ('ip', port); 
$ redis_xx-> auth ("password"); 

// Obtenga la longitud de la cola de mensajes existente 
$ count = 0; 
$ max = $ redis_xx-> lLen ("call_log"); 

// Obtener el contenido de la cola de mensajes, stitch sql 
$ insert_sql = "insertar en fb_call_log (` interface_name`, `createtime`) valores"; 

// Deshacer la matriz 
$ roll_back_arr = array (); 

while ($ count <$ max) { 
    $ log_info = $ redis_cq01-> lPop ("call_log"); 
    $ roll_back_arr = $ log_info; 
    if ($ log_info == 'nil' ||! isset ($ log_info) ) { 
        $ insert_sql. = ";"; 
        break; 
    } 

    // Recorte el tiempo y la información 
    $ log_info_arr = explotar ("% ", $ log_info);
    $ insert_sql. = "('". $ log_info_arr [0]. "', '". $ log_info_arr [1]. "'),"; 
    $ count ++; 
} 

// 判定 存在 数据 , 批量 入库
if ($ count! = 0) { 
    $ link_2004 = mysql_connect ('ip: puerto', 'usuario', 'contraseña'); 
    if (! $ link_2004) { 
        die ("No se pudo conectar:". mysql_error ()); 
    } 

    $ crowd_db = mysql_select_db ('fb_log', $ link_2004); 
    $ insert_sql = rtrim ($ insert_sql, ","). ";"; 
    $ res = mysql_query ($ insert_sql); 

    // 输出 入库 log 和 入库 结果; 
    fecha de eco ("Ymd H: i: s"). "insertar". $ cuenta. "resultado de información de registro:"; 
    echo json_encode ($ res);

        foreach ($ roll_back_arr como $ k) { 
            $ redis_xx-> rPush ("call_log", $ k); 
        } 
    } 
    // 释放 连接 mysql_free_result 
    ($ res); 
    mysql_close ($ link_2004); 
} 
$ redis_cq01-> close (); 
?>
Código de copia

En cuarto lugar, obtener datos de caché de datos de Redis

 

Código de copia
/ ** 
     * [0] Verifique si la conexión actual de Redis es exitosa 
     * [1] Obtenga los datos, primero obtenga de Redis, si no, luego obtenga de la base de datos 
     * / 
    public function findDataRedisOrMysql ($ listKey = 'message01') 
    { 
        / / Verificar el estado de conexión actual Verificar 
        si el servicio se está ejecutando si (RedisInstance :: MasterInstance ()! = False) ( 
            $ redis = RedisInstance :: MasterInstance (); 
            $ redis-> select (2); 
            / ** 
             * Primero de Redis Para obtener los datos 
             * lRange Si está vacío, significa que no hay datos; de lo contrario, devuelve una matriz no vacía 
             * / 
            $ redisData = $ redis-> lRange ($ listKey, 0, 9); 
            $ resultData = []; 
            if (! Empty ($ redisData)) {
                $ resultData ['status_code'] = 200; 
                $ resultData ['msg'] = 'Fuente de datos de Redis Cache'; 
                foreach ($ redisData como $ key => $ val) { 
                    $ resultData ['listData'] [] = json_decode ($ val, verdadero); 
                } 
            } else { 
                $ resultData ['redis_msg'] = 'Redis ha caducado'; 
                $ condiciones = matriz ('estado' => ': estado'); 
                $ mysqlData = M ('Usuario') -> where ($ condiciones) -> bind (': status', 1, \ PDO :: PARAM_STR) -> select (); 
                if ($ mysqlData) { 
                    $ resultData ['status_code'] = 200;
                    $ redis-> select (2); 
                    foreach ($ mysqlData como $ key => $ val) { 
                        $ resultData ['listData'] [] = $ val; 
                        // Escribe Redis como caché 
                        $ redis-> rPush ($ listKey , json_encode ($ val)); 
                    } 
                    // También establezca un tiempo de vencimiento 
                    $ redis-> expire ($ listKey, 30); 
                } else { 
                    $ resultData ['status_code'] = 500; 
                    $ resultData ['mysql_msg'] = ' El origen de datos de Mysql es Fail '; 
                } 
            } 
        } else { 
            $ resultData [' redis_msg '] ='El servidor de Redis se fue ';
            $ resultData ['mysql_msg'] = 'Mysql Data2'; 
            $ condiciones = matriz ('estado' => ': estado'); 
            $ mysqlData = M ('Usuario') -> where ($ condiciones) -> bind (': status', 1, \ PDO :: PARAM_STR) -> select (); 
            foreach ($ mysqlData como $ key => $ val) { 
                $ resultData ['listData'] [] = $ val; 
            } 
        } 
        homePrint ($ resultData); 
    }
Código de copia

 

Cuarto, estadísticas de nivel fuera de línea y script de limpieza de datos

Código de copia
<? php 
/ ** 
* registro estático: registro diario de código de estadísticas fuera de línea y registro eliminado hace cinco días 
* * / 

// estadísticas fuera de línea 
$ link_2004 = mysql_connect ('ip: puerto', 'usuario', 'pwd'); 
si (! $ link_2004) { 
    die ("No se pudo conectar:". mysql_error ()); 
} 

$ crowd_db = mysql_select_db ('fb_log', $ link_2004); 

// Estadísticas de los datos de ayer 
$ day_time = date ("Ymd", hora () -60 * 60 * 24 * 1); 
$ static_sql = "get sql"; 

$ res = mysql_query ($ static_sql, $ link_2004); 

// Obtenga los resultados en la biblioteca 

// Borre los datos antes de 15 días 
$ before_15_day = date ("Ymd", time () -60 * 60 * 24 * 15); 
$ delete_sql = "eliminar de xxx donde createtime <'". $ before_15_day. "'";
intente { 
    $ res = mysql_query ($ delete_sql);
} catch (Exception $ e) { 
    echo json_encode ($ e). "\ n"; 
    echo "eliminar resultado:". json_encode ($ res). "\ n"; 
} 

mysql_close ($ link_2004); 
?>
Código de copia

Cinco: implementación de código

Se implementa principalmente, la llamada de scripts de almacenamiento por lotes y scripts de estadísticas a nivel de día, y crontab se ejecuta de forma rutinaria.

# Script de almacenamiento por lotes 
* / 2 * * * * / home / cuihuan / xxx / lamp / php5 / bin / php /home/cuihuan/xxx/batchLog.php >> / home / cuihuan / xxx / batchlog.log 

# days Guión de estadísticas de nivel 
0 5 * * * / home / cuihuan / xxx / php5 / bin / php /home/cuihuan/xxx/staticLog.php >> / home / cuihuan / xxx / staticLog.log

Resumen: en comparación con otras formas complicadas de lidiar con una alta concurrencia, esta solución es simple y efectiva: a través de la compresión de caché redis, el almacenamiento por lotes mysql para resolver cuellos de botella en la base de datos, el cálculo fuera de línea para resolver datos estadísticos y la limpieza regular para garantizar el tamaño de la biblioteca.

Supongo que te gusta

Origin www.cnblogs.com/liliuguang/p/12718799.html
Recomendado
Clasificación