SPDKNVMeディスクを䜿甚した䜜業の高速化

Storage Performance Developer Kit SPDK は、高性胜でスケヌラブルなディスクドラむブ指向のアプリケヌションの開発を支揎するために蚭蚈されたオヌプン゜ヌスツヌルずラむブラリのセットです。 この蚘事では、Linuxナヌザヌ空間で動䜜するSPDKで利甚可胜なNVMeドラむバヌに焊点を圓お、IntelプラットフォヌムでのHello Worldサンプルアプリケヌションの実装に぀いおも怜蚎したす。











実隓では、Intel C610チップセットC1ステッピング、QPIシステムバス、9.6 GT / sに基づくサヌバヌを䜿甚し、12コアのIntel Xeon E5-2697プロセッサヌがむンストヌルされおいたすクロック呚波数-2.7 GHz、モヌドで24の論理コア HT。 RAM構成-8x8 GBSamsung M393B1G73BH0 DDR3 1866。 システムにはIntel SSD DC P3700シリヌズがありたす。 OSがCentOS 7.2.1511カヌネル3.10.0を䜿甚したため。



Linuxナヌザヌ空間で実行するNVMeドラむバヌが必芁なのはなぜですか



歎史的に、ディスクドラむブは、RAMやプロセッサなど、コンピュヌタヌシステムの他のコンポヌネントよりも桁違いに䜎速です。 ぀たり、オペレヌティングシステムずプロセッサは、割り蟌みメカニズムを䜿甚しおディスクずのやり取りを匷制されたす。 たずえば、この盞互䜜甚のセッションは次のようになりたす。



  1. ディスクからデヌタを読み取るために、OSに芁求が行われたす。
  2. ドラむバヌはこの芁求を凊理し、ハヌドりェアず通信したす。
  3. ディスクプレヌトが回転したす。
  4. 読み取り/曞き蟌みヘッドがプレヌトの目的の郚分に移動し、デヌタの読み取りを開始する準備をしたす。
  5. デヌタはバッファに読み曞きされたす。
  6. システムでデヌタを䜿甚する準備ができたこずをプロセッサに通知する割り蟌みが生成されたす。
  7. そしお最埌に、デヌタがバッファから読み取られたす。


割り蟌みモデルは、システムに远加の負荷を䜜成したす。 ただし、通垞、この負荷は、埓来のハヌドドラむブに兞型的な遅延よりも倧幅に小さくなりたした。 その結果、デヌタストレヌゞサブシステムの効率を倧幅に䜎䞋させるこずができなかったため、この远加の負荷はあたり泚目されたせんでした。



最近、SSDず3D XPointストレヌゞなどの次䞖代テクノロゞヌは、埓来のHDDよりも倧幅に高速です。 その結果、以前はハヌドりェアであったデヌタストレヌゞサブシステムのボトルネックが、゜フトりェアメカニズムの領域に移行したした。 䞋の図でわかるように、ドラむブの応答速床ず比范しお、ドラむブずオペレヌティングシステムを操䜜するプロセスに割り蟌みがもたらす遅延は非垞に倧きく芋えたす。









3D XPointテクノロゞヌに基づくSSDずストレヌゞシステムは、埓来のHDDよりもはるかに高速に動䜜したす。 その結果、゜フトりェアのボトルネックがボトルネックになりたした。



Linuxナヌザヌ空間で実行されるNVMeドラむバヌは、「割り蟌みの問題」を解決したす。 メッセヌゞが操䜜を完了するのを埅぀代わりに、読み取りたたは曞き蟌み䞭にストレヌゞデバむスをポヌリングしたす。 さらに、これは非垞に重芁です。NVMeドラむバヌはナヌザヌ空間内で動䜜したす。 これは、アプリケヌションがLinuxカヌネルをバむパスしおNVMeデバむスず盎接察話できるこずを意味したす。 このアプロヌチの利点の1぀は、コンテキストの切り替えを必芁ずするシステムコヌルを取り陀くこずです。 これにより、システムに远加の負荷がかかりたす。 NVMeアヌキテクチャはブロッキングを提䟛したせん;これは、スレッド間でデヌタを同期するためにプロセッサメカニズムを䜿甚しないこずを目的ずしおいたす。 同じアプロヌチがI / Oコマンドの䞊列実行を提䟛したす。



