Configurando tmpfs '/ run / lock' para centenas de milhares de arquivos de bloqueio de 0 byte, e lidando com o limite de inode

2

Eu tenho uma situação em que preciso criar centenas de milhares de arquivos de bloqueio de 0 byte para controle de concorrência.

Eu testei criá-los usando:

for i in 'seq 1 50000'; do touch "/run/lock/${i}.lock"; done

Como os arquivos são 0 bytes, eles não criam nenhum espaço na partição. Olhando para df -h :

Filesystem      Size  Used Avail Use% Mounted on
tmpfs            50M  344K   49M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            246M     0  246M   0% /run/shm
none            100M     0  100M   0% /run/user

A figura 0% não é alterada na linha /run/lock .

No entanto, o tamanho da memória aumenta em uma média de aproximadamente 1 KB por arquivo de bloqueio. Descobri isso comparando free -h antes e depois de criar 70.000 arquivos de bloqueio dentro de /run/lock . Esse aumento de memória foi refletido no uso da memória real (memória virtual menos os buffers / cache).

Mais tarde, descobri que esse aumento de 1 KB é mais provável devido aos inodes. Então eu verifiquei o uso do inodo usando df -i :

Filesystem      Inodes  IUsed   IFree IUse% Mounted on
tmpfs            62729    322   62407    1% /run
none             62729  50001   12728   80% /run/lock
none             62729      1   62728    1% /run/shm
none             62729      2   62727    1% /run/user

Como você pode ver, os arquivos de bloqueio aumentam os inodes dentro da partição /run/lock .

Atualmente, estou no Ubuntu e as /run montagens não são refletidas em /etc/fstab . A execução de mount me dá:

tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)

Eu tenho algumas perguntas sobre isso (mas a primeira é a mais importante):

  1. Como eu aumento o limite de inode permanentemente para /run/lock ? Então esse limite sobrevive a reinicializações?
  2. Seria melhor para mim criar meu próprio diretório e montar o tmpfs nele para usá-lo, em vez de usar /run/lock ?
  3. O limite de tamanho de cada partição é completamente independente um do outro? Isso é armazenar arquivos em /run não parece afetar /run/lock e vice-versa.
  4. O 1KB é derivado do inode? Percebi que ao criar arquivos não vazios, o bloco básico é de 4KB para cada arquivo.
  5. Por que /run recebe o tipo de sistema de arquivos tmpfs , mas /run/lock , /run/shm , /run/user fornece "nenhum" ao tipo de sistema de arquivos, especialmente porque todos eles são suportados pelo TMPFS? Por que eles não são todos lidos como tmpfs na coluna Filesystem ?
  6. Se todos os diretórios forem restringidos de maneira independente, como o assassino OOM manipula uma situação em que há várias partições TMPFS completas, cada uma delas dimensionada para 50% da RAM e onde também há processos disputando RAM bem. Obviamente, não se pode usar mais de 100% da RAM. De acordo com o link , ele menciona que o sistema estará em deadlock. Como isso funciona?
por CMCDragonkai 03.08.2015 / 09:45

2 respostas

1

Respondendo a algumas de suas perguntas, em ordem:

  1. Você pode usar mount -o remount,nr_inodes=NUM /run/lock no script de inicialização do aplicativo (no caso de ser executado com uid = 0). Também deve ser seguro adicionar uma linha relevante a / etc / fstab , mas não testou.
  2. A separação faz algum sentido aqui, pois no caso de preencher todos os inodes não irá interferir com o resto do sistema.
  3. Sim, completamente independente.
  4. [...]
  5. Com sistemas de arquivos virtuais (não baseados em dispositivos), você pode colocar qualquer dispositivo como no comando mount, é apenas o tipo que importa.
  6. [...]

Não tenho certeza se seu aplicativo cria arquivos vazios abrindo-o (e por quanto tempo), mas você também pode considerar aumentar o limite de arquivos abertos (verifique ulimit ), para evitar esgotamento.

    
por 03.08.2015 / 11:54
0

Você está fazendo isso na direção errada. Você pode usar a semântica do sistema de arquivos para reforçar a consistência.

  1. Quando você quiser ler um arquivo, basta abrir e ler. Você deve sempre usar open , nunca access para esta operação. Se você estiver usando uma biblioteca PHP para fazer isso, verifique se ele apenas chama open e não access no arquivo - mas fopen deve funcionar bem.

  2. Quando você quiser atualizar ou criar um novo arquivo, execute as seguintes operações: -

    • Crie um novo arquivo usando um mecanismo de criação de arquivo temporário. Se um não existir - crie um novo nome de arquivo que é improvável que exista (filename.XXXXXX, em que X é substituído por caracteres aleatórios). Certifique-se de abrir em O_EXCL.
    • Grave os dados relevantes no arquivo.
    • Renomeie o arquivo com o nome do arquivo antigo.

Isso é operacionalmente seguro, porque as renomeações são definidas como atômicas. Um leitor abrindo o arquivo verá o arquivo antigo ou o novo arquivo, mas nunca um arquivo inexistente no cache.

No pior dos casos, com muitas verificações simultâneas de cada arquivo, um número de gravadores irá substituir um ao outro brevemente. Mas isso é muito mais barato do que usar um bloqueio de arquivo em cada arquivo.

Como alternativa, em vez de ter um arquivo de bloqueio para cada arquivo - considere, na verdade, apenas bloquear cada objeto de cache individual diretamente. Eu ainda não acho que isso seria escalar no entanto.

Usar as semânticas rename e link nesse caso garante consistência com seu cache e é muito mais barato gerenciar do que bloquear arquivos.

    
por 03.08.2015 / 10:20