Slide 1

Slide 1 text

Points of implementation of Repository to avoid Deadlock @dnskimox デッドロックを回避する リポジトリ実装の勘所

Slide 2

Slide 2 text

HELLO! 男爵 @dnskimox Dansyaku / Tanga Kenichi A backend developer at 2 自己紹介

Slide 3

Slide 3 text

Table of Contents ✘ Sample of DDD like domain model ✘ Implementation policy of Repository ✘ Making persistence of Value Object ✘ Deadlock examples and corrections ✘ Points of implementation of Repository ✘ More fundamental solutions of deadlock 3 目次

Slide 4

Slide 4 text

Preconditions of System ✘ RDB is Amazon Aurora (compatible with MySQL 5.7). ✘ Default storage engine is InnoDB ✘ Default transaction separation level is Repeatable Read. ✘ Primary keys in tables are UUID. 4 MySQL 5.7、InnoDB、リピータブルリード、UUID

Slide 5

Slide 5 text

Sample Domain Model like DDD DDD風のサンプルドメインモデル

Slide 6

Slide 6 text

CloudSign Salesforce Dashboard(SPA) Client Service MakeInvoice 架空の請求書発行SaaS

Slide 7

Slide 7 text

7 請求書、カスタムフィールド、カスタムフィールドマス ター

Slide 8

Slide 8 text

8 請求書テーブル、カスタムフィールドテーブル、カスタム フィールドマスターテーブル

Slide 9

Slide 9 text

Implementation policy of Repository リポジトリ実装の方針

Slide 10

Slide 10 text

10 参考書籍:実践ドメイン駆動設計

Slide 11

Slide 11 text

11 集約毎とリポジトリを一対一で用意する

Slide 12

Slide 12 text

12 実装クラスはSQLを発行する機能を持ち、ロックありで集約を 取得した場合、SELECT 〜 FOR UPDATE文を発行

Slide 13

Slide 13 text

Making persistence of Value Object 値オブジェクトの永続化について

Slide 14

Slide 14 text

14 参考書籍:エンタープライズアプリケーションアーキテク チャパターン

Slide 15

Slide 15 text

15 依存オブジェクトは唯一つの親を持つ 親以外からの参照は存在しない - A dependent must have exactly one owner. - There must be no references from any object other than the owner to the dependent Dependent Mapping

Slide 16

Slide 16 text

Update logic for custom fields is very simple 16 DELETE FROM custom_fields where invoice_id = X; INSERT INTO custom_fields (id, invoice_id, …) VALUES (uuid(), X, …); INSERT INTO custom_fields (id, invoice_id, …) VALUES (uuid(), X, …); 値オブジェクトの更新は非常にシンプル

Slide 17

Slide 17 text

Why that sql is effectively update value objects? ✘ Value Object don't have an identity. ✘ A permanent Value Object necessarily depends on one parent entity. ✘ Value Object is immutable. 17 なぜこのSQLが効果的に働くのか?

Slide 18

Slide 18 text

Deadlock examples and corrections デッドロックの実例と修正方法

Slide 19

Slide 19 text

1. Illegal aggregate boundary about table reference テーブル参照における集約の境界違反

Slide 20

Slide 20 text

20 ロックの競合が発生しやすいクエリ TX1 > SELECT * FROM invoices iv JOIN custom_field cf ON cf.invoice_id = iv.id JOIN custom_field_master cfm ON cf.master_id = cfm.id WHERE iv.id = X FOR UPDATE; TX2 > SELECT * FROM invoices iv JOIN custom_field cf ON cf.invoice_id = iv.id JOIN custom_field_master cfm ON cf.master_id = cfm.id WHERE iv.id = Y FOR UPDATE; TX2 > (Waiting for lock granted …)

Slide 21

Slide 21 text

21 ドメインモデルを再確認

Slide 22

Slide 22 text

22 custom_field_mastersの値を共有しているzuzu a

Slide 23

Slide 23 text

23 custom_fields側に値を非正規化する

Slide 24

Slide 24 text

24 ロックの競合が発生しづらいクエリ TX1 > select * from invoices iv join custom_field cf on cf.invoice_id = iv.id where iv.id = X fo update; TX2 > select * from invoices iv join custom_field cf on cf.invoice_id = iv.id where iv.id = Y fo update; TX2 > (Query returns immediately)

Slide 25

Slide 25 text

Correction Don`t select tables belonging to aggregate to recreate an aggregate. Select tables belonging to an aggregate itself only. 25 集約の再構築には、自身に所属するテーブルだけを使う

Slide 26

Slide 26 text

2. Gaplock problem on DELETE/INSERT approach DELETE/INSERT方式におけるギャップロックの問題

Slide 27

Slide 27 text

27 デッドロックの発生しやすいクエリ TX1 > select * from custom_fields where invoice_id = X for update; TX1 > delete from custom_fields where invoice_id = X; TX1 > insert into custom_fields values (uuid(), X, …); TX1 > (Waiting for lock granted …) TX2 > select * from custom_fields where invoice_id = Y for update; TX2 > delete from custom_fields where invoice_id = Y; TX2 > insert into custom_fields values (uuid(), Y, …); TX2 > Deadlock Detected!

Slide 28

Slide 28 text

28 クラス図(修正前)zuzu a

Slide 29

Slide 29 text

29 クラス図(修正後)zuzu

Slide 30

Slide 30 text

Correction Mix in many objects into aggregate in spite of difference of its life cycle Extract value object having its own life cycle from aggregate as a new aggregate. 30 独自のライフサイクルを持つ値オブジェクトを、新たな集 約として抽出する

Slide 31

Slide 31 text

3. Other complicated deadlock problems その他の込み入った問題たち

Slide 32

Slide 32 text

Correction Issue a query only one time and raise a deadlock alert to engineers. Retry queries having deadlock lisk automatically. 32 ロックが競合する可能性のあるクエリは、自動的にリトラ イする

Slide 33

Slide 33 text

Points of implementation of Repository リポジトリ実装の勘所

Slide 34

Slide 34 text

Points of implementation of Repository ✘ Don’t share a database row with another aggregate. ✘ If another lifecycle is detected extract a new aggregate. ✘ Retry failed transaction for deadlock. 34 リポジトリ実装の勘所

Slide 35

Slide 35 text

More fundamental solutions of deadlock より根本的なデッドロック対策

Slide 36

Slide 36 text

More fundamental solutions of deadlock ✘ Consider to change transaction separation level. Do you really need that level of integrity? Think about boundary of aggregate. 36 トランザクション分離レベルの変更を検討する

Slide 37

Slide 37 text

THANKS! Any questions? You can find me at ✘  @dnxkimox ✘ https:/ /dnskimox.hateblo.jp ✘ https:/ /note.com/dnskimo 37 ご清聴ありがとうございました!

Slide 38

Slide 38 text

Reference documents ✘ Implementing Domain-Driven Design ✘ Patterns of Enterprise Application Architecture 38 参考文献