Webサービスをカネを使わずに宣伝する方法、らしい

ウェブサービスの宣伝は、自分がウザいと思うほど行っても全く足りていない」を読んだ。

涙ぐましい努力だ。

実際のところ、ある程度カネを使った方がコストパフォーマンスがいいような気もするが、やったことないからわからない。

とりあえず簡単にやれそうなのは、

  1. 楽にRT、ブクマできるような、短い文章。
  2. プレスリリースを定期的に打つために、バージョンアップをうまくスケジュールする。
  3. スクリーンショットの見栄えが良くなるように作る。
  4. OGPを設定する。
  5. プレスリリースはサービスがこなれてきてから。

あたりだろうか。他のは、できる人はすごいなぁ。
「エンジニアみたいなシャイな人間にはトコトン合わない場合が多い」と書いてあるけど、全くその通りだと思う。

OGPというのは初めて見た。ちょっと調べてみよう。

Amazon RDSのMulti-AZ

Amazon RDS MYSQL Performance Benchmarking」を読んだ。

Amazon RDSのMulti-AZ構成を使うと、性能が落ちるらしいので、ベンチマークを確認したくてググっていたら見つけたページだ。
リンク先のPDFに詳細な結果が出ていた。

結論としては、Multi-AZを使っても、Smallならそんなに性能は落ちない。が、Large以上でもSmall並みの性能しか出ない

なんとも微妙な機能である。
DBの性能が足りなくなっても、スケールアップで解決するのが難しくなるわけだ。

実際には、ベンチマークの種類によるのだろう。
仕組みとして、遅くなるのは書き込みだけのはずなので、読み込み中心のアプリケーションならMulti-AZを使ってもスケールアップの効果は出るのかもしれない。この辺はこのベンチマークからは判断できなかった。

まあ、お値段も倍になるし、ちょっと選択しにくい機能ではある。
Amazon RDS、結構使いにくいサービスなんだよなぁ。
Multi-AZを使わないと毎日数分のダウンタイムがあったりするし。

EvernoteがSQLデータベースを使う理由

Evernote tech blogの「WhySQL?」を読んだ。

いわゆるNoSQLの類を使わない理由として、

  1. ACIDトランザクションがないとクライアント-サーバ間のプロトコルが複雑になる。
  2. ユーザごとにデータセットが分かれているので、巨大なデータセットを扱う必要がない。

と言ったことを挙げている。

Javaプログラムのメモリリークを見つける方法

Plumbrというツールを使うと、Javaプログラムのメモリリークを見つけることができるらしい。「Screencast: how to use Plumbr」にその概要が書かれている。

Plumbrは、実行中にオブジェクトの生成と破棄を解析して、生成されたのに破棄されないオブジェクトを探し出してくれるらしい。
オブジェクトのライフサイクルはアプリケーションによって違うので、それを学習する機能まであるとか。
オーバーヘッドは1〜2%で、非常に小さいとしている。

ずいぶん凝ったものだな、と思っていたら、有料ツールのようだ。

リークしているオブジェクトの種類を調べるのはそんなに難しくないけど、大規模アプリだと手間がかかるだろう。
よくわからない大きいプログラムにメモリリークがあるらしい、とわかった時はこういうツールにすがりたくなるかも知れない。

SSD の write cliff

Hard drives vs. SSDs」なる記事を読んだ。
コンシューマ向けSSDには、持続的な書き込み時のレイテンシに大きなバラツキがあることを「write cliff」と呼ぶらしい。

コンシューマ向けSSDの、このような性能低下は、書き込み時にのみ起こる。
レイテンシは1ミリ秒未満から、3秒以上に及ぶこともあるそうだ。

エンタープライズ向けのドライブにはこのような問題は存在しないという。
ただし、高い。

書き込み性能が高いSSDは高いよ、というお話であった。

SimpleDBにログを出力する

Logging the cloud with SimpleDB」を読んだ。

EC2で多数のサーバを運用しているとき、ログがそれぞれのマシンのローカルディスクにあるのは不便だ。しかも、インスタンスストレージにログを出力していると、インスタンスに障害が起こったときにログが消えてしまう。

これらの問題は、SimpleDBに保存すればすべて解決する。
SimpleDBは可用性が高く、サーバにログインしなくても内容を読むことができて、安い。

この記事では、LogBacksimpledb-appender を使っている。Appenderを切り替えるだけなので、実にお手軽だ。

