O Estado das Bibliotecas Python SSH

Neste post uma nova opção para bibliotecas Python SSH, ssh2-python, deve ser comparada com Paramiko para demonstrar o seu respectivo desempenho com particular ênfase nos pedidos concomitantes e não-bloqueantes.

Na procura de uma biblioteca Python SSH para usar numa aplicação, não existem muitas opções. De facto, a única biblioteca de propósito geral que até agora tem estado disponível é a Paramiko, que implementa a API SSH2 em código Python.

Para o melhor ou para o pior – é sem dúvida que a biblioteca tem ajudado um grande número de pessoas com requisitos semelhantes, incluindo este autor, uma vez que tem sido historicamente a única opção – a Paramiko tem sido o estandarte de facto para as bibliotecas SSH Python até agora.

No entanto, deixa muito a desejar de um ponto de vista de desempenho, estabilidade e consumo de recursos.

Felizmente, existe agora outra opção na forma de ssh2-python que se baseia na biblioteca libssh2 C.

Muitas aplicações de automação como Ansible e Fabric fazem uso de Paramiko e provavelmente estariam interessadas em conhecer outras opções agora existentes. Espero que este post ajude estas e outras aplicações a determinar qual a biblioteca mais adequada.

Performance Comparison

ssh2-python é uma nova biblioteca Python SSH baseada na biblioteca libssh2 C. Não tem dependências e fornece rodas binárias Linux, OSX e Windows com libssh2 incluído.

paramiko é escrito em Python e faz uso de dependências de extensão nativas como a criptografia. Suporta Linux, OSX e Windows e as suas dependências nativas fornecem rodas binárias.

Test Setup

Test está a usar a biblioteca padrão de Python’s threadingdiv> para concorrência. Um post de blog posterior examinará o desempenho não bloqueador nas bibliotecas através da biblioteca de co-rotinas de eventos.

Embora o threading não seja um bom modelo para o escalonamento de I/O de rede, é o único modo de simultaneidade que a Paramiko suporta nativamente e é o que é usado por aplicações como Ansible. Outros projectos como o parallel-ssh, do qual também sou autor, utilizam o patching de macacos do gevent para tornar a Paramiko cooperativamente concorrente. Isto também vem com desvantagens significativas que o cliente actualmente em desenvolvimento ssh2-python baseado nativamente não bloqueador visa resolver. Ver o trabalho em curso para mais detalhes sobre isso.

O script de teste cria sessões SSH em paralelo a um servidor SSH (OpenSSH) via dispositivo de loop back (localhost), começando por um e aumentando por um até à conclusão de cada iteração. Isto mostra como as duas bibliotecas escalam à medida que o número de sessões paralelas aumenta.

Número máximo de linhas e, por conseguinte, as sessões paralelas são definidas para 50. Todos os testes são realizados num CPU quad core físico.

Em todos os testes é utilizada a última versão disponível de cada biblioteca, 2.2.1 e 0.5.3 para Paramiko e ssh2-python respectivamente. Para ssh2-python foi utilizado libssh2, última versão disponível 1.8.0. Todos os testes realizados sob Python 2.7.

As bibliotecas são comparadas em seis operações SSH separadas, bem como o tempo total gasto do início ao fim por sessão SSH.

As seis operações são comparadas:

  • Inicialização da sessão e autenticação com agente SSH (auth)
  • Canal aberto (channel_open)
  • li>Executar Canal (execute)

  • Leitura do Canal – (channel_read)
  • Canal fechar e obter estado de saída (close_and_exit_status)
  • li>SFTP ler (sftp_read)

Uma explicação rápida do que estas operações fazem:

  • Inicialização e autenticação da sessão – executar aperto de mão com servidor SSH e autenticar através de um agente SSH do sistema.
  • Canal aberto – é necessário abrir um novo canal SSH numa sessão autenticada por comando remoto para executar.
  • Canal executado – comando shell run cat num ficheiro estático
  • Canal lido – recuperando a saída do comando.
  • Fechamento do canal – executado quando o comando é terminado, a fim de recolher o estado de saída.
  • SFTP read – iniciar sessão SFTP, abrir manípulo de ficheiro remoto, ler dados. Ler dados não é escrito em lado nenhum.

