シンプルな定期タスク解決方法:最小バージョン2.8以上の場合は、サーバー上でレイズように、この機能は、Redisのバージョン2.8以降に導入されたことをRedisの鍵空間の通知(通知イベントボンドの失敗後)注;
(A)ビジネスシナリオ:
1.タイミングタスクを開始するためのビジネストリガ必要性が、指定した時間内にタスクを実行するために行くとき(例えば、自動的にオーダー、オートコンプリート注文や他の機能をキャンセル)
、鍵空間通知のRedisのが失敗にキーイベントが送信されます2、クライアントが通知を受け取ることができ、このイベントに耳を傾けます
(B)サービスを準備します。
1、変更設定ファイルレイズ(redis.conf)[システム構成ウィンドウファイル:redis.windows.conf]
開封後は、CPUの消費量が存在することになるので、デフォルトはオープンキースペース通知しませんRedisの
注:E:KeyEventのイベント、イベント__keyevent @ <DB> __接頭辞として公開します。
X:キーが期限切れとイベントを削除する必要があります期限切れのイベント、。
元の構成は次のとおりです。
notify-keyspace-events ""
次のように設定を変更します。
notify-keyspace-events "Ex"
設定を保存した後、構成を検証し、Redisのサービスを再起動します
[root@chokingwin etc]#
service redis-server restart /usr/local/redis/etc/redis.conf
Stopping redis-server: [ OK ]
Starting redis-server: [ OK ]
、その後、ターンRedisのファイルディレクトリに切り替える前に、ウィンドウシステムの再起動をRedisの、次に近いサービス(Redisのサーバー--service-停止)のRedis(Redisのサーバー--serviceスタート)
C)ファイルのコード:
phpredisが鍵空間通知をサブスクライブ達成、自動的に順序、自動的に注文をキャンセルすることができます。以下は、テストケースであります
4つのファイルを作成し、自分がRedisのデータベース構成パラメータを変更します
db.class.php
<phpclass mysqliのプライベートMySQLの$ {;?プライベート$結果; / ** *データベース接続 * @param $ CONFIGコンフィギュレーションの配列* / パブリック関数、Connect()の {$ CONFIG =配列( 'ホスト' => '127.0.0.1'、 => 'ルート'、 'ユーザー名' 'パスワード' => '168 168'、 'データベース' => 'テスト'、 'ポート' => 3306、 );ホスト= $ $ CONFIG [ 'ホスト']; //ホストアドレス $ユーザ名= $ CONFIG [ 'ユーザ名 ']; // ユーザ名 $パスワード= $ CONFIG [ 'パスワード ']; // パスワード $データベース= $ CONFIG [ 'データベース ']; // データベース $ポート= $ CONFIG [ 'ポート'];//端口号 の$ this - > mysqliの=新しいmysqliの($ホスト、$ユーザ名、$パスワード、$データベース、$ポート)。 } / ** *データクエリ * @param $表データテーブル * @paramヌル$フィールドフィールド * @paramヌル$ここ条件 * @return混合数のクエリ結果* / パブリック関数SELECT(表$、$フィールド=ヌル、$ = nullの場合) {$ SQL = "{$` SELECT * FROM表} `"; //エコー$ SQL;終了し; 。IF(!空($フィールド))= {フィールド$ '`'破(「`、 ` '$フィールド)。 '' '; $ SQL = str_replace(' *'、$フィールド、$ SQL); !} IF(空($ WHERE)){$ SQL = $ SQL' WHERE「$ WHERE。 ; }の$ this - >を=の$ this - > mysqli->クエリ結果($ SQL);戻ります$ this->結果。 } / ** * @return混合すべての結果を得る* / パブリック関数はfetchAll() {戻りの$ this - > result-> fetch_all(MYSQLI_ASSOC)。 } / ** *插入数据 * @param $表数据表 * @param $データ数据数组 * @return混合插入ID * / パブリック関数insert($表、$データ) $キー=> $として{foreachの($データ値){$データ[$キー] =の$ this - > mysqli-> real_escape_string($値)。 } $キー= '`'。破( '`、`'、array_keys($データ))。'`'; $値= '\'」。破( " ''"、array_values($データ))。'\' '; $ SQL = "INSERT INTO` {$テーブル} `({$キー})VALUES({$値})"。の$ this - > mysqli->クエリ($ SQL)。リターンの$ this - > mysqli-> INSERT_ID。 * @param $过滤条件 * @return混合受影响记录* / パブリック関数の更新($表、$データ、$) {foreachの($データ$キー=> $値として){$データ[$キー] =の$ this - > mysqli-> real_escape_string($値); } $セット=配列(); foreachの($キーとして$データ=> $値){$ KSTR = '''。$キー。'`'; $ VSTR = '\'」。$値。'\' '; ($ KSTR、$セット'=' $ VSTR。。)array_push。 } $ KAV =破( ''、$セット)。$ SQL = "UPDATE` {$テーブル} `SET {$ KAV} {$}"。の$ this - > mysqli->クエリ($ SQL)。リターンの$ this - > mysqli-> affected_rows。 * @return混合受影响记录* / ($場合$テーブル)を削除パブリック関数 {$ SQL = "'{$テーブル}` {$ここ} FROM DELETE"。の$ this - > mysqli->クエリ($ SQL)。リターンの$ this - > mysqli-> affected_rows。 } }
index.phpを
<?phpの require_onceを'Redis2.class.php'; $ Redisの=新しい\ Redis2( '127.0.0.1'、 '6379'、 ''、 '15'); $ order_sn = 'SN'.time()' T'.rand(10000000,99999999); $ use_mysql = 1; //是否使用数据库、1使用、2不使用 するif($ use_mysql == 1){ / * * //数据表 * TABLE `order`(CREATE *` ordersn`のVARCHAR(255)NOT NULL DEFAULTを''、 * `status` VARCHAR(255)NOT NULLとDEFAULT ''、 *` createtime` VARCHAR(255)NOT NULLとDEFAULT ''、 * `id` INT(11)符号なしNOT NULL AUTO_INCREMENT、 * PRIMARY KEY(` id`) *) ENGINE = InnoDBのAUTO_INCREMENT = 27 DEFAULT CHARSET = utf8mb4。 MySQLの新しい新しい= $ \ MySQLの(); $はmysql->接続(); $データ= [ 'ordersn' => $ order_sn、 'ステータス' => 0、」CREATETIME '=> DATE('はYmd H:I:S '時間())]; $はmysql-> INSERT('注文」、$データ); } $ =リスト[order_sn $、$ use_mysql]; $ =キー破( ':'、$リスト); $ redis- > SETEX($キー、3は、 「Redisの遅延タスクを」); // 3秒のコールバック後に $ test_del = falseは、キャッシュを削除するためにコールバックした後、そこに期限切れになるかどうか//テスト。結果:いいえコールバック IF($ test_del == trueに){ // SLEEP(1); ($ order_sn)$ redis-> [削除]; } エコー$ order_sn; / * *その他のキーテストは、コールバックを持つことになり、結果:コールバック * $ = K 'テスト'; * $ redis2-> SET(K $、 '100'); * $ redis2->期限切れ($ K、10)。
psubscribe.php
<PHP? ini_set( 'default_socket_timeout'、-1); //ないタイムアウト するrequire_once 'Redis2.class.php'; $ redis_db = '15'; $ = Redisの新しい新\ Redis2( '127.0.0.1'、 '6379'、 ''、$ redis_db); // Redisのクライアントサブスクリプションタイムアウト状況解決 ; $ redis-> setOptionを() //キーは、通知、サブスクリプションキー__keyeventを参照してください有効期限が切れたときに@ <DB> __:有効期限が切れ、このフォーマットを固定され、DBは、それが分離するように単一のデータベースを使用するのが最適ですので、サブスクリプションの有効期限を開くために、すべてのキーは、このライブラリを押し上げされた後から、データベースの数を表している (配列(「$ redis-> psubscribe __のKeyEvent @」 。$ redis_db .'__:期限切れ')、' keyCallback「); //コールバック関数、処理ロジックの書き込み 機能keyCallback(Redisの$、$パターン、チャンネル$、$ MSG)が { エコー値がPHP_EOLであり、 エコー「パターン:$パターン; "\ N- エコー"チャンネル:$チャンネル\ N- "; エコー"ペイロード:$ MSG \ N \ N "; $一覧=爆発( ':'、$ MSG)。 $ order_sn = ISSET($リスト[0])$リスト[0]:? '0'; $ use_mysql = ISSET($リスト[1])$リスト[1]:? '0'; IF($ use_mysql == 1){ するrequire_once 'db.class.php'。 $ mysqlの=新しい\ mysqlの(); 接続$はmysql->(); $どこ= "ordersn = '" $ order_sn。。 "'"; $はmysql->を選択し( '順序'、 ''、$場合)。 $発見= $はmysql-> fetchAllの(); しますprint_r($発見)。 IF(ISSET($発見[0] [ 'ステータス'])&& $発見[0] [ 'ステータス'] == 0){ $データ=配列( 'ステータス' => 3)。 。$ = "ID =" $発見[0] [ 'ID']。 $はmysql->更新( '注文'、$データ、 ')/*$redis->psubscribe(array('__keyevent@'.$redis_db.'__:expired、機能($のRedis、$パターン、$チャンネル、$ MSG){ エコーPHP_EOL; エコー「パターン:$パターン\ N "; エコー"チャンネル:$チャンネル\ nは"; エコー"ペイロード:$ MSG \ N \ N"; // ................ }); * /
Redis2.class.php
<?PHPの クラスRedis2 { プライベート$はRedisの。 パブリック関数の__construct($ホスト= '127.0.0.1'、$ポート= '6379'、$パスワード= ''、$デシベル= '15') { の$ this - >のRedis =新しいRedisの(); の$ this - > redis-> CONNECT($ホスト、$ポート)。//连接のRedis ます$ this-> redis-> AUTH($パスワード); //密码验证 ます$ this-> redis->($デシベル)を選択します。//选择数据库 } パブリック関数SETEX($キー、$時間、$ヴァル) { 戻りの$ this - > redis-> SETEX($キー、$時間、$ヴァル); } パブリック関数セット($キー、$ヴァル) { の$ this - > redis->セット($キー、$ヴァル)を返します。 返します$ this-> redis-> GET($キー)。 } パブリック関数($キー= NULL、= 0 $時間)期限切れ { の$ this - > redis->($キー、$時間)期限切れに戻ります。 } パブリック関数psubscribe($パターン=配列()、$コールバック) { の$ this - > redis-> psubscribe($パターン、$コールバック)。 } パブリック関数setOptionを() { の$ this - > redis-> setOptionを(\のRedis :: OPT_READ_TIMEOUT、-1)。 } パブリック関数LRANGE($キー、$、$始端) { 戻りの$ this - > redis-> LRANGE($キー、$開始、$エンド); } パブリック関数lPush($キー、$値1、値2 $ =ヌル、$値N = NULL){ 返します$ this-> redis-> lPush($キー、$をvalue1、$ value2の= nullを、$値N = NULL); } 削除パブリック関数は、($ KEY1、$ KEY2 =ヌル、$ KEY3 = NULL) { ($ KEY1、$ KEY2 =ヌル、$ KEY3 = NULL)の$ this - > redis->削除返します。 } }
ウィンドウシステム試験方法:CMDコマンドインタフェースで最初はpsubscribe.phpを実行し、そのページはindex.phpを開きます。
モニターの背景は常に実行されている(サブスクリプション)
phpredis膨張によって、この手順を行うには問題があり、リスナーの実装を成功さは、コード内でキーの有効期限が切れて、コールバック処理psCallback()の内部。冒頭で述べ2つの要件が達成されています。しかし、ここで問題があります:Redisのサブスクリプションの操作を実行した後に、端末は必要性がでそこにぶら下がってきた、ブロックされた状態になります。このスクリプトは、実際の需要を満たしていない、コマンドラインでの人間とサブスクリプションが必要です。
実際には、我々はコールバック要求を期限切れに耳を傾け、それはイベントが期限切れのメッセージ、トリガコールバック関数を持っているときにバックグラウンドで実行されているデーモンと同じ期待されています。バックグラウンドデーモンが背景のようにほぼ同じであるとしてリスナーは、常に実行したいです
私は達成されます。
Linuxは、nohupコマンドを持っています。ただ、コマンドを実行する機能をハングアップしません。ファイルが書き込み可能でない場合、一方nohupを出力すべてのスクリプトは、ファイル/nohup.outし、<ユーザのホームディレクトリ>に、カレントディレクトリにファイルnohup.out入れています。したがって、このコマンドを使用して、後にかかわらず、我々は、ターミナルウィンドウを閉じているかどうかの、あなたは、PHPスクリプトが実行されたさせることができます。
書き込みpsubscribe.phpファイル:
<?PHPの #は/ usr / binに/ envをPHP! ini_set( 'default_socket_timeout'、-1); //ませんタイムアウト するrequire_once 'Redis2.class.php'; $ redis_db = '15'; $ Redisの=新しい新\ Redis2( ' 127.0.0.1 '' 6379 ''」、$ redis_db); //はRedisのクライアントのサブスクリプションのタイムアウトを状況解決 $ redis-> setOptionを(); //キーが通知サブスクリプションキー__keyeventを見るために有効期限が切れ@ <DB> __:すべてのサブスクリプションの有効期限を開くには、キーの後に、このライブラリを押し上げされますので、それを隔離するために単一のデータベースを使用するのが最善であるように固定され、このフォーマットは、DBは、データベースの数を表し期限切れ $ redis- > psubscribe(。配列は( '__たKeyEvent @は' $ redis_dbは.'__:期限切れ')、' keyCallback「); //コールバック関数、どこ処理ロジックの書き込み 機能keyCallback(Redisの$、$パターン、チャンネル$、$ MSG) { PHP_EOLエコー; エコー"パターン:$パターン\ N-"; エコー"チャンネル:$チャンネル\ N-"。 エコー"ペイロード:$ MSG \ N \ N"; $一覧=爆発( ':'、$ MSGを)。 $ order_sn = ISSET($リスト[0])$リスト[0]:? '0'; $ use_mysql = ISSET($リスト[1])$リスト[1]:? '0'; IF($ use_mysql == 1){ するrequire_once 'db.class.php'。 $ mysqlの=新しい\ mysqlの(); 接続$はmysql->(); $どこ= "ordersn = '" $ order_sn。。 "'"; $はmysql->を選択し( '順序'、 ''、$場合)。 $発見= $はmysql-> fetchAllの(); しますprint_r($発見)。 IF(ISSET($発見[0] [ 'ステータス'])&& $発見[0] [ 'ステータス'] == 0){ $データ=配列( 'ステータス' => 3)。 。$ = "ID =" $発見[0] [ 'ID']。 $はmysql->更新( '注文'、$データ、$)。 } } } //或者 /*$redis->psubscribe(array('__keyevent@'.$redis_db.'__:expired ')、機能($のRedis、$パターン、$チャンネル、$ MSG){ エコーPHP_EOL; エコー「パターン: $パターン\ n "は、 エコー"チャンネル:$チャンネル\ nは"; エコー"ペイロード:$ MSG \ N \ N"; // ................ }); * /
注:私たちは初め、断言パスPHPコンパイラであります:
#!/ usr / binに/ envをPHP
これは、PHPスクリプトを実行する必要があります。
その後、nohupは&の最後に実行psubscribe.php、注意を払うを中断しません。
[ルート@ chokingwin HiGirl]#nohupを./psubscribe.php& [1] 4456 nohupを:入力を無視すると`nohup.out」に出力を追加
説明:スクリプトは確かに4456のプロセスID上に実行されています。
期限切れの出力がある場合に、次のnohup.out猫ルックnohuo.out、外観を見ます:
nohup.out [ルート@ chokingwin HiGirl]#猫 __たKeyEvent @ 0 __::パターンの有効期限が切れ __keyevent @ 0 __::期限切れのチャンネル ペイロード:名前を
成功した結果の後に3秒を超える、すなわち、index.phpを実行します
出会いの問題:与えられた後、監視スクリプトにいくつかの時間をコマンドラインモードを使用して:.エラーを送信中にQUERYパケットPID = xxxは
溶液:長い待ち時間がコールバック接続データベース前に、メッセージキュー、および待ち時間に接続されているので、データベースWAIT_TIMEOUT = 28800、それほど長いメッセージから次のメッセージのように8時間以上は、このエラーは、WAIT_TIMEOUTを提供します10、および実際のエラーは、MySQLサーバが解消されたことがわかり、例外をキャッチ
限り、ビジネスロジックプロセスは、すべてのデータベース接続をクローズするためのイニシアチブを取るよう、問題オフ有効近いデータベース接続を解決することができます
次のようにYiiの解決策は以下のとおりです。
Yiiの:: $ APP-> DB->近いです();
表示処理方法:
PS -aux | grepをpsubscribe.php
a:显示所有程序 u:以用户为主的格式来显示 x:显示所有程序,不以终端机来区分
求人を見るプロセスID:[ジョブ-l]コマンド
WWW @ iZ232eoxo41Z:〜/ tinywan $ジョブ-l [1] - 1365停止(TTY出力)sudoのはnohup psubscribe.php>を/ dev / null 2>&1 [2] + 1370停止(TTY出力)sudoをnohupをpsubscribe.php> / dev / null 2>&1
背景方法で実行中のプロセスを終了:
殺す-9プロセスIDを
nohup.outファイル方式を空にする:
猫を/ dev / null> nohup.out
私たちは、nohupを時間を使用し、一般的に&と組み合わせて使用されているが、実際の使用には、多くの人がこの問題に関するプログラムの背中を置くが、実際にはこれが可能な場合、現在のアカウントの非正規exitまたはend、または独自のコマンドオーバー。
だから、nohupコマンドの順序を使用してバックグラウンドで実行した後、私たちは次のことを実行する必要があります。
1.まず入力し、終了はnohupをを促しました。
2.次に、現在のアカウントを終了し、通常の終了を行います。
3.次に、リンクターミナルへ行きます。背景には、プログラムを実行します。
各nohupをが正常に実行された直後に閉鎖されるべきではない私たちは常に、端末を終了するには、exitを使用する必要があります。ようにコマンドをバックグラウンドで実行されていることを確認します。
これらは、自動化の遅延タスクを達成するための詳細はPHP + Redisので受注(詳細なチュートリアル)をキャンセルしています
より多くの情報を学び、ご覧ください。
テンセントT3-T4標準ブティックDaquanのPHPアーキテクトのチュートリアルディレクトリは、限り、あなたは読んで保証賃金は(継続的に更新された)より高いレベルに上昇します