Como os servidores da web “ouvem” endereços IP, interrompem ou pesquisam?

86

Estou tentando entender os detalhes mais baixos dos servidores da web. Eu estou querendo saber se um servidor, digamos Apache, está continuamente pesquisando novos pedidos ou se funciona por algum tipo de sistema de interrupção. Se é uma interrupção, o que está provocando a interrupção, é o driver da placa de rede?

    
por user2202911 09.11.2014 / 21:39

2 respostas

181

A resposta curta é: algum tipo de sistema de interrupção. Essencialmente, eles usam E / S de bloqueio, o que significa que eles dormem (bloqueiam) enquanto esperam por novos dados.

  1. O servidor cria um soquete de escuta e bloqueia enquanto aguarda novas conexões. Durante esse tempo, o kernel coloca o processo em um estado suspensão interrompível e executa outros processos. Este é um ponto importante: ter a pesquisa do processo continuamente desperdiçaria a CPU. O kernel é capaz de usar os recursos do sistema de forma mais eficiente, bloqueando o processo até que haja trabalho a ser feito.

  2. Quando novos dados chegam à rede, a placa de rede emite uma interrupção.

  3. Vendo que há uma interrupção da placa de rede, o kernel, através do driver da placa de rede, lê os novos dados da placa de rede e os armazena na memória. (Isso deve ser feito rapidamente e geralmente é tratado dentro do manipulador de interrupções).

  4. O kernel processa os dados recém-chegados e os associa a um soquete. Um processo que está bloqueando nesse soquete será marcado como executável, o que significa que agora ele está qualificado para ser executado. Ele não é necessariamente executado imediatamente (o kernel pode decidir executar outros processos ainda).

  5. A seu gosto, o kernel irá ativar o processo do servidor web bloqueado. (Desde que agora é executável.)

  6. O processo do servidor da Web continua executando como se nenhum tempo tivesse passado. Sua chamada de sistema de bloqueio retorna e processa novos dados. Então ... vá para o passo 1.

por 09.11.2014 / 22:14
7

Existem muitos detalhes "inferiores".

Primeiro, considere que o kernel tem uma lista de processos e, a qualquer momento, alguns desses processos estão em execução e outros não. O kernel permite a cada processo em execução uma fatia do tempo da CPU, depois a interrompe e passa para a próxima. Se não houver processos executáveis, então o kernel provavelmente emitirá uma instrução como HLT para a CPU que suspende a CPU até lá é uma interrupção de hardware.

Em algum lugar no servidor, há uma chamada de sistema que diz "me dê algo para fazer". Existem duas grandes categorias de maneiras que isso pode ser feito. No caso do Apache, ele chama accept em um soquete que o Apache abriu anteriormente, provavelmente escutando na porta 80 O kernel mantém uma fila de tentativas de conexão, e adiciona a essa fila toda vez que um TCP SYN é recebido. Como o kernel sabe que um TCP SYN foi recebido depende do driver do dispositivo; para muitos NICs, provavelmente há uma interrupção de hardware quando os dados de rede são recebidos.

accept pede que o kernel retorne para mim o próximo início de conexão. Se a fila não estava vazia, então accept apenas retorna imediatamente. Se a fila estiver vazia, o processo (Apache) será removido da lista de processos em execução. Quando uma conexão é iniciada mais tarde, o processo é retomado. Isso é chamado de "bloqueio", porque para o processo que o chama, accept() parece uma função que não retorna até que tenha um resultado, o que pode demorar algum tempo a partir de agora. Durante esse tempo, o processo não pode fazer mais nada.

Quando o accept for retornado, o Apache saberá que alguém está tentando iniciar uma conexão. Em seguida, chama fork para dividir o processo do Apache em dois processos idênticos. Um desses processos passa a processar a solicitação HTTP, as outras chamadas accept novamente para obter a próxima conexão. Assim, há sempre um processo mestre que não faz nada além de chamar accept e gerar subprocessos, e então há um subprocesso para cada solicitação.

Isso é uma simplificação: é possível fazer isso com encadeamentos em vez de processos, e também é possível fork , portanto, há um processo de trabalho pronto para ser processado quando uma solicitação é recebida, reduzindo assim a sobrecarga de inicialização. Dependendo de como o Apache está configurado, pode fazer qualquer uma dessas coisas.

Essa é a primeira ampla categoria de como fazer isso, e é chamada de bloqueio de E / S porque as chamadas do sistema como accept e read e write que operam em sockets suspenderão o processo até que eles tenham algo para devolver.

A outra maneira ampla de fazer isso é chamada de não-bloqueio ou baseada em evento ou E / S assíncrona . Isso é implementado com chamadas de sistema como select ou epoll . Cada um faz a mesma coisa: você dá a eles uma lista de sockets (ou, em geral, descritores de arquivos) e o que você quer fazer com eles, e o kernel bloqueia até que esteja pronto para fazer uma dessas coisas.

Com este modelo, você pode dizer ao kernel (com epoll ), "Diga-me quando houver uma nova conexão na porta 80 ou novos dados para ler em qualquer uma dessas 9471 outras conexões abertas". epoll bloqueia até que uma dessas coisas esteja pronta, então você faz isso. Então você repete. Chamadas de sistema como accept e read e write nunca bloqueiam, em parte porque, quando você as chama, epoll acabou de informar que elas estão prontas, então não há razão para bloquear, e também porque quando você abra o soquete ou o arquivo que você especificar que deseja no modo de não bloqueio, para que essas chamadas falharão com EWOULDBLOCK em vez de bloquear.

A vantagem deste modelo é que você precisa apenas de um processo. Isso significa que você não precisa alocar uma pilha e estruturas de kernel para cada solicitação. Nginx e HAProxy usam este modelo, e é um grande razão eles podem lidar com tantas conexões mais do que o Apache em um hardware similar.

    
por 12.11.2014 / 20:38