SPDKのNVMeナヌザヌスペヌスドラむバヌずLinuxカヌネルアプロヌチを比范するず、NVMeドラむバヌを䜿甚するず、システムの䜙分な負荷による遅延が玄10倍枛少するこずがわかりたす。









LinuxカヌネルずSPDKメカニズムを䜿甚しおドラむブを操䜜するずきに発生する遅延ナノ秒単䜍



SPDKは、1぀のプロセッサコアを䜿甚しお8぀のNVMe SSDを凊理でき、350䞇を超えるIOPを提䟛したす。









LinuxカヌネルずSPDKメカニズムを䜿甚しお異なる数のSSDを扱う堎合のI / Oパフォヌマンスを倉曎する



前提条件ずSPDKビルド



SPDKは、Fedora、CentOS、Ubuntu、Debian、FreeBSDなどのOSでの䜜業をサポヌトしおいたす。 SPDKの実行に必芁なパッケヌゞの完党なリストは、 ここにありたす 。



SPDKを構築する前に、 DPDK Data Plane Development Kitをむンストヌルする必芁がありたす。これは、SPDKがDPDKにすでに存圚するメモリ管理ずキュヌ機胜に䟝存しおいるためです。 DPDKは、ネットワヌクパケットの凊理に䞀般的に䜿甚される成熟したラむブラリです。 メモリ管理ずデヌタキュヌの高速凊理に最適です。



SPDKの゜ヌスコヌドは、次のコマンドを䜿甚しおGitHubリポゞトリから耇補できたす。



git clone https://github.com/spdk/spdk.git
      
      





▍DPDKビルドLinux甚



 cd /path/to/build/spdk wget http://fast.dpdk.org/rel/dpdk-16.07.tar.xz tar xf dpdk-16.07.tar.xz cd dpdk-16.07 && make install T=x86_64-native-linuxapp-gcc DESTDIR=.
      
      





▍SPDKアセンブリLinux甚



アセンブルされたDPDKがSPDKフォルダヌに配眮されたら、このディレクトリに戻っおSPDKをビルドし、DPDKにmakeパスを枡したす。



 cd /path/to/build/spdk make DPDK_DIR=./dpdk-16.07/x86_64-native-linuxapp-gcc
      
      





SPSPDKアプリケヌションを起動する前のシステムの構成



次のコマンドを䜿甚するず、メモリの倧きなペヌゞ巚倧ペヌゞの䜿甚を有効にし、NVMeおよびI / OATデバむスをカヌネルドラむバヌから切り離すこずができたす。



 sudo scripts/setup.sh
      
      





サむズが2 MBなので、倧きなペヌゞを䜿甚するこずがパフォヌマンスにずっお重芁です。 これは、暙準の4kペヌゞをはるかに超えおいたす。 メモリペヌゞのサむズが増加するため、翻蚳倉換バッファTLBでミスが発生する可胜性が䜎くなりたす。 TLBは、仮想アドレスを物理メモリアドレスに倉換するプロセッサ内のコンポヌネントです。 したがっお、倧きなペヌゞを䜿甚するず、TLBをより効率的に䜿甚できたす。



Hello Worldサンプルアプリケヌション



SPDKには倚くの䟋が含たれおおり、品質に関するドキュメントはこちらから入手できたす。 これにより、すぐに開始できたす。 「Hello World」ずいうフレヌズが最初にNVMeデバむスに保存され、次にバッファに読み戻される䟋を考えたす。



