私はNational Highway Traffic Safety Administration APIから約25,000,000個のVIN番号のVIN仕様を取得しています。それは大量のデータであり、何らかの方法でデータを変換しないため、curl
Pythonよりも作業を実行するためのより効率的で軽い方法です(PythonのGILは並列処理を少し難しくするためです)。
以下のコードでは、vins.csv
2,500万VINの大規模サンプルを含むファイルを100 VINチャンクに分割します。これは4つのコアを使用してGNU Parallelに渡されます。nhtsa_vin_data.csv
最後に、すべてが崩壊します。
$ cat vins.csv | parallel -j10% curl -s --data "format=csv" \
--data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ \
>> /nas/BIGDATA/kemri/nhtsa_vin_data.csv
このプロセスは毎分約3,000 VINの書き込みから始まり、時間の経過とともに徐々に遅くなりました(現在約1,200 /分)。
私の質問
nhtsa_vin_data.csv
コマンドが拡張されるにつれてオーバーヘッドを追加することはありますか?- これは
>>
Linuxがタスクを処理する方法に関連していますか?
アップデート#1 - ソリューション
@slmによる最初の解決策 - 並列tmpファイルオプションを使用して、各カール出力を独自の.parファイルに書き込み、最後にマージします。
$ cat vins.csv | parallel \
--tmpdir /home/kemri/vin_scraper/temp_files \
--files \
-j10% curl -s \
--data "format=csv" \
--data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ > /dev/null
cat <(head -1 $(ls *.par|head -1)) <(tail -q -n +2 *.par) > all_data.csv
@oletangeの2番目の解決策 - --line-bufferを使用して、出力をディスクの代わりにメモリにバッファリングします。
$ cat test_new_mthd_vins.csv | parallel \
--line-buffer \
-j10% curl -s \
--data "format=csv" \
--data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ \
>> /home/kemri/vin_scraper/temp_files/nhtsa_vin_data.csv
パフォーマンスに関する考慮事項
私はここで提案されている2つのソリューションがとても便利で興味深いことを知っていました。いくつかのテストを実行し、どちらが私のユースケースでうまくいくかを確認できることを願っています。
また、NHTSAがここでボトルネックを引き起こす可能性は無視できないため、ある種のスループットテスト(@oletangeおよび@slmの提案)を実行することをお勧めします。
答え1
私はこれがAPIデータを収集する分岐したコマンド間で>>
ファイル競合を引き起こすと思います。nhtsa_vin_data.csv
curl
parallel
次のようにアプリを調整します。
$ cat p.bash
#!/bin/bash
cat vins.csv | parallel --will-cite -j10% --progress --tmpdir . --files \
curl -s --data "format=csv" \
--data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/
curl
これにより、コマンドにデータを書き込むことができる独自の独立ファイルが提供されます。
はい
私はあなたが私に与えた3つのVINを持ってき1HGCR3F95FA017875;1HGCR3F83HA034135;3FA6P0T93GR335818;
たvins.csv
。その後、ファイルが次の属性を持つように複数回コピーしました。
$ tail -1 vins.csv | grep -o ';' | wc -l
26
行
$ wc -l vins.csv
15 vins.csv
その後、このデータを使用してスクリプトを実行します。
$ ./p.bash
Computers / CPU cores / Max jobs to run
1:local / 1 / 1
Computer:jobs running/jobs completed/%of started jobs/Average seconds to complete
local:1/0/100%/0.0s ./pard9QD3.par
local:1/1/100%/10.0s ./paruwK9L.par
local:1/2/100%/8.5s ./parT6rCS.par
local:1/3/100%/7.3s ./pardzT2g.par
local:1/4/100%/6.8s ./parDAsaO.par
local:1/5/100%/6.8s ./par9X2Na.par
local:1/6/100%/6.7s ./par6aRla.par
local:1/7/100%/6.7s ./parNR_r4.par
local:1/8/100%/6.4s ./parVoa9k.par
local:1/9/100%/6.1s ./parXJQTc.par
local:1/10/100%/6.0s ./parDZZrp.par
local:1/11/100%/6.0s ./part0tlA.par
local:1/12/100%/5.9s ./parydQlI.par
local:1/13/100%/5.8s ./par4hkSL.par
local:1/14/100%/5.8s ./parbGwA2.par
local:0/15/100%/5.4s
物を一つに集める
上記の実行が完了したら、cat
すべてのファイルを収集して単一の.csv
ファイルを取得できます。
$ cat *.par > all_data.csv
各ファイルには含まれているCSVデータの独自のヘッダー行があるため、これを行うときは注意してください。結果ファイルからヘッダーの削除を処理するには:
$ cat <(head -1 $(ls *.par|head -1)) <(tail -q -n +2 *.par) > all_data.csv
パフォーマンスが低下します
私のテストでは、DOTウェブサイトはAPIにアクセスし続けながらクエリを制限しました。私の実験で見た上記の時間は短いですが、APIサイトにクエリが送信されるたびに減少します。
私のラップトップに見える外観は次のとおりです。
$ seq 5 | parallel --will-cite --line-buffer 'yes {} | head -c 1G' | pv >> /dev/null
5GiB 0:00:51 [99.4MiB/s] [ <=> ]
メモ:上記はOle Tangeの回答で借りて修正しました。パイプを介して5 GBのデータを書き込み、parallel
それに転送しますpv >> /dev/null
。pv
これにより、パイプを介したスループットを監視し、MB/s タイプの測定値を取得できます。
私のラップトップのスループットは約100MB / sです。
NHTSA API FAQ
アプリケーションプログラミングインターフェース
「Batch Decoding VINs(Flat Format)」の場合、他の操作と同様にURLを介してこのクエリを実行する例はありますか?
この特定のAPIの場合、VINセットを「;」で区切ってボックスに入れるだけです。 ";"前に「、」で区切ってモデル年を表示することもできます。このサービスで入力できるVINの数には制限があります。
ボックスの例はサンプルです:5UXWX7C5 * BA、2011;
APIの使用には上限があると前述した。
このサービスで入力できるVINの数には制限があります。
引用する
答え2
パフォーマンスは通常、次のいずれかに制限されます。
- ネットワーク帯域幅。これを使用して、
sudo iftop
ネットワーク接続が100%使用されていることを確認できます。 - ネットワーク待ち時間。相手側のサーバーが応答するのに長い時間がかかる場合、帯域幅使用率は100%で表示されません。
- ディスクI/O。
iostat -dkx 1
これを使用して、ディスクのI / Oが100%使用されていることを確認できます。 - CPU。
top
CPU使用率が100%の場合に使用できます。1
個々のCPUスレッドを表示するにはタップします。そのうちの1つが100%の場合、この制限が適用されるシングルスレッドプログラムがあります。
GNU Parallelは、より多くの帯域幅、ディスクI / O、およびCPUを活用するためにタスクを並列に実行するのに優れています。
しかし、それにも制限があります。
GNU Parallelは通常出力を/tmp
。/tmp
幸いなことに、CSVで作業するときは、行の順序にほとんど気にしません。完全な行であれば、行が混在していても問題になりません。
バージョン> 20170822を使用している場合、--line-buffer
GNU Parallelはいいえディスクのバッファリングされた出力 - ライン全体をメモリにバッファリングします。これを完了するにはCPUのパフォーマンスが増えるため、parallel
CPUが100%使用されていることを確認してください。あまり使用していない場合は、ボトルネックがまだ発生していません。
$ cat vins.csv | parallel --line-buffer curl -s --data "format=csv" \
--data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ \
>> /nas/BIGDATA/kemri/nhtsa_vin_data.csv
次のようにして、ローカルのボトルネックがあるかどうかを確認できます。
$ seq 1000 | parallel --line-buffer 'yes {} | head -c 1G' | pv >> /nas/BIGDATA/test
私の不都合なラップトップでは約100MB / sを得ます。そうすれば、私の不都合なラップトップはdot.govの1Gbit / sを処理できます。