HN🔥 41
💬 20

なぜ私たちは「Serializable」分離レベルを恐れるのか?バグの恐怖よりも優先すべきこと(2024年版)

b-man
5日前

ディスカッション (7件)

0
b-manOP
👍415日前

多くのエンジニアが「Serializable(直列化可能)」というデータベース分離レベルを避け、より緩い一貫性レベルで妥協しようとします。しかし、複雑な並行処理環境において、データ競合や不可解なバグに時間を費やすくらいなら、最初からSerializableを採用する方がトータルコストは低いのではないでしょうか?この記事では、Serializableに対する過度な懸念と、それが隠蔽している「本質的なバグ」のリスクについて深掘りします。

1
lukas221
約20時間前

デフォルトでシリアライザブル(直列化可能)分離レベルを使わないのは、デフォルトでメモリ安全なプログラミング言語を使わないのと同じことだと思う。

確かに遅すぎる場合もあるけど、本来はデフォルトであるべきだよ。

他の分離レベルで正しいデータベースコードを書ける人なんてほとんどいない。みんな自分にはできると思ってるけど、マルチスレッドのコードを書くよりもずっと難しいんだ。データベースはパフォーマンスのために、直感的じゃない奇妙な動きをするからね。

2
mastermedo
約20時間前

>驚くべきことに、弱い分離レベルが原因のバグに関する話や論文は、強い分離レベルが原因で実用的でないほどパフォーマンスが低下したケースよりもずっと多い。

記事が「シリアライザブルはパフォーマンスへの影響が大きい」という主張を裏付けてくれることを期待してたんだけど、自分の経験上そんなことはないからね。記事も基本的には同じことを言ってる。

シリアライザブルを使うなら、ホット行(頻繁に更新される行)を作らないように少し気をつける必要がある。頻繁に書き込まれる値はシャーディングして避けること。パフォーマンスを向上させる別の方法は、読み込み後の書き込みを伴わないトランザクションの順序付けにTrueTimeのような仕組みを使うこと。データベースが標準でそんな保証を提供してない場合は少し面倒だけどね。GoogleのSpannerがいい例だ。シリアライザブル分離レベルを提供しているけど、ホットスポットさえ考慮すればかなりのパフォーマンスが出るよ。

3
sanqui
約19時間前

最近になってシリアライザブル・トランザクションについて知ったんだけど、これがデフォルトになってないなんて正気の沙汰とは思えないな。イベントソーシング・パターンと組み合わせるとすごく理にかなってる。たしか、決定関数の中で状態をクエリしてから、集約やバージョン管理を実装しなくても安全にイベントを発行できる(つまり「動的な整合性境界」を持てる)はずだ。重要なのは、イベントが発行される前にクエリした情報が少しでも変更されたらトランザクションが失敗して、確実な結果が得られるまでビジネスロジックをリトライしなきゃいけないってことだね。

4
hyperpape
約19時間前

>論文によると、「22件の脆弱性のうち5件はレベルベースで、デフォルトの弱い分離レベルが脆弱性の裏にある異常を引き起こしていた。残りの17件はスコープベースで、データベースへのアクセスがトランザクション内で適切にカプセル化されておらず、並行するAPIリクエストがデータベースバックエンドの分離レベルに関係なく脆弱性を突くことができた」とのこと。

あまり断定的な意見は言いたくないけど、ひねくれた見方をすると、ここから得られる苦い教訓は「データベースはデフォルトで低い分離レベルであるべき」ってことかもね。開発者がそもそもトランザクションを正しく使えてないなら、わざわざ一番厳格な方法でトランザクションを処理してパフォーマンスを無駄にする必要なんてあるの?

5
SoftTalker
約18時間前

シリアライザブル分離レベルが必要ない場合もあるだろうけど、使っているデータベースの並行性モデルとそれが何を意味するのかは絶対に理解しておく必要がある。そして、それらすべてが同じではないと認識することだね。Oracle、Postgres、MySQL、SQL Serverはどれも全然違うから。

6
zadikian
約18時間前

Flexcoinのハックについて気になってたんだけど、元の記事が表示されなかったからアーカイブを貼っておくね:https://web.archive.org/web/20240423000007/https://hackingdistributed.com/2014/04/06/another-one-bites-the-dust-flexcoin/  どうやらこんな単純な話だったみたい:

  mybalance = database.read("account-number")
  newbalance = mybalance - amount
  database.write("account-number", newbalance)
  dispense_cash(amount)   // または顧客へビットコインを送金

で、MongoDBにはこれをアトミックにやる方法がなかったの? リード・コミッテッド(read-committed)をサポートしているRDBMSなら、その行に対して「read for update」を実行すればうまく処理できたはずだけど。