web-dev-qa-db-ja.com

低レイテンシーUnix / Linux

ほとんどの低レイテンシ/高頻度プログラミングジョブ(ジョブ仕様に基づく)は、UNIXプラットフォームに実装されているようです。多くの仕様では、彼らは「低レイテンシLinux」タイプの経験を持つ人々に特定の要求を出します。

これがリアルタイムのLinux OSを意味しないと仮定すると、人々はこれが何を指しているのかについて私に助けを与えることができますか? CPUアフィニティをスレッドに設定できることは知っていますが、それよりもはるかに多くのことを求めていると思います。

カーネルのチューニング? (とにかくsolarflareのような製造元がカーネルバイパスネットワークカードを製造していると聞きましたが)?

DMAまたはプロセス間でメモリを共有する可能性はありますか?人々が簡単なアイデアを教えてくれれば、Googleで調査を行うことができます。

(この質問はおそらく高頻度取引に詳しい誰かを必要とするでしょう)

11
user997112

私はIBとヘッジファンドの設定でHFTグループをサポートするかなりの量の仕事をしました。ここではsysadminビューから回答しますが、その一部はそのような環境でのプログラミングにも適用できます。

雇用主が「低レイテンシー」のサポートについて言及する場合、通常、探していることがいくつかあります。これらのいくつかは「未加工の速度」の質問です(購入する10gカードの種類と、それを入れるスロットを知っていますか)。しかし、それらの多くは、高頻度取引環境が従来のトレーディング環境と異なる点に関するものです。 Unix環境。いくつかの例:

  • Unixは伝統的に、リソースを使い果たすことなく多数のプロセスの実行をサポートするように調整されていますが、HFT環境では、コンテキストのオーバーヘッドを最小限に抑えてoneアプリケーションを実行することになるでしょう。切り替えなど。古典的な小さな例として、Intel CPUでハイパースレッディングをオンにすると、より多くのプロセスを一度に実行できますが、個々のプロセスが実行される速度に大きなパフォーマンスの影響があります。同様に、プログラマーとしては、スレッド化やRPCなどの抽象化のコストを調べ、モノリシックなソリューション(クリーン度は低くなりますが)がオーバーヘッドを回避する場所を見つける必要があります。

  • TCP/IPは通常、接続のドロップを防ぎ、利用可能な帯域幅を効率的に使用するように調整されています。あなたの目標が非常に速いリンクから可能な限り低いlatencyを取得することである場合-より制約されたリンクから可能な限り高いbandwidthを取得する代わりに-あなたはネットワークスタックの調整を調整する必要があります。同様に、プログラミングの側から、利用可能なソケットオプションを確認し、待ち時間を短縮するよりも、帯域幅と信頼性を調整したデフォルトのオプションを確認します。

  • ネットワークの場合と同様に、ストレージの場合も、アプリケーションの問題とストレージのパフォーマンスの問題を区別する方法を知り、I/O使用のどのパターンがプログラムのパフォーマンスに干渉する可能性が最も低いかを知りたいでしょう(例として、非同期を使用することの複雑さIOがあなたに利益をもたらすことができるところ、そして欠点は何か)を学んでください。

  • 最後に、もっと痛いです:私たちUnix管理者は多くが監視する環境の状態に関する情報をできるだけ欲しいので、SNMPエージェントのようなツール、Nagiosのようなアクティブな監視ツール、およびデータ収集を実行したいと思います。 sar(1)のようなツール。コンテキストスイッチを完全に最小化し、ディスクとネットワークの使用をIO厳しく制御する必要がある環境では、監視の費用とベアメタルパフォーマンスの間の適切なトレードオフを見つける必要があります同様に、コーディングを容易にするがパフォーマンスを犠牲にしているテクニックは何ですか?

最後に、時間とともに来る他のものがあります。あなたが経験で学ぶトリックと詳細。しかし、これらはより専門的であり(いつepollを使用するのですか?なぜ理論的に同一のPCIeコントローラーを備えたHPサーバーの2つのモデルがそれほど異なるように動作するのですか?)、特定のショップが使用しているものとより関連があり、1年から別の年に変わる可能性が高い。

26
jimwise

@jimwiseからの優れたハードウェア/セットアップチューニングの回答に加えて、「低レイテンシLinux」が意味します。

  • 確定性の理由(GCの起動中の不意の遅延なし)、低レベルの機能へのアクセス(I/O、シグナル)、言語能力(TMPとSTLの完全な使用、型安全性)のためのC++。
  • メモリよりも高速を優先:> 512 GBのRAMが一般的です。データベースはメモリ内にあるか、事前にキャッシュされるか、またはエキゾチックなNoSQL製品です。
  • アルゴリズムの選択:可能な限り速くvs正気/理解可能/拡張可能、例えばarray-of-objects-with-bool-propertiesの代わりにロックフリーの複数ビット配列。
  • 異なるコア上のプロセス間での共有メモリなどのOS機能の完全な使用。
  • 安全。 HFTソフトウェアは通常証券取引所に配置されるため、マルウェアの可能性は受け入れられません。

これらのテクニックの多くはゲーム開発と重複しています。これが、金融ソフトウェア業界が最近冗長なゲームプログラマーを吸収する理由の1つです(少なくとも家賃の延滞を支払うまで)。

根本的な必要性は、セキュリティ(株、商品、FX)価格などの非常に高い帯域幅の市場データストリームを聞いて、セキュリティ、価格に基づいて非常に高速な購入/販売/何もしない決定を行うことができることです。そして現在の保有物。

もちろん、これはすべてうまくいく可能性があります 見当違い も。


ビット配列 ポイントについて詳しく説明します。注文の長いリストで動作する高周波トレーディングシステムがあるとします(5000のIBMを購入、1万のDellを販売など)。次のタスクに進むことができるように、すべての注文が完了したかどうかをすばやく判断する必要があるとしましょう。従来のOOプログラミングでは、これは次のようになります。

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(); } );

このコードのアルゴリズムの複雑さは、O(N))になります。これは線形スキャンであるためです。メモリアクセスの観点からパフォーマンスプロファイルを見てみましょう:std内のループの各反復:: any_of()はインライン化されたo.isFilled()を呼び出すため、_isFilled、1バイト(またはアーキテクチャ、コンパイラ、コンパイラの設定に応じて4バイト)のメモリアクセスになります(128バイトとしましょう)。合計。したがって、128バイトごとに1バイトにアクセスしています。1バイトを読み取ると、最悪の場合を想定して、CPUデータキャッシュミスが発生します。これにより、RAMこれは、RAM( 詳細についてはこちらを参照 )から行全体を読み取るだけで8ビットを読み取るため、メモリアクセスプロファイルはNに比例します。 。

これと比較してください:

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); }

これのメモリアクセスプロファイルは、最悪のケースを想定すると、ELEMSをRAM行の幅で割ったものです(可変-デュアルチャネルまたはトリプルチャネルなど)です)。

つまり、実際には、メモリアクセスパターンのアルゴリズムを最適化しています。 RAMの量は役に立ちません-この必要性を引き起こすのはCPUデータキャッシュサイズです。

これは役に立ちますか?


YouTubeの低レイテンシプログラミング(HFT用)に関する優れたCPPConトークがあります: https://www.youtube.com/watch?v=NH1Tta7purM

15
JBRWilkinson