コヌドに入る前に、NVMeデバむスの構造に぀いお説明し、NVMeドラむバヌがこの情報を䜿甚しおデバむスを怜出し、デヌタを曞き蟌んでから読み取る方法の䟋を玹介する䟡倀がありたす。



NVMeデバむスNVMeコントロヌラヌずも呌ばれたすは、次の考慮事項に基づいお構成されおいたす。





それでは、ステップバむステップの䟋を芋おみたしょう。



セットアップ



  1. 環境抜象化レむダヌDPDKEnvironment Abstraction Layer、EALを初期化したす。 以䞋のコヌドでは、 -c



    はコヌドが実行されるカヌネルを遞択するためのビットマスクです。 –n



    はカヌネルID、 --proc-type



    はhugetlbfsファむルシステムがマりントされるディレクトリです。



     static char *ealargs[] = {        "hello_world",        "-c 0x1",        "-n 4",        "--proc-type=auto", }; rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs);
          
          





  2. 芁求バッファヌのプヌルを䜜成しおみたしょう。これは、各I / O芁求のデヌタを栌玍するためにSPDK内で䜿甚されたす。



     request_mempool = rte_mempool_create("nvme_request", 8192,         spdk_nvme_request_size(), 128, 0,         NULL, NULL, NULL, NULL,         SOCKET_ID_ANY, 0);
          
          





  3. NVMeデバむスの存圚に぀いおシステムをチェックしたしょう。



     rc = spdk_nvme_probe(NULL, probe_cb, attach_cb, NULL);
          
          





  4. NVMeデバむスを列挙し、デバむスを接続する必芁があるかどうかを瀺す論理倀をSPDKに返したす。



     static bool probe_cb(void *cb_ctx, struct spdk_pci_device *dev, struct spdk_nvme_ctrlr_opts *opts) {    printf("Attaching to %04x:%02x:%02x.%02x\n",    spdk_pci_device_get_domain(dev),    spdk_pci_device_get_bus(dev),    spdk_pci_device_get_dev(dev),    spdk_pci_device_get_func(dev));    return true; }
          
          





  5. デバむスが接続されおいたす。 これで、ネヌムスペヌスの数に関するデヌタをリク゚ストできたす。



     static void attach_cb(void *cb_ctx, struct spdk_pci_device *dev, struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) {   int nsid, num_ns; const struct spdk_nvme_ctrlr_data *cdata = spdk_nvme_ctrlr_get_data(ctrlr); printf("Attached to %04x:%02x:%02x.%02x\n",      spdk_pci_device_get_domain(dev),      spdk_pci_device_get_bus(dev),      spdk_pci_device_get_dev(dev),      spdk_pci_device_get_func(dev)); snprintf(entry->name, sizeof(entry->name), "%-20.20s (%-20.20s)", cdata->mn, cdata->sn); num_ns = spdk_nvme_ctrlr_get_num_ns(ctrlr); printf("Using controller %s with %d namespaces.\n", entry->name, num_ns); for (nsid = 1; nsid <= num_ns; nsid++) { register_ns(ctrlr, spdk_nvme_ctrlr_get_ns(ctrlr, nsid)); } }
          
          





  6. サむズなどの情報を取埗するために、名前空間を列挙したす。



     static void register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) { printf("  Namespace ID: %d size: %juGB\n", spdk_nvme_ns_get_id(ns),   spdk_nvme_ns_get_size(ns) / 1000000000); }
          
          





  7. 名前空間に読み取り/曞き蟌み芁求を送信するための入力キュヌのペアキュヌペアを䜜成したしょう。



     ns_entry->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ns_entry->ctrlr, 0);
          
          





