O AIO fsync poderia melhorar o desempenho do dpkg?

O AIO fsync poderia melhorar o desempenho do dpkg?

O gerenciador de pacotes Debian poderia dpkgobter uma melhoria notável de desempenho usando uma das operações AIO fsync(), em vez de sync_file_range() + fsync()?

A API fsync2() [proposta] é essencialmente idêntica à API AIO_FSYNC/AIO_FDSYNC existente, exceto que é síncrona e é isso que os aplicativos desejam evitar.

O único argumento que me foi apresentado contra [usar] AIO_FSYNC é que "a implementação é apenas uma fila de trabalho", o que é em grande parte sem sentido porque é independente da implementação do sistema de arquivos, mas permite a paralelização automática do lado do kernel de todas as operações fsync emitidas. Isso permite que o (s) sistema (s) de arquivos otimizem automaticamente as gravações desnecessárias do diário ao concluir operações fsync simultâneas - XFS, ext4, etc. já fazem isso quando os aplicativos do usuário executam fsync() simultaneamente a partir de muitos processos/threads.....

Esta implementação simples permite uma carga de trabalho simples de "descompactar com aio fsync" (ou seja, "escrever muitos arquivos de 4kB e aio_fsync() em lotes à medida que avançamos, retirando fsync()s completos antes de enviarmos um novo lote") carga de trabalho no XFS para ir de cerca de 2.000 arquivos/s (latência de E/S de gravação síncrona vinculada) a mais de 40.000 arquivos/s (iops de gravação vinculados ao armazenamento de back-end).

--Dave Chinner

A carga de trabalho de exemplo tem semelhanças com apt-get installou dpkg -i(em parte dependendo do tamanho dos arquivos nos pacotes instalados :-). dpkgdeve efetivamente fsync() todos os arquivos descompactados, antes de renomeá-los no lugar.

dpkgfoi otimizado usando conselhos de Ted T'so. A otimização consiste em adicionar chamadas para sync_file_range() em determinados pontos. Esta chamada de sistema faznãofornecem as mesmas garantias que fsync(). Por favor, leia a documentação paraintervalo_de_arquivo_sincronizado()e observe o aviso proeminente :-).

Nenhuma dessas operações grava os metadados do arquivo. Portanto, a menos que o aplicativo execute substituições estritamente de blocos de disco já instanciados, não há garantias de que os dados estarão disponíveis após uma falha.

dpkgaciona o write-back de dados imediatamente após gravar cada arquivo, usando SYNC_FILE_RANGE_WRITE. Ele grava todos os arquivos do pacote primeiro. Em seguida, há uma segunda passagem pelos arquivos, que aguarda o write-back dos dados usando SYNC_FILE_RANGE_WAIT_BEFORE, chama fsync()e, finalmente, renomeia o arquivo no lugar.

Veja commits:

Minha hipótese é que paralelizar as operações fsync() poderia melhorar o desempenho, permitindo lotes mais eficientes dometadadosgrava, particularmente agrupando em lote as barreiras associadas/liberações de cache de disco que são necessárias para garantir que os metadados no disco sejam consistentes em todos os momentos.

EDIT: Parece que minha hipótese era muito simples, pelo menos ao usar o sistema de arquivos ext4:

A segunda série de chamadas sync_file_range(), com a operação SYNC_FILE_RANGE_WAIT_BEFORE, será bloqueada até que o write-back iniciado anteriormente seja concluído. Isto basicamente garante que a alocação atrasada foi resolvida; isto é, os blocos de dados foram alocados e gravados, e o inode atualizado (na memória), mas não necessariamente enviado para o disco.

A chamada [fsync()] forçará o inode para o disco. No caso do sistema de arquivos ext4, o primeiro [fsync()] irá realmente enviar todos os inodes para o disco, e todas as chamadas [fsync()] subsequentes são, na verdade, sem operação (assumindo que os arquivos 'a', 'b' e 'c' estejam todos no mesmo sistema de arquivos). Mas o que isso significa é que minimiza o número de commits (pesados) do jbd2 ao mínimo.

Ele usa uma chamada de sistema específica do Linux ---sync_file_range() --- mas o resultado deve ser um desempenho mais rápido em todos os sistemas de arquivos. Portanto, não considero isso um hack específico do ext4, embora provavelmente torne as coisas mais rápidas para o ext4 do que qualquer outro sistema de arquivos.

--Ted T'so

Pode ser que algum outro sistema de arquivos se beneficie do uso de operações AIO fsync().

bcachefs(em desenvolvimento) afirma isolar IO entre arquivos diferentes muito melhor que o ext4. Portanto, isso pode ser particularmente interessante de testar.

Parece que o ext4 pode não ser tão otimizado para um padrão AIO fsync() puro (acho que outros sistemas de arquivos também poderiam ter a mesma restrição). Nesse caso, suponho que seria possível fazer todas as mesmas chamadas sync_file_range() primeiro, depois iniciar todas as operações AIO fsync() como uma segunda rodada e terminar renomeando todos os arquivos no lugar como fsync() operações concluídas.


VELHO:

O primeiro passo em tal investigação deve ser a medição :-).

É possível desabilitar a parte fsync(), usando echo "force-unsafe-io" > /etc/dpkg/dpkg.cfg.d/force-unsafe-io.

Até agora, tentei rodar apt-get installem strace -f -wc, em um contêiner Debian 9. Por exemplo, instalando o aptitudepacote usando "unsafe io", existem apenas 495 chamadas fsync() síncronas. Durante a instalação aptitudenormalmente, existem 1011 chamadas fsync(). "unsafe io" também desativou a SYNC_FILE_RANGE_WAIT_BEFOREchamada, reduzindo o número de chamadas sync_file_range() de 1036 para 518.

No entanto, ficou muito menos claro se isso reduziu o tempo médio gasto. Se isso aconteceu, não parece ser mais do que a variação aleatória entre as execuções. Até agora, testei isso em ext4 e XFS, em um HDD mecânico.


apt-getdiz que o tamanho total dos 518 arquivos descompactados foi de 21,7 MB (veja o resultado abaixo).

Em relação às chamadas 495 fsync(), que permaneceram presentes mesmo ao solicitar "inseguro io":

No ext4, a saída do strace mostrou o tempo gasto nas chamadas fsync() restantes em cerca de 11 segundos. No XFS, o valor correspondente foi de cerca de 7 segundos. Em todos os casos, esse foi o tempo necessário para a instalação aptitude.

Portanto, mesmo que "inseguro io" esteja proporcionando uma pequena melhoria na instalação aptitude, parece que você precisaria /varser montado em um dispositivo significativamente mais rápido (menor latência) do que o resto do sistema, antes que a diferença fosse realmente perceptível. Mas não estou interessado em otimizar esse nicho.

A execução em strace -f -y -e trace=fsync,renamemostrou que, para as chamadas fsync() restantes, 2 delas estavam ativadas /etc/ld.so.cache~e 493 delas eram para arquivos dentro, /var/lib/dpkg/ou seja, o banco de dados do pacote.

318 das chamadas fsync() estão em /var/lib/dpkg/updates/. Estes são incrementos no banco de dados dpkg /var/lib/dpkg/status. Os incrementos são acumulados no banco de dados principal ("checkpointed") no final da execução do dpkg.


The following NEW packages will be installed:
  aptitude aptitude-common libboost-filesystem1.62.0 libboost-iostreams1.62.0 libboost-system1.62.0 libcgi-fast-perl libcgi-pm-perl
  libclass-accessor-perl libcwidget3v5 libencode-locale-perl libfcgi-perl libhtml-parser-perl libhtml-tagset-perl libhttp-date-perl
  libhttp-message-perl libio-html-perl libio-string-perl liblwp-mediatypes-perl libparse-debianchangelog-perl libsigc++-2.0-0v5 libsqlite3-0
  libsub-name-perl libtimedate-perl liburi-perl libxapian30
0 upgraded, 25 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/6000 kB of archives.
After this operation, 21.7 MB of additional disk space will be used.

Responder1

A questão sugere que isso não ajudará no ext4 ou no XFS.

Também testei a instalação de um pacote muito maior ( linux-image-4.9.0-9-amd64). Ainda parecia levar o mesmo tempo, independentemente de --force-unsafe-io.

ext2

No ext2, --force-unsafe-ioreduziu o tempo de instalação linux-imagede 50 segundos para 13 segundos.

O kernel em que executei os testes foi o 5.0.17-200.fc29.x86_64, que usa CONFIG_EXT4_USE_FOR_EXT2.

Testei ext2 usando a implementação aio_fsync() do espaço do usuário. No entanto, a melhor melhoria não dependeu do uso do AIO fsync().

Minha melhora foi na verdade devido a um efeito colateral. Eu mudei o dpkg para fazer todas as operações fsync() primeiro e depois todas as operações rename(). Enquanto o dpkg sem patch chamava rename() após cada fsync(). Usei profundidades de fila AIO de até 256. AIO fsync() com profundidade de fila 1 foi significativamente mais lento que fsync() síncrono - parece que houve alguma sobrecarga. A melhor melhoria também exigia a realização de todas as SYNC_FILE_RANGE_WRITEoperações originais primeiro. A versão melhorada foi instalada linux-imageem cerca de 18 segundos.

Esta ordem de operações é na verdade o que Ted T'so sugeriu originalmente :-D. O que acontece é que CONFIG_EXT4_USE_FOR_EXT2fsync() também sincroniza o diretório pai de maneira útil. Você deseja fazer toda a manipulação do nome do arquivo primeiro, para evitar várias atualizações no disco para cada diretório. Acho que isso não acontece com a CONFIG_EXT2implementação antiga ou com um ext4sistema de arquivos normal.

ext4: faça fsync para sincronizar o diretório pai sem diário de verdade desta vez

[...] Isso também inclui o modo padrão ext2, obviamente. [...]

https://elixir.bootlin.com/linux/v5.0.17/source/fs/ext4/fsync.c#L38

 * If we're not journaling and this is a just-created file, we have to
 * sync our parent directory (if it was freshly created) since
 * otherwise it will only be written by writeback, leaving a huge
 * window during which a crash may lose the file.  This may apply for
 * the parent directory's parent as well, and so on recursively, if
 * they are also freshly created.

Como antes, substituir o estágio fsync() por sync() parece fornecer um desempenho perturbadoramente bom, correspondendo --force-unsafe-io:-). sincronizar() ou sincronizar() parecem ser muito bons se você conseguir usá-los.

btrfs

Quando comecei a testar aio_fsync() no btrfs, descobri que as operações fsync() podem causar o bloqueio de rename() do arquivo, devido a uma correção recente de integridade de dados. Decidi que não estou interessado em btrfs.

Por que rename() demora mais quando fsync() é chamado primeiro?

informação relacionada