파일 크기 제한에 표준 출력이 추가됨

파일 크기 제한에 표준 출력이 추가됨

저는 National Highway Traffic Safety Administration API에서 약 25,000,000개의 VIN 번호에 대한 VIN 사양을 가져오고 있습니다. 그것은 많은 양의 데이터이고 어떤 방식으로든 데이터를 변환하지 않기 때문에 curlPython보다 작업을 수행하는 데 더 효율적이고 가벼운 방법인 것 같습니다(Python의 GIL은 병렬 처리를 약간 어렵게 만들기 때문입니다).

아래 코드에서는 vins.csv2,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,000VIN 쓰기에서 시작되었으며 시간이 지남에 따라 점차 느려졌습니다(현재 약 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의 두 번째 솔루션 - --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

성능 고려사항

나는 여기에 제안된 두 가지 솔루션이 모두 매우 유용하고 흥미롭다는 것을 알았으며 앞으로 두 버전을 더 많이 사용할 것입니다(성능 및 추가 API 작업 비교를 위해). 몇 가지 테스트를 실행하고 어느 것이 내 사용 사례에 더 잘 작동하는지 확인할 수 있기를 바랍니다.

또한 NHTSA가 여기서 병목 현상을 일으킬 가능성이 무시할 수 없기 때문에 일종의 처리량 테스트(@oletange 및 @slm 제안)를 실행하는 것이 좋습니다.

답변1

나는 이로 인해 API 데이터를 수집하는 분기된 명령 사이에 >>파일 경합이 발생할 것이라고 생각합니다.nhtsa_vin_data.csvcurlparallel

다음과 같이 앱을 조정하겠습니다.

$ 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. 그런 다음 파일이 다음과 같은 특성을 갖도록 여러 번 복사했습니다.

라인당 VIN
$ 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의 답변에서 빌려 수정되었습니다. 파이프를 통해 5GB의 데이터를 쓰고 parallel이를 로 전송합니다 pv >> /dev/null. pv이를 사용하여 파이프를 통한 처리량을 모니터링하고 MB/s 유형 측정을 얻을 수 있습니다.

내 노트북의 처리량은 약 100MB/s입니다.

NHTSA API FAQ

응용 프로그래밍 인터페이스

"Batch Decoding VINs (Flat Format)"의 경우 다른 작업과 유사하게 URL을 통해 이 쿼리를 수행하는 예가 있습니까?

이 특정 API의 경우 VIN 세트를 ";"으로 구분하여 상자에 넣기만 하면 됩니다. ";" 앞에 ","로 구분하여 모델 연도를 표시할 수도 있습니다. 이 서비스를 통해 입력할 수 있는 VIN 수에는 제한이 있습니다.

상자의 예는 샘플입니다: 5UXWX7C5*BA, 2011;

원천: https://vpic.nhtsa.dot.gov/MfrPortal/home/faq"요금"을 검색하세요

API 사용에는 상한이 있다고 위에서 언급했습니다.

이 서비스를 통해 입력할 수 있는 VIN 수에는 제한이 있습니다.

인용하다

답변2

성능은 일반적으로 다음 중 하나로 제한됩니다.

  1. 네트워크 대역폭. 이를 사용하여 sudo iftop네트워크 연결이 100% 사용되었는지 확인할 수 있습니다.
  2. 네트워크 대기 시간. 상대방 서버가 응답하는 데 오랜 시간이 걸리면 대역폭 사용률이 100%로 표시되지 않습니다.
  3. 디스크 I/O. iostat -dkx 1이를 사용하여 디스크의 I/O가 100% 사용되었는지 확인할 수 있습니다.
  4. CPU. topCPU 사용률이 100%인 경우에 사용할 수 있습니다. 1개별 CPU 스레드를 보려면 누릅니다 . 그 중 하나가 100%이면 이 제한이 적용되는 단일 스레드 프로그램이 있는 것입니다.

GNU Parallel은 더 많은 대역폭, 디스크 I/O 및 CPU를 활용하기 위해 작업을 병렬로 실행하는 데 탁월합니다.

그러나 그것은 또한 한계가 있습니다.

GNU Parallel은 일반적으로 출력 을 /tmp./tmp

다행스럽게도 CSV로 작업할 때 행 순서에 거의 신경 쓰지 않습니다. 완전한 행이라면 행이 혼합되어 있어도 문제가 되지 않습니다.

버전 >20170822를 사용하는 경우 --line-bufferGNU Parallel은아니요디스크의 버퍼링된 출력 - 전체 라인을 메모리에 버퍼링합니다. 이 작업을 완료하려면 더 많은 CPU 성능이 필요하므로 parallelCPU가 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를 처리할 수 있을 것입니다.

관련 정보