AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 436823
Accepted
Siva
Siva
Asked: 2018-04-11 09:06:48 +0800 CST2018-04-11 09:06:48 +0800 CST 2018-04-11 09:06:48 +0800 CST

Processos de script em paralelo

  • 772

Eu gostaria de analisar os IPs wrt do log de acesso do apache. Eu usei o código a seguir, mas demorou quase 90 segundos.

grep "^$CLIENT_IP" /var/log/http/access.log > /tmp/access-$CLIENT_IP.log

Então eu tentei alternativa como abaixo.

sed -i -e "/^$CLIENT_IP/w /tmp/access-$CLIENT_IP.log" -e '//d' /var/log/http/access.log

mesmo isso levou mais de 60 segundos também.

Existem 1200 IPs para analisar. Gostaria de saber se existe alguma maneira de implementar o paralelismo para reduzir o tempo de execução.

shell-script shell
  • 3 3 respostas
  • 146 Views

3 respostas

  • Voted
  1. Best Answer
    Kusalananda
    2018-04-11T11:46:42+08:002018-04-11T11:46:42+08:00

    Estou assumindo que você está fazendo isso em um loop de shell em todos os endereços IP, possivelmente com os endereços IP provenientes de um arquivo de texto. Sim, isso seria lento, com uma invocação de sedou greppor endereço IP.

    Em vez disso, você pode se safar com um único uso de sed, se se preparar com cuidado.

    Primeiro temos que criar um sedscript, e fazemos isso a partir de um arquivo ip.listque contém os endereços IP, um endereço por linha:

    sed -e 'h' \
        -e 's/\./\\./g' \
        -e 's#.*#/^&[[:blank:]]/w /tmp/access-#' \
        -e 'G' \
        -e 's/\n//' \
        -e 's/$/.log/' ip.list >ip.sed
    

    Este sedmaterial faz, para cada endereço IP,

    1. Copie o endereço para o "hold space" (um buffer extra em sed).
    2. Altere .o "espaço padrão" (a linha de entrada) para \.(para corresponder aos pontos corretamente, seu código não fez isso).
    3. Anexar ^e anexar [[:blank:]]/w /tmp/access-ao espaço padrão.
    4. Anexe a linha de entrada não modificada do espaço de retenção ao espaço do padrão com uma nova linha entre eles.
    5. Exclua essa nova linha.
    6. Acrescente .logao final da linha (e imprima implicitamente o resultado).

    Para um arquivo que contém

    127.0.0.1
    10.0.0.1
    10.0.0.100
    

    isso criaria o sedscript

    /^127\.0\.0\.1[[:blank:]]/w /tmp/access-127.0.0.1.log
    /^10\.0\.0\.1[[:blank:]]/w /tmp/access-10.0.0.1.log
    /^10\.0\.0\.100[[:blank:]]/w /tmp/access-10.0.0.100.log
    

    Observe que você terá que corresponder a um caractere em branco (espaço ou tabulação) após o endereço IP, caso contrário, as entradas de log 10.0.0.100irão para o /tmp/access-10.0.0.1.logarquivo. Seu código omitiu isso.

    Isso pode ser usado em seu arquivo de log (sem loop):

    sed -n -f ip.sed /var/log/http/access.log
    

    Nunca testei a gravação em 1200 arquivos de um único e mesmo sedscript. Se não funcionar, tente a awkvariação abaixo.


    Uma solução semelhante awkenvolve primeiro ler os endereços IP em uma matriz e, em seguida, compará-los com cada linha. Isso requer uma única awkinvocação:

    awk 'FNR == NR  { list[$1] = 1; next }
         $1 in list { name = $1 ".log"; print >>name; close name }' ip.list /var/log/http/access.log
    

    Aqui, fornecemos awka lista de IP e o arquivo de log ao mesmo tempo. Quando NR == FNRsabemos que ainda estamos lendo o primeiro arquivo (a lista), adicionamos os números IP na matriz associativa listcomo chaves e continuamos com a próxima linha de entrada.

    Se a FNR == NRcondição não for verdadeira, estamos lendo do segundo arquivo (o arquivo de log) e testamos se o primeiro campo da linha de entrada é uma chave list(esta é uma comparação de string simples, não uma correspondência de expressão regular) . Se for, anexamos a linha ao arquivo nomeado apropriadamente.

    Devemos ter cuidado ao fechar o arquivo de saída, caso contrário, podemos ficar sem descritores de arquivo aberto. Portanto, haverá muitos arquivos abrindo e fechando para anexar, mas ainda será mais rápido do que chamar awk(ou qualquer utilitário) uma vez por endereço IP.


    Eu estaria interessado em saber se essas coisas funcionam para você e qual pode ser o tempo de execução aproximado. Testei as soluções apenas em conjuntos de dados extremamente pequenos.


    Claro, poderíamos seguir sua ideia de apenas força bruta, lançando várias instâncias de, por exemplo grep, no sistema em paralelo:

    Ignorando o fato de que não combinamos os pontos nos endereços IP corretamente, podemos fazer algo como

    xargs -P 4 -n 100 sh -c '
        for n do
            grep "^$n[[:blank:]]" /var/log/http/access.log >"/tmp/access-$n.log"
        done' sh <ip.list
    

    Aqui, xargsfornecerá no máximo 100 endereços IP por vez do ip.listarquivo para um script de shell curto. Ele providenciará quatro invocações paralelas do script.

    O script de shell curto:

    for n do
        grep "^$n[[:blank:]]" /var/log/http/access.log >"/tmp/access-$n.log"
    done
    

    Isso apenas iterará sobre os 100 endereços IP fornecidos xargsem sua linha de comando e aplicará praticamente o mesmo grepcomando que você tinha, a diferença é que haverá quatro desses loops executando em paralelo.

    Aumente -P 4para -P 16ou algo relacionado ao número de CPUs que você possui. A aceleração provavelmente não seria linear, pois cada instância paralela de grepleria e gravaria no mesmo disco.

    Exceto pelo -Psinalizador para xargs, todas as coisas nesta resposta devem poder ser executadas em qualquer sistema POSIX. O -Psinalizador para xargsnão é padrão, mas implementado em sistemas GNU xargse BSD.

    • 3
  2. Dark Matter
    2018-04-11T09:37:32+08:002018-04-11T09:37:32+08:00

    Para várias abordagens: https://stackoverflow.com/questions/9066609/fastest-possible-grep

    Além disso, se você está fazendo muito isso, um SSD provavelmente é o caminho a percorrer. Tocar no HD é o assassino para algo assim.

    Você tem um grande número de greps diferentes para executar. Crie um script que inicie comandos de script (digamos, um por núcleo) em segundo plano e, em seguida, rastreie quando eles terminarem, conforme forem concluídos, inicie mais.

    Quando eu estava fazendo isso, consegui que todos os 12 núcleos rodassem com 100% de uso da CPU, mas você pode descobrir que seu limite de recursos é outra coisa. Dado que todos os seus trabalhos desejam o mesmo arquivo, se você não estiver em um SSD, convém copiar esse arquivo para que não sejam compartilhados.

    • 1
  3. Ole Tange
    2018-04-16T14:49:29+08:002018-04-16T14:49:29+08:00

    Se /var/log/http/access.logfor maior que a RAM e, portanto, não puder ser armazenado em cache, executar mais processos em paralelo pode ser uma boa alternativa para ler access.logvárias vezes - especialmente se você tiver vários núcleos. Isso executará um greppor IP em paralelo (+ alguns processos de empacotamento de ajuda).

    pargrep() {
        # Send standard input to grep with different match strings in parallel
        # This command would be enough if you only have 250 match strings
        parallel --pipe --tee grep ^{} '>' /tmp/access-{}.log ::: "$@"
    }
    export -f pargrep
    # Standard input is tee'ed to several pargreps.
    # Each pargrep gets 250 match strings and thus starts 250 processes.
    # For 1200 ips this starts 3600 processes taking around 1 GB RAM,
    # but it reads access.log only once
    cat /var/log/http/access.log |
      parallel --pipe --tee -N250 pargrep {} :::: ips
    
    • 0

relate perguntas

  • Um script que imprime as linhas de um arquivo com seu comprimento [fechado]

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • Como salvar um caminho com ~ em uma variável?

  • MySQL Select com função IN () com array bash

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve