a) O tal “log assíncrono” que implementei é bem boboca: a ideia é que os métodos que precisam logar alguma coisa, em vez de escreverem diretamente no arquivo, ponham a string a ser logada em uma fila*. Essa fila, por sua vez, é consumida periodicamente por uma thread que grava os dados em arquivo. As complicações, é claro, aparecem quando você precisa ter logs rotacionados (ou seja, para o arquivo não ficar muito grande, a ideia é renomear o arquivo que ficou muito grande, fechá-lo, e abrir um outro arquivo. ). Há algumas sutilezas que podem aparecer quando, por exemplo, alguém usa algum utilitário para examinar o tal arquivo de log ENQUANTO a aplicação está funcionando.
b) Tem de ser, porque ao você ínserir alguma coisa em um banco de dados (e supondo que a tabela tenha uma chave primária, o que normalmente é verdade), os seguintes passos normalmente são efetuados pelo seu servidor de bancos de dados, e vários deles exigem acesso a disco (mesmo que “delayed”):
- O registro é gravado sequencialmente no log de transações (um arquivo basicamente sequencial, como o arquivo-texto que citei anteriormente);
- Quando o processo de “journaling” do seu banco de dados é efetuado, no final da transação, os dados são movidos do log de transações para a sua tabela, que normalmente é representada como uma b-tree**. Como você deve saber bem, uma b-tree é uma árvore balanceada em disco, e pode ser que, por algum motivo, seja necessário efetuar o “split” do nó que está sendo gravado, porque ele encheu. Isso quer dizer que uma simples gravação de um registro pode ocasionar vários acessos ao disco.
- Se a tabela tiver mais índices (o que é inevitável quando você quer usar a tabela para fazer análises e emitir relatórios), então os outros índices também têm de ser atualizados. Arquivos de índices normalmente também são representados como b-trees.
- O pico de utilização de memória pode ocorrer, por exemplo, se a aplicação gera muitos dados durante muito tempo, de forma que você não consiga gravar tudo que está tentando ser logado em arquivo. Aí a fila vai crescer, crescer e crescer até que a aplicação fique mais ociosa.
** A menos que você especifique, no momento de criação de sua tabela, que você queira representá-la como uma tabela hash. Tabelas hash são de uso bem mais limitado, porque é necessário especificar o valor correto da chave para encontrar algo rapidamente e os registros não ficam “ordenados”.