itlchn 20 - Kien truc he thong chung khoan - Phan 2

29
Một trong những Broker (công ty môi giới) chính trên thị trường VN Số tài khoản khách hàng: ~100.000 Thị phần môi giới: Đứng thứ 4 trên HSX, thứ 2 trên HNX (số liệu quý 1 năm 2016) Số lệnh đặt trong ngày: ~20.000 lệnh. Cao điểm khi thị trường nóng có thể vượt 30.000 lệnh Case study: VNDS

Transcript of itlchn 20 - Kien truc he thong chung khoan - Phan 2

Một trong những Broker (công ty môi giới) chính trên thị trường VN

Số tài khoản khách hàng: ~100.000

Thị phần môi giới: Đứng thứ 4 trên HSX, thứ 2 trên HNX (số liệu quý 1 năm 2016)

Số lệnh đặt trong ngày: ~20.000 lệnh. Cao điểm khi thị trường nóng có thể vượt 30.000 lệnh

Case study: VNDS

Hệ thống core: phát triển bởi FSS, một đơn vị phát triển core chứng khoán có tiếng trên thị trường Việt Nam

Một số phần trong hệ thống được phát triển hoặc nâng cấp bởi VNDS

Hệ thống hỗ trợ nhiều kênh đặt lệnh: Online, ATD/BD, BO, Bloomberg (via FIX 4.2 protocol) …

Hệ thống VNDS (trước khi nâng cấp)

Hệ thống hoạt động không thật sự ổn định

Các vấn đề gặp phải: dead locking database (nhiều lúc phải restart Oracle DB của Back Office)

Gửi lặp lệnh vào sở(xảy ra vào ngày 27-08-2014 khi VNDS gửi nhiều hơn 20.000 lệnh lặp vào sàn HNX)

Khả năng xử lý của hệ thống đạt max ~10 lệnh/s, độ trễ ~4s

Hệ thống VNDS (trước khi nâng cấp)

Hệ thống có khả năng xử lý ổn định 5000-10000 lệnh/s

Độ trễ hệ thống < 4ms (không tính độ trễ sinh ra do đường truyền kết nối đến sở, khoảng 70 ms đối với sở HSX)

-> Mục tiêu nâng hiệu năng của hệ thống lên 1000 lần

Mục tiêu đặt ra khi nâng cấp

Tách hoàn toàn phần xử lý lệnh khỏi BO, xây dựng một hệ thống chuyên biệt mới hoàn toàn xử lý việc này: ORS/OMS (Orders routing and management system)

Hệ thống ORS sẽ thực hiện load toàn bộ dữ liệu cần thiết từ BO vào đầu ngày giao dịch (BOD) và thực hiện xóa toàn bộ dữ liệu (reset) vào cuối ngày giao dịch (EOD)

Dữ liệu cần đồng bộ trong ngày (rút tiền, nộp tiền, mở tài khoản mới … ) sẽ được thực hiện qua hoặc web service hoặc messages push

Thiết kế hệ thống

Ngôn ngữ: C/C++ và Java

• 90% hệ thống phát triển bằng Java (plain java, không sử dụng bất cứ framework nào)

• 10% hệ thống (các modules xử lý dữ liệu thị trường và Gateways) phát triển bằng C/C++

• 100% C: May be the next version!

OS: Linux/UNIX: Lựa chọn hiển nhiên ở server side

Lựa chọn ngôn ngữ và OS

Messages queues: ActiveMQ, ZeroMQ• Apache ActiveMQ: Open source về messages broker được sử dụng rộng rãi nhất hiện nay• ZeroMQ: Giải pháp opensource về messaging nhanh nhất hiện tại. Hỗ trợ Inproc, IPC, TCP, reliable

multicast (PGM) …

FIX engines: QuickFiX CPP, QuickfixJ

Databases: PostgresQL

Web server: Jetty

Lựa chọn công nghệ

Cần một tool đủ tốt để theo dõi hệ thống chạy trên môi trường production, theo thời gian thực

