俺の報告

RoomClipを運営するエンジニアの日報(多分)です。

Google Analyticsでみる数値運動の周期性をフーリエ解析で眺める - 日報 #145

Google Analyticsのアプリが綺麗になりましたね。
Web Master Toolも一部リッチになったみたいで、
益々世界はデータを無視する言い訳ができないようになってきました。
データアクセスコストが低いなら、そりゃ見るべきです。

さて、
ということで本当毎日のようにGAを眺める日々なわけですが、
そういう生活をしている人なら必ずあることを感じると思います。
タイトルにある、周期性です。
当たり前ですが、多少のボラティリティこそあれ、
時間別にみるセッション数などは「大体同じ形」になります。
大きなトレンドがあったとしても、大体同じ形のままベースアップしていく感じです。
勿論例外もありますが、逆に「例外だ」と判定される理由は、基本的には同じ形である確率が高いからだとも言えます。

これをもっと分解して、分単位でみたとき、1時間というユニットで相互に同じ形になることは恐らくないでしょう。
秒単位でみたときに1分というユニットで相互に同じ形になることも恐らくないでしょう。
(有限個のパターンになるかもしれませんが、、、)
「アクセスの周期性」という意味における最小単位は1日と捉えるのが妥当かと思います。
多分。詳しく見てないけど。

