Qual é o status de E / S assíncrona POSIX (AIO)?

93

Existem páginas espalhadas pela web que descrevem os recursos do POSIX AIO em vários detalhes. Nenhum deles é terrivelmente recente. Não está claro o que exatamente eles estão descrevendo. Por exemplo, o site "oficial" (?) Para suporte de I / O assíncrono do kernel Linux aqui diz que os soquetes não funcionam, mas as páginas de manual "aio.h" em minha estação de trabalho Ubuntu 8.04.1 parecem sugerir que ele funciona para descritores de arquivo arbitrários. Depois, há outro projeto que parece funcionar na camada da biblioteca com ainda menos documentação.

Eu gostaria de saber:

  • Qual é o objetivo do POSIX AIO? Dado que o exemplo mais óbvio de uma implementação que posso encontrar diz que ela não oferece suporte a soquetes, a coisa toda parece estranha para mim. É apenas para E / S de disco assíncrono? Se sim, por que a API hipergeral? Se não, por que a E / S de disco foi a primeira coisa a ser atacada?
  • Onde há exemplos de programas POSIX AIO completos que posso ver?
  • Alguém realmente usa isso, de verdade?
  • Quais plataformas suportam POSIX AIO? Que partes eles apóiam? Alguém realmente apóia o implícito "Qualquer I / O para qualquer FD" que <aio.h>parece promissor?

Os outros mecanismos de multiplexação disponíveis para mim são perfeitamente bons, mas os fragmentos aleatórios de informação flutuando por aí me deixaram curioso.

Glifo
fonte

Respostas:

27

E / S de rede não é uma prioridade para AIO porque todos os que escrevem servidores de rede POSIX usam uma abordagem sem bloqueio baseada em eventos. A abordagem de "bilhões de threads de bloqueio" do Java no estilo antigo é horrível.

A E / S de gravação de disco já está armazenada em buffer e a E / S de leitura de disco pode ser pré-buscada no buffer usando funções como posix_fadvise. Isso deixa a E / S de disco direta e sem buffer como a única finalidade útil para AIO.

E / S direta sem buffer só é realmente útil para bancos de dados transacionais, e aqueles tendem a escrever seus próprios threads ou processos para gerenciar a E / S de disco.

Então, no final, isso deixa o POSIX AIO na posição de não servir a nenhum propósito útil. Não use isso.

Zan Lynx
fonte
8
Que tal ler / gravar de sistemas de arquivos de rede (NFS, Samba)?
Alex B
1
bem. Eu tenho vários grandes escritores idiotas que, se eu deixá-los ir para o cache, atingirão a proporção de dirty_ratio em picos, bloqueando todos os outros. Se eu apenas usar IO direto neles, é muito lento. Se eu tivesse apenas 1 thread, poderia gerenciar sozinho, mas será difícil suportar diferentes prioridades de IO em 1 banda de rodagem. AIO + CFQ realmente pareceria uma boa combinação, se AIO funcionasse
n-alexander
37
Discordo. E / S de disco tende a ser armazenada em buffer, mas pode estar bloqueando. Quando poll () ing um arquivo FD, ele sempre relata que o FD é legível, mesmo quando irá bloquear. Isso torna impossível realizar operações sem bloqueio em arquivos de disco de maneira acidental, a menos que se use threads ou AIO.
Hongli
2
@Matt: A ordem não é importante para sockets de datagrama. @Zan: E / S assíncrona é muito bom para pré-buffer de dados de streaming em tempo real, por exemplo, reprodutores de mídia.
Ben Voigt
13
Não é verdade que AIO é inútil em sistemas baseados em eventos. Você pode realmente obter uma rede de cópia zero com AIO adequada, o que não é possível com a notificação baseada em eventos para recv (). Outras coisas podem conspirar para tornar isso principalmente uma limitação teórica, mas acho que a falta de um AIO adequado (a la OVERLAPPED no Windows) é um dos últimos grandes buracos no Linux.
Jon Watte de
69

Fazer E / S de soquete de forma eficiente foi resolvido com kqueue, epoll, portas de conclusão de IO e outros semelhantes. Fazer E / S de arquivo assíncrono é meio tardio (além da E / S sobreposta do Windows e do suporte inicial solaris para posix AIO).

Se você está procurando fazer socket I / O, provavelmente é melhor usar um dos mecanismos acima.

O principal objetivo do AIO é, portanto, resolver o problema de E / S de disco assíncrono. É mais provável que seja por isso que o Mac OS X suporta apenas AIO para arquivos regulares, e não soquetes (já que kqueue faz isso muito melhor de qualquer maneira).

As operações de gravação são normalmente armazenadas em cache pelo kernel e eliminadas posteriormente. Por exemplo, quando o cabeçote de leitura do drive passa pelo local onde o bloco deve ser escrito.

No entanto, para operações de leitura, se você deseja que o kernel priorize e ordene suas leituras, AIO é realmente a única opção. Aqui está porque o kernal pode (teoricamente) fazer isso melhor do que qualquer aplicativo de nível de usuário:

  • O kernel vê todas as E / S de disco, não apenas seus trabalhos de disco de aplicativos, e pode ordená-los em um nível global
  • O kernel (pode) saber onde está o cabeçote de leitura do disco e pode escolher as tarefas de leitura que você passa para ele na ordem ideal, para mover o cabeçote na menor distância
  • O kernel pode tirar vantagem da fila de comandos nativos para otimizar ainda mais suas operações de leitura
  • Você pode ser capaz de emitir mais operações de leitura por chamada de sistema usando lio_listio () do que com readv (), especialmente se suas leituras não forem (logicamente) contíguas, economizando um pouquinho de sobrecarga de chamada de sistema.
  • Seu programa pode ser um pouco mais simples com AIO, já que você não precisa de um thread extra para bloquear em uma chamada de leitura ou gravação.