Cost để benchmark ~0 (hoặc vài magnitude thấp hơn cost xử lý orders của hệ thống)

• Observer effect: “Measurements of certain systems cannot be made without affecting the systems”

-> Tự phát triển

Performance Statistics 23:06:35 Tag Avg(us) Min Max Std Dev Count INSERT into forward VALUES(DEFAU 97.79 62 42186 328.64 18740 Update Complex Accounts 0.20 0 1351 11.31 18761 QFJ-01 214.26 60 20778 546.56 18761 DOrder 507.66 163 53537 1011.87 18762

Performance Statistics 23:07:05 Tag Avg(us) Min Max Std Dev Count INSERT into forward VALUES(DEFAU 82.35 66 132 13.07 1360 Update Complex Accounts 0.07 0 35 1.00 1339 QFJ-01 169.18 59 4196 374.89 1339 DOrder 366.78 162 8208 526.34 1338

Benchmarking hệ thống

Log4J: Quá phức tạp, quá chậm-> Chuyển sang sử dụng phiên bản customize của logback. Thực hiện tuning/test và chỉ để lại những options đảm bảo performance.

OpenJDK, Sun JDK: Chậm, độ ổn định về performance kém

-> Chuyển sang dùng jrockit và sử dụng các options để tuning garbage collector

Logging và JVM

Hệ thống hoạt động 100% (hay gần như 100%) theo cơ chế asynchronous

• No hazelcast, redis hay bất cứ giải pháp in memory data-grid nào

• Hệ thống cache dữ liệu trên memory bất cứ khi nào có thể. Databases chỉ được dùng chủ yếu cho việc backup và recovery khi xảy ra sự cố cần restart hệ thống

• Việc trao đổi thông tin đi và về chủ yếu được thực hiện qua các messages queues

Thiết kế: Tổng quan

Một vài con số cơ bản về communication cost (round-trip latency)

• In-process (inter-threads): ~10 us• Inter-process (IPC): ~15 us• TCP/UDP on local host: ~50us• TCP/UDP on different servers: ~300 us

Tại sao phải chọn kiến trúc asynchronous

Yêu cầu bắt buộc: phải hỗ trợ chuẩn FIX (Financial Information Exchange) do đây là chuẩn giao tiếp chung của tất cả các hệ thống tài chính hiện đại

Ưu điểm của chuẩn FIX: Dễ đọc, có thể tùy ý mở rộng hoặc bổ sung thêm nghiệp vụ. Có sẵn các open source để sử dụng (QuickFIX hay QuickFixJ)

Nhược điểm: Cồng kềnh, cost để parsing messages cao

Thiết kế: Nhận lệnh

Viết tắt của Financial Information Exchange

Được đưa vào sử dụng từ 1992, hiện FIX protocol đã trở thành chuẩn giao tiếp chung của thế giới cho giao dịch chứng khoán điện tử

FIX protocol bao gồm: communication protocol, messages specification và business guide line

Giới thiệu về FIX protocol

http://www.fixtradingcommunity.org/FIXimate/FIXimate3.0/

FIX message sample: 8=FIX.4.4 9=221 35=D 34=33 449=ORS_1_ACTIVE 52=20151023-03:56:04.321 56=HSX_GATEWAY 57=1 11=50000018 38=10 40=2 44=73.5 54=2 55=MSN 59=0 60=20151023-03:56:04.321 453=3 448=021 447=C 452=1 448=0211 447=D 452=12 448=021C686899 447=D 452=3 10=187

HSX message sample (AutoT protocol): A!1I021021150000018021C686899MSN S10 10 73.500M C

FIX message dài khoảng 200 bytes trong khi AutoT message tương ứng dài khoảng 70 bytes.

Giới thiệu về FIX protocol (tiếp)

Các modules GWIN tiếp nhận lệnh theo FIX protocol

Các modules GWIN hoàn toàn stateless, hoạt động như các switches. Có thể dễ dàng load balancing tùy ý

Sau khi parsing message và kiểm tra các giá trị truyền vào hợp lệ, GWIN sẽ gửi các message này vào OMS

Thiết kế: Nhận lệnh (tiếp)

Thiết kế: Diagram

Asynchronous (gần như 100%)

Toàn bộ các tài khoản do OMS quản lý được cache trên memory

Chỉ một số orders gần nhất được cache trên memory (giá trị có thể tùy chỉnh)

Orders và các thay đổi liên quan đến tài khoản sau khi update trên memory được đẩy vào các queues để thực hiện ghi bất đồng bộ xuống DB

Thiết kế: OMS

Tự xây dựng dựa trên array thuần túy

Thuật toán và implementation phần orders caching được thiết kế để không phải sử dụng bất cứ cơ chế locking nào

1 single thread sẽ quản lý việc đưa objects mới lên cache và remove objects cũ ra khỏi cache. 1 thread khác quản lý việc cập nhật các objects nằm trên cache

Thiết kế: OMS Orders cache

Code sample:

Code unsafe: public OrderBase getOrderFromCache(int seq, OrderBase newInfo) { if (orders[seq] == null) return null;orders[seq].setField(OrderBase.CUM_QTY, newInfo.getField(OrderBase.CUM_QTY));orders[seq].setField(OrderBase.LAST_QTY, newInfo.getField(OrderBase.LAST_QTY));orders[seq].setField(OrderBase.LAST_PX, newInfo.getField(OrderBase.LAST_PX));return orders[seq]; }

Code safe:

public OrderBase getOrderFromCache(int seq, OrderBase newInfo) { OrderBase order = orders[seq]; if (order == null) return null;order.setField(OrderBase.CUM_QTY, newInfo.getField(OrderBase.CUM_QTY));order.setField(OrderBase.LAST_QTY, newInfo.getField(OrderBase.LAST_QTY));order.setField(OrderBase.LAST_PX, newInfo.getField(OrderBase.LAST_PX));return order; }

Thiết kế: OMS Orders cache (tiếp)

Cache 100% số tài khoản (có thể sharding theo OMSs)

Tự xây dựng dựa trên array thuần túy

Thuật toán và implement phần cache tài khoản được thiết kế để giảm thiểu sử dụng locking

• Thread nhận lệnh đặt/hủy/sửa và thread cập nhật trạng thái lệnh từ sở không lock lẫn nhau

Thiết kế: OMS accounts cache

Code unsafe

class Account { private long balance; public Account(long balance) { this.balance = balance; } public boolean hold (long amount) { if (balance >= amount) { balance -= amount; return true; } return false; } public void unhold(long amount) { balance += amount; } public long getBalance() { return balance; }}

Thiết kế: OMS accounts cache (tiếp)

Tài khoản ban đầu có 10.000.000 VND. Thread 1 gọi hold 1.000.000 VND, Thread 2 gọi unhold 1.000.000 VND, vậy tài khoản cuối cùng có bao nhiêu VND?

• 9.000.000• 10.000.000• 11.000.000• 1 trong các khả năng trên

Ví dụ kinh điển trong lập trình

Code safe?class Account { private long balance; public Account(long balance) { this.balance = balance; } public synchronized boolean hold (long amount) { if (balance >= amount) { balance -= amount; return true; } return false; } public synchronized void unhold(long amount) { balance += amount; } public long getBalance() { return balance; }}

Thiết kế: OMS accounts cache (tiếp)

CPU architect (đơn giản hóa)

Code safe (như sách dạy)class Account { private volatile long balance; public Account(long balance) { this.balance = balance; } public synchronized boolean hold (long amount) { if (balance >= amount) { balance -= amount; return true; } return false; } public synchronized void unhold(long amount) { balance += amount; } public long getBalance() { return balance; }}

-> Safe but awfully slow

Thiết kế: OMS accounts cache (tiếp)

Code safeclass Account { private long initBalance; private long hold; private long unhold; public Account(long balance) { initBalance = balance; hold = 0; unhold = 0; } public boolean hold (long amount) { if (initBalance - hold + unhold >= amount) { hold += amount; return true; } return false; } public void unhold(long amount) { unhold += amount; } public long getBalance() { return initBalance - hold + unhold; }}

Thiết kế: OMS accounts cache (tiếp)

Trong thế giới thiết kế đa luồng, unitest có thể không hữu ích như bạn nghĩ

Xác suất xảy ra conflict giữa các threads lớn hay nhỏ?

Định luật Murphy: “Anything that can possibly go wrong, does”

Bài học:

Hệ thống đã được thử load test tới khoảng 1500 lệnh/s đối với 1 OMS chạy trên 1 Linux server 4 cores.

End to end latency đo được: ~71 ms (~67 ms ping time vào sở HSX)

10:56:04.321 INFO - GWIN<--: 35=D555=11=000168689966=092815-FIXIN02-1309494=021111=092815-FIXIN02-1309-0-OrderServerATD01-ATDORS467230214461781838=1040=244=7350054=255=MSN59=060=20151023-03:56:26.10578=179=000168689980=10467=0100=150=dunguyen10:56:04.321 INFO - Hold balance MSN, 021C686899, -10. Current balance -1010:56:04.321 INFO - -->GW: 8=FIX.4.49=22135=D34=33449=ORS_1_ACTIVE52=20151023-03:56:04.32156=HSX_GATEWAY57=111=5000001838=1040=244=73.554=255=MSN59=060=20151023-03:56:04.321453=3448=021447=C452=1448=0211447=D452=12448=021C686899447=D452=310=18710:56:04.391 INFO - <--GW: 8=FIX.4.49=32235=834=35549=HSX_GATEWAY52=20151023-03:56:04.38756=ORS_1_ACTIVE212=49213=2I21 932 231050000018231010 73.5 19104 6=011=5000001814=1017=19104 31=73.532=1037=5000001838=1039=241=5000001844=73.554=255=MSN58=2I60=20151023-03:56:04150=3151=0453=2448=21 447=B452=1448=021C686899447=B452=310=10610:56:04.391 INFO - Unhold balance MSN, 021C686899, -10. Current balance 010:56:04.392 INFO - -->GWIN FIXIN02: 35=81=00016868996=73500.011=092815-FIXIN02-1309-0-OrderServerATD01-ATDORS467230214461781814=1017=102315105604-HSX_GATEWAY-38-ORS_1_ACTIVE-1910431=73500.032=1037=5000001838=1039=240=244=7350054=255=MSN59=060=20151023-03:56:26.105150=F151=078=179=000168689980=10467=1100=150=dunguyen

(10:56:04.319) QFIX <- 8=FIX.4.49=22135=D34=33449=ORS_1_ACTIVE52=20151023-03:56:04.32156=HSX_GATEWAY57=111=5000001838=1040=244=73.554=255=MSN59=060=20151023-03:56:04.321453=3448=021447=C452=1448=0211447=D452=12448=021C686899447=D452=310=187(10:56:04.319) AutoT Send DT(3996,5382) A!1I021021150000018021C686899MSN S10 10 73.500M C (10:56:04.386) AutoT Recv DT(5382,3997) A!2I21 932 231050000018231010 73.5 19104 (10:56:04.386) QFIX -> 8=FIX.4.49=33735=834=697249=HSX_GATEWAY52=20151023-03:56:04.38756=GW_INTEGRATION_ACTIVE212=49213=2I21 932 231050000018231010 73.5 19104 6=011=932 14=171017=19104 31=73.532=1037=932 38=1039=241=932 44=73.554=155=MSN58=2I60=20151023-03:56:04150=3151=8290453=2448=21 447=B452=1448=021C057269447=B452=310=113

VNDS: Một số kết quả đạt được của hệ thống sau khi nâng cấp

Thank you!

Any questions?

Q&A

Thảm khảo thêm : http://bit.ly/itlchn-stockcore-event