Swoole: Is it Node in PHP or am I wrong?

Posted on: July 28, 2020 04:48 PM

Posted by: Renato

Categories: PHP PHP Swoole

Views: 11

O que é essa coisa de Swoole?

documentação :

“Framework de programação assíncrona de nível de produção para PHP Permite que desenvolvedores de PHP escrevam serviços TCP, UDP, soquete Unix, HTTP, Websocket de alto desempenho, escaláveis ​​e simultâneos, HTTP, Websocket na linguagem de programação PHP sem muito conhecimento sobre programação de E / S sem bloqueio e baixo kernel Linux de vários níveis ”.

Swoole funciona como uma extensão do PHP e está escrito em C. Parece promissor, certo? Hospedando servidor HTTP com PHP? Websockets no próprio PHP? Muitas outras possibilidades, algumas parecendo exóticas? E tudo isso com a manutenção de alto desempenho. Vamos conferir!

Como fazê-lo funcionar?

Os métodos de instalação em plataformas nativas variam.

Para Linux, tudo se resume a um comando
pecl pecl install swoole

Para o MacOS, o brew pode ser usado:
brew install swoole
brew install homebrew / php / php72-swoole

E no Windows, a instalação nativa não é possível, mas devemos usar o Docker de qualquer maneira.

Dockerizing Swoole

Obviamente, a melhor idéia para executar o PHP e o Swoole é o contêiner do Docker. Vamos ver como criar um contêiner que nos permitirá usar o Swoole. Primeiro, precisamos de um Dockerfile.

FROM php: o último
RUN pecl instala o swoole
ADICIONE php.ini / usr / local / etc / php
RUN usermod -u 1000 www-data

Isso foi bem direto. Depois de estender a imagem oficial do PHP Docker, instalar o Swoole com pecl e copiar o php.ini - conseguimos. A última linha é uma correção padrão do Docker para MacOS.

Quando se trata do arquivo de configuração php.ini que é copiado, é ainda mais simples - requer apenas uma linha: extension = swoole.so .

O que isso oferece?

Swoole tem uma variedade de funcionalidades. A maioria deles é assíncrona. Aqui estão alguns dos mais interessantes (outros podem ser encontrados na documentação do Swoole ):

  • Servidor e cliente TCP / UDP,
  • Servidor e cliente HTTP,
  • Servidor e cliente Websocket,
  • Servidor e cliente de protocolo Redis,
  • Cliente MySQL ,
  • Atomics,
  • Sistema de arquivo.

Vamos ver como usar três deles: servidor HTTP, servidor Websocket e sistema de arquivos. Estes são os mais importantes na minha opinião. 

Servidor HTTP usando Swoole

Swoole nos permite executar um servidor HTTP simples que funciona de forma assíncrona. Aqui está o código simples que também usará o acesso assíncrono ao sistema de arquivos para responder com o arquivo index.html a cada solicitação que ele manipular.

 
  chdir(__DIR__);
  $http = new swoole_http_server('php', 8080);
   
  $http->on('start', function ($server) {
  echo "Server has been started!\n";
  });
   
  $http->on('request', function ($request, $response) {
  swoole_async_readfile('index.html', function($filename, $content) use ($response) {
  $response->header('Content-Type', 'text/html');
  $response->end($content);
  });
  });
   
 

$http->start();

Como podemos ver, parece um pouco com o Node.

Primeiro, criamos o objeto swoole_http_server que se assemelha ao servidor HTTP. Em seguida, vinculamos duas funções anônimas para dois eventos: um para iniciar , que será executado quando o servidor for iniciado, e outro para solicitação , que será executada para cada solicitação. Leva uma solicitação e respostas objetos como parâmetros .

O objeto de solicitação contém todos os dados relacionados à solicitação em si: caminho solicitado, cabeçalhos e assim por diante. Por outro lado, é usado para fornecer saída, definir cabeçalhos etc. Vale ressaltar que esses dois objetos não são compatíveis com PSR, mas são objetos Swoole personalizados.

No evento de solicitação , o sistema de arquivos assíncrono é usado para carregar os dados de um arquivo. Quando os dados estão disponíveis, um retorno de chamada é acionado com o conteúdo carregado. Em seguida, esse conteúdo é usado para preencher o objeto de resposta e fechar a resposta. Isso envia os dados de volta ao navegador efetivamente.

Parece arrumado e acima de tudo - funciona. Mas e o desempenho?

Referência do servidor HTTP