O ficheiro estático que é usado para o cat comando remoto é um 26KB ficheiro de licença do repositório ssh2-python.

O ficheiro utilizado para leitura SFTP é um arquivo tar comprimido de 11MB.

Todas as durações são em milisegundos (ms).

Resultados do teste

Gráficos mostram valores medianos por intervalos de trinta segundos.

Gráfico de todas as operações

Aqui está como as duas bibliotecas se comparam nas cinco operações separadas mais o tempo total gasto.

Clique na imagem para uma versão maior.

ssh2 comparação paramiko

Como se pode ver acima, as durações paramiko são dominadas por leitura SFTP, autenticação e canal aberto, que continuam a aumentar à medida que a concorrência se eleva.

Para ssh2-python, o maior tempo gasto é em SFTP lido, seguido de auth e canal aberto.

Both bibliotecas mostram picos intermitentes de duração que são esperados dado o número de fios e chamadas de bloqueio utilizadas.

Operações individuais

Tempos para operações que não incluem SFTP e total para mostrar uma visão mais próxima do resto dos timings.

Clique na imagem para uma versão maior.

ssh2 paramiko comparisonssh2 comparação paramiko

Realização relativa

Realização relativa das médias de operações medianas das duas bibliotecas durante a duração do teste. As durações totais e SFTP lidas são para as médias.

Por exemplo, se uma operação Paramiko fosse duas vezes mais rápida do que a operação equivalente ssh2-python, o seu desempenho relativo seria x0.5 de ssh2-python enquanto durações idênticas resultariam em x1 desempenho relativo.

>th>Paramikoth>ssh2th>Paramiko/ssh2-diferença relativa python

>>total

Operation
auth 1.16 sec 675 ms x1.71
channel open 1.248 sec 141 ms x8.85
channel read 78 ms 29 ms x2.68
close and exit status 4 ms 1 ms x4
execute 24 ms 3 ms x8
sftp_read 19.35 seg 1.13 seg x17.12
20,82 seg 2.04 s x10.2

Postface

No total, ssh2-python mostra-se ser consideravelmente mais rápido, particularmente em operações pesadas como o SFTP, para o qual a leitura é cerca de x17 vezes mais rápida em média em comparação com o Paramiko. Outras operações que beneficiam particularmente são canal aberto, x8 mais rápido, e executar, também x8. No total, no caso de teste acima mencionado ssh2-python é mostrado ser cerca de uma ordem de magnitude (x10) mais rápido, em média.

Também notar que o consumo de memória não é agarrado, mas é significativamente mais baixo com ssh2-python como esperado, uma vez que se baseia numa biblioteca nativa.

As para comparações entre uma biblioteca SSH de código Python puro e uma baseada numa biblioteca C sendo “injusta” – a biblioteca de código Python “puro” também usa extensões de código nativo para operações de criptografia, tornando o argumento discutível. Note como a operação com a menor diferença de desempenho é a autenticação, que é maioritariamente tratada por extensões de código nativo em Paramiko.

Não há também qualquer requisito para escrever uma implementação SSH API de baixo nível puramente em Python. Muitas razões para não o fazer de facto, uma vez que estes resultados vão de certa forma no sentido de mostrar.

Apêndice

O script de teste utilizado pode ser encontrado abaixo:

    li> script de teste de desempenho

O script de teste escreve dados de duração para um InfluxDB local através do seu serviço Graphite usando um modelo measurement.field*.

Graphs acima foram gerados pelo Grafana, tal como consultado do InfluxDB pelo InfluxGraph usando a mesma configuração de modelo do InfluxDB.

Para replicar resultados, tenha o cuidado de usar as versões exactas das bibliotecas aqui usadas, incluindo libssh2. Versões mais antigas de libssh2 não são completamente seguras e causarão crashes.

Disclaimer – Embora eu seja o autor de ssh2-python, não tenho interesse em libssh2 ou Paramiko. O meu interesse no seu respectivo desempenho é para uso em parallel-ssh.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *