« March 2010 | Main | June 2010 »

April 2010

April 26, 2010

MySQL and the XFS stack overflow problem

I have heard that there have been talks at MySQL UC on running MySQL (InnoDB) on top of XFS for better write concurrency than ext3.

Last weekend I had a chance to discuss on Twitter the xfs stack overflow problem (that became apparent this month, on x86_64 systems with 8k stack) and how it would affect (if any) MySQL servers.  If I understand correctly, the problem is that stack overflow might occur when a dirty page needs to be paged-out to xfs.

The conclusion was that for stability of MySQL running on xfs:

  1. xfs should not be used on top of LVM or any other MD (i.e. software RAID, etc.)
  2. xfs volumes should only contain ibdata files (that are accessed using O_DIRECT) so that the files on xfs would never exist as dirty pages within the OS

References:

April 24, 2010

REST におけるトランザクションについて (Re: Web を支える技術)

といいつつ、ひとつだけ理解できないというか、納得できないところが。トランザクションのところがなんだかRESTっぽくないのがすごく気になる

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESSプラスシリーズ)(山本 陽平) - ただのにっき(2010-04-23)

Web を支える技術」は自分もとてもいい本だと思う (教科書としてすばらしいし復習用としても読みやすいのでイイ) のですが、トランザクションの所だけは分かりづらいなと感じました。その原因は、atomic transaction で解決できる課題を例として使っているという点と、トランザクションと更新クエリのレイヤ分割がされていない、という2つの点によるものではないでしょうか。

HTTP 上でトランザクションを表現する必要があるケースのほとんどは、atomic transaction ではなく、2相コミットもしくは long-running transaction を行う場合だと思います。

たとえば、HTTP 上で2層コミットを行っているシステムの代表例としては、おさいふケータイのチャージ機能が挙げられます (あれって HTTPS ですよね?)。また、たとえば、数量に限定がある商品を課金代行サービスを使って販売する場合等においては、long-running transaction が必須になります。

なので、トランザクションレイヤを RESTful に表現する手法は理解しておいて損がないものだと思います。具体的には、

  • トランザクションの開始は POST を使ったトランザクションリソースの生成
  • トランザクション開始後は POST ではなく PUT を使い、クライアントがリクエスト ID を指定することで、ネットワーク障害への耐性を確保
  • トランザクションのコミットも再送可能じゃないと困るので PUT
  • コミットの返り値を確認してからトランザクションリソースを DELETE

といったあたりが基本になると思います。

以下、具体例として、「アライブドアチケット」というチケット販売サイトから、ミュージカル「夜のhidek様」のチケット (2010年5月24日の公演) を購入する例を示します。支払いには Yappo! ペイメントを利用します。

まずは、残席があるか確認します。

GET http://ticket.alivedoor.com/musical/20100524/夜のhidek様/seats-left HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

{
  "seats-left": 11
}

「夜のhidek様」は、歌舞伎町でも大人気な、あの往年のアイドルが主演する人気ミュージカル。残席が少ないです。今すぐチケットを買わないといけません。トランザクションリソースを生成して、トランザクションを開始します。

POST https://ticket.alivedoor.com/buy HTTP/1.1
Content-Length: 0

HTTP/1.1 201 Created
Location: https://ticket.alivedoor.com/buy/934085
...

次に、座席を確保します。サーバは席が確保できれば「201 Created」を、既に満席になっていれば「409 Conflict」を返します。

PUT https://ticket.alivedoor.com/buy/934085/1 HTTP/1.1
Content-Type: application/json

{
  "url"    : "http://ticket.alivedoor.com/musical/20100524/夜のhidek様",
  "seats"  : 2
}

HTTP/1.1 201 Created
...

座席が確保できたら、支払い金額を確認します。

GET https://ticket.alivedoor.com/buy/934085 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

{
  "amount": "10000",
  "currency": "JPY"
}

次に、クライアントは Yappo! ペイメントを使って、アライブドアチケットの口座に指定された金額を振り込みます。振込が完了すると、Yappo! ペイメントは振込IDを返すので、その振込IDを指定してトランザクションをコミットします。

PUT https://ticket.alivedoor.com/buy/934085/commit HTTP/1.1
Conetnt-Type: application/json

{
  "payment_id" : "https://payment.yappo.jp/paymentid/02394895923408904930"
}

HTTP/1.1 200 OK
...

「200 OK」が返ってきたので、支払が完了し、取引が成立したことがわかります (失敗した場合は「409 Conflict」が返ってくるでしょう)。最後にトランザクションリソースを削除します。

DELETE https://ticket.alivedoor.com/buy/934085 HTTP/1.1

HTTP/1.1 200 OK
...

以上のような流れになると思います。「夜のhidek様」言いたかっただけ (ry

処理の対象となるリソース (上の例では http://ticket.alivedoor.com/musical/20100524/夜のhidek様) が、トランザクション中の Request-URI に含まれていないのが気持ち悪い、という意見もあるかもしれません。ですが自分は、トランザクションリソースを使う場合は、HTTP はトランザクション処理に専念、HTTP 上のペイロードで処理対象のリソースを表現する方が、レイヤが分かれるので良いと考えます。