Video and slides synchronized, mp3 and slide download available at URL http://bit.ly/2pZSlTn.
Sam Adams presents an overview of the architecture LMAX Exchange uses to deliver over $2 trillion a year through their platform, and shares their experience of how taking a scientific approach to testing and tuning software has helped them to build a high-availability stateful system. Filmed at qconlondon.com.
Sam Adams is currently the Head of Software Engineering at LMAX Exchange. He has had an eclectic career to date: variously modeling the metabolism of drugs and food additives, creating tools to manage and mine scientific data, and now building a high performance exchange at one of the UK's fastest growing Tech Companies.
2. InfoQ.com: News & Community Site
Watch the video with slide
synchronization on InfoQ.com!
https://www.infoq.com/presentations/
lmax-trading-architecture
• Over 1,000,000 software developers, architects and CTOs read the site world-
wide every month
• 250,000 senior developers subscribe to our weekly newsletter
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• 2 dedicated podcast channels: The InfoQ Podcast, with a focus on
Architecture and The Engineering Culture Podcast, with a focus on building
• 96 deep dives on innovative topics packed as downloadable emags and
minibooks
• Over 40 new content items per week
3. Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
Presented at QCon London
www.qconlondon.com
5. Typical day:
1,000's active clients
100,000's trades occur
100,000,000's orders placed
– very bursty: spikes of 100s / ms
1,000,000,000's market data updates sent
11. public class ArrayBlockingQueue<E>
{
final Object[] items;
int takeIndex;
int putIndex;
int count;
/** Main lock guarding all access */
final ReentrantLock lock;
}
ArrayBlockingQueue vs Disruptor
locking & contention
12. public class ArrayBlockingQueue<E>
{
final Object[] items;
int takeIndex;
int putIndex;
int count;
/** Main lock guarding all access */
final ReentrantLock lock;
}
public class RingBuffer<E>
implements DataProvider<E>
{
// ...
final long indexMask;
final Object[] entries;
final Sequence cursor;
// ...
}
public class BatchEventProcessor<E>
{
final DataProvider<E> dataProvider;
final Sequence sequence;
}
ArrayBlockingQueue vs Disruptor
locking & contention
vs
single writers
25. javassist generated proxies to interfaces
public interface TradingInstructions
{
void placeOrder(PlaceOrderInstruction instruction);
void cancelOrder(CancelOrderInstruction instruction);
}
See GeneratedRingBufferProxyGenerator in disruptor-proxy for inter-thread version
https://github.com/LMAX-Exchange/disruptor-proxy
Event:
long sequence
byte operationIndex
byte[] data
int length
26. See GeneratedRingBufferProxyGenerator in disruptor-proxy for inter-thread version
https://github.com/LMAX-Exchange/disruptor-proxy
public void placeOrder(PlaceOrderInstruction arg0)
{
// ...
event.initialise(sequence, 1); // operation index
marshaller.encode(arg0, event.outputStream());
// ...
}
Publisher proxy:
Event:
long sequence
byte operationIndex
byte[] data
int length
27. See GeneratedRingBufferProxyGenerator in disruptor-proxy for inter-thread version
https://github.com/LMAX-Exchange/disruptor-proxy
Invoker invokers[];
TradingInstructions implementation;
public void onEvent(Event event)
{
Invoker invoker = invokers[event.getOperationIndex()];
invoker.invoke(event.getInputStream(), implementation);
}
public void invoke(InputStream input, TradingInstructions implementation)
{
PlaceOrderInstruction arg0 = marshaller.decode(input);
implementation.placeOrder(arg0);
}
Subscriber proxy:
Event:
long sequence
byte operationIndex
byte[] data
int length
42. All Orders[ ]
Order Added
Order Cancelled
Order Added
Trade
Trade
Order Added
...
Matching Engine
Order Book
43. All Orders[ ]
Order Added
Order Cancelled
Order Added
Trade
Trade
Order Added
...
Matching Engine
Order Book
Market Analysis
Order Book Image
Event Store
AML Alerts
Order Book Image
44. Where latency doesn’t matter...
- How big are the bursts?
- Buffers are your friend
Does data loss matter?
Market Analysis
Order Book Image
Event Store
AML Alerts
Order Book Image
62. public class Cash
{
long value;
}
Calculations with money
- double: inexact
- BigDecimal: expensive
Fixed-point arithmetic with long
But I want type-safety...
63. long price1 = 1250000L;
long quantity1 = 1520L;
// BUG
long price2 = quantity1;
Prices, precision: 6dp
1250000L → 1.250000
Quantities, precision: 2dp
1520L → 15.20
64. https://checkerframework.org/
With Type Annotations & Units Checker:
@Price long price1 = 1250000L;
@Qty long quantity1 = 1520L;
// Compilation error
@Price long price2 = quantity1;
Prices, precision: 6dp
1250000L → 1.250000
Quantities, precision: 2dp
1520L → 15.20
65. public class HashMap<K,V>
{
Node<K,V>[] table;
static class Node<K,V>
{
K key;
V value;
Node<K,V> next;
}
public class Long2ObjectOpenHashMap<V>
{
long[] keys;
V[] values;
}
java.util vs fastutil
Map<Long,X> vs LongMap<X>
66. public class HashMap<K,V>
{
Node<K,V>[] table;
static class Node<K,V>
{
K key;
V value;
Node<K,V> next;
}
public class Long2ObjectOpenHashMap<V>
{
long[] keys;
V[] values;
}
java.util vs fastutil
Map<Long,X> vs LongMap<X>
67. False sharing: revisit the Disruptor
public class ArrayBlockingQueue<E>
{
final Object[] items;
int takeIndex;
int putIndex;
int count;
/** Main lock guarding all access */
final ReentrantLock lock;
}
68. public class RingBuffer
{
// ...
final Object[] entries;
final Sequence cursor;
// ...
}
public class Sequence
{
long p1, p2, p3, p4, p5, p6, p7;
long value;
long p9, p10, p11, p12, p13, p14, p15;
}
False sharing: revisit the Disruptor
69. public class RingBuffer
{
// ...
final Object[] entries;
final Sequence cursor;
// ...
}
public class Sequence
{
@Contended
long value;
}
False sharing: revisit the Disruptor
Java 8: