Computer >> Máy Tính >  >> Lập trình >> Redis

Xây dựng nền tảng giao dịch thời gian thực với Redis

Danh mục đầu tư hình thành nền tảng của ngành quản lý tài sản và của cải. Kể từ khi Harry Makowitz đi tiên phong trong lý thuyết danh mục đầu tư hiện đại, các chuyên gia quản lý tài sản và tài sản đã bị ám ảnh về việc tối đa hóa lợi nhuận trên danh mục đầu tư của họ ở một mức độ rủi ro nhất định. Ngày nay, các chuyên gia trong ngành có sự tham gia của hàng triệu nhà đầu tư bán lẻ, những người đã thay đổi vĩnh viễn quan điểm đầu tư. Những người mới tham gia này đang tạo ra sự phân nhánh lớn cho công nghệ làm nền tảng cho cơ sở hạ tầng giao dịch của các công ty môi giới bán lẻ, sàn giao dịch và nhà thanh toán bù trừ.

Lấy ví dụ, cơn sốt cổ phiếu GameStop vào tháng 1 năm 2021. Các nhà đầu tư bán lẻ bắt đầu giao dịch cổ phiếu GameStop ở mức kỷ lục. Các nhà đầu tư này cũng đổ xô vào các cổ phiếu meme khác như AMC Entertainment, khiến mức độ biến động toàn thị trường tăng hơn 76% trong vài ngày giao dịch theo chỉ số VIX. Sự biến động này đã dẫn đến áp lực về giá đối với hàng nghìn chứng khoán. Hàng triệu nhà đầu tư đang điên cuồng cố gắng truy cập danh mục đầu tư của họ cùng một lúc, nhưng phải đối mặt với các ứng dụng không thể đáp ứng kịp nhu cầu. Các nhà đầu tư không tử tế với những công ty có ứng dụng hoạt động không tốt khi họ cần nhất.

Xây dựng nền tảng giao dịch thời gian thực với Redis

Trong thời điểm điên cuồng này, hầu hết các nhà đầu tư đều tìm kiếm hai điểm dữ liệu về danh mục đầu tư của họ mà họ cần truy cập vào mọi lúc:

  1. Tổng giá trị của danh mục đầu tư tại thời điểm đó là bao nhiêu?
  2. Lãi hoặc lỗ của các chứng khoán cụ thể trong danh mục đầu tư của chúng là gì?

Câu trả lời cho những câu hỏi này có thể khiến nhà đầu tư mua, bán hoặc nắm giữ các chứng khoán cụ thể. Trong các thị trường chuyển động nhanh ngày nay, bất kỳ sự chậm trễ nào đều có thể đồng nghĩa với việc mất cơ hội và lợi nhuận. Bạn cần truy cập giá theo thời gian thực để trả lời những câu hỏi này — tuy nhiên, có hai thách thức lớn:

  • Cập nhật giá của hàng nghìn chứng khoán đồng thời
  • Trả lời hàng triệu yêu cầu của khách hàng cùng một lúc.

Giá của chứng khoán có thể nhanh chóng thay đổi dựa trên khối lượng giao dịch, sự biến động của một chứng khoán cụ thể và sự biến động trên thị trường. Mặt khác, một công ty môi giới có thể có hàng triệu khách hàng, mỗi người có vài chục chứng khoán trong danh mục đầu tư của họ. Ngay sau khi khách hàng đăng nhập, danh mục đầu tư của họ cần được cập nhật giá mới nhất — và cập nhật chúng khi nhà môi giới nhận được giá từ các sàn giao dịch.

Về cơ bản, chúng tôi đang tạo một biểu đồ chứng khoán theo thời gian thực. Nhiều ứng dụng môi giới không cố gắng làm điều này trên quy mô lớn. Thay vào đó, các ứng dụng này kéo giá mới nhất thay vì đẩy giá cho hàng triệu khách hàng. Ví dụ:có thể có một nút làm mới trên trang danh mục đầu tư của họ.

