Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

Dealing with Contention (HelloInterview) のメモ

0
Last updated at Posted at 2026-04-05

この記事で学んだことをメモる。

Patterns

TODO: Isolation Levels

ref. https://qiita.com/kudojp/private/8cf02f2a2b27c6501439#postgres-%E3%81%AE%E5%A0%B4%E5%90%88

TODO: Transaction - Pessimistic vs OCC

多分、

  • 競合頻度低い、待ち不要、パフォーマンス重視、 -> OCC
  • そうでないなら、Pessimistic Lock。

例えば、Ticket master は、1つの席は1人しか予約できないので待ちは不要 -> OCC を使った。

image.png

🟢 Pessimistic row lock によりパフォーマンスが悪化する理由

① コネクションプールの枯渇(最も頻発する原因)
データベースの処理能力は、CPU やディスクだけでなく「同時に張れる接続数(コネクション数)」によって物理的に制限されています。

③ DB サーバーの CPU / メモリ リソースの限界
ロック待ちが発生している間、DB 内部では「デッドロックの検知機構」が常にバックグラウンドで動いています。
待ち行列(キュー)が数百、数千と膨れ上がると、DB カーネルはこの「誰が誰を待っているか」の依存グラフを解析するだけで莫大な CPU パワーを消費し、サーバー全体の処理能力が著しく低下します。

なお、競合状態が発生しなかったとしても、SELECT FOR UPDATE による row lock を使うだけでパフォーマンスは 70-90% に落ちる。

Distributed Transaction

以下にまとめた。

TODO: Distributed Locks

DD :one: "How do you prevent deadlocks with pessimistic locking?" 🔥

🟢 Ordered Locking

= Always acquire locks in a consistent order regardless of the business logic flow.

Sort all the resources you need to lock by some deterministic key (like user ID or database primary key) before acquiring any locks.

If I need to lock users 123 and 456, always lock 123 first even if your business logic processes 456 first. This prevents circular waiting because all transactions follow the same acquisition order.

🟢 Database Timeout Configurations (as fallback)

Use this when ordered locking isn't practical. (TODO: いつ?)

With transaction timeouts, deadlocked transactions get killed after a reasonable wait period. Then the system should retry with proper ordering.

🟢 Database Automatic Deadlock Detection (as fallback)

Most modern databases also have automatic deadlock detection that kills one transaction when cycles are detected.

DD :two: "What if your coordinator service crashes during a distributed transaction?"

= classic 2PC failure scenario.

1st commit の後に coordinator がダウンし、それぞれのサービス(あるいはDB)が 2nd commit を待ち続けてしまう。これにより、それぞれのサービス(あるいはDB)内でリソースがロックされ、その他の処理が無限にブロックされてしまう。

image.png

解決策としては、
coordinator において 2PC commit 中に永続ログ(WAL等)を残すようにする。
coordinator の failover/reboot 時にこの永続ログ(WAL等)を読み込み、クラッシュ時に実行途中だったトランザクションを特定して、残りの処理(コミットまたはアボート)を完了させる。

なお、最近の enterprise transaction managers はこれを自動でやってくれる。

📝 Saga だと、ロックを取らない。Saga を使え。

DD :three: "How do you handle the ABA problem with optimistic concurrency?" 🔥

ABA problem は、OCC において、revertible なカラムを version key として選択したことにより、read-modify-write が正しく実行されない問題である。

解決策は、dedicated version column を用い、version を単調増加させることである。

例えば、

  • (A-1) クライアントA が Post レコードを読み取る。like_count = 100 であったとする。
  • (A-2) クライアントA は、WHERE like_count = 100 を指定した Post レコードの更新クエリを投げる。

しかし、この A-1 と A-2 の間に挟まって以下が発生したとする。

  • (B-1) クライアントB がこのPostレコードに更新を加える。これにより、like_count = 101 になる。
  • (C-1) あるユーザーがこのPostへのLike を取り消し、like_count = 100 に戻る。

これにより、(A-2) でレコードを上書きする時点で、(B-1) による更新が含まれない古いデータに基づいて上書きしてしまい、適切な read-modify-write が行われない。

DD :four: "What about performance when everyone wants to update the same resource?" 🔥

= Row lock on the hot record はスケールしない。
なお、書き込み対象の Hot record を複数に分けることはできないため、シャーディングは使えない。

例えば、

  • Twitter で、有名人の新着ポストにみんなが一斉にLikeをする。(Post.liked_count の更新)
  • Auction system で、人気の商品にBidが集まる。(Item.highest_bid_id の更新)
  • Ticketmaster で、Taylor Swift のライブの座席を取り合う。(Ticket.status の更新)

🟢 解決策1: 仕様を変える

  • Twitter の like → eventual consistency を受け入れる。Post.liked_count を非同期更新にする。
  • Auction system の bid → もしその人気商品が複数あるなら、その商品のオークションを数個に分ける。
  • Ticketmaster の seat booking → virtual waiting queue を導入する。(ref)

TODO: Twitter の Like をUI上でリアルタイム更新にするには?
-> 多分、BEで、非同期で 3sec おきとかにincremental aggregationを走らせ、その結果をwebsocketでFEへ送る。FEでは、このdiffを6分割して0.5秒おきに画面更新する。(Client-side Interpolation)

🟢 解決策2: キューベースの非同期処理にする

更新リクエストをキューに入れる。リソースごとに、Single Worker でこれらを一つずつ sequential に実行していく。
ユーザーは処理が終了するまで待つ必要があるが、(Worker視点で見ると) strong consistency が担保される。

TODO: single worker のスループットを超えた更新リクエストが発生したらどうする? → ワーカーがメッセージをバッチで処理すればよい?(これ解決策3でいいのでは)

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?