それでは、
周期が1日単位で、サンプリング数が時間だとして、
これはつまり、1日を1秒としてみたとき、秒間24個のサンプリングをした波形をみているのに等しいわけですね。
これに周期性を発見したというのであれば、フーリエ解析したくなるのは人の常です。
便利なサイト(http://gijyutsu-keisan.com/calc/analysis/calc_fft/calc.php)もあることですし、
数ヶ月分のデータの時間ごとのセッション数推移を、
サンプリング周波数(ナイキスト周波数)48Hzで、24Hzまでの分解能で周波数特性を調べてみましょう。

具体的な数値は、まぁ秘匿事項にしますが、
とても面白い結果になりました。
適当な3日分のデータと、
4ヶ月分のデータで、
上位の周波数特性が同じになりました。
数値は適当にごまかしてますが、
2Hz, 4Hz, 6Hz, 8Hz あたりに大きなピークがでてきます。
ずごい雑に、こいつらがきっと「1日以内での周期を特定している周波数ピーク」だと解釈してみましょう。
そこそこ大きい周波数ですね。
ちなみに、0.8Hz付近にもピークがでるあたりをみると、ものっすごい「1週間系のやつかな、、」とか思っちゃいますが、
これは無視します。
で、実際、2,4,6,8Hzあたりのピークを足し合わせると「1日の大体同じ形」とやらを再現できます。
もしかしたら、世の中の人の生活周期は「12時間、6時間、4時間、3時間」で区切りできるのかもしれません。
さぁすごいリアリティがなくなってきたので、
どうせなら妄想全開ワールドまでいきましょう。

となると、4ヶ月分のデータのフーリエ解析結果において、 小さな周波数でピークがでているものがあるのか?というのが気になってきます。
それがきっと「トレンド」のはずです。

で実際4ヶ月分を48Hz分のサンプリング周波数、まぁ要は 0.02秒のサンプリング時間でFFTしてみると、
同じように2,4,6,8Hzにピークが現れます。
ですが、それと同じくらいのピークが0.04Hzや、0.01Hzあたりにも出現してきます。
こんな小さい周波数、1秒1日計算なので、0.04Hzは25日で1回サイクル、
0.01Hzは100日で1回サイクルという大きな波形が重ね合わさっているわけです。
こ!!!これは!!!
0.04Hzは1ヶ月で、0.01Hzは大体1シーズンなんじゃないの!?

はいはい、妄想はここまで。
まぁつまりデータ解析もたまには楽しいねっていう、
そういう話でした。

MySQLのインデックスの運用 - 日報 #144

高速でGWが過ぎ去りましたが、日々充実しております。
ありがたいことですね。

さて、表題の通りMySQLのインデックスについて少し触れたいと思います。
というのも、とあるクエリが「インデックスを使ったり使わなかったりする」というような現象にでくわしたのです。
まぁ色々要因があると思いますが、
少なくともインデックスについて知見を深めなければなりません。
ということでちょいと勉強したことをば。

インデックスは言わずと知れたB-Tree構造です。
そこまではいいとして、運用保守についてやや理解が及んでなかったのです。
その辺について。

インデックス周りで、今回のケースみたいな奇妙な動きがあった時は、大体下記の手順で疑いにかかるとよいという結論になりました。

1. インデックス破損していないか?

インデックスは強制終了やハードウェア故障、OSのバグなど発生するようです。
中でもMyISAMは強制終了(クラッシュ)でよく起こるそうです。
InnoDBではほぼ起きないらしいので、もしこのエンジンを使っているならば、 あんまりこの項目は重要ではないですが、
とにかく、どうすればこの破損を捕捉できるかというと、

CHECK TABLE table_name

だそうです。
規模がでかいテーブルだとそこそこ秒数かかるので注意が必要です。
でも前述のとおりInnoDBではほとんどこの可能性は低いとみていいみたいです。
じゃぁ次は何かというと、、、

2. インデックス統計情報が間違ってない?

インデックスが正しく使われるかどうかについては、
全てクエリオプティマイザが実権を握っているわけです。
で、クエリオプティマイザは何でもってインデックス使用の判断をするかというと、
これも単純で、最終的にアクセスするデータの量、つまりコストベースなわけです。
なので、このアクセス予定のデータ量が誤っているとインデックスを使うべきかどうかの判定はコロコロ変わってしまうんですね。

で、そのデータ量の取得にはrecord_in_rang APIか、info() APIかが使われるみたいなんだけど、
細かいことはおいといて、
MyISAMだと正確な値を返すが、InnoDBだと概算値になるんです。
InnoDBでインデックスのカーディナリティを見た時にコロコロ変わるのはコレが原因です。
(テーブルの行数とかも変わりますよね)
んで、これはどうやって推計計算しているかっつぅと、
innodb_stats_sample_pages
というパラメータで指定したサンプル数だけページ(ノード)を取得して、
そこから他のページのレコードの数を推計計算するという、
いわゆるサンプリング手法で計算しているみたいです。
インデックスの量や、レコード数が増えてきたら、このサンプル数を増やす必要がありますね。
デフォルトでは8ページみたいですので、16とかにしておきます。
理論上、これでボラティリティは下がるはずです。

ということで、インデックスのカーディナリティが変に変動したり、
インデックスの使用判定がバラついたりするのであれば、
innodb_stats_sample_pagesを増やしたり、ANALYZE TABLEをしてみたりするといいかもしれません。

さて、大体以上ですが、
番外編として、断片化について。

インデックスの断片化は大きく分けて3つあります。
1. 行の断片化
一行のデータがバラバラに格納されてる状態。
これは最悪ですね。インデックスで一発で引き当てたとしてもI/Oで時間がかかるというクソパターンです。
2. 行間の断片化
id連番で連続に格納されているべきデータがバラついたりする現象です。
idが飛び飛びになったりすると起こりがちなものですね。
id:1-10をとってこい!っていう分かりやすい命令が、
ポインタベースで10個バラバラにかき集めるんじゃぁ、HDDが火を吹きますね。
3. 空き容量断片化
恐らく一番多いパターンです。
よく言われる断片化の典型パターンですね。

これもInnoDBではあまり起きないようですが、
さすがにでかいDBをずーっと運用してたら断片化はします。
1,2についての断片化具合を確かめるのは困難ですが、
3については、「実際のデータ長と、平均のデータ長✕行数の差分」で空き容量を確認することができます。
まぁこんなクエリですね。

SELECT
     `TABLE_ROWS` AS tbl_rows,
     `AVG_ROW_LENGTH` AS avg_length,
     `DATA_LENGTH` AS total_length,
     (`DATA_LENGTH` - `TABLE_ROWS` * `AVG_ROW_LENGTH`) AS flag
FROM information_schema.TABLES
WHERE TABLE_NAME = 'hogehoge'

これがあまりに太るようであれば、OPTIMIZEコマンドを流すと良いと思われます。
一番いい方法はなんと「意味のないAlter文を流す」だそうです。

ALTER TABLE hogehoge ENGINE=INNODB;

みたいな。
「えぇー。。。」って感じですが、まぁそれがよくある手法みたいですよ。

ということで、長くなりましたが、そんな感じです。
何かのご参考になれば。

スループットとレイテンシ - 日報 #143

日々色々なことが起きております。

スループットとレイテンシについて、ちょっと考える機会があったのでさわりだけ共有。

スループットとレイテンシ」と聞くと、、、 なんだか愉快な小動物の兄弟がチーズ工場で大立ち回りをするような欧風昔話タイトルのようですが、
全く違います。
wikipediaを見てみます。
スループット
基本的な定義は、

単位時間あたりの処理能力のこと

であり、ネットワークにおいては、

単位時間あたりのデータ転送量を指す。

んだそうです。
依存するのはバスラインの抵抗とか、対応する帯域幅とかになるんでしょうか。
特に記載がないのでわかりませんね。

一方、レイテンシ
基本的な定義は、

デバイスに対して、データ転送などを要求してから、その結果が返送されるまでの遅延時間

だそうです。
データ転送とか言ってるので、スループットが深く関わってきそうですね。
でもよくわかりません。
ただ結局、スループットは「転送量」で、レイテンシは「時間」という単位みたいです。
これはどちらも「能力」の基準のように見えるのでごちゃごちゃするのかもしれません。
この掛け算を運動量のように考えることもできそうですが、
その話は一旦置いといて、
じゃぁ例えば「むちゃくちゃデカイファイルをとあるLANケーブル越しに転送して、受取側は受信し切った後に、そのファイルが正しいファイルかを判定して、その旨を返す」とします。
勿論物凄い時間がかかります。
つまり、レイテンシがとんでもなく大きいということですね。
この時、何が原因でレイテンシが高くなったのか?と言われた時、
いくつか要因が考えられます。
一番手前側から列挙していくと、

  1. 送信側のDisk Readがへちょい
  2. データ転送の速度がへちょい
  3. 受信側のDisk Writeがへちょい
  4. 受信ファイルの判定がへちょい

という感じです。
この時、2番の「データ転送の速度がへちょい」に該当するのが、
スループットと思われます。
このよくありそうな「へちょい」連鎖のうち、
僕がよく遭遇していたのが3番とか1番あたりのDisk I/Oの話でした。
正直2番に悩まされることが殆どなかったのですが、
この度2番に引っかかるという事態に遭遇し、
中々勉強になっております。

CPU的意味で負荷分散しているクラウド設計において、 スループット減少のボトルネックを発見した時は結構気持ちがなえます。
だってどんなに計算能力を向上させたとしても、
LBとサーバ間とか、VPCルータとLB間とか、
ひいてはクラウド全体の利用bpsに完全に依存してしまっているからです。
「しょぼいCPUでもいくつも並べれば凄い計算ができるんやで!」
と思っていましたが、
例えば画像のような「そこそこデカイファイル」を扱う場合は、
当たり前のようにスループットについて精密に考える必要があるわけです。
いやもう書いてて本当当たり前ですよね。
デカイ荷物運ぼうぜ!っていう目標をたてて、 すごい沢山人数集めたけど、 運ぶ道が細くて渋滞してたら、何の意味もないもんね。

いやもう、
なんか1個1個ですね、、、

オートスケーリングで気をつけること3つ - 日報 #142

さくら自作CDNが回りだして非常にいい感じだったのですが、
まだまだ課題は山積みです。
帯域制限、LBセッション、各サーバCPUという一般的なボトルネックに加えて、
NFSというボトルネック箇所もあり、
今後の展開は中々香ばしいものになりそうです。

今日は相変わらず話すことがないので、オートスケーリング周りで気をつけることを列挙してバイバイしたいと思います。

オートスケーリングする時に注意しとくと捗ること。

1. 起動デプロイにする

AMIが固定されるので、インスタンス起動時に最新版にオートデプロイされる必要があります。
cronでも@reboot設定などで対応できますし、起動スクリプトにしてもいいと思います。

2. インスタンスTerminate時のログ処理

自動でインスタンスが削除されるので、
インスタンスに固有のデータをためとくと回収不能になります。
得たログなどは必ずどこかへ送信しきらないといけません。
FluentdなどはOS停止信号を得ると自動でbufferを処理し切る設定などがありますが、
一般的にはshutdown時のスクリプトに色々書いておくのが必要になると思います。

3. Memcachedの外部化

インスタンスは常にポコスカ生まれたり死んだりするので、
とにかくインスタンス固有の何かに頼るのを諦めなければなりません。
厄介なのはMemcachedですが、ElastiCacheを使ってデータを共有しておくことが重要です。

4. その他諸々

ぼんやりした話ですが、 SSHでサーバに入ることを前提とする作業などは微妙なオペレーションになります。
VPCをしっかり設計していればNATの振り分けポートを敷き詰めるように配置できるのか知りませんが、、、
WANに浮いている状態では実質SSHはあまりいい方法ではなくなります。
また、Launch、Terminate時にCloudWatchからNotification送れるのでそれも設定するといいと思います。

以上ですた。

bashでオプション取得 - 日報 #141

新しいオフィスはとてもいい感じです。
こんな雰囲気。

f:id:tom_rc:20150422224246j:plain

机がグッと広がりましたが、
さっさと狭くなるように人員増強、スケールアップしていきたいと思います。

ほいでほいで。
コードをシコシコ書く時間というのが減ってきておりまして、
(勿論まだ膨大にありますが、、、)
概ねいいんですが、何となく不安感もありつつ、みたいな感じです。

っていうか、雨多くないですか?
雨多いわー
雨凄い多くてやだわ。
凄い雨多くてやだわ。
やだわ、雨多くて凄い。
雨多くて凄いやだわ。

書くことない、すごい書くことない。
びっくりするほど書くことない。

じゃぁshでハイフンのオプションを取得するスクリプト置いとくわ。
多分色んなやり方あると思うけど、俺が思いつく限り簡易な奴。

./option.sh -a A -b B -c C

的な感じで。

#! /bin/bash

A='defA'
B='defB'
C='defC'

while [ -n "$1" ]
do
  OPT=$1
    case ${OPT} in
      '-a' )
        shift
        A=$1
      ;;
      '-b' )
        shift
        B=$1
      ;;
      '-c' )
        shift
        C=$1
      ;;
    esac
    shift