Những thách thức thế hệ tiếp theo này không hề nhỏ và không thể dễ dàng giải quyết bằng cơ sở dữ liệu dựa trên đĩa vốn không được thiết kế để xử lý hàng triệu thao tác mỗi giây. Yêu cầu của ngành tài chính cần một cơ sở dữ liệu có thể mở rộng quy mô dễ dàng và xử lý hàng trăm triệu thao tác mỗi giây. Tiếp theo là Redis Enterprise, một nền tảng cơ sở dữ liệu trong bộ nhớ, có tiềm năng giải quyết vô số thách thức này.

Xây dựng nền tảng giao dịch thời gian thực với Redis

Đây là blog đầu tiên trong số một loạt blog bao gồm các trường hợp sử dụng thời gian thực khác nhau trong thế giới tài chính. Chúng tôi sẽ trình bày chi tiết và những thách thức kinh doanh của từng trường hợp sử dụng và vai trò của Redis Enterprise trong việc giải quyết những thách thức đó. Là một phần của blog, chúng tôi cung cấp các thiết kế mẫu, mô hình dữ liệu và mẫu mã. Chúng tôi cũng sẽ thảo luận về những ưu và nhược điểm của từng cách tiếp cận.

Trong bài đăng trên blog này, chúng tôi sẽ đề cập đến những điều sau:

  • Triển khai mẫu về mô hình dữ liệu danh mục đầu tư chứng khoán có hiệu suất cao và có thể mở rộng trên Redis Enterprise.
  • Cập nhật giá chứng khoán trong danh mục đầu tư theo thời gian thực khi nhà môi giới nhận được giá mới nhất từ ​​các sàn giao dịch.

Khi ứng dụng khách đã truy xuất danh mục đầu tư và nhận được giá mới nhất, ứng dụng có thể:

  • Tính tổng giá trị danh mục đầu tư của danh mục đầu tư.
  • Tính toán lãi hoặc lỗ trên mỗi danh mục đầu tư đang nắm giữ.

Mô hình dữ liệu danh mục chứng khoán

Hãy bắt đầu bằng cách lập mô hình nắm giữ trong danh mục đầu tư. Trong hình minh họa bên dưới, CVS Health Corp. (NYSE:CVS) là một trong những ví dụ của chúng tôi. Có hai lô CVS riêng biệt — lô đầu tiên được mua vào ngày 4 tháng 1 năm 2021 và lô thứ hai vào ngày 1 tháng 3 năm 2021. Số lượng cổ phiếu tương tự đã được mua trong đợt mua giao dịch cho từng lô. Cả hai giao dịch đều dành cho 10 cổ phiếu, tuy nhiên ở các mức giá trên mỗi cổ phiếu khác nhau - $ 68.3378 cho lô đầu tiên và $ 68,82 cho lô thứ hai. Tổng số lượng CVS nắm giữ trong danh mục đầu tư là 20 với chi phí trung bình được tính như sau:((68.3378 đô la * 10) + (68.82 đô la * 10)) / 20 =68.5789 đô la cho mỗi cổ phiếu.

Xây dựng nền tảng giao dịch thời gian thực với Redis

Thực hiện các yêu cầu

Xây dựng nền tảng giao dịch thời gian thực với Redis

Biểu diễn dữ liệu của Redis là phẳng — chẳng hạn, người ta không thể nhúng Bộ vào trong một Bộ khác. Do đó, mô hình dữ liệu như được mô tả bởi một sơ đồ ER không nhất thiết phải được thực hiện trực tiếp. Việc triển khai trực tiếp Mô hình thực thể có thể không có các đặc điểm hiệu suất mong muốn, vì vậy bạn sẽ phải suy nghĩ khác đi một chút khi bắt đầu triển khai. Trong phần này, chúng tôi đề cập đến một số nguyên tắc thiết kế cơ bản cần thiết khi thiết kế triển khai mở rộng và hiệu suất cao bằng Redis.

Mô hình dữ liệu ở đây đề cập đến các thực thể sau:

Xây dựng nền tảng giao dịch thời gian thực với Redis

Sơ đồ ER cung cấp hình ảnh đại diện có thể giúp người ta thấy được điều gì đang xảy ra.

Điều còn thiếu trong biểu đồ trên là tập hợp giá sắp đến mặc dù chúng được ghi lại trong lịch sử giá của chứng khoán — và việc tính toán giá trị tức thời và lợi nhuận khi giá thay đổi. Vì vậy, biểu đồ ER thể hiện dữ liệu tương đối tĩnh là bối cảnh mà việc định giá danh mục đầu tư được thực hiện.

Kiến trúc tổng thể

Những điểm chính cần được xem xét về hệ thống này bao gồm:

  • Tính kịp thời (tức là độ trễ) là rất quan trọng. Đây là đặc tính thúc đẩy tổng thể.
  • Việc tính toán giá trị danh mục đầu tư kết hợp dữ liệu cụ thể của tài khoản (tức là thông tin lô) với dữ liệu được chia sẻ giữa các tài khoản (tức là giá chứng khoán). Do đó, dữ liệu dành riêng cho tài khoản là bối cảnh sử dụng dữ liệu được chia sẻ.
  • Giá trị danh mục đầu tư chỉ cần được tính cho những tài khoản mà nhà đầu tư trực tuyến (một phần nhỏ trong tổng số tài khoản).
  • Dữ liệu chảy qua hệ thống, từ các sàn giao dịch nơi giá được tạo ra đến các máy khách (máy duyệt, ứng dụng điện thoại di động) trình bày các giá trị danh mục đầu tư cho các nhà đầu tư trực tuyến.
  • Các lĩnh vực cụ thể có mức độ năng động cao bao gồm tốc độ luồng dữ liệu đầu vào và số lượng nhà đầu tư trực tuyến.

Với những điểm này, một số cách tiếp cận chung là:

  • Dựa vào kiến ​​trúc trong bộ nhớ của Redis để truy cập độ trễ thấp vào cả dữ liệu tĩnh và động.
  • Tối ưu hóa mô hình hóa dữ liệu bằng cách sử dụng cấu trúc dữ liệu của Redis để cung cấp quyền truy cập nhanh chóng vào dữ liệu ngữ cảnh đang thay đổi chậm chạp.
  • Sử dụng cấu trúc giao tiếp của Redis (Luồng, Nhóm khách hàng, Quán rượu / Phụ) để xử lý các yêu cầu dữ liệu động.
  • Giảm dung lượng lưu trữ dữ liệu xuống chỉ những gì cần thiết mà không ảnh hưởng đến hiệu suất tổng thể của hệ thống.
  • Thực hiện các tính toán dành riêng cho khách hàng trên chính khách hàng. Điều này mở rộng quy mô một cách tự nhiên và tự động với số lượng nhà đầu tư trực tuyến, giúp giảm bớt gánh nặng quy mô một cách đáng kể.

Dưới đây là các thành phần tính toán chính và luồng dữ liệu:

Xây dựng nền tảng giao dịch thời gian thực với Redis

Lưu ý rằng Redis Enterprise bao gồm một hoặc nhiều nút trên nhiều máy — được triển khai tại chỗ, Kubernetes, triển khai đám mây kết hợp, dịch vụ được quản lý hoặc dịch vụ đám mây của bên thứ nhất gốc — và sẽ có hàng trăm nghìn nhà đầu tư trực tuyến với khách hàng của họ (s ) của sự lựa chọn.

Các thành phần của Redis Enterprise

Cập nhật giá bảo mật sẽ được Redis Streams tiếp thu. Các cập nhật cho chứng khoán sẽ được trộn lẫn với nhau trong luồng này và sẽ cần được tách biệt để làm cho dữ liệu hữu ích. Một nhóm người tiêu dùng sẽ được sử dụng để thực hiện phân tách đó và để xử lý dữ liệu thành hai cấu trúc, theo bảo mật:

  • Cơ sở dữ liệu RedisTimeSeries, để theo dõi lịch sử thay đổi giá (cũng như ghi lại giá mới nhất cho bất kỳ khách hàng nào chỉ cần kết nối)
  • Kênh môi giới Pub / Sub để gửi thông báo thay đổi giá đến những khách hàng đã đăng ký kênh đó (tức là các nhà đầu tư có danh mục đầu tư bao gồm chứng khoán đó)

