DDD Sous Pression — DDD FR mai 2019

DDD Sous Pression — DDD FR mai 2019

DDD sous pression: retour d'expérience sur la construction d'un système boursier

Ces derniers mois, nous avons construit en partant de zéro un système de bourse électronique (un exchange). Cette soirée sera l’occasion de revenir sur nos découvertes à la fois en terme technique, mais aussi métier, sur ce type de projet qui présente des contraintes assez rares en termes de performances et de fiabilités, le tout dans un environnement métier souvent mal-compris (et mal aimé).

Nous présenterons comment nous avons cherché à ne pas faire disparaitre le métier sous le poids des micro-optimisations techniques, pour répondre à cette question : est-il possible d’allier haute performance et expression métier, est-ce que le DDD sous pression est possible ?

Arnaud LEMAIRE et Jean-Baptiste DUSSEAUT (LGO Group)

Beb422437c1dfb5366f197919e41ac50?s=128

Arnaud LEMAIRE

May 02, 2019
Tweet

Transcript

  1. DDD sous pression Retour d’expérience sur la construction d’un exchange

    Arnaud LEMAIRE @lilobase Jean Baptiste Dusseaut @bodysplash
  2. « Un métier simple mais pas facile »

  3. C’est quoi un trade ? 1 BUY 2@200 2 SELL

    3@200 1 2 TRADE 2@200
  4. C’est quoi un trade ? 1 BUY 2@200 2 SELL

    3@200 1 2 TRADE 2@200 Un ordre
  5. C’est quoi un trade ? 1 BUY 2@200 2 SELL

    3@200 1 2 TRADE 2@200 Un ordre Un trade
  6. C’est quoi un trade ? 1 BUY 2@200 2 SELL

    3@200 1 2 TRADE 2@200 3 BUY 1@200 3 2 TRADE 1@200
  7. L’exécution BUY 2@202 TRADE 2@202

  8. L’exécution BUY 2@202 Le carnet d’ordre TRADE 2@202

  9. Le carnet d’ordre 7 BUY 1@199 2 SELL 3@202 4

    BUY 2@200 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198
  10. Le carnet d’ordre 7 BUY 1@199 2 SELL 3@202 4

    BUY 2@200 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 BUY 2@202 10 BUY 1@198
  11. Le carnet d’ordre 7 BUY 1@199 2 SELL 3@202 4

    BUY 2@200 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 BUY 2@202 10 BUY 1@198 TRADE 2@202
  12. Le carnet d’ordre 7 BUY 1@199 2 SELL 3@202 4

    BUY 2@200 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 BUY 2@202 10 BUY 1@198 contre-ordre TRADE 2@202
  13. Le carnet d’ordre 7 BUY 1@199 2 SELL 3@202 4

    BUY 2@200 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 BUY 2@202 10 BUY 1@198 contre-ordre TRADE 2@202 Niveau de prix
  14. Le carnet d’ordre 2 SELL 1@202 3 SELL 4@203 9

    BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  15. Le carnet d’ordre BUY 2@200 2 SELL 1@202 3 SELL

    4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  16. Le carnet d’ordre BUY 2@200 2 SELL 1@202 3 SELL

    4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  17. Le carnet d’ordre 2 BUY 2@200 BUY 2@200 2 SELL

    1@202 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  18. Le carnet d’ordre 2 BUY 2@200 2 SELL 1@202 3

    SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  19. Le carnet d’ordre 2 BUY 2@200 L’ordre est mis dans

    la file 2 SELL 1@202 3 SELL 4@203 9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  20. L’allocation 2 BUY 2@200 2 SELL 1@202 3 SELL 4@203

    9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 7 BUY 1@199 4 BUY 2@200
  21. L’allocation 2 BUY 2@200 2 SELL 1@202 3 SELL 4@203

    9 BUY 3@199 1 SELL 2@204 6 SELL 3@204 UY 1@199 SELL 2@2 5 BUY 5@198 8 BUY 2@198 10 BUY 1@198 SELL 2@200 7 BUY 1@199 4 BUY 2@200
  22. 1 L’allocation : FIFO 2 BUY 2@200 SELL 2@200 4

    BUY 2@200
  23. 1 L’allocation : FIFO 2 BUY 2@200 SELL 2@200 4

    BUY 2@200 4 1 TRADE 2@200
  24. L’allocation : FIFO 2 BUY 2@200 4 BUY 2@200 4

    1 TRADE 2@200
  25. L’allocation : FIFO 2 BUY 2@200 4 1 TRADE 2@200

  26. 1 L’allocation : pro-rata 2 BUY 2@200 SELL 2@200 4

    BUY 2@200
  27. 1 L’allocation : pro-rata 2 BUY 2@200 SELL 2@200 4

    BUY 2@200 4 1 TRADE 1@200 2 1 TRADE 1@200
  28. 1 L’allocation : pro-rata 2 BUY 2@200 SELL 2@200 4

    BUY 2@200 4 1 TRADE 1@200 2 1 TRADE 1@200
  29. 1 L’allocation : pro-rata 2 BUY 2@200 SELL 2@200 4

    BUY 2@200 4 1 TRADE 1@200 2 1 TRADE 1@200
  30. 1 L’allocation : pro-rata 2 BUY 2@200 SELL 2@200 4

    BUY 2@200 4 1 TRADE 1@200 2 1 TRADE 1@200 2 BUY 1@200 4 BUY 1@200
  31. Orders •Fill Or Kill •Immediate Or Cancel •Market •Stop orders

    •…
  32. Nous ne sommes pas seuls

  33. Arbitrage Arbitrage $5200 $5198 $5197

  34. Front-running

  35. Front-running

  36. Front-running

  37. 30ms Front-running

  38. 30ms 90ms Front-running

  39. 30ms 90ms 120ms Front-running

  40. 30ms 90ms 120ms 40ms Front-running

  41. 30ms 90ms 120ms 40ms 60ms Front-running

  42. 30ms 90ms 120ms 40ms 60ms Front-running

  43. 30ms 90ms 120ms 40ms 60ms Front-running

  44. 30ms 90ms 120ms Front-running

  45. 30ms 90ms 120ms Front-running +30ms

  46. 30ms 90ms 120ms Front-running +30ms +90ms

  47. 30ms 90ms 120ms Front-running +30ms +90ms

  48. 30ms 90ms 120ms Front-running +30ms +90ms

  49. 30ms 90ms 120ms Front-running +30ms +90ms

  50. Front running interne Délit d’initié 2 BUY 2@200 # BUY

    2@200
  51. Front running interne Délit d’initié 2 BUY 2@200 SELL 2@200

    # BUY 2@200
  52. Front running interne Délit d’initié 2 BUY 2@200 SELL 2@200

    # BUY 2@200 Exchange
  53. Une concurrence (quasi) impossible

  54. Chaque exécution est fonction de l’exécution précédente Execution

  55. Chaque exécution est fonction de l’exécution précédente Execution

  56. Chaque exécution est fonction de l’exécution précédente Execution Execution

  57. Chaque exécution est fonction de l’exécution précédente Execution Execution

  58. Avec une charge, pas très prévisible

  59. Avec une charge, pas très prévisible Vous avez interet a

    etre pret
  60. Que vous avez intérêt à absorber rapidement

  61. Un chemin critique qui ne s’arrête pas à l’exécution BUY

    2@200
  62. Un chemin critique qui ne s’arrête pas à l’exécution BUY

    2@200 Et parfois notre utilisateur est vraiment une fonction !
  63. Si on résume 1 million d’ordres par seconde sur un

    seul thread, 24h sur 24 et 7j sur 7 Le tout sans pouvoir paralléliser…
  64. Un état de l’art « Discutable »

  65. None
  66. None
  67. None
  68. None
  69. BlockchainTransparency

  70. None
  71. Anti front-running

  72. non-custody

  73. Execution engine Première approche

  74. Une exécution sous contrainte Single Thread Pas de concurrence

  75. Une exécution sous contrainte Single thread in memory Non bloquant

    (donc sans I/O)
  76. Une exécution sous contrainte Single thread in memory Messages entrant

    séquencés
  77. Le ring buffer Single thread in memory

  78. Le ring buffer Thread #1 Thread #2 Business Thread

  79. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 2 taches composée de 4 étapes
  80. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 taches composée de 4 étapes
  81. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 2 taches composée de 4 étapes
  82. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 2 taches composée de 4 étapes
  83. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 2 taches composée de 4 étapes
  84. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 2 taches composée de 4 étapes
  85. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 6 2 taches composée de 4 étapes
  86. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 6 7 2 taches composée de 4 étapes
  87. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 6 7 8 2 taches composée de 4 étapes
  88. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 6 7 8 2 taches composée de 4 étapes Sans pipelining : 8 ticks
  89. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 2 taches composée de 4 étapes
  90. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 taches composée de 4 étapes
  91. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 2 taches composée de 4 étapes
  92. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 2 taches composée de 4 étapes
  93. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 2 taches composée de 4 étapes
  94. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 2 taches composée de 4 étapes
  95. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 2 taches composée de 4 étapes Sans pipelining : 5 ticks
  96. Le pipelining Temps Step #1 Step #2 Step #3 Step

    #4 1 2 3 4 5 2 taches composée de 4 étapes Sans pipelining : 5 ticks Parallélisme sans concurrence
  97. Le pipelining Thread #1 Thread #2 Business Thread

  98. Le pipelining Thread #1 Thread #2 Business Thread

  99. Le pipelining Thread #1 Thread #2 Business Thread Lock-free :

    memory barrier
  100. Le pipelining Logger Unmarshalling Business Thread Producer

  101. Le pipelining private Disruptor<PlatformEvent> createDisruptor() { Disruptor<PlatformEvent> disruptor = new

    Disruptor <>(
 PlatformEvent ::new, bufferSize(), new ThreadFactoryBuilder()
 .setNameFormat("disruptor").build(), ProducerType.MULTI, new BlockingWaitStrategy()); disruptor.handleEventsWith(logger).and(marshaller) .then(business_handler) .then(output); return disruptor; }
  102. Le pipelining private Disruptor<PlatformEvent> createDisruptor() { Disruptor<PlatformEvent> disruptor = new

    Disruptor <>(
 PlatformEvent ::new, bufferSize(), new ThreadFactoryBuilder()
 .setNameFormat("disruptor").build(), ProducerType.MULTI, new BlockingWaitStrategy()); disruptor.handleEventsWith(logger).and(marshaller) .then(business_handler) .then(output); return disruptor; } Architecture LMAX ?
  103. Le parking

  104. Mais… Le disruptor n’est que le commencement

  105. Haute disponibilité Et aussi survivre au reboot, tout simplement Execution

    engine 1 Execution engine 2 Execution engine 3 ? ? ? ?
  106. Execution engine 1 Event Sourcing ? Execution engine 2 ?

    ?
  107. Execution engine 1 Command sourcing ! Execution engine 2 Execution

    engine 3
  108. Execution engine 1 Command sourcing ! Execution engine 2 Execution

    engine 3 Le metier doit etre deterministe
  109. Raft

  110. Raft

  111. Mais… Merde²

  112. None
  113. UDP avec acquittement négatif Broker less

  114. Json, un load tester pour votre GC MTU & taille

    de vos messages Encoding Binaire
  115. Aeron…

  116. Media Driver Sender Conductor Receiver Media Driver Sender Conductor Receiver

    Client Publisher Conductor Subscriber Client Subscriber Conductor Publisher Aeron: Messaging
  117. Subscription Recording Replayed subscription Segments Aeron archive : replay

  118. Aeron Cluster : Raft Media Driver Sender Conductor Receiver Archiving

    Media Driver Consensus module Clustered Service Business logic Snapshot
  119. Le monde extérieur

  120. Gateways Execution engine

  121. Gateways Execution engine Order placed

  122. Gateways Execution engine Order placed Order Canceled

  123. Gateways Execution engine Order placed Order Canceled Match

  124. Gateways Execution engine Order placed Order Canceled Match Gateway

  125. Gateways Execution engine Order placed Order Canceled Match Gateway

  126. Gateways Execution engine Order placed Order Canceled Match Gateway

  127. Projections « lentes » Execution engine 1 Execution engine 2

    Execution engine 3 Consommateur CRC 32 check
  128. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  129. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  130. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  131. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  132. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  133. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  134. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  135. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  136. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  137. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  138. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  139. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  140. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  141. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  142. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  143. Web gateway Web socket gateway AFR Execution Engine Exchange view

    Accounting Internal gateway Accounting import Settlement CA OTS Blockchain / Custody
  144. « Une implémentation complexe mais pas compliquée »

  145. Mais finalement on parle de DDD ? Et le métier,

    il est où ?
  146. En réalité il est peu impacté, la performance se construit

    grâce à l’orchestration de celui-ci Mais finalement on parle de DDD ? Et le métier, il est où ?
  147. Just…

  148. Just… •Faire attention aux allocations

  149. Just… •Faire attention aux allocations •Data-structures adaptées

  150. Just… •Faire attention aux allocations •Data-structures adaptées •Escape Analysis, utilisation

    de la pile
  151. By The Way

  152. By The Way •Property Based Testing

  153. By The Way •Property Based Testing •Check sur les Invariants

    du Domain
  154. Merci ! lgo.group Arnaud LEMAIRE @lilobase Jean Baptiste Dusseaut @bodysplash