modxcms-jp / evolution-jp

https://modx.jp/
32 stars 25 forks source link

過負荷時の公開/非公開処理やキャッシュ制御の問題 #184

Open soushi opened 5 years ago

soushi commented 5 years ago

リクエストが非常に多いタイミングで公開/非公開処理が走るとうまく処理が行えない問題がありました。 ほぼ同時刻に大量のリクエストが発生し、それぞれのリクエストが公開/非公開状態を確認して処理を進めようとするため負荷も増大(DBにも更新が入るので通常の処理よりも重たい)。そしてキャッシュファイル編集合戦になり、キャッシュファイルが削除されたタイミングで偶然新しいリクエストがくると「キャッシュがないもの」として処理を進めたりでサイト全体の動作がちょっと読めない状態になってしまいました。

うまい解決方法はまだ思いついてはいませんが、少なくとも公開/非公開処理については排他処理を実装する事でだいぶ負荷も変わるのでは?と考えています。

yama commented 5 years ago

公開/非公開処理の開始と同時にファイルかDBかでロックを生成し、生成を確認してからゴニョゴニョ。という感じでしょうか。

soushi commented 5 years ago

はい、そのような流れでいいのかなと考えています。 InnoDBだったらトランザクションを利用するのも有りですが、MyISAMなのでファイルかDB上でフラグを使った排他制御になると思います。

懸念として「公開処理をしているプロセスが何らかの原因で中断した(落ちた)場合」で、ロック状態が残り続けると今度は公開/非公開が機能しなくなるという状態が発生します。 対策でロックにはギブアップ期間を考える必要もあるものの、1リソースの公開と10000リソースの一斉公開ではかかる時間も違うためバランス重要ですね。

キャッシュの編集合戦もちょっと考えたいです。

過負荷状態の時に、/cache/の下を見てるとファイルができては消えてとめまぐるしかったです。

yama commented 5 years ago

負荷を軽減する方法も必要っぽいですが、先に排他処理を実装したほうが成果を確認しやすくて よさそうですね。 たしかファイルまわりはサーバ的にはけっこう負荷が高いんじゃないでしたっけ? キャッシュとかセッションはDB側で巻き取る設定があると対策になりそうでしょうか? いちおう、仕組み的にはそれっぽいものはエイリアス・URLの紐づけのために実装していて、 それを流用できるかもです。

yama commented 5 years ago

ロックファイルが存在する間はキャッシュを見ない。 ロックファイルのタイムスタンプが生成後60秒を超えていたら無効としてよいがエラー通知はする。 基本はこんな感じ?

yama commented 5 years ago

あと、キャッシュファイルの一括削除は、system関数が使えるかどうかを判定した上で、 system関数が使える場合はシェルコマンド一発で削除してしまえば一瞬ですよね、たしか。

yama commented 5 years ago

$modx->config['use_posix']みたいな設定を追加して、posixコマンドが使える場合は posixを使う。ってのはどうでしょう?touchコマンドが使えるかどうかで判定できると思います。

soushi commented 5 years ago

system関数を利用しても一瞬というわけではないですね。そのsystem関数を実行したphpからするとワンステップに見えるだけで、結局system関数が実行した外部コマンドがなかでゴニョゴニョしている時間は必要になります。 ちょっと抜けがあるかもですが「キャッシュ更新責任者なプロセス」を決めてロック後に色々実行させるといいかなと考えています。 例えばこんな感じです。

//キャッシュを作るところ
$hasCacheUpdater = false;
while( !mkdir('cachelock') ){
  $hasCacheUpdater = true;
  //多少スリープいれる?
}
if( $hsCacheUpdater ){
  //ここにキャッシュ削除と生成処理
  rmdir('cachelock'); //キャッシュ生成おわり
}
//キャッシュを見るところ
if( !is_dir('cachelock') ){
  //キャッシュを見る処理
}

phpのmkdir()を使うと「ロックファイル生成」と「誰かが作っているかどうか」を同時に確認できます。 またmkdir()はphpの中でもカーネルに対してmkdir()をダイレクトに要求しているのでsystem()経由の実行より精度が高いと思っています。

ちょっと思いつきで書いただけなのでもうちょっと考えないとダメかなと思っています。