Saída padrão Anexar às limitações de tamanho de arquivo

5

Estou obtendo as especificações VIN da API de Administração de Segurança no Trânsito em Autoestradas Nacionais para aproximadamente 25.000.000 de números VIN. Isso é uma grande quantidade de dados, e como eu não estou transformando os dados de forma alguma, curl parecia uma maneira mais eficiente e leve de realizar a tarefa do que Python (já que o GIL do Python torna o processamento paralelo um pouco mais dor).

No código abaixo, vins.csv é um arquivo contendo uma grande amostra dos 25M VINs, divididos em blocos de 100 VINs. Estas estão sendo passadas para o GNU Parallel, que está usando 4 núcleos. Tudo é despejado em nhtsa_vin_data.csv no final.

$ 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

Este processo estava escrevendo cerca de 3.000 VINs por minuto no começo e vem ficando progressivamente mais lento com o tempo (atualmente em torno de 1.200 / minuto).

Minhas perguntas

  • Existe alguma coisa no meu comando que esteja sujeita a aumentar a sobrecarga à medida que nhtsa_vin_data.csv aumenta de tamanho?
  • Isso está relacionado a como o Linux lida com as operações >> ?

UPDATE # 1 - SOLUÇÕES

Primeira solução por @slm - use as opções do arquivo tmp do parallel para gravar cada saída de onda em seu próprio arquivo .par, combine no final:

$ 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

Segunda solução por @oletange - use o --line-buffer para armazenar em buffer a saída para a memória em vez do disco:

$ 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

Considerações de desempenho

Acho que as duas soluções sugeridas aqui são muito úteis e interessantes e definitivamente usarão ambas as versões mais no futuro (tanto para comparar o desempenho quanto o trabalho adicional da API). Espero poder executar alguns testes para ver qual deles tem melhor desempenho para o meu caso de uso.

Além disso, a execução de algum tipo de teste de throughput, como @oletange e @slm, seria sensato, já que a probabilidade de a NHTSA ser o gargalo aqui não é desprezível.

    
por kemri 15.07.2018 / 03:28

2 respostas

3

Suspeito que o >> esteja causando a contenção no arquivo nhtsa_vin_data.csv entre os comandos curl que parallel está forking para coletar os dados da API.

Eu ajustaria sua inscrição assim:

$ 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/

Isso dará ao seu curl comandos de seu próprio arquivo isolado para gravar seus dados.

Exemplo

Eu peguei esses 3 VINs, 1HGCR3F95FA017875;1HGCR3F83HA034135;3FA6P0T93GR335818; , que você me forneceu e coloquei em um arquivo chamado vins.csv . Eu então os repliquei várias vezes para que esse arquivo acabasse tendo essas características:

VINs por linha
$ tail -1 vins.csv | grep -o ';' | wc -l
26
Número de linhas
$ wc -l vins.csv
15 vins.csv

Eu então executei meu script usando esses dados:

$ ./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

Colocando as coisas em conjunto

Quando o procedimento acima estiver concluído, você poderá usar cat todos os arquivos juntos para obter um único arquivo .csv ala:

$ cat *.par > all_data.csv

Tenha cuidado ao fazer isso, pois cada arquivo tem sua própria linha de cabeçalho para os dados CSV contidos nele. Para lidar com a retirada dos cabeçalhos dos arquivos de resultados:

$ cat <(head -1 $(ls *.par|head -1)) <(tail -q -n +2 *.par) > all_data.csv

Seu desempenho mais lento

Nos meus testes, parece que o site do DOT está restringindo as consultas enquanto elas continuam acessando a API. O tempo acima que vi em meus experimentos, embora pequeno, estava diminuindo à medida que cada consulta era enviada ao site da API.

Meu desempenho no meu laptop foi o seguinte:

$ seq 5 | parallel --will-cite --line-buffer 'yes {} | head -c 1G' | pv >> /dev/null
   5GiB 0:00:51 [99.4MiB/s] [                                                                                                                                                                  <=>       ]

NOTA: O texto acima foi emprestado da resposta de Ole Tange e modificado. Ele grava 5 GB de dados em parallel e canaliza para pv >> /dev/null . pv é usado para que possamos monitorar o rendimento através do tubo e chegar a um tipo de medição MB / s.

Meu laptop conseguiu gerar ~ 100MB / s de taxa de transferência.

Perguntas frequentes sobre a API do NHTSA

API

For the ‘Decode VIN (flat format) in a Batch’ is there a sample on making this query by URL, similar to the other actions?

For this particular API you just have to put a set of VINs within the box that are separated by a “;”. You can also indicate the model year prior to the “;” separated by a “,”. There is an upper limit on the number of VINs you can put through this service.

Example in the box is the sample: 5UXWX7C5*BA,2011; 5YJSA3DS*EF

Source: https://vpic.nhtsa.dot.gov/MfrPortal/home/faq searched for "rate"

O acima menciona que há um limite superior ao usar a API:

There is an upper limit on the number of VINs you can put through this service.

Referências

por 15.07.2018 / 04:26
3

O desempenho geralmente é limitado por um deles:

  1. Largura de banda da rede. Você pode usar sudo iftop para ver se sua conexão de rede é 100% utilizada.
  2. Latência de rede. Se o servidor na outra extremidade demorar muito para responder, você não verá 100% de utilização de largura de banda.
  3. Disco I / O. Você pode usar iostat -dkx 1 para ver se a E / S de qualquer um dos seus discos é 100% utilizada.
  4. CPU. Você pode usar top se suas CPUs forem 100% utilizadas. Pressione 1 para ver os encadeamentos individuais da CPU. Se um deles estiver em 100%, você terá um único programa encadeado, limitado por isso.

O GNU Parallel é bom em executar trabalhos em paralelo para utilizar mais largura de banda, E / S de disco e CPU.

Mas também tem suas limitações.

O GNU Parallel normalmente armazena em cache a saída em /tmp . Isso significa que sua E / S de disco em /tmp pode ser o gargalo.

Por sorte, lidar com o CSV raramente se preocupa com a ordem das linhas: é bom se as linhas se misturam, contanto que sejam linhas completas.

Se você usa --line-buffer da versão > 20170822, então o GNU Parallel faz a saída do buffer not no disco - ele armazena apenas uma linha na memória. É preciso um pouco mais de poder de processamento da CPU, portanto, verifique se parallel usa 100% da CPU. Se ele usa menos, então você não atingiu esse gargalo.

$ 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

Você pode ver se tem um afunilamento local ao:

$ seq 1000 | parallel --line-buffer 'yes {} | head -c 1G' | pv >> /nas/BIGDATA/test

No meu laptop ruim tenho cerca de 100 MBytes / s. Então meu laptop ruim seria capaz de lidar com 1 Gbit / s de dot.gov.

    
por 15.07.2018 / 06:07