スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

LogCounterはどうでしょう?

お題:App Engineでカウンターを作る

前提:

  • カウント数を集計する用途だけでなく、ユニークな連番を振る用途にも使いたい
  • 1つのエンティティをカウンター代わりに使うのは負荷集中に弱いので避けたい

こんな実装はどうでしょう?

  • MemcacheService#incrementでカウントアップし、値を返す
    • CountLogエンティティを新規追加する(以下プロパティを備える)
      • createdAt: グローバルなタイムスタンプ(後述)
      • value: カウント値
  • memcache上に値がない場合(初期化時またはmemcache上の値の破棄時)
    • CountLogのcreatedAtの降順で最初のエンティティを取得し、そのvalue値をmemcacheに入れる
    • CountLogがない場合は、0をmemcacheに入れる
  • 古いCountLogはcronで消す
  • グローバルなタイムスタンプ生成:
    • System#currentTimeMillis()の値とmemcacheに記録した前回の値+1と比較して大きい方を返す

考察:

  • 要するにMemcacheService#incrementで連番を振るのですが、それだけだとdurabilityがあやしいので、ログを記録して補おうという考えです
  • このLogCounterのカウントアップ処理は新規エンティティの追加処理となるのでボトルネックにならないはず
  • memcache上に値がない場合の排他があやしい感じがしますが、気になる場合はロックを使えばいいでしょう
  • パフォーマンス重視な場合は、CountLog追記部分だけTask Queueで非同期処理にすれば、memcacheアクセスのみとなりかなり高速になると思います