SimpleDBは容量制限が結構きついし、S3に比べて容量当たりの価格が高い。
だから、これを一時的な出力先として、ときどきまとめて圧縮してS3に保存するというような運用になるのだろう。

Windowsの非同期I/Oと、OVERLAPPED構造体の寿命

The Old New Thingの「Ready... cancel... wait for it! (part 2)」を読んだ。

この記事の結論はこうだ。

I/O完了ルーチンを使う場合、OVERLAPPED構造体はI/O完了ルーチンの実行が終わるまで解放してはならない。一般的には、OVERLAPPED構造体をスタックではなくヒープに割り当て、I/O完了ルーチンの最後で破棄するようにする。

普通そうするだろ、という話は置いておいて。

part1の復習

なんでこんなことを問題にしているんだろう? と不思議に思ったが、この記事は以下のような少し特殊なケースを前提にしているように思う。

  • したいことは、タイムアウトつきのブロッキングI/Oを行う関数を作ること。
  • タイムアウトしたときのキャンセルを可能にするために、非同期I/Oを使う。
  • 関数は、I/Oが成功、失敗、タイムアウトのいずれかで抜ける。I/O実行中に抜けることはない。
  • 楽しようと思って、OVERLAPPED構造体をスタックに置いちゃってる。

具体的には、part1 の記事に載っているコードである。以下に引用してみる。
part1の最後の対応を入れてあるのは、part2で問題にしているのはこの後の話だからだ。

 HANDLE h = ...; // handle to file opened as FILE_FLAG_OVERLAPPED
 OVERLAPPED o;
 BYTE buffer[1024];
 InitializeOverlapped(&o); // creates the event etc
 if (ReadFile(h, buffer, sizeof(buffer), NULL, &o) ||
     GetLastError() == ERROR_IO_PENDING) {
  if (WaitForSingleObject(o.hEvent, 1000) != WAIT_OBJECT_0) {
   // took longer than 1 second - cancel it and give up
   CancelIo(h);
   WaitForSingleObject(o.hEvent, INFINITE); // added
   // Alternatively: GetOverlappedResult(h, &o, TRUE);
   return WAIT_TIMEOUT;
  }
  ... use the results ...
 }
 ...

CancelIoの後にWaitForSingleObjectが必要なのは、CancelIoもI/O完了の一つの理由だから。CancelIoを呼べばI/Oが無かったことになるわけではない。だから、キャンセルした後もカーネルがI/Oを完了するまで、OVERLAPPED構造体を破棄するのを待っているわけだ。

part2 - I/O完了ルーチン

part1 の2番目のExerciseは、ReadFileではなくてReadFileExを使う場合には、これでは不完全である、ということだった*1

重要な違いは、ReadFileExではI/O完了ルーチンを指定できること。

I/O完了ルーチンは、I/Oが完了した後、スレッドのAPCキューに積まれる。I/Oが完了したからといって、すぐにスレッドに割り込むとプログラマが困る、とWindowsの設計者は考えたのだろう。積まれたI/O完了ルーチンは、スレッドがalertable stateになったときに呼び出される。Windowsは、待機を伴うAPIを呼ぶときにalertable stateになります、とプログラマが指定したときにのみ、APCキューに積まれたAPCが呼ばれる親切設計である。何気なくSleepしたらいきなり別の関数が呼び出されて面食らうようなことはない。

しかし上のコードでは、関数内でalertable stateに入らない。I/O完了ルーチンを指定すると、それが実行されないまま関数を抜けてしまう。当然、OVERLAPPED構造体も破棄される。しかし、I/O完了ルーチンはそのOVERLAPPED構造体のアドレスと一緒にAPCキューに積まれて、実行されるときを待っている…。

教訓

まとめると、part1とpart2で扱われた内容は、OVERLAPPED構造体の寿命だ。

  • part1では、カーネルからI/O完了通知を受け取るまではOVERLAPPED構造体を破棄してはならないこと。
  • part2では、I/O完了ルーチンを指定したら、それが実行されるまではOVERLAPPED構造体を破棄してはならないこと。

が指摘されていた。そして注意すべきは、キャンセルもまたI/O完了の要因の一つということであった。

*1:元記事のコメントでも指摘されているように、上のコードは、単純にReadFileをReadFileExに変えただけではきちんと動かない。ReadFileExはo.hEventを無視するので。しかし、それはここでは問題にしない。おそらく、それほど丁寧に書かれた記事ではないのだろう。