Sơ đồ sau mô tả chi tiết phần này của kiến ​​trúc:

Xây dựng nền tảng giao dịch thời gian thực với Redis

Yếu tố quan trọng nhất trong mô hình của chúng tôi là dữ liệu tài khoản cụ thể đại diện cho các lô và bảo mật liên quan. Chúng tôi sẽ so sánh hai cách triển khai như một ví dụ về cách suy nghĩ về việc lập mô hình dữ liệu trong Redis, tập trung vào hiệu suất. Có thể triển khai các cách khác — mục tiêu của chúng tôi ở đây là giới thiệu các nguyên tắc thiết kế tổng thể và quy trình tư duy khi triển khai dữ liệu trong Redis.

Chúng tôi sẽ sử dụng thông tin sau làm ví dụ cụ thể:

Xây dựng nền tảng giao dịch thời gian thực với Redis

Chúng tôi đang định giá theo mệnh giá tiền tệ thấp nhất có thể để tránh thả nổi và giữ mọi thứ ở dạng số nguyên. Chúng tôi có thể cho phép khách hàng xử lý việc chuyển đổi sang đô la và xu. Trong ví dụ này, chúng tôi đang sử dụng giá có độ chính xác đến hai chữ số thập phân.

Mô hình dữ liệu A

Việc triển khai đầu tiên của chúng tôi ghi lại id của tất cả các lô trong tài khoản bằng cách sử dụng SET, được xác định bằng id tài khoản và sau đó sử dụng một Redis HASH cho mỗi LOT, được xác định bởi LOT ID, với mã, số lượng và giá mua là các trường. Nói cách khác, chúng tôi đang sử dụng HASH để lập mô hình cấu trúc thực thể LOT, với mỗi thuộc tính của thực thể LOT là một trường trong Redis HASH.

Với mô hình dữ liệu này, chúng tôi có một khóa cho mỗi tài khoản và một giá trị chứa tất cả LOT ID cho tài khoản đó được lưu trữ dưới dạng Redis SET:

lotids:<ACCOUNT_ID> SET <LOTID>

Ngoài ra, đối với mỗi lotid, chúng tôi sẽ có một HASH có các trường là mã, số lượng và giá mua:

lot:<LOTID> HASH <ticker TICKER> <quantity INTEGER> <price INTEGER>

Cụ thể, chúng tôi sẽ tạo các khóa như sau:

127.0.0.1:6379> SADD lotids:ACC-1001 LOT-9001 LOT-9002
(integer) 2
127.0.0.1:6379> HMSET lot:LOT-9001 ticker AAPL quantity 200 price 12556
OK
127.0.0.1:6379> HMSET lot:LOT-9002 ticker CAT quantity 1200 price 18063
OK

Mô-đun RedisTimeSeries cho phép lưu trữ và truy xuất các cặp thời gian và giá trị liên quan, cùng với các lần chèn khối lượng lớn và các lần đọc có độ trễ thấp. Chúng tôi sẽ có giá mới nhất cho các mã mà khách hàng quan tâm sẽ truy cập khi sử dụng các khóa chuỗi thời gian tương ứng:

price_history:<TICKER> TIMESERIES <price INTEGER>

127.0.0.1:6379> TS.GET price_history:APPL
1) (integer) 1619456853061
2) 12572
127.0.0.1:6379> TS.GET price_history:CAT
1) (integer) 1619456854120
2) 18021

và đăng ký kênh giá để cập nhật:

<TICKER> SUBSCRIPTION_CHANNEL

Để lấy tất cả dữ liệu, khách hàng sẽ thực hiện các thao tác sau:

  1. 1 lần SMEMBERS trên lotids khóa — độ phức tạp thời gian O (N) với N là số lô
  2. N lần NHẬN trên phím — độ phức tạp thời gian N lần O (1)
  3. T lần TS.GET trên price_history phím - độ phức tạp về thời gian T nhân với O (1) với T là số mã chứng khoán
  4. 1 lần ĐĂNG KÝ trên kênh - độ phức tạp về thời gian O (T) (một người có thể đăng ký tất cả các kênh trong một lần gọi SUBSCRIBE)