Para testar o desempenho do servidor HTTP usando o Swoole, criei um aplicativo no Node - que pode fazer exatamente a mesma coisa que no Swoole - e também um servidor NGINX que serve index.html como um arquivo estático. Tudo encaixado em 3 recipientes separados.

Então, usei a ferramenta wrk para atingir esses contêineres com força. Os resultados foram surpreendentes.

O diagrama mostra os resultados de Swoole, Nginx e Node no teste de desempenho Os resultados da Swoole foram muito melhores do que o esperado!

Isso foi uma surpresa. Eu não esperava que o Swoole ultrapassasse o NGINX, mas ele realmente conseguiu! Nó estava fora de distância. O poder bruto dessa extensão é realmente impressionante, mas desaparece com mais trabalho sendo feito na solicitação. Infelizmente, Swoole tem duas pequenas desvantagens que tornam irrelevantes esses benchmarks brutos. Nós os encontraremos mais tarde.

Servidor Websocket usando Swoole

Como mencionado anteriormente, o Swoole oferece um método para criar um servidor websocket. Funciona de forma assíncrona, segue a mesma metodologia que o HTTP e outras funcionalidades do Swoole. Na minha opinião, é uma das partes mais importantes da Swoole. Vamos lá, websockets em PHP? Estou dentro. Vamos ver como fica.

 

 
  $server = new swoole_websocket_server('php', 9501);
   
  $server->on('start', function (swoole_websocket_server $server) {
  echo "Server has been started!\n";
  });
   
  $server->on('open', function (swoole_websocket_server $server, $request) {
  echo "websocket: new connection, id: {$request->fd}\n";
  });
   
  $server->on('message', function (swoole_websocket_server $server, $frame) {
  echo "websocket: {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
  $server->push($frame->fd, "Replying, you sent " . $frame->data);
  });
   
  $server->on('close', function (swoole_websocket_server $server, $fd) {
  echo "websocket: connection with id {$fd} has been closed\n";
  });
   
  $server->start();

Parece semelhante ao exemplo do servidor HTTP.

Primeiro, criamos o objeto swoole_websocket_server que se assemelha ao servidor websocket. Em seguida, vinculamos 4 funções anônimas a 4 eventos. Um para iniciar o evento, que funcionará como o evento de início do servidor HTTP. Outro evento para abrir que será executado assim que um novo websocket for conectado. Outro evento de mensagem que será executado quando um soquete da web enviar uma mensagem para o servidor. E finalmente - para fechar o evento que é executado quando um soquete da web é desconectado.

Os Websockets conectados ao servidor são identificados pelo ID exclusivo que é incrementado com cada um dos novos Websockets.

Problemas encontrados ao usar o Swoole

Tudo funcionou bem até agora, mas houve dois problemas que encontrei durante os testes de algumas soluções usando o Swoole. Estes foram:

  • nenhum suporte HTTPS real no servidor HTTP,
  • sem suporte para variáveis ​​globais em scripts.

O primeiro é fácil de mitigar. Só precisamos configurar um proxy reverso usando o NGINX ou qualquer balanceador de carga e pronto. Mas, ao fazer isso, perdemos um aumento extremo no desempenho que a Swoole oferece.

O segundo é mais complicado. Swoole gera processos de trabalho para lidar com solicitações, o que significa que, se criarmos uma variável global, seu valor será independente entre os threads e não funcionará. Aqui está um exemplo mostrando esse comportamento.

 

 
  $contador = 0 ;
   
  $http = new swoole_http_server ( 'php' , 8080 );
  $http -> on ( 'request' , função ( $request , $response ) use ( $counter ) {
  $response -> header ( "Tipo de conteúdo" , "texto / sem formatação" );
  $resposta -> fim ( $counter ++);
  });
   
  $http -> start ();

Seria de esperar que a resposta retornasse 0, depois 1, 2, 3 e assim por diante, mas sempre retorna 0.

Entrei em contato com os autores do Swoole para verificar se é um bug, mas não é. Para obter o comportamento esperado, podemos definir worker_num = 1 na configuração, mas isso diminui o desempenho.

 

Conclusão

Swoole, como tudo, tem seus lados brilhantes e cantos escuros. Eu acho que ainda é uma boa idéia trazer programação assíncrona para PHP. Ele pode ser usado em vários casos, desde prototipagem rápida, por microsserviços concisos de responsabilidade única, servidores de jogos de baixa latência e terminando sendo um servidor de back-end para grandes estruturas. Prometendo mesmo.

https://tsh.io/blog/swoole-is-it-node-in-php-or-am-i-wrong/

Share
About Author

Renato

Developer

Add a Comment
Comments 0 Comments

No comments yet! Be the first to comment