done

echo "A = ${A}"
echo "B = ${B}"
echo "C = ${C}"

echo 'done'

これで、いけるかと。

ハイフンとアンダースコアのSEO効果とコード上の対応 - 日報 #140

明日オフィス引っ越しでございます。

さておき。
SEOについて色々と調査し施策を突っ込んでおります。
色々と仮説は出てきていますが、
如何せん「なんもわかんねぇなぁ」という世界観で、
ほとほと困り果てております。
とにかく施策を小さく試して反応を見るの繰り返しですね。

SEOの施策は本当にテクニカルなものから、
サイト構造に至るまで数多ありますが、今日はすごーーい小さなチップスを。

URLにおける「ハイフン」と「アンダースコア」は鬱陶しい問題みたいです。
「room-clip」と「room_clip」ならば、前者はroomとclipの2単語として、
後者ならroom_clipという1単語として解釈される、
みたいな話です。
ホンマかいなと。

Google社の「お前もアーカイブ化してやろうか!むはははは!」な世界観にかける熱意を心底尊敬している僕からすると、彼らがそんなリスキーなことやるとは思えないです。
そりゃ確かにクソなコンテンツに対して厳しく取り締まる存在としてのGoogleと捉えれば、
そんくらいの厳しいルールを敷いてくるとも思えなくはないですが、
かといってもアンダースコアとハイフンなんて流石に無茶言い過ぎだろと思うわけです。
言い換えれば、そんなアルゴリズムじゃ自然文で書かれたコンテンツを解釈することなんて無理だと思うのです。
だもんで、
きっと「あんま関係ねぇんだろうなぁ、、、」と思いながらも、
それでも対応しなくちゃならないのがSEOという世界なわけです。