Độ phức tạp thời gian tổng thể là O (N + T).

Cụ thể, hoạt động một và hai sẽ là:

127.0.0.1:6379> SMEMBERS lotids:ACC1001
1) "LOT-9001"
2) "LOT-9002"
127.0.0.1:6379> HGETALL lot:LOT-9001
1) "ticker"
2) "AAPL"
3) "quantity"
4) "200"
5) "price"
6) "12556"
127.0.0.1:6379> HGETALL lot:LOT-9002
1) "ticker"
2) "CAT"
3) "quantity"
4) "1200"
5) "price"
6) "18063"

Chúng tôi có thể giảm thiểu độ trễ của mạng bằng cách sử dụng pipelining (một hình thức phân lô ở phía máy khách) và / hoặc sử dụng lặp lại các tập lệnh LUA (sử dụng SCRIPT LOAD &EVALSHA). Lưu ý bên cạnh:Các giao dịch có thể được thực hiện bằng cách sử dụng các đường ống và có thể giảm độ trễ mạng, nhưng điều này là dành riêng cho khách hàng và mục tiêu của họ là tính nguyên tử trên máy chủ, vì vậy chúng không thực sự giải quyết được vấn đề về độ trễ của mạng. Đường ống bao gồm các lệnh có đầu vào và đầu ra phải độc lập với nhau. Tập lệnh LUA yêu cầu tất cả các khóa phải được cung cấp trước rằng tất cả các khóa đều được băm vào cùng một vị trí (xem tài liệu Redis Enterprise về chủ đề này để biết thêm chi tiết).

Với những ràng buộc này, chúng ta có thể thấy rằng việc phân công các hoạt động cho các đường ống là:

  • đường dẫn 1:Lệnh đơn của hoạt động số 1
  • đường ống 2:Tất cả N lệnh của hoạt động # 2
  • đường ống 3:Tất cả N lệnh của hoạt động # 3 và # 4

và không thể sử dụng tập lệnh LUA vì mỗi thao tác sử dụng các khóa khác nhau và các khóa đó không có phần chung nào có thể được băm vào cùng một vị trí.

Khi sử dụng mô hình này, chúng tôi có độ phức tạp về thời gian là O (N + T) và ba bước nhảy mạng.

Mô hình dữ liệu B

Một mô hình thay thế là làm phẳng cấu trúc thực thể LOT và đại diện cho từng thuộc tính thực thể bằng cách sử dụng một khóa được xác định bằng id tài khoản — một khóa như vậy cho mỗi thuộc tính (số lượng, mã, giá) của lô. Các trường trong mỗi HASH sẽ là ID LOT và giá trị tương ứng với số lượng, mã hoặc giá. Do đó, chúng tôi có các khóa:

tickers_by_lot: <ACCOUNT_ID> HASH <LOTID TICKER>

quantities_by_lot:<ACCOUNT_ID> HASH <LOTID INTEGER>

prices_by_lot:<ACCOUNT_ID> HASH <LOTID INTEGER>

Các hàm băm này sẽ thay thế các khóa LOTID và LOT từ Mô hình Dữ liệu A, trong khi price_history<TICKER> các khóa sẽ vẫn như cũ.

Tạo khóa:

HSET tickers_by_lot:ACC-1001 LOT-9001 AAPL LOT-9002 CAT
HSET quantities_by_lot:ACC-1001 LOT-9001 200 LOT-9002 1200
HSET prices_by_lot:ACC-1001 LOT-9001 125.56 LOT-9002 180.63

Truy xuất các giá trị:

127.0.0.1:6379> HGETALL tickers_by_lot:ACC-1001
1) "LOT-9001"
2) "AAPL"
3) "LOT-9002"
4) "CAT"
127.0.0.1:6379> HGETALL quantities_by_lot:ACC-1001
1) "LOT-9001"
2) "200"
3) "LOT-9002"
4) "1200"
127.0.0.1:6379> HGETALL prices_by_lot:ACC-1001
1) "LOT-9001"
2) "12556"
3) "LOT-9002"
4) "18063"

Các hoạt động mà khách hàng yêu cầu bây giờ sẽ là:

  1. 1 lần HGETALL trên lot_quantity phím — độ phức tạp thời gian N x O (1)
  2. 1 lần HGETALL trên lot_ticker phím — độ phức tạp thời gian N x O (1)
  3. 1 lần HGETALL trên lot_price phím — độ phức tạp thời gian N x O (1)
  4. T lần TS.GET trên price_history khóa — độ phức tạp về thời gian T x O (1) với T là số mã chứng khoán
  5. 1 lần ĐĂNG KÝ trên kênh — độ phức tạp thời gian 1 x O (T)

Điều này có độ phức tạp thời gian tổng thể là O (N + T) - giống như trước đây.

Từ quan điểm đường ống, điều này trở thành:

  • Đường ống một — tất cả các lệnh của hoạt động # 1, # 2 và # 3
  • Đường ống hai — tất cả các lệnh T của hoạt động # 4 và # 5

Vì vậy, chúng tôi đã giảm một số lần nhảy mạng — không nhiều về mặt tuyệt đối mà là 33% về mặt tương đối.

Ngoài ra, chúng tôi có thể dễ dàng sử dụng LUA vì chúng tôi biết các khóa và chúng tôi có thể ánh xạ tất cả các khóa cho bất kỳ tài khoản cụ thể nào vào cùng một khe. Do sự đơn giản của các hoạt động, chúng tôi sẽ không đào sâu thêm về LUA, nhưng xin lưu ý rằng thiết kế này ít nhất là có thể làm được!

Trong một điểm chuẩn đơn giản, Mô hình Dữ liệu B chạy nhanh hơn 4,13 mili giây (được đánh giá trên hàng nghìn lần chạy). Do điều này chỉ được chạy một lần mỗi khi khách hàng được khởi tạo tài khoản, điều này có thể không ảnh hưởng đến hiệu suất tổng thể.

Tóm tắt

Trong blog này, chúng tôi đã chỉ ra hai cách triển khai có thể có của mô hình Thực thể bằng cách sử dụng kiểu dữ liệu Redis. Chúng tôi cũng đã giới thiệu phân tích độ phức tạp về thời gian cần được thực hiện bất cứ khi nào chọn loại dữ liệu Redis, cùng với việc xem xét các cải tiến hiệu suất mạng — một bước quan trọng khi yêu cầu quy mô lớn và hiệu suất cao. Trong các blog tiếp theo, chúng tôi sẽ mở rộng thêm về những ý tưởng này khi mô hình dữ liệu được mở rộng.

Chúng tôi đã đưa ra một số thách thức kinh doanh trong việc quản lý danh mục đầu tư chứng khoán trên quy mô lớn và đã chỉ ra những điều sau:

  • Mô hình dữ liệu Redis để triển khai danh mục đầu tư chứng khoán có thể mở rộng và theo thời gian thực.
  • Hệ thống cập nhật giá theo thời gian thực, hiệu suất cao có thể được sử dụng để tính toán tổng giá trị của danh mục đầu tư và lãi hoặc lỗ của mỗi lần nắm giữ.

Với hai tính năng quan trọng này, ứng dụng khách môi giới có thể cung cấp các bản cập nhật danh mục đầu tư theo thời gian thực để thực hiện và mở rộng quy mô để xử lý hàng triệu tài khoản. Thiết kế này có thể trình bày tổng giá trị của danh mục đầu tư và lãi hoặc lỗ trên mỗi lần nắm giữ trong thời gian thực. Mô hình và kiến ​​trúc dữ liệu này cũng có thể được áp dụng cho các trường hợp sử dụng ngoài chứng khoán để bao gồm tiền điện tử, trao đổi quảng cáo, v.v.