Unix / Linux có độ trễ thấp


11

Hầu hết các công việc lập trình tần số cao / độ trễ thấp (dựa trên thông số công việc) dường như được triển khai trên các nền tảng unix. Trong rất nhiều thông số kỹ thuật họ đưa ra yêu cầu cụ thể cho những người có loại trải nghiệm "độ trễ thấp linux".

Giả sử điều này không có nghĩa là một hệ điều hành linux thời gian thực, mọi người có thể giúp tôi với những gì nó có thể được đề cập không? Tôi biết bạn có thể thiết lập mối quan hệ CPU với các luồng, nhưng tôi cho rằng họ đang yêu cầu nhiều hơn thế.

Điều chỉnh hạt nhân? (mặc dù tôi nghe nói các nhà sản xuất như solarflare vẫn sản xuất card mạng bỏ qua kernel)?

Điều gì về DMA hoặc có thể chia sẻ bộ nhớ giữa các quá trình? Nếu mọi người có thể cho tôi những ý tưởng ngắn gọn, tôi có thể đi và thực hiện nghiên cứu trên google.

(Câu hỏi này có thể sẽ yêu cầu ai đó quen thuộc với Giao dịch cao tần)


2
Điều chỉnh hạt nhân là cách để tạo ra một hệ điều hành phi thời gian thực nhất có thể. Ghim chủ đề cũng là bắt buộc. Bạn có thể đọc thêm về điều đó trong bài viết này: Coralblocks.com/index.php/2014/04/
rdalmeida 29/07/2015

Câu trả lời:


26

Tôi đã thực hiện một số lượng công việc khá lớn hỗ trợ các nhóm HFT trong cài đặt IB và Hedge Fund. Tôi sẽ trả lời từ chế độ xem sysadmin, nhưng một số điều này cũng có thể áp dụng cho lập trình trong các môi trường như vậy.

Có một vài điều mà một nhà tuyển dụng thường tìm kiếm khi họ đề cập đến hỗ trợ "Độ trễ thấp". Một số trong số đó là những câu hỏi "tốc độ thô" (bạn có biết nên mua loại thẻ 10g nào và đặt vào vị trí nào không?), Nhưng nhiều trong số đó là về cách môi trường Giao dịch Tần số Cao khác với cách truyền thống Môi trường Unix. Vài ví dụ:

  • Unix theo truyền thống được điều chỉnh để hỗ trợ chạy một số lượng lớn các quy trình mà không bỏ đói bất kỳ quy trình nào trong số đó cho tài nguyên, nhưng trong môi trường HFT, bạn có thể muốn chạy một ứng dụng với chi phí tối thiểu tuyệt đối để chuyển đổi ngữ cảnh, v.v. Như một ví dụ nhỏ cổ điển, bật siêu phân luồng trên CPU Intel cho phép nhiều tiến trình chạy cùng một lúc - nhưng có tác động đáng kể đến hiệu suất đối với tốc độ mà mỗi tiến trình riêng lẻ được thực thi. Là một lập trình viên, bạn cũng sẽ phải xem xét chi phí trừu tượng như phân luồng và RPC, và tìm ra nơi mà một giải pháp nguyên khối hơn - trong khi ít sạch hơn - sẽ tránh được chi phí.

  • TCP / IP thường được điều chỉnh để ngăn chặn sự sụt giảm kết nối và sử dụng hiệu quả băng thông có sẵn. Nếu mục tiêu của bạn là có được độ trễ thấp nhất có thể từ một liên kết rất nhanh - thay vì để có được băng thông cao nhất có thể từ một liên kết bị ràng buộc nhiều hơn - bạn sẽ muốn điều chỉnh điều chỉnh của ngăn xếp mạng. Từ phía lập trình, bạn cũng sẽ muốn xem xét các tùy chọn ổ cắm có sẵn và tìm ra cái nào mặc định được điều chỉnh nhiều hơn cho băng thông và độ tin cậy hơn là giảm độ trễ.

  • Cũng như kết nối mạng, với lưu trữ - bạn sẽ muốn biết cách giải quyết vấn đề về hiệu suất lưu trữ từ một sự cố ứng dụng và tìm hiểu các kiểu sử dụng I / O nào ít có khả năng can thiệp vào hiệu suất chương trình của bạn (như một ví dụ, tìm hiểu mức độ phức tạp của việc sử dụng IO không đồng bộ có thể trả cho bạn và những nhược điểm là gì).

  • Cuối cùng, và đau đớn hơn: quản trị viên Unix của chúng tôi muốn có càng nhiều thông tin về trạng thái của môi trường mà chúng tôi giám sát càng tốt, vì vậy chúng tôi muốn chạy các công cụ như tác nhân SNMP, công cụ giám sát hoạt động như Nagios và công cụ thu thập dữ liệu như sar (1). Tuy nhiên, trong một môi trường mà các bộ chuyển ngữ cảnh cần được giảm thiểu tuyệt đối và việc sử dụng IO và đĩa và mạng được kiểm soát chặt chẽ, chúng ta phải tìm ra sự đánh đổi đúng đắn giữa chi phí giám sát và hiệu suất của các hộp được theo dõi. Tương tự, những kỹ thuật nào bạn đang sử dụng giúp mã hóa dễ dàng hơn nhưng lại khiến bạn mất hiệu suất?

Cuối cùng, có những thứ khác chỉ đi cùng với thời gian; thủ thuật và chi tiết mà bạn học được với kinh nghiệm. Nhưng những thứ này chuyên dụng hơn (khi tôi sử dụng epoll? Tại sao hai mô hình máy chủ HP với bộ điều khiển PCIe giống nhau về mặt lý thuyết lại hoạt động khác nhau như vậy?), Gắn chặt hơn với bất kỳ cửa hàng cụ thể nào của bạn đang sử dụng và có nhiều khả năng thay đổi từ năm này sang năm khác .


1
Cảm ơn bạn, mặc dù tôi đã quan tâm đến một câu trả lời lập trình, điều này rất hữu ích và nhiều thông tin.
dùng997112

5
@ user997112 Đây là câu trả lời lập trình. Nếu nó không giống như vậy, hãy tiếp tục đọc cho đến khi nó xảy ra :)
Tim Post

15

Ngoài câu trả lời điều chỉnh phần cứng / thiết lập tuyệt vời từ @jimwise, "linux có độ trễ thấp" có nghĩa là:

  • C ++ vì lý do xác định (không có độ trễ bất ngờ trong khi GC khởi động), truy cập vào các cơ sở cấp thấp (I / O, tín hiệu), sức mạnh ngôn ngữ (sử dụng đầy đủ TMP và STL, loại an toàn).
  • thích bộ nhớ quá tốc độ:> 512 Gb RAM là phổ biến; cơ sở dữ liệu là các bộ nhớ trong, bộ nhớ cache hoặc các sản phẩm NoQuery kỳ lạ.
  • lựa chọn thuật toán: càng nhanh càng tốt so với sane / có thể hiểu được / có thể mở rộng, ví dụ như mảng không khóa, nhiều bit thay vì mảng của các đối tượng với các thuộc tính bool.
  • sử dụng đầy đủ các tiện ích HĐH như Bộ nhớ dùng chung giữa các tiến trình trên các lõi khác nhau.
  • đảm bảo. Phần mềm HFT thường được đặt cùng trong một Sở giao dịch chứng khoán nên khả năng phần mềm độc hại là không thể chấp nhận được.

Nhiều trong số các kỹ thuật này trùng lặp với phát triển trò chơi, đó là một lý do tại sao ngành công nghiệp phần mềm tài chính hấp thụ bất kỳ lập trình viên trò chơi nào gần đây (ít nhất là cho đến khi họ trả tiền thuê nhà).

Nhu cầu cơ bản là có thể lắng nghe một luồng dữ liệu thị trường băng thông rất cao như giá bảo mật (cổ phiếu, hàng hóa, fx) và sau đó đưa ra quyết định mua / bán / không làm gì rất nhanh dựa trên bảo mật, giá cả và nắm giữ hiện tại.

Tất nhiên, điều này cũng có thể đi sai một cách ngoạn mục , quá.


Vì vậy, tôi sẽ giải thích về điểm mảng bit . Giả sử chúng ta có một hệ thống Giao dịch cao tần hoạt động trong một danh sách dài các Đơn đặt hàng (Mua 5k IBM, Bán 10k DELL, v.v.). Giả sử chúng ta cần nhanh chóng xác định xem tất cả các đơn đặt hàng đã được lấp đầy chưa, để chúng ta có thể chuyển sang nhiệm vụ tiếp theo. Trong lập trình OO truyền thống, điều này sẽ giống như:

class Order {
  bool _isFilled;
  ...
public:
  inline bool isFilled() const { return _isFilled; }
};

std::vector<Order> orders;
bool needToFillMore = std::any_of(orders.begin(), orders.end(), 
  [](const Order & o) { return !o.isFilled(); } );

độ phức tạp thuật toán của mã này sẽ là O (N) vì nó là quét tuyến tính. Chúng ta hãy xem cấu hình hiệu suất về các truy cập bộ nhớ: mỗi lần lặp của vòng lặp bên trong std :: any_of () sẽ gọi o.isFilt (), được nội tuyến, do đó trở thành quyền truy cập bộ nhớ của _isFilt, 1 byte (hoặc 4 phụ thuộc vào cài đặt kiến ​​trúc, trình biên dịch và trình biên dịch của bạn) trong một đối tượng giả sử tổng cộng 128 byte. Vì vậy, chúng tôi đang truy cập 1 byte trong mỗi 128 byte. Khi chúng ta đọc 1 byte, giả sử trong trường hợp xấu nhất, chúng ta sẽ bị mất bộ đệm dữ liệu CPU. Điều này sẽ gây ra yêu cầu đọc tới RAM, đọc toàn bộ dòng từ RAM ( xem tại đây để biết thêm thông tin ) chỉ để đọc ra 8 bit. Vì vậy, hồ sơ truy cập bộ nhớ tỷ lệ thuận với N.

So sánh điều này với:

const size_t ELEMS = MAX_ORDERS / sizeof (int);
unsigned int ordersFilled[ELEMS];

bool needToFillMore = std::any_of(ordersFilled, &ordersFilled[ELEMS+1],
   [](int packedFilledOrders) { return !(packedOrders == 0xFFFFFFFF); }

cấu hình truy cập bộ nhớ của trường hợp này, giả sử trường hợp xấu nhất một lần nữa, là ELEMS chia cho chiều rộng của dòng RAM (khác nhau - có thể là kênh đôi hoặc kênh ba, v.v.).

Vì vậy, trong thực tế, chúng tôi tối ưu hóa các thuật toán cho các mẫu truy cập bộ nhớ. Không có dung lượng RAM nào có thể giúp - đó là kích thước bộ đệm dữ liệu CPU gây ra nhu cầu này.

Không giúp đỡ à?


Có một CPPCon xuất sắc nói về tất cả các chương trình có độ trễ thấp (cho HFT) trên YouTube: https://www.youtube.com/watch?v=NH1Tta7purM


"Nhiều mảng bit thay vì mảng của các đối tượng với các thuộc tính bool", ý của bạn là gì?
user997112

1
Tôi đã xây dựng với các ví dụ và liên kết.
JBRWilkinson

Tiến thêm một bước - thay vì sử dụng toàn bộ byte để cho biết liệu một đơn hàng có được lấp đầy hay không - bạn chỉ có thể sử dụng một bit. Vì vậy, trong một bộ đệm (64 byte) - bạn có thể biểu thị trạng thái của 256 đơn hàng. Vì vậy - ít bỏ lỡ.
quixver

Ngoài ra - nếu bạn đang thực hiện quét bộ nhớ tuyến tính - trình tải trước phần cứng thực hiện công việc tải dữ liệu của bạn rất tốt. Miễn là bạn truy cập bộ nhớ tuần tự hoặc sải bước hoặc một cái gì đó đơn giản. Nhưng nếu bạn đang truy cập bộ nhớ theo bất kỳ cách thức không tuần tự nào - trình nạp trước CPU sẽ bị lẫn lộn. Ví dụ: tìm kiếm nhị phân. Tại thời điểm đó, lập trình viên có thể giúp cpu với các gợi ý - _mm_prefetch.
quixver

-2

Vì tôi đã không đưa một hoặc hai phần mềm tần số cao vào sản xuất nên tôi sẽ nói những điều quan trọng nhất:

  1. Cấu hình phần cứng và quản trị viên hệ thống cùng với các kỹ sư mạng KHÔNG xác định kết quả tốt về số lượng đơn đặt hàng được xử lý bởi hệ thống giao dịch, nhưng họ có thể hạ cấp thời gian lớn nếu họ không biết những điều cơ bản được nêu ở trên.
  2. Người duy nhất thực sự làm cho hệ thống thực hiện giao dịch tần số cao là một nhà khoa học máy tính kết hợp mã trong c ++

    Trong số các kiến ​​thức được sử dụng là

    A. So sánh và hoán đổi hoạt động.

    • cách CAS được sử dụng trong bộ xử lý và cách máy tính hỗ trợ nó được sử dụng trong cái gọi là xử lý cấu trúc Không khóa. Hoặc xử lý không khóa. Tôi sẽ không viết cả một cuốn sách ở đây. Trong trình biên dịch GNU và trình biên dịch Microsoft ngắn gọn có hỗ trợ sử dụng trực tiếp các lệnh CAS. Nó cho phép mã của bạn có "Số không" trong khi trích xuất phần tử từ hàng đợi hoặc đặt mã mới vào hàng đợi.
  3. Nhà khoa học tài năng sẽ sử dụng nhiều hơn. Anh ta nên tìm thấy trong các "mẫu" mới gần đây xuất hiện trong Java. Được gọi là mẫu DISRUPTOR. Việc trao đổi LMAX ở Châu Âu đã giải thích với cộng đồng tần số cao rằng việc sử dụng dựa trên luồng trong các bộ xử lý hiện đại sẽ làm mất thời gian xử lý khi phát hành bộ nhớ cache của bộ nhớ nếu hàng đợi daya không phù hợp với kích thước của bộ đệm cpu hiện đại = 64

    Vì vậy, để đọc, họ đã công khai một mã java cho phép quá trình đa luồng sử dụng bộ đệm CPU phần cứng một cách chính xác mà không cần giải quyết xung đột. Và nhà khoa học máy tính giỏi CÓ THỂ tìm thấy mô hình đó đã được chuyển sang c ++ hoặc tự chuyển.

    Đây là một cách thành thạo ngoài bất kỳ cấu hình quản trị viên. Đây là trong trung tâm thực sự của tần số cao ngày hôm nay.

  4. Anh chàng khoa học máy tính ĐÃ viết rất nhiều mã C ++ không chỉ để giúp đỡ người QA. Nhưng cũng để
    • xác nhận trong các giao dịch được chứng minh tốc độ đạt được
    • lên án sử dụng các công nghệ cũ khác nhau và phơi bày chúng bằng mã riêng của mình để cho thấy chúng không mang lại kết quả tốt
    • viết mã c ++ giao tiếp đa luồng sở hữu mã dựa trên tốc độ kernel / chọn kernel đã được chứng minh thay vì sử dụng lại các công nghệ cũ. Tôi sẽ cho bạn ví dụ - thư viện tcp hiện đại là ICE. Và những người đã làm điều đó là tươi sáng. Nhưng ưu tiên của họ là trong lĩnh vực tương thích với nhiều ngôn ngữ. Vì thế. Bạn có thể làm tốt hơn trong c ++. Vì vậy, tìm kiếm các ngoại lệ hiệu suất cao nhất dựa trên cuộc gọi chọn ASYNCHRONOUS. Và không dành cho nhiều người tiêu dùng nhiều nhà sản xuất - không phải cho HF.
      Và bạn sẽ ngạc nhiên khi thấy rằng đường ống được sử dụng CHỈ CHO thông báo kernel của tin nhắn đến. Bạn có thể đặt số tin nhắn 64 bit ở đó - nhưng đối với nội dung bạn chuyển đến hàng đợi CAS không khóa. Kích hoạt bởi select()cuộc gọi kernel không đồng bộ .
    • hơn thế nữa. Tìm hiểu về việc gán với mối quan hệ luồng c ++ với luồng của bạn thực hiện đường ống / xếp hàng các tin nhắn của bạn. Chủ đề đó nên có ái lực cốt lõi. Không ai khác nên sử dụng cùng số lõi CPU.
    • và như thế.

Như bạn có thể thấy - tần số cao là một L FINH VỰC PHÁT TRIỂN. Bạn không thể chỉ là một lập trình viên C ++ để thành công.

Và khi tôi nói để thành công, ý tôi là quỹ phòng hộ mà bạn sẽ làm việc cho SILL công nhận những nỗ lực du lịch trong việc bồi thường hàng năm vượt quá con số mà mọi người và nhà tuyển dụng nói đến.

Thời gian của câu hỏi thường gặp về hàm tạo / hàm hủy đơn giản đã biến mất mãi mãi. Mất thời gian. Mã sử ​​dụng lại mô hình thay đổi. Nó không chỉ là về bao nhiêu lớp bạn đã thực hiện trong đa hình. Đó là về hiệu suất thời gian xác nhận thẳng của mã bạn có thể sử dụng lại.

Vì vậy, đó là lựa chọn của bạn để đi vào học tập ở đó, hoặc không. Nó sẽ không bao giờ đạt được một dấu hiệu dừng lại.


6
Bạn có thể muốn đặt một số nỗ lực vào chính tả và định dạng. Ở dạng hiện tại, bài này hầu như không thể hiểu được.
CodeInChaos

1
Bạn mô tả tình hình của 10 năm trước. Các giải pháp dựa trên phần cứng dễ dàng vượt trội hơn C ++ thuần hiện nay, bất kể C ++ của bạn được tối ưu hóa như thế nào.
Sjoerd

Đối với những người muốn biết các giải pháp dựa trên phần cứng là gì - chủ yếu là các giải pháp FPGA, nơi mã thực sự được ghi vào bộ nhớ nhanh và không bị thay đổi mà không được gọi là bộ nhớ ROM. Chỉ đọc
alex p

@alapi Bạn rõ ràng không biết bạn đang nói về cái gì. FPGA là một cái gì đó khác với "mã được ghi vào bộ nhớ nhanh."
Sjoerd
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.