Dito isso, posix AIO tem uma interface bastante estranha, por exemplo:

  • O único meio eficiente e bem suportado de retorno de chamada de evento é por meio de sinais, o que torna difícil o uso em uma biblioteca, pois significa usar números de sinal do namespace de sinal global de processo. Se o seu sistema operacional não suporta sinais em tempo real, isso também significa que você tem que percorrer todas as suas solicitações pendentes para descobrir qual delas realmente terminou (esse é o caso do Mac OS X, por exemplo, não do Linux). A captura de sinais em um ambiente multithread também cria algumas restrições complicadas. Normalmente, você não pode reagir ao evento dentro do manipulador de sinal, mas tem que gerar um sinal, escrever em um pipe ou usar signalfd () (no linux).
  • lio_suspend () tem os mesmos problemas que select (), não se ajusta muito bem ao número de jobs.
  • lio_listio (), conforme implementado, tem um número bastante limitado de jobs que você pode passar, e não é trivial encontrar esse limite de forma portável. Você tem que chamar sysconf (_SC_AIO_LISTIO_MAX), que pode falhar, neste caso você pode usar o AIO_LISTIO_MAX define, que não está necessariamente definido, mas então você pode usar 2, que é definido como garantido para ser suportado.

Quanto à aplicação do mundo real usando posix AIO, você poderia dar uma olhada em lighttpd (lighty), que também postou uma medição de desempenho ao introduzir o suporte.

A maioria das plataformas posix suporta posix AIO agora (Linux, BSD, Solaris, AIX, tru64). O Windows oferece suporte por meio de E / S de arquivo sobreposto. Meu entendimento é que apenas Solaris, Windows e Linux realmente suportam assíncrono. arquivo de E / S até o driver, enquanto os outros sistemas operacionais emulam o assíncrono. E / S com threads de kernel. Linux sendo a exceção, sua implementação posix AIO em glibc emula operações assíncronas com threads de nível de usuário, enquanto sua interface de E / S assíncrona nativa (io_submit () etc.) é verdadeiramente assíncrona até o driver, assumindo que o driver suporte isso .

Acredito que seja bastante comum entre os sistemas operacionais não suportar posix AIO para qualquer fd, mas restringi-lo a arquivos regulares.

Arvid
fonte
O Windows teve E / S OVERLAPPED suportando arquivos de disco desde que o Win32 foi lançado. Não é nada novo. E no POSIX, o namespace de sinal não é global de processo, é por thread. Os sinais são entregues a threads particulares (ou aio é uma exceção a isso, não se lembra com certeza?).
Ben Voigt,
1
Não há como especificar para qual thread o AIO entrega seus sinais. No linux, parece entregá-lo principalmente ao thread que emitiu o comando aio _ * (), mas nem sempre (a única solução que encontrei para isso foi criar vários signalfds). Houve um patch para o Linux na lista de discussão do kernel alguns anos atrás que adicionaria isso, mas nunca chegou, e teria sido uma extensão do POSIX. No Mac OS X, os sinais parecem ser entregues principalmente ao thread principal (na minha experiência). Eu não acho que POSIX requer um comportamento específico, se exigir, eu adoraria ver a parte da especificação.
Arvid
5
A implementação de aio_read / write da glibc usa threads em userland, então nem mesmo threads de kernel são usados ​​aqui.
Marenz
O que significa "sempre normalmente"? As gravações são armazenadas em cache pelo kernel para qualquer método ou ao usar AIO? Parece que deve haver uma maneira de o software ter certeza de que a gravação foi concluída com êxito; caso contrário, a integridade e as metas transacionais não podem ser cumpridas.
MikeB
Outro exemplo ativo onde você pode usar AIO é o nginx. Todos os modos são suportados. Se você preferir descarregar para threads de usuário, você normalmente achará muito pior do que o IO direto, mas o AIO nativo do Linux está no mesmo nível do IO direto. A situação em que AIO pode ser substancialmente benéfica é a forte pressão do cache de página. A diferença conceitual entre Async e Direct IOs pode ser vista aqui ftp.dei.uc.pt/pub/linux/kernel/people/suparna/aio-linux.pdf
pavio
2

Existe aio_write - implementado em glibc; a primeira chamada da função aio_read ou aio_write gera uma série de threads de modo de usuário, aio_write ou aio_read post solicitações para essa thread, a thread faz pread / pwrite e quando termina a resposta é postada de volta para a thread de chamada bloqueada.

Também é 'real' aio - suportado pelo nível do kernel (precisa do libaio para isso, veja a chamada io_submit http://linux.die.net/man/2/io_submit ); também precisa de O_DIRECT para isso (também pode não ser suportado por todos os sistemas de arquivos, mas os principais suportam)

Veja aqui:

http://lse.sourceforge.net/io/aio.html

http://linux.die.net/man/2/io_submit

Diferença entre POSIX AIO e libaio no Linux?

MichaelMoser
fonte
Muitas das deficiências de aio_writesão abordadas acima, em stackoverflow.com/a/5307557/13564
Glyph