【高同時シンプルソリューション】redisキューキャッシュ+mysql一括入庫+phpオフライン統合

11160 ワード

需要背景:
mysqlに格納する必要がある呼び出し統計ログストレージと統計需要があります.ストレージ・データのピークは1日1千万に達し、ボトルネックは直接入庫して同時に高すぎてmysqlを潰す可能性があることです.
もんだいぶんせき
思考:応用ウェブサイトアーキテクチャの回折過程において、最新のフレームワークとツール技術を応用することはもちろん最良の選択である.しかし,既存のフレームワークに基づいて簡単に依存できるソリューションを提案できれば,自己向上の試みではないだろうか.
解決:
問題1:ログの入庫が望ましいことを要求する.しかし、直接入庫mysqlは確かに担げません.ロット入庫は問題ありません.done.【一括入庫と直接入庫の性能差異参考文献】
問題2:一括入庫には高い同時メッセージキューが必要であり、redis listシミュレーションで実現することを決定し、ロールバックを容易にする.
問題3:ログの量は結局大きくて、最近の30条を保存して十分で、phpでオフライン統計とスクリプトを整理することを決定します.
done、次はドラッグの簡単な実現過程です.
一:データベーステーブルとストレージの設計
logシステムのデータベースに対するパフォーマンスがより多く、安定性とセキュリティがそれほど高くないことを考慮すると、ストレージエンジンはselect insertのインデックスのないarchiveのみをサポートします.確かにupdate需要があればmyISAMも採用できます.
logがリアルタイムで記録されたすべてのデータであることを考慮すると、数は巨大である可能性があり、プライマリ・キーはbigintを採用し、自己増加すればよい.
logシステムは書き込みを主とすることを考慮して、統計はオフライン計算を採用して、フィールドはすべてインデックスが現れないで、一方ではデータの挿入効率に影響する可能性があるため、また読む時にデッドロックをもたらして、データの書き込みに影響します.
二:redisストレージデータ形成メッセージキュー
高同時性のため、できるだけ簡単で、直接、コードをつけます.
/***************************************************************************
*
*         ,  redis    .
* $Id$
*
**************************************************************************/

/**
* @file saveLog.php
* @date 2015/11/06 20:47:13
* @author:cuihuan
* @version $Revision$
* @brief
*
**/

//   info
$interface_info = $_GET['info'];

//   redis  
$redis = new Redis();
$redis->connect('xx', 6379);
$redis->auth("password");

//          
$now_time = date("Y-m-d H:i:s");
$redis->rPush("call_log", $interface_info . "%" . $now_time);
$redis->close();


/* vim: set ts=4 sw=4 sts=4 tw=100 */
?>

三:データの定期的な一括入庫.
redisメッセージキュー内のデータをタイミングで読み出し、一括入庫します.

/**
 *   redis        ,  sql,    。
 * @update 2015-11-07              
 *
 * @Author:cuihuan
 * 2015-11-06
 * */

// init redis
$redis_xx = new Redis();
$redis_xx->connect('ip', port);
$redis_xx->auth("password");

//            
$count = 0;
$max = $redis_xx->lLen("call_log");

//          ,  sql
$insert_sql = "insert into fb_call_log (`interface_name`, `createtime`) values ";

//     
$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;
    }

    //       info
    $log_info_arr = explode("%",$log_info);
    $insert_sql .= " ('".$log_info_arr[0]."','".$log_info_arr[1]."'),";
    $count++;
}

//       ,    
if ($count != 0) {
    $link_2004 = mysql_connect('ip:port', 'user', 'password');
    if (!$link_2004) {
        die("Could not connect:" . mysql_error());
    }

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

    //     log     ;
    echo date("Y-m-d H:i:s")."insert ".$count." log info result:";
    echo json_encode($res);
    echo "
"
; // if(!$res){ foreach($roll_back_arr as $k){ $redis_xx->rPush("call_log", $k); } } // mysql_free_result($res); mysql_close($link_2004); } // redis $redis_cq01->close(); ?>

四:オフライン天級統計とデータ・スクリプトのクリーンアップ
?php
/**
* static log :                   
*
* @Author:cuihuan
* 2015-11-06
* */

//     
$link_2004 = mysql_connect('ip:port', 'user', 'pwd');
if (!$link_2004) {
    die("Could not connect:" . mysql_error());
}

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

//        
$day_time = date("Y-m-d", time() - 60 * 60 * 24 * 1);
$static_sql = "get sql";

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

//        

//   15      
$before_15_day = date("Y-m-d", time() - 60 * 60 * 24 * 15);
$delete_sql = "delete from xxx where createtime < '" . $before_15_day . "'";
try {
    $res = mysql_query($delete_sql);
}catch(Exception $e){
    echo json_encode($e)."
"
; echo "delete result:".json_encode($res)."
"
; } mysql_close($link_2004); ?>

五:コード配置
主に配置、一括入庫スクリプトの呼び出しと天レベル統計スクリプト、crontabルーチン実行です.
#       
*/2 * * * * /home/cuihuan/xxx/lamp/php5/bin/php /home/cuihuan/xxx/batchLog.php >>/home/cuihuan/xxx/batchlog.log

#       
0 5 * * * /home/cuihuan/xxx/php5/bin/php /home/cuihuan/xxx/staticLog.php >>/home/cuihuan/xxx/staticLog.log

まとめ:他の複雑な方法で高同時処理を行うよりも、このソリューションは簡単で効果的です.redisキャッシュによる耐圧、mysqlロット入庫によるデータベースボトルネックの解決、オフライン計算による統計データの解決、定期的なクリーンアップによるライブラリのサイズの保証.