ホームページ >バックエンド開発 >PHPチュートリアル >[高同時実行性のシンプルなソリューション] redis キャッシュ キュー + mysql バッチ ストレージ + php オフライン統合

[高同時実行性のシンプルなソリューション] redis キャッシュ キュー + mysql バッチ ストレージ + php オフライン統合

WBOY
WBOYオリジナル
2016-06-23 13:10:39956ブラウズ

要件の背景: 統計ログ ストレージと統計を呼び出す需要があり、これには mysql 内のストレージが必要です。保存されるデータのピーク値は 1 日に数千万に達する可能性があり、直接ストレージの同時実行性がボトルネックとなります。高すぎると、mysql がダウンする可能性があります。

問題分析

思考: アプリケーション Web サイトのアーキテクチャの進化の過程では、最新のフレームワークとツール技術を適用することが確かに最良の選択ですが、既存のフレームワークに基づいてシンプルで信頼性の高いソリューションを提案できるのであれば、おそらくそれが最善の選択です。自分自身を改善しようとする試み。解決策:

  • 問題 1: ログをデータベースに保存する必要がありますが、mysql はデータベースへの直接ログインを処理できません。データベースへのバッチ ログインには問題ありません。 [バッチ ウェアハウスとダイレクト ウェアハウスのパフォーマンスの違いに関する参考記事]
  • 質問 2: バッチ ウェアハウスは同時実行性の高いメッセージ キューを必要とするため、ロールバックが簡単な Redis リスト シミュレーションを使用して実装することにしました。
  • 質問 3: 結局ログの量が膨大なので、最新の 30 エントリを保存するだけで十分であると考え、PHP でオフライン統計とクリーニング スクリプトを作成することにしました。

完了しました。以下は Xiaoyan の簡単な実装プロセスです

1: データベースのテーブルとストレージを設計します

  • データベースのパフォーマンスはログ システムの方が高く、安定性とセキュリティはそれほど高くないことを考慮すると、ストレージ エンジンは当然のことながら、インデックスなしの選択挿入アーカイブのみをサポートします。本当に更新する必要がある場合は、myISAM を使用することもできます。
  • ログはすべてリアルタイムに記録されたデータであり、その量が膨大になる可能性があることを考慮して、主キーはbigintを使用し、単独でインクリメントできるようにしています。
  • ログ システムが主に書き込まれることを考慮すると、統計はオフラインで計算され、データ挿入の効率に影響を与える可能性があり、デッドロックが発生する可能性があるため、フィールドにインデックスを表示すべきではありません。読み取り中はデータの書き込みに影響します。

2 つ: 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 */?>

3: データは一定の間隔でバッチに保存されます。

Redis メッセージ キュー内のデータを定期的に読み取り、バッチで保存します。

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 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 "n";    // 数据库插入失败回滚    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();?>

4: オフラインの日レベルの統計とデータ スクリプトのクリーニング

?php/*** static log :每天离线统计代码日志和删除五天前的日志** @Author:cuihuan@baidu.com* 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 

5: コードのデプロイメント

主にデプロイメント、バッチ ウェアハウス スクリプトと日レベルの統計スクリプトの呼び出し、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 バッチ ウェアハウスを使用し、統計データを解決するためにオフライン計算を使用し、ライブラリのサイズを確保します。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。