ですが、
昨今のWebのフレームワークでこの問題に対処するのは結構煩わしいものです。
だって、URIメソッド名に対応してたりするじゃないですか。
んでPHPではメソッド名に「ハイフン」を使えないじゃないですか。
(多分)
だから書き換えないとイカンのですよ。
ということで、Codeigniterの場合は、CI_Routerとかいう無視したいコアをハックする必要があります。

こんな感じ。

class MY_Router extends CI_Router {
  function __construct() {
     parent::__construct();
  }

  function set_class($class) {
    $this->class = str_replace('-', '_', $class));
    parent::set_class($class);
  }

  function set_method($method) {
    $this->method = str_replace('-', '_', $method);
    parent::set_method($method);
  }  
 
  function _validate_request($segments) {
    if (count($segments) == 0) {
      return $segments;
    }
    $segments = str_replace('-', '_', $segments);
      return parent::_validate_request($segments);
    }
}

validateもclassも変えないとアカンのです。
うーん、、、なんかバグの温床になりそうでとても嫌な感じです。
もう少しなんかいいのないですかね。
ないよね。
そうだよね。
低気圧のせいで頭痛くない?
痛くないと。
そうだよね。
じゃぁね

リクエストに対してレスポンスを返す、って難しいね - 日報 #139

今日はただの日記です。
技術的っぽいタイトルは詐欺です。
「相手の身になってサービスを提供する」というのは難しいんだなぁという体験をしたのでそれについて。

とある日、警察官を名乗る方がボクんちにいらっしゃいまして、
「災害時の連絡網などに使うから、名前と住所と連絡先、諸々を教えてくれ」
と仰ったそうです。
その時は妻が家に1人でおりまして、
「はて本当にこの人は警察官なのかしらん。警察手帳を見せてもらったところで真偽判定できないし…」
と不安に思いながらも、
まぁいいかということで、調べりゃすぐ分かるような、さほど重要じゃない部分の個人情報のみを伝えたそうです。

その後ちょっと経って、やっぱり不安になった彼女は、
僕に「こんなことあったけど、どないしよ」と相談してきたわけです。
色々話しあった結果、
「じゃぁ改めて警察署に行って、ウチが渡した個人情報が存在しているか確認しようや」
という、面倒ながらも確実な確認方法を採用したわけです。

とまぁ、こう説明すれば、この時僕らが抱えていた不安は明白だと思います。
要は「ウチに来た『自称警察官』は本当に警察官だったのか?」ということですね。
そして、妻が最も不安に思ったのは、その誰だかわからない『自称警察官』が、
「この時間帯はどうやら女性が1人でいるらしい」
という認識を抱いてしまったことだったわけです。
だから、まずやるべきことは
「手渡した個人情報が確実に警察署に届けられており、警察署側に我が家への来訪履歴があることを確認する」
ことです。
これがもしTRUEならば、この不安はもう終わりです。
反省としては「そんな簡単に応対しちゃダメよ」「ちゃんと相手の身分を確定させてから情報は教えましょう」くらいのものです。
で、仮にFALSEだった場合、
訪ねてきた警察官は『第三者』だったわけで、恐らく悪意の第三者でしょう。
そうなったらこれこそ警察へ届け出すべき事案なわけで、
パトロールしてもらえばいいわけです。

別にここまでの流れは、僕としては至極普通というか、それ以外ねぇだろくらいに当たり前だと思ってました。

んで、

実際に警察へこの話をしたのです。
概ね冒頭のような話をして、
「不安だから、確認を、、、」
みたいなことをいうと、電話先でも対面でも血相を変えてこんなことを仰られるのです。

「個人情報は徹底して管理していますし、そもそもこれは巡回連絡といって災害時にとても大事になるものだから、協力して頂いているという経緯がありますし、しかも任意だから断れるし、それに個人情報を僕らが勝手に触ると厳罰も待ってますからそんなことしませんし、それにそれに…」

でもスゲー気持ちは分かります。
確かに、色々と指摘を受けまくるであろう領域だし、
半分言いがかりのように詰問されたりした事案とかもきっとあったのでしょう。
スゲー気持ちは分かります。

僕としては警察官の方は勿論信頼しておりますし、
特に重要な個人情報(クレカとか)でもないし、
ぶっちゃけ保管されている情報なんて僕がFBに上げてる情報にくらべりゃ屁みたいなもんです。
なので「そこは全く気にしてません」と答えるわけですが、
やっぱりまわりまわって、
「でも、個人情報は安全ですから安心して下さい」
と仰られるわけです。

そんなやりとりを4,5分もしていると、心配性で小心者の僕からすると、
交番の空気が、
「なんか意識高いクレーマー来たぞ」
みたいなあらぬ感じになってないかすごい不安になってくるわけです。
ま、マズイぞ、と思って、その空気を脱却しようともがけばもがくほど、 「大丈夫!個人情報は安全ですよ(ニコッ)」と返されてしまい、
もう泥沼の闘いになってしまうんです。

最終的に、コレはもう納得するっきゃないと判断し、
「分かりました、個人情報は安全なんですね」
と応対をしたところで高らかにゴングが鳴り響き、幕引きと相成ったわけです。
(ちなみに、来訪されたのは本当に警察官で、かつ巡回連絡だったことの事実確認自体は1分ほど済みました。)
勿論おっしゃられていた事自体は本当に大事なことですし、
凄く丁寧かつ迅速な応対もしてくださって安心したわけです。
誤解なきように、本当に警察官の方々の日々の業務には感謝しております。
翻って、
本当に「リクエストに対してレスポンスを返す」ということは難しいことなんだなぁと思いました。
サービスを分析して「ユーザはきっとこういうものを求めている」とか、
統計処理の結果「ユーザのインサイトはこれだ!」とか、
すごく大事な仮説だし、ポジティブな活動なんだけど、
実際にちゃんとテストしてアンケートとって、
ちゃんと効果計測をしないとなぁと、
心から実感した出来事でした。