アクセスカウンタが時々リセットされる (アクセスカウンタにデータベースを利用)†
- ページ: BugTrack
- 投稿者: umorigu
- 優先順位: 低
- 状態: 完了
- カテゴリー: 本体バグ
- 投稿日: 2017-05-24 (水) 02:32:06
- バージョン: 1.5.1
- リリース予定バージョン: 1.5.2
メッセージ†
アクセスカウンタがリセットされてしまう。
Database等を使ってリセットされないようなオプションを用意する。
Database等を使ってリセットされないようなオプションを用意する。SQLiteがPHP5.1で組み込まれているので利用しやすい。
plugin/counter.inc.php:
// Use Database (1) or not (0)
define('PLUGIN_COUNTER_USE_DB', 0);
PLUGIN_COUNTER_USE_DB を 1 にするとDB利用カウンタになる。(PDOオプションは設定可能、デフォルトは SQLite利用で counter/counter.db に保存される。
変換ツール†
ファイル利用カウンタのデータをデータベース上のデータに変換するツールです。
counter_db_tool.php
ToDo†
- 済
counterプラグインにDB(PDO)実装を追加する
- 済
ファイル利用カウンタをDB利用カウンタに変換するツール
- 済
populerプラグインの対応
- 済
renameプラグインの対応
コメント†
コメント: 既存実装 (ファイルシステム版)†
- 現行のcounterの排他処理はちゃんと記述されているように見えましたが、Modify処理(ftruncate→fputs)がアトミックではないので何らかの理由でサーバー側のプロセスが異常終了するとカウンタが消失してしまうということでしょうか。 -- Yorkfield
- コメントありがとうございます。正直なところ、カウンタがリセットされる原因がはっきりわかっているわけではないです。BugTrack/191も解決済みになっています。ただ、このサイトのトップページでもでもたびたびリセットが発生しています(ここのバックエンドはNFSだと思われます)し、私の運用しているサイトでも発生します。ファイルベースでは限界があるのかな、と思って確実な動作が期待できるDBにしてみました -- umorigu
- なるほど、flock自体が信頼できない環境ですか。それを想定するなら、ファイルベースではmkdir(やsymlink)を使ったファイルロックを自前で実装するしか無いかもしれませんね。ロック解除待ちでポーリングが必要、プロセス異常終了時にロックディレクトリが残ってしまう対策などがあるので、できれば今更使いたくはないところですが。 -- Yorkfield
- 更新処理を「一時ファイル生成→Rename」にすれば、書き込みがアトミックになるので多少は問題が緩和するかもしれません。(カウント前とカウント後のどちらかの値は読めるので0リセットは起こらなくなる。) -- Yorkfield
- Renameを使う手法もあるのですね。NFS環境でRenameがアトミックになるのか、また微妙な問題になるので今回はDatabase利用で解決することにします -- umorigu
コメント: SQLite版†
- counterプラインのオプションとして、カウンタをSQLiteのDBで保持するようにしました。 commit:1a7d267248ea -- umorigu
- このサイト(PukiWiki-dev)でDB利用カウンタを運用開始しました -- umorigu
- 従来のcounterは「排他ロック→Read→Modify(+1)→Write→アンロック」という排他制御がされています。しかし、SQLite版のcounterは排他制御が不十分で、「Read→Modify→Write」の間に他のアクセスが割り込むとそのアクセスではWriteする前の値をReadしてしまいます。その結果、カウント数が実アクセス数より少なくなる恐れがあります。
EXCLUSIVEトランザクションを使えば問題は解決できると思いますが、SQLiteは行ロックが無くデータベース全体のロックになること、Wikiページ全てで1つのデータベースを共有する構成であることからパフォーマンス面で懸念があります。 -- Yorkfield
- 鋭いご指摘ありがとうございます。もともとそれほど厳密なカウントでなく、またご指摘のように過剰なロックでパフォーマンスが落ちてしまうことを避けるために、多少の誤差には目をつぶることにしました。(リセットされてしまうよりはマシ、ということです)。未確認ですが、SQLite依存の処理は使っていないのでMySQLなど他のDBを使っても動作すると思います -- umorigu
- UPDATEの際は必ず+1する (SET total = total + 1) ことにすれば、既存処理と同程度の精度にはなりますね。表示する値とのズレを気にしていたのですが、表示の方がずれても問題は少ないということに気が付きました。対応しました commit:5e61ada134 -- umorigu
- UPDATE時+1は良いですね。カウンタ100の時に3人が同時アクセスすると3人ともカウンタ100を見ることにはなりますが、カウンタは103までまわるので、大局的には問題が無いです。 -- Yorkfield
- PukiWiki-official もDB利用カウンタ(PLUGIN_COUNTER_USE_DB:1)での運用に切り替えました -- umorigu
- カウンタがリセットされるぐらいflockが期待通りに動かない環境ならSQLiteのトランザクションも期待できないことに気づきました。やっぱりMySQL使わないとダメか… -- umorigu
- ://sqlite.org/lockingv3.html や ://sqlite.org/howtocorrupt.html を見ると、「NFS上のロックに見られるようにロック実装自体に問題があるとデータベースは壊れる」ようなことが書かれているので、そういう環境だとだめそうですね……。 -- Yorkfield
- flockはカウンタだけでなくページ編集などでも使われているので、flockが動かない環境まで考慮する必要があるならカウンタ以外にも影響が出そうです。(余談:ロックがどこで使われているか軽く眺めていて気になったのですが、lib/backup.phpはそもそもロックしてない?) -- Yorkfield
- flockが動かないとページ更新処理も全滅なのですが、アクセスカウンタはページが閲覧されただけでもwriteされるので他のwriteの箇所よりも更新頻度が高く、このため影響が見えやすいのだと思います -- umorigu
- ここまでの議論で、OSDN.netのプロジェクトWebサーバーはストレージがNFSであり、SQLiteではDBファイルが壊れる危険があることがわかりました。 (→OfficialサイトはMySQL利用に変更。counterプラグイン - PDO設定の変更) -- umorigu
コメント: MySQL版†
- アクセスカウンタを、プロジェクトDB ( osdn.net/docs-ja/MySQL_Howto ) として提供されいてるMySQL利用に切り替えました。MySQLはクライアント-サーバ方式なのでデータが壊れることはありません -- umorigu
- やはり接続のオーバーヘッドがあるようで、DB利用に伴ってパフォーマンスが落ちていますね。以前(ファイル利用カウンタ)の時はトップページ(FrontPage)の表示(HTML convert time)は0.1秒かからないぐらいだったのが、今は0.2-0.6秒になることが多いようです -- umorigu