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 threading
div> 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
) - Leitura do Canal – (
channel_read
) - Canal fechar e obter estado de saída (
close_and_exit_status
)
li>Executar Canal (execute
)
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.
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 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.
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.