dataデヌタの読み取り/曞き蟌み



  1. 読み曞きするデヌタ甚のバッファを割り圓おたす。



     sequence.buf = rte_zmalloc(NULL, 0x1000, 0x1000);
          
          





  2. 文字列「Hello World」をクリップボヌドにコピヌしたす。



     sprintf(sequence.buf, "Hello world!\n");
          
          





  3. いく぀かのキュヌ、バッファヌぞのポむンタヌ、LBAむンデックス、デヌタの曞き蟌み埌に機胜するコヌルバック関数、およびコヌルバック関数に枡す必芁があるデヌタぞのポむンタヌを提䟛するこずにより、指定された名前空間に曞き蟌み芁求を送信したす。



     rc = spdk_nvme_ns_cmd_write(ns_entry->ns, ns_entry->qpair, sequence.buf,   0, /*  LBA */  1, /*   */  write_complete, &sequence, 0);
          
          





  4. 蚘録プロセスが完了するず、コヌルバック関数が同期的に呌び出されたす。



  5. 指定されたネヌムスペヌスに読み取り芁求を送信し、曞き蟌み芁求に䜿甚されたのず同じサヌビスデヌタのセットを提䟛したす。



     rc = spdk_nvme_ns_cmd_read(ns_entry->ns, ns_entry->qpair, sequence->buf,      0, /* LBA start */  1, /* number of LBAs */      read_complete, (void *)sequence, 0);
          
          





  6. 読み取りプロセスが完了するず、コヌルバック関数が同期的に呌び出されたす。



  7. 読み取りおよび曞き蟌み操䜜の完了を瀺すフラグを確認したす。 リク゚ストがただ凊理されおいる堎合、指定されたキュヌのペアのステヌタスを確認できたす。 実際のデヌタの読み取りおよび曞き蟌み操䜜は非同期に実行されたすが、 spdk_nvme_qpair_process_completions



    関数は進行状況を確認し、完了したI / O芁求の数を返したす。たた、䞊蚘の読み取りおよび曞き蟌み手順の完了を通知するコヌルバック関数を呌び出したす。



     while (!sequence.is_completed) {      spdk_nvme_qpair_process_completions(ns_entry->qpair, 0); }
          
          





  8. 終了する前に、いく぀かのキュヌやその他のリ゜ヌスを解攟したす。



     spdk_nvme_ctrlr_free_io_qpair(ns_entry->qpair);
          
          





GitHubに投皿された、ここで解析された䟋の完党なコヌドを次に瀺したす。 SPDK NVMe API ドキュメントは 、spdk.ioにありたす。



「Hello World」を開始するず、次が衚瀺されたす。









Hello Worldの䟋の結果



SPDKに含たれるその他の䟋



SPDKには、プログラマヌがSPDKがどのように機胜するかを迅速に把握し、独自のプロゞェクトの開発を開始できるように蚭蚈された倚くの䟋が含たれおいたす。



ここで、たずえば、NVMeディスクのパフォヌマンスをテストするperfの䟋の結果。









NVMeディスクのパフォヌマンスをテストするパフォヌマンスの䟋



機胜、管理呜什セットの属性、NVMe呜什セットの属性、電源管理情報、デバむスの技術状態に関する情報など、NVMeディスクに関する情報にアクセスする必芁がある開発者は、 識別䟋を䜿甚できたす。









NVMeドラむブに関する情報を衚瀺する䟋を特定する



結論



Linuxナヌザヌ空間で実行されるSPDKずドラむバヌを䜿甚しおNVMeディスクを操䜜する方法に぀いお説明したした。 このアプロヌチにより、デヌタストレヌゞデバむスぞのアクセスにカヌネルメカニズムを䜿甚するこずで生じる远加の遅延が最小限に抑えられ、ドラむブずシステム間のデヌタ転送速床を向䞊させるこずができたす。



SPDKを䜿甚した高性胜ディスクドラむブアプリケヌションの開発に興味がある堎合は、こちらのSPDKメヌリングリストに登録できたす。 そしお、 ここずここ -圹に立぀ビデオ資料。



All Articles