標準プラグインのsqlite.rbは、つぶやき、ユーザ、リスト、ふぁぼを恒久的に保存するためのプラグインで、SQLiteなので他の言語やプログラムでも気軽に統計などを取ったりして遊べる、一度取得したツイートをデータベースから取得するのでAPI消費が緩やかになるなどのメリットがある。
最近うちのmikutterが遅くなってきてて、何があったのかなと思ってたら、このSQLiteのファイルが250MBにまで膨れ上がってた。当然これを消すとサクサク動くようになる。
SQLiteプラグインの最適化
・・・では、sqliteプラグインを削除すればいいのかというとそう簡単に諦めません。
従来のみくったーでは、データベースの書き込みは別スレッドで遅延実行してた。これによって並列実行され、表側には負荷がかからないと思い込んでいたのが全ての間違いで。SQLiteは結局、Rubyで実装されているわけではないので、アクセス中は他のスレッドは動かない。ということは、結局挙動的にはメインスレッドで動いてるのと似たようなことになる。一方TwitterAPIで問い合わせに行くと、IO Waitになるのでその間他のスレッドが実行されるので、体感負荷はこっちのほうが小さい。これは0.0.3.0までの話。
どうしたものかといろいろ調べていたら、そういえばトランザクションの処理が荒いままだということを思い出した。
SQLiteは明示的にトランザクションを張ってなければinsertやupdateの前後でトランザクションを張ってしまう。そしてこれのコストがかなり高いので、大量に書き込むときはトランザクションを貼るというのはセオリーなんだけれど、やってなかった。
・・・というわけで、0.0.3.1では、SQLiteのexecuteメソッドに渡す引数を配列にして、Queueに入れて、一定時間キューに追加されなかったらそれらをまとめて一つのトランザクション内で書き込むという改良をした。
最適化の結果
結果どうだったかというと、体感速度は変わらず。ただし起動は3秒速くなった。あとつぶやきを短時間に大量に受信したときにも負荷は落ちているはずで、一件あたり0.1秒ほど速くなっているみたいなんだけど、体感速度変化なし。
結局のところ、データが多ければ処理は遅くなるはずで、俺のようにいっぱい溜め込むと読み込みですら足を引っ張ることがあると。
考察
mikutterが流速速いと遅すぎて使い物にならないのは周知の事実だけれども、流速が速いほうがためこまれるつぶやきの量は多くなるわけで、余計に事態が悪化していく。では、他のツイッタークライアントはこういった問題にどう対処しているかというと、そもそも溜め込んでいないのでこういう問題とは無縁というのがほとんど。
それもそのはず、mikutterでも、ほとんどのSQLiteキャッシュは一度も使われず、ある程度昔のレコードになると全く使われない。
更に、再起動するまではmikutterコアが一定期間メモリキャッシュをするので、大抵SQLiteにまで問い合わせがいくことはなく、基本的に問い合わせはレコードが見つからずに終わることが殆ど。
SQLiteプラグインの消失 - DEAD END -
このことから、現状のmikutterでは、SQLiteによる恒久的キャッシュの意味は薄いんじゃないかなと考えて、残念だけど0.0.3.2では標準プラグインからは降格させる予定。今はうちのgithubで元気にしているよ。mikutterで統計とか取って遊んでた人はこれで引き続き使えます。
mikutterって、昔APIが少なかったころ、またTwitterが不安定だったころに設計されていて、できるだけTwitterにアクセスしなくていいように、Twitterを信頼しないという思想のもと書かれているところが多いんだけど、最近ではそんなにTwitterも不安定じゃないし、そういうところは一度見直したほうがいいと思ってる。Twitterも大きくなったよなぁ。