Restic: lidar com grande poda muito mais eficiente

Criado em 4 fev. 2019  ·  52Comentários  ·  Fonte: restic/restic

Saída de restic version

restic 0.9.3 compilado com go1.10.4 em linux/amd64

O que restic deve fazer diferente? Qual funcionalidade você acha que devemos adicionar?

Em geral, gosto muito de restic, e a criação/recuperação de snapshots funciona perfeitamente.
Mas executar restic com repositórios grandes é quase impossível. Tenho um repositório com 5 TB/30 snapshots.
A intenção era fazer isso como um buffer circular (remover o mais antigo, adicionar o mais novo).

Adicionar um instantâneo e removê-lo funciona perfeitamente, mas como você necessariamente precisa podar seu repositório, pode levar SEMANAS para liberar apenas 1 TB (por causa da reescrita).
Isso torna quase impossível usar restic já que você não pode criar novos snapshots durante esse período.

Como você já mencionou aqui
você pode fazer algo para melhorar isso.

Exemplo:
encontrou 5967884 de 7336415 blobs de dados ainda em uso, removendo 1368531 blobs
excluirá 144.850 pacotes e reescreverá 142.751 pacotes, isso libera 1,082 TiB (levou 2 semanas!)

Especialmente em repositórios remotos onde você acabou de comprar armazenamento (com acesso ssh) e os recursos da CPU são limitados, é muito mais rápido carregar todo o repositório novamente.

prune feature enhancement

Comentários muito úteis

Eu tenho trabalhado nisso recentemente. Aqui está o que eu fiz:

  • Carregue o índice existente em vez de verificar todos os pacotes (e, em seguida, verifique todos os pacotes que não estavam no índice)
  • Verificação paralela dos instantâneos para blobs usados
  • Reescrevendo em paralelo pacotes parcialmente usados
  • Escreva o novo índice usando as informações do índice já na memória

Atualmente estou trabalhando para descobrir o nível de paralelismo a ser usado para reescrever pacotes parcialmente usados ​​(estou planejando basear isso no número configurado de conexões para o back-end). Eu também preciso fazer muito mais testes em vários cenários de erro.

Aqui estão alguns números de desempenho (usando um repositório com 875 GiB de dados, cerca de 180.000 pacotes e 36 snapshots, usando um servidor de descanso de loopback como back-end):

  • Código atual:

    • 35-40 minutos (cada) para construir o índice no início e no final da poda (70-80 minutos no total)

    • 4-5 minutos para encontrar blobs usados

    • Alguns segundos para reescrever pacotes parcialmente usados

  • Minhas mudanças até agora:

    • Alguns segundos para carregar o índice existente (um pouco mais se precisar verificar pacotes não indexados)

    • Menos de 2 minutos para encontrar blobs usados

    • Alguns segundos para escrever o novo índice

Também estou planejando configurar um caso de teste gerado que envolverá muito mais reescrita de pacotes.

Todos 52 comentários

Com desempenho para restaurações para grandes repositórios/repos com arquivos grandes agora resolvidos pela ramificação fora de ordem de @ifedorenko , parece que este é o próximo pedregulho para usar restic em ambientes de vários terabytes onde o repositório não está no local disk e não está sendo acessado por meio do servidor REST em uma interface de loopback.

Atualmente, uma poda vazia (remoção de um snapshot 100% idêntico a um snapshot anterior) em um repositório em um bucket S3 local de AZ em instâncias de ponta da AWS com largura de banda teórica de 10 gbit/s é executada em:

1) construção de novo índice -- ~ 160 pacotes/segundo
2) encontrar dados ainda em uso - total de 56 segundos
3) pacotes de reescrita -- ~3 pacotes/segundo

160 pacotes/segundo é lento, mas ainda tolerável (~80 minutos de tempo de execução contra um repositório de 3 TB).

Mas a reescrita @ 3 pacotes/segundo será executada por quase 10 horas, mesmo para o meu noop prune (excluirá 0 pacotes e reescreverá 111098 pacotes, isso libera 180,699 GiB). Para uma redução significativa em um repositório grande, você congela os novos backups por mais de 24 horas.

Parece que as reescritas do pacote atualmente acontecem em um único thread, portanto, permitir que isso seja executado em vários trabalhadores pode ajudar um pouco, mesmo que a cópia atual e a abordagem de limpeza sejam mantidas.

Pessoalmente, eu não gastaria tempo otimizando a implementação da poda de bloqueio atual, acho que a poda sem bloqueio é a melhor solução a longo prazo.

Eu tenho trabalhado nisso recentemente. Aqui está o que eu fiz:

  • Carregue o índice existente em vez de verificar todos os pacotes (e, em seguida, verifique todos os pacotes que não estavam no índice)
  • Verificação paralela dos instantâneos para blobs usados
  • Reescrevendo em paralelo pacotes parcialmente usados
  • Escreva o novo índice usando as informações do índice já na memória

Atualmente estou trabalhando para descobrir o nível de paralelismo a ser usado para reescrever pacotes parcialmente usados ​​(estou planejando basear isso no número configurado de conexões para o back-end). Eu também preciso fazer muito mais testes em vários cenários de erro.

Aqui estão alguns números de desempenho (usando um repositório com 875 GiB de dados, cerca de 180.000 pacotes e 36 snapshots, usando um servidor de descanso de loopback como back-end):

  • Código atual:

    • 35-40 minutos (cada) para construir o índice no início e no final da poda (70-80 minutos no total)

    • 4-5 minutos para encontrar blobs usados

    • Alguns segundos para reescrever pacotes parcialmente usados

  • Minhas mudanças até agora:

    • Alguns segundos para carregar o índice existente (um pouco mais se precisar verificar pacotes não indexados)

    • Menos de 2 minutos para encontrar blobs usados

    • Alguns segundos para escrever o novo índice

Também estou planejando configurar um caso de teste gerado que envolverá muito mais reescrita de pacotes.

Courtney:

Parece super promissor! Queria confirmar que esta é a filial em que você está trabalhando? Estou feliz em testar.

https://github.com/cbane/restic/tree/prune-aggressive

Não, esse branch faz parte do fork do repositório principal. Ainda não enviei minhas alterações para nenhum lugar público. Devo ser capaz de enviar minha versão de trabalho em andamento para o GitHub em alguns dias para que você possa experimentá-la.

OK, eu tenho uma versão que deve estar pronta para outras pessoas experimentarem. É neste ramo: https://github.com/cbane/restic/tree/prune-speedup

Limitações atuais:

  • Não implementei nenhuma configuração automática do número de trabalhadores de reempacotamento. Por enquanto, defina a variável de ambiente RESTIC_REPACK_WORKERS para o número de trabalhadores que você deseja usar. O padrão será 4 se não estiver definido.
  • Preciso trabalhar no tratamento de erros ao reembalar. Não fiz nenhuma alteração real do reempacotamento de thread único existente; Eu preciso examinar os vários casos de erro e ter certeza de que fazer o reempacotamento em paralelo não causa nenhum problema.

Hum, isso parece incrível. Obrigado por seu trabalho!

Eu testei isso um pouco com uma cópia do repositório de 3 TB + no Amazon S3 e até agora parece incrível. Uma poda de reempacotamento que levaria semanas agora é concluída em menos de uma hora, e isso está usando EBS relativamente lento como espaço tmp.

Um verdadeiro divisor de águas aqui! Excelente trabalho, @cbane!

Eek, eu percebi que tinha errado a corrida.

Uma área que ainda é de encadeamento único e parece que poderia se beneficiar da paralelização é a etapa "verificação de pacotes que não estão no índice" - que ainda pode levar de 3 a 4 horas em repositórios de vários terabytes - mas isso ainda é um enorme, melhora enorme, obrigado!

@cbane Não consegui abrir um problema no seu fork, então deixe-me saber se há um lugar melhor para isso.

Durante outra execução de teste, o repack falhou no final (reescrevendo o último pacote), rodando com 32 trabalhadores:

found 1396709 of 2257203 data blobs still in use, removing 860494 blobs
will remove 0 invalid files
will delete 119301 packs and rewrite 88485 packs, this frees 896.269 GiB
using 32 repack workers
Save(<data/c136027b25>) returned error, retrying after 723.31998ms: client.PutObject: Put https://ak-logical-db-backup.s3.dualstack.us-west-1.amazonaws.com/xxxxx: Connection closed by foreign host https://ak-logical-db-backup.s3.dualstack.us-west-1.amazonaws.com/xxxx. Retry again.
Save(<data/09d4692900>) returned error, retrying after 538.771816ms: client.PutObject: Put https://ak-logical-db-backup.s3.dualstack.us-west-1.amazonaws.com/xxxxx: Connection closed by foreign host https://ak-logical-db-backup.s3.dualstack.us-west-1.amazonaws.com/xxxxx. Retry again.
Save(<data/23d0d4f842>) returned error, retrying after 617.601934ms: client.PutObject: Put https://ak-logical-db-backup.s3.dualstack.us-west-1.amazonaws.com/xxxx: Connection closed by foreign host https://ak-logical-db-backup.s3.dualstack.us-west-1.amazonaws.com/xxxx. Retry again.
[10:02] 100.00%  88484 / 88485 packs rewritten
panic: reporting in a non-running Progress

goroutine 386596 [running]:
github.com/restic/restic/internal/restic.(*Progress).Report(0xc42011c2c0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0)
        internal/restic/progress.go:122 +0x242
github.com/restic/restic/internal/repository.Repack.func2(0x8, 0xe17f58)
        internal/repository/repack.go:66 +0x136
github.com/restic/restic/vendor/golang.org/x/sync/errgroup.(*Group).Go.func1(0xc4389246c0, 0xc56f509160)
        vendor/golang.org/x/sync/errgroup/errgroup.go:57 +0x57
created by github.com/restic/restic/vendor/golang.org/x/sync/errgroup.(*Group).Go
        vendor/golang.org/x/sync/errgroup/errgroup.go:54 +0x66

Tenho uma nova versão disponível, na mesma filial de antes. Eu também rebasei contra master .

Aqui estão as principais mudanças da versão anterior:

  • Converteu o reempacotamento de ter cada trabalhador fazendo todas as etapas de reempacotamento de um único pacote em um pipeline.
  • Corrigida a falha relatada no final da reembalagem.
  • O reempacotamento agora dimensiona automaticamente o número de trabalhadores para os estágios do pipeline com base no número de CPUs e no limite de conexão configurado para o back-end. (A variável de ambiente RESTIC_REPACK_WORKERS não é mais usada.)
  • Pequenos ajustes para encontrar blobs usados.
  • Paralelizou a varredura de pacotes desconhecidos.

Eu ainda quero fazer mais algum trabalho em encontrar blobs usados. Atualmente, cada instantâneo é processado por um único trabalhador. Isso pode deixar os recursos da CPU não utilizados se houver menos instantâneos do que CPUs ou se houver grandes diferenças de tamanho entre os instantâneos. Eu gostaria que ele espalhasse o processamento de subárvores entre diferentes trabalhadores; Acho que sei como fazer isso, só preciso realmente implementá-lo.

Eu me inclinaria a continuar discutindo coisas sobre esse problema (ou o futuro pull request para isso), para que tudo fique aqui no repositório principal em vez de se espalhar.

Apenas testado. Ele resolve a falha no final da reembalagem e funciona muito, muito bem.

O único local adicional que poderia se beneficiar do paralelismo aumentado é a exclusão de pacotes, que atualmente é de thread único.

Isso é particularmente difícil durante a primeira poda de um repositório que não pode ser removido anteriormente, pois há muitos pacotes que precisam ser excluídos.

Mesmo com a exclusão de encadeamento único, no entanto, um esquecer/limpar diariamente em um repositório de pacotes de 1,7 TB e 356 mil que reescreve pacotes de 14,7 mil e exclui pacotes de 33 mil agora leva pouco menos de 20 minutos.
Anteriormente, era impossível podar.

Excelente trabalho, obrigado!

OK, eu tenho outra versão disponível. A única mudança real desta vez é que agora exclui pacotes não utilizados em paralelo (além de alguns pequenos ajustes em algumas alterações anteriores). Implementei a verificação de instantâneo modificada, mas ela não acelerou o suficiente e não havia uma boa maneira de relatar o progresso ao usuário, então a removi novamente.

Estou planejando abrir um pull request para isso em breve, assumindo que nada quebrou. (Mas vou limpar o histórico primeiro.) @fd0 , você quer dar uma olhada nisso primeiro?

Funcionou muito bem em nosso teste. Reescreveu 30 mil pacotes em 225 segundos, excluiu 73 mil pacotes em 50 segundos.

O tempo de execução total contra um repositório de 1,74 TiB no S3 com 32 snapshots sobreviventes foi de pouco mais de 6 minutos.

Trabalho brilhante.

@cbane eu tentei seu branch https://github.com/cbane/restic/tree/prune-speedup

mas este é o erro que recebo :(

root<strong i="9">@srv</strong> ~/restic-backups # restic --no-cache prune
repository 49b87c6a opened successfully, password is correct
listing files in repo
loading index for repo
[0:28] 1.01%  30 / 2982 index files
pack cbbebd8d already present in the index
github.com/restic/restic/internal/index.(*Index).AddPack
    internal/index/index.go:266
github.com/restic/restic/internal/index.Load.func1
    internal/index/index.go:230
github.com/restic/restic/internal/repository.(*Repository).List.func1
    internal/repository/repository.go:640
github.com/restic/restic/internal/backend.(*RetryBackend).List.func1.1
    internal/backend/backend_retry.go:133
github.com/restic/restic/internal/backend/rest.(*Backend).listv2
    internal/backend/rest/rest.go:423
github.com/restic/restic/internal/backend/rest.(*Backend).List
    internal/backend/rest/rest.go:358
github.com/restic/restic/internal/backend.(*RetryBackend).List.func1
    internal/backend/backend_retry.go:127
github.com/cenkalti/backoff.RetryNotify
    vendor/github.com/cenkalti/backoff/retry.go:37
github.com/restic/restic/internal/backend.(*RetryBackend).retry
    internal/backend/backend_retry.go:36
github.com/restic/restic/internal/backend.(*RetryBackend).List
    internal/backend/backend_retry.go:126
github.com/restic/restic/internal/repository.(*Repository).List
    internal/repository/repository.go:634
github.com/restic/restic/internal/index.Load
    internal/index/index.go:202
main.pruneRepository
    cmd/restic/cmd_prune.go:202
main.runPrune
    cmd/restic/cmd_prune.go:128
main.glob..func18
    cmd/restic/cmd_prune.go:28
github.com/spf13/cobra.(*Command).execute
    vendor/github.com/spf13/cobra/command.go:762
github.com/spf13/cobra.(*Command).ExecuteC
    vendor/github.com/spf13/cobra/command.go:852
github.com/spf13/cobra.(*Command).Execute
    vendor/github.com/spf13/cobra/command.go:800
main.main
    cmd/restic/main.go:86
runtime.main
    /snap/go/3947/src/runtime/proc.go:200
runtime.goexit
    /snap/go/3947/src/runtime/asm_amd64.s:1337

@antetna Parece que seu repositório tem vários arquivos de índice que cobrem os mesmos pacotes. Não sei como isso pode acontecer, mas adicionei um caso de teste para o conjunto de testes e posso reproduzir seu erro. Vou trabalhar para consertá-lo.

@antetna OK, acabei de enviar uma nova versão para o mesmo branch (não fast-forward) que funciona com meu caso de teste de índice duplicado. Você poderia tentar?

Estou planejando abrir um pull request com a versão atual deste branch em breve, a menos que alguém perceba algum problema.

Muito obrigado @cbane! A poda padrão levou cerca de 55 horas para remover meu repositório de instantâneos de ~ 860 GB 12000+. Com sua abordagem paralela mais agressiva, reduziu para pouco mais de 3 horas.

Olá @cbane , trabalho incrível!

Executando este PR aqui no Debian 9 amd64, compilado com Go 1.12.1, obtendo o seguinte erro após 220 minutos de execução no meu repositório de 30 TB:

checking for packs not in index
[0:52] 16.45%  178 / 1082 packs
[5:23] 100.00%  1082 / 1082 packs
repository contains 3213929 packs (259446787 blobs) with 15.025 TiB
processed 259446787 blobs: 30090 duplicate blobs, 4.906 GiB duplicate
load all snapshots
find data that is still in use for 3 snapshots
[0:04] 0.00%  0 / 3 snapshots
tree 6f144a19eaae0e81518b396bfdfc9dd5c6c035bdba28c6a90d6f70e692aa1c55 not found in repository
github.com/restic/restic/internal/repository.(*Repository).LoadTree
        internal/repository/repository.go:707
github.com/restic/restic/internal/restic.FindUsedBlobs.func3
        internal/restic/find.go:52
github.com/restic/restic/internal/restic.FindUsedBlobs.func3
        internal/restic/find.go:74
github.com/restic/restic/internal/restic.FindUsedBlobs.func3
        internal/restic/find.go:74
github.com/restic/restic/internal/restic.FindUsedBlobs.func3
        internal/restic/find.go:74
github.com/restic/restic/internal/restic.FindUsedBlobs.func4
        internal/restic/find.go:89
gopkg.in/tomb%2ev2.(*Tomb).run
        vendor/gopkg.in/tomb.v2/tomb.go:163
runtime.goexit
        /usr/local/go/src/runtime/asm_amd64.s:1337

Como devo me recuperar disso?

Obrigado,
-- Durval.

@DurvalMenezes Parece que seu repositório está faltando alguns arquivos de pacote. Você já podou antes? restic check tem sucesso? Se isso não acontecer, deve dar-lhe uma ideia mais detalhada do que está errado.

Você pode recuperar um pouco executando restic rebuild-index e, em seguida, executando um novo backup. Se algo nos pacotes ausentes ainda estiver disponível no local do backup, um novo backup o adicionará ao repositório novamente. Isso pode fazer com que seus backups existentes funcionem novamente. Se isso não resolver, acho que você precisará esquecer os instantâneos afetados antes de poder fazer uma poda.

Obrigado pela resposta, @cbane. Mais, abaixo:

Você já podou antes?

Não, esta é a minha primeira ameixa. Para encurtar a história: meu repositório tem ~ 95 instantâneos de 3 dirtrees locais no meu NAS; esses 3 dirtrees totalizam ~30TB e ~60M de arquivos/subdiretórios, e estão demorando cada vez mais para fazer backup, a ponto de fazer backup de apenas 24 horas de novos dados (abaixo de 10GB) estava levando mais de 24 horas para ser executado. O conselho no fórum era executar restic forget (o que eu fiz, deixando apenas os últimos 3 instantâneos) e depois restic prune , o que fiz primeiro usando restic 0.9.5 (mas abortou depois de ~ 24 horas devido a OOM). Em seguida, atualizei a máquina (uma VM no Google Compute Cloud) para o dobro da RAM e usei seu PR, que deu o erro acima.

A verificação restic é bem-sucedida? Se isso não acontecer, deve dar-lhe uma ideia mais detalhada do que está errado.

Estou executando restic check nas últimas 90 horas (também usando seu PR), e até agora me deu esta saída: restic-check-PARTIAL_output.txt

Conforme observado no final do arquivo acima, restic check exibiu sua mensagem mais recente ("verificar instantâneos, árvores e bolhas") há mais de 3 dias... Estou começando a me perguntar que está travado e nunca terminará :-/ Na verdade, um "strace" no processo mostra que ele abre o mesmo arquivo de cache local repetidamente:

```data; strace -t -f -p 2608 -e abre em 2>&1 | grep aberto | egrep -v inacabado\|retomada | cabeça
Ter, 23 de julho 00:41:59 UTC 2019
[Pid 26508] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2608] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 10
[Pid 2615] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 5482] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2615] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 3688] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 5482] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 10
[Pid 2608] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 11
[Pid 2638] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2638] 00:41:59 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5

And then, almost 10 hours later: 

Ter, 23 de julho 10:14:27 UTC 2019
[Pid 2632] 10:14:27 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2639] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2634] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2613] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2634] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 3688] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2617] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 3688] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2634] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
[Pid 2611] 10:14:28 openat (AT_FDCWD, "/ tmp / restic-check-cache-370688148 / abb62ab49b950e4b2ab5eb82c4386a9b199a08eb6fd93bdaccd0e4dbe10d29a2 / data / 53 / 53d242f8d6444bc2bd49e6689b4c7688fec8996c5e86863bf146a9eb28f54b5d", O_RDONLY | O_CLOEXEC) = 5
```

Você pode recuperar um pouco executando o índice de reconstrução restic e, em seguida, executando um novo backup. Se algo nos pacotes ausentes ainda estiver disponível no local do backup, um novo backup o adicionará ao repositório novamente. Isso pode fazer com que seus backups existentes funcionem novamente

Acho que vou tentar isso em seguida; se este restic check não terminar nas próximas 24 horas, eu vou SIGINT e então executo um restic rebuild-index . Para o índice de reconstrução, devo usar este PR? A cabeça-mestre de restic? Ou outra coisa?

Obrigado novamente,
-- Durval.

Sim, isso não parece promissor. Provavelmente, a melhor coisa a fazer é fazer um restic rebuild-index , depois executar novos backups de seus três diretórios e esquecer todos os outros instantâneos. Depois disso, você deve ser capaz de fazer um restic prune com sucesso.

Eu não toquei no código rebuild-index , então você pode fazer isso com a versão que quiser.

@cbane , apenas para mantê-lo informado: eu comecei um restic rebuild-index usando seu PR há 5 dias (eu entendo que qualquer versão serviria, mas usar o seu torna as coisas mais simples) e está em execução desde então. Após os primeiros dias desesperadores (quando extrapolando as porcentagens parecia indicar que funcionaria por mais de 30 dias), ele parece ter ganhado alguma velocidade e deve funcionar por 'apenas' mais 10 dias ou mais (pelo menos em sua atual fase de 'contagem de arquivos no repositório').

Presumindo que este rebuild-index termine bem, o plano é então executar um restic prune com seu PR. Vai deixar você saber como vai.

Mantendo todos atualizados: meu crédito gratuito de $ 300 GCloud terminou, totalmente devorado pela VM de 104 GB que tive que criar para executar o prune (e, presumo, também o rebuild-index ). Estou ficando sem opções :-/ Atualizarei quando/se eu encontrar uma saída para essa bagunça.

Eu tentei o branch "prune-speedup" e os resultados são muito promissores!

Back-end: S3

# bin/restic version
restic 0.9.5 compiled with go1.12.4 on linux/amd64
# bin/restic prune
repository 6240cd5d opened successfully, password is correct
counting files in repo
building new index for repo
[1:30:34] 100.00%  319784 / 319784 packs
repository contains 319784 packs (5554019 blobs) with 1.445 TiB
processed 5554019 blobs: 0 duplicate blobs, 0 B duplicate
load all snapshots
find data that is still in use for 30 snapshots
[3:38:52] 100.00%  30 / 30 snapshots
found 5376708 of 5554019 data blobs still in use, removing 177311 blobs
will remove 0 invalid files
will delete 3526 packs and rewrite 4850 packs, this frees 26.925 GiB
[1:28:21] 100.00%  4850 / 4850 packs rewritten
counting files in repo
[1:20:27] 100.00%  314240 / 314240 packs
finding old index files
saved new indexes as [b7029105 797145b1 0ed8981e 7f19c455 dff4d9be a52d8e7a 0cf9f266 ab32a9e4 f34331b3 84c84cbb 563896c9 9902e35d 817ef96c 6b4dcfef 32d3e18c 1d782d96 b12554dd d4b69bcf 8ec94a43 66cbd035 8e9cb96d d74b5246 ca7d7ca3 1f209708 9fe26189 28414ee2 88ff07fb 24280466 8757a1f9 8706ff35 5fab942b 549409c3 f781a762 9417afec 4b2361aa 6b43f992 8da8dfe7 54ec498e 5be6fb8a 17411b83 270f3ce3 ba520d35 95913ad0 f8f15108 cbc67971 a419ff7c 875cfcc7 13f55ece bd488aa4 7f5b588a cddd40b4 7a79d1ce bd7e3d0f 2cdcd635 ee6e28c3 98146287 50867bde 41a056ae 836ce971 e9451c8b 0f9cc7e6 52dedc04 c4e8e7f6 2e4966f0 ba4fa5b3 ddc9a766 b995fd36 fd6b3ac8 1c12bcc3 4c98c3c9 39ac7cd5 42ebf4c1 1a48465e b5245192 73a73c5e daa6ee8d d26ce697 9f84d9b3 bc371def b141466a 6906b3c1 282ce115 d8024363 10f0b924 ad4fad64 9450aada 31378365 65d785b3 98b085d0 768f420c f22512b3 be3223ba 031d5488 f2b7fcf6 87177471 fd269664 b239b89e 6bf972ea 0d6f8f36 87362542 fff9c2cd 5c85ac76 f91daae1 dc594a83 220bdc83]
remove 1459 old index files
[2:33] 100.00%  8376 / 8376 packs deleted
done
# 

Agora com a versão dev:

# bin/restic_linux_amd64 version
restic 0.9.5-dev (compiled manually) compiled with go1.12.4 on linux/amd64
# bin/restic_linux_amd64 prune
repository 6240cd5d opened successfully, password is correct
counting files in repo
building new index for repo
[57:21] 100.00%  314240 / 314240 packs
repository contains 314240 packs (5376708 blobs) with 1.419 TiB
processed 5376708 blobs: 0 duplicate blobs, 0 B duplicate
load all snapshots
find data that is still in use for 29 snapshots
[1:48:18] 100.00%  29 / 29 snapshots
found 5356653 of 5376708 data blobs still in use, removing 20055 blobs
will remove 0 invalid files
will delete 212 packs and rewrite 1427 packs, this frees 3.114 GiB
[14:16] 100.00%  1427 / 1427 packs rewritten
counting files in repo
[57:47] 100.00%  313618 / 313618 packs
finding old index files
saved new indexes as [004d6eb2 630de131 1b85faed 0fb7a978 bc500e05 34f7d187 447c3b59 ada047d2 5430430e 768f606e a5c341ea a75059c5 71d0fbec c63f5c56 ba43e69d f47699f5 d7cd2587 5826bcae 6250ec67 6af77aa4 cbf8c1f9 a7809b5f c3242748 8bb7d037 8ca69481 5a8877c3 fb30ea48 4bdb6269 eeeba466 7cdc444a bc15ddd5 c5544612 b8a5004c 2879403a c33778b7 e692013a 41ce8a1d 55b4be0a 5714b820 1adca569 b06ccd6b 16467da7 79ed066a 64c7e397 43217ede af7350a4 73c65a0f 35260990 a232ea42 c843bfa5 332aded7 0e294517 26984755 3c36a14b 68b2024e 267bf0b2 a41c4f64 aa46affb c7a6e2ac 0d34c60f 766d21f0 0d7b8b41 4fea4363 a1a3c5cd 73809a0e 56a67410 25314d47 a32ded24 68feae36 78ef5cbb b051a740 6a51f900 d2ee860f 1ad44787 c6c4358d 89de2f69 a157bd2b 77995b94 3bc58934 b905be42 0a1df2e7 ba67a98c 263b5266 7a809abc 34ff6f07 d96adc12 8f69fc74 ebb053eb 8fb68f6a 11224e7d 990f61f8 764941fc ed95513b 1c17c8aa 3226a7cb 76988c78 e4d8f156 b4d4c952 8c379d51 e968f3c9 f9cfff55 464cf3e1 f9d23c32 136957e3 02e397b1]
remove 105 old index files
[0:32] 100.00%  1639 / 1639 packs deleted
done
#

Parece uma grande melhoria! Parabéns!
Vou postar mais resultados se eu experimentar mais máquinas nas próximas semanas.

@fbarbeira A partir da saída que você postou, parece que você não está realmente usando minha versão aprimorada. Aqui está a saída que recebo quando eu podo meu grande repositório no Backblaze B2:

repository 399dfab1 opened successfully, password is correct
listing files in repo
loading index for repo
[0:02] 100.00%  71 / 71 index files
checking for packs not in index
repository contains 208840 packs (1675252 blobs) with 1006.203 GiB
processed 1675252 blobs: 0 duplicate blobs, 0 B duplicate
load all snapshots
find data that is still in use for 32 snapshots
[0:16] 100.00%  32 / 32 snapshots
found 1675113 of 1675252 data blobs still in use, removing 139 blobs
will remove 0 invalid files
will delete 4 packs and rewrite 24 packs, this frees 26.404 MiB
[3:31] 100.00%  24 / 24 packs rewritten
saving new index
[10:31] 70 index files
remove 71 old index files
[0:04] 100.00%  28 / 28 packs deleted
done

A principal fonte de lentidão nisso é a velocidade limitada de upload no meu modem a cabo.

A saída de restic version também deve ser algo assim:

restic 0.9.5 (v0.9.5-31-g09b92d6d) compiled with go1.11.6 on linux/amd64

Alguma intenção de mesclar esta atualização @fd0 ?

Eu apreciaria muito essa melhoria tornando-o em um lançamento oficial também. A rotação de backup tornou-se tão lenta que o restic está começando a não ser mais uma opção, infelizmente.

@cbane , um item que definitivamente não é um bloqueador, mas pensei em sinalizar: as reescritas do pacote de ameixas ficam mais lentas à medida que os repositórios crescem.

Por exemplo, a etapa de reescrita de pacote para um repositório de 3.984.097 pacotes reescreve pacotes a 110 pacotes/segundo em um i3.8xlarge conversando com um bucket do S3 na mesma AZ.

A mesma combinação de instância + armazenamento de apoio com um repositório menor (450.473) reescreve a 200 pacotes/segundo.

@pmkane , essa disparidade de velocidade existe mesmo se eles estiverem reescrevendo o mesmo número de pacotes? Ou está sempre lá, não importa quantos pacotes estejam sendo reescritos? Além disso, é apenas a reescrita do pacote ou outros estágios também diminuem?

Não há nada óbvio no código que o tornaria mais lento à medida que o repositório aumentasse. Adicionei suporte à criação de perfil ao estágio de reescrita do pacote em minha versão local para ajudar a rastrear a origem da lentidão. No entanto, meu maior repositório tem apenas cerca de 200.000 pacotes, o que não me dá uma boa comparação para o que você está vendo. Você estaria disposto a executá-lo com a criação de perfil habilitada e disponibilizar os arquivos de saída?

@cbane , não tenho certeza se é uma função do número de pacotes ou do tamanho do repositório. Posso executar alguns testes em uma duplicata do nosso repositório menor e ver. Feliz por executar uma versão com perfil e compartilhar os resultados.

Alguns exemplos de tempos para o repositório do pacote de 460k -- tempos de 3,7 mm a seguir:

carregando índice para repo
[0:01] 100,00% 154/154 arquivos de índice

encontrar dados que ainda estão em uso para 36 instantâneos
[0:34] 100,00% 36/36 instantâneos
[0:26] 100,00% 4555/4555 pacotes reescritos (175 pacotes/segundo)
[0:21] 151 arquivos de índice
[0:01] 100,00% 11.401 / 11.401 pacotes excluídos

3.752.505 pacotes de recompra. Também vale a pena notar que o uso de memória aumenta de ~ 1 GB RSS para 8 GB RSS na etapa "encontrar dados que ainda estão em uso para 14 instantâneos". Restic eventualmente acaba em ~16GB RSS. Talvez inevitável, dado o grande tamanho do repositório:

carregando índice para repo
[0:33] 100,00% 1188/1188 arquivos de índice

encontrar dados que ainda estão em uso para 14 instantâneos
[2:12] 100,00% 14/14 instantâneos
[49:07] 100,00% 339187 / 339187 pacotes reescritos (115 pacotes/segundo)
salvando novo índice
[10:59] 1176 arquivos de índice
remover 1188 arquivos de índice antigos
[4:51] 100,00% 409728 / 409728 pacotes excluídos

@cbane , peço desculpas. Red herring nas velocidades de poda - quando eu estava fazendo alguns perfis independentes, notei que os dois repositórios estavam em AZs diferentes, então a diferença era inteiramente devido à latência diferente para a AZ mais distante.

Em nosso repositório grande (20.791TiB, 40.522.693 blobs), estamos recebendo o seguinte erro ao remover na etapa "encontrar dados que ainda estão em uso":

árvore 5e40b6de93549df6443f55f0f68f24bf36671e28590579c78bc62f7557490c56 não encontrada no repositório
github.com/restic/restic/internal/repository.( Repositório).LoadTreeinternal/repository/repository.go:711github.com/restic/restic/internal/restic.FindUsedBlobs.func3interno/restic/find.go:52github.com/restic/restic/internal/restic.FindUsedBlobs.func3interno/restic/find.go:74github.com/restic/restic/internal/restic.FindUsedBlobs.func4internal/restic/find.go:89gopkg.in/tomb%2ev2.( Tomb).run
vendedor/gopkg.in/tomb.v2/tomb.go:163
runtime.goexit
/usr/lib/golang/src/runtime/asm_amd64.s:1337

todos os backups foram concluídos com êxito e uma verificação restic não retorna nenhum erro.

Qualquer escavação adicional que valha a pena fazer aqui, @cbane ?

Um índice de reconstrução permitiu que a poda fosse bem-sucedida. Não tenho certeza se há uma boa maneira de tornar a poda mais resiliente, para que ela possa resolver o problema nativamente.

Hmm, recebi o mesmo erro novamente hoje. Resolvido com um índice de reconstrução, mas estou começando a me perguntar se a própria poda pode estar causando o problema. Um cheque restic volta limpo a cada vez.

árvore 7dc9112b587a2b67a2459e6badf7c14f986408e05dbe8a68e7458a30740ea951 não encontrada no repositório
github.com/restic/restic/internal/repository.( Repositório).LoadTreeinternal/repository/repository.go:711github.com/restic/restic/internal/restic.FindUsedBlobs.func3interno/restic/find.go:52github.com/restic/restic/internal/restic.FindUsedBlobs.func3interno/restic/find.go:74github.com/restic/restic/internal/restic.FindUsedBlobs.func4internal/restic/find.go:89gopkg.in/tomb%2ev2.( Tomb).run
vendedor/gopkg.in/tomb.v2/tomb.go:163
runtime.goexit
/usr/lib/golang/src/runtime/asm_amd64.s:1337

Fazemos restaurações completas uma vez por semana para verificar a integridade do backup, para complementar as restaurações diárias de arquivos pontuais.

Embora a verificação restic não tenha mostrado nenhum problema com o backup, as restaurações completas falham devido a um blob ausente. Então, parece que algo pode ter sido podado ao longo do caminho que não deveria.

Não está claro se é um bug no branch speedup, algo no código de poda base ou algo completamente diferente. Infelizmente, não tenho um grande caso de teste reproduzível, mas esta é a segunda vez que vimos esse tipo de corrupção de repositório com nosso maior repositório. Nossos repositórios menores não mostraram nenhum problema.

Infelizmente, testar com poda de estoque é impossível, devido ao tamanho dos repositórios.

Vamos reverter para o snapshot do EBS, por enquanto, mas continuaremos monitorando esse problema e outros e teremos prazer em testar onde faz sentido!

Eu adicionei um pequeno PR #2507 que deve melhorar a situação. Agradeceria se alguns de vocês pudessem fazer alguns testes sobre isso...
Obrigado!

Lendo o código de poda - o reempacotamento lê os blobs e salva os novos pacotes em série. Se você estiver reempacotando pela rede, esse será o gargalo.

@DurvalMenezes seu NAS está na rede local ou pela internet? Se na rede local você se conecta a ela via wifi ou ethernet?

Parece que uma vitória fácil seria paralelizar a leitura de blobs / salvar pacotes na rede.


Separadamente, eu me pergunto se uma estratégia melhor seria tentar fazer a poda incremental em vez disso. Algo como a coleção de fósseis de duas etapas da duplicação: https://github.com/gilbertchen/duplicacy/wiki/Lock-Free-Deduplication#two -step-fossil-collection

Separadamente, eu me pergunto se uma estratégia melhor seria tentar fazer a poda incremental em vez disso. Algo como a coleção de fósseis de duas etapas da duplicação: https://github.com/gilbertchen/duplicacy/wiki/Lock-Free-Deduplication#two -step-fossil-collection

Por favor, veja #1141 para uma discussão sobre este tópico.

Os dois novos comandos 'cleanup-index' e 'cleanup-packs' do PR #2513 também devem melhorar muito a situação. Com esses comandos, você pode fazer uma poda sem reempacotar se seu repositório estiver são.

Então, acidentalmente, fiz duas coisas: executei um backup de hora em hora 11 vezes por hora em vez de 1 e não executei meu trabalho de esquecimento nos últimos 384 dias. Eu tenho 101417 instantâneos. Achei que seria muito lento esquecer / podar isso, acho que vou excluí-lo.

Você pode experimentar o nº 2718 - no entanto, não há melhorias para "esquecer" os instantâneos.
Se a etapa de esquecer é o seu problema, eu aconselho você a:

  • descubra quais instantâneos você deseja manter, por exemplo, examinando seus últimos logs de backup ou apenas fazendo outro backup.
  • exclua todos, exceto esses arquivos manualmente do diretório /snapshots do seu repositório
  • depois disso, execute prune (se quiser com #2718)

Eu só queria mantê-los por alguns dias, então vou excluir todo o diretório no S3 e começar de novo. Comecei o processo de esquecimento e estava demorando muito, pensei que o branch mais novo ajudaria (não parece), ou pelo menos alguém poderia achar divertido.

Eu realmente quero experimentar este branch (ou realmente, gostaria que fosse puxado para o master). tentei testar e conseguir

Fatal: não é possível abrir o arquivo de configuração: Stat: O AWS Access Key Id que você forneceu não existe em nossos registros.

Funciona sem problemas usando a compilação mestre. Também consegui usar o branch em https://github.com/restic/restic/pull/2340 sem problemas.

Posso usar esse branch em um repositório montado em NFS, apenas o repositório armazenado da AWS não funciona. Não faço ideia de como resolver...

obrigado por todo o bom trabalho independentemente

@vtwaldo21 Qual branch você experimentou? Era #2718?
Sua mensagem de erro indica que você tem algum problema com suas credenciais da AWS. Isso também pode explicar por que o NFS funcionou sem problemas.

Outros comandos restic funcionam com seu repositório da AWS?

@aawsome , eu sou um idiota e transpus os números da ramificação/edição e as coisas realmente confundiram. Desculpe.

A ramificação 2718 funcionou bem (nos repositórios com suporte da AWS e do NFS). Não posso dizer definitivamente que foi mais rápido ou não, pois ainda está em execução
Branch 2340, foi o único com o problema e por que eu estava neste tópico do fórum.

Branch 2340 é baseado em 0.9.5, um pouco mais antigo, mas não tão ruim. Eu estava fazendo testes simples como este:

binário restic é o caminho é instalado apenas via RPM (0.9.6)

instantâneos de descanso
[funciona]
instantâneos restic.2718/restic
[funciona]
instantâneos restic.2340/restic
Fatal: não é possível abrir o arquivo de configuração: Stat: O AWS Access Key Id que você forneceu não existe em nossos registros.

Portanto, embora o erro implique algo com credenciais da AWS, estou literalmente executando os comandos de volta para trás sem alterações de variável. Parece que há algo mais errado com este ramo.

Minhas ameixas levam dias para um repositório de ~ 2 TB, muito interessado em 2718 e 2340 sendo mesclados no master

@cbane muito obrigado por todo o seu trabalho! Acabamos de mesclar o nº 2718, que retrabalha o código de remoção, e acho que resolve esse problema, assim como o nº 2340.

Sinto muito pela forma como lidamos com sua contribuição, espero que você possa aceitar minhas desculpas. :desapontado:

Conversei com @MichaelEischer , ele mencionou que o PR #2340 inclui mais ideias que ainda não foram implementadas, então estou reabrindo esta edição.

@cbane você está interessado em trabalhar conosco para mesclar essas ideias no código atual? Eu posso entender totalmente se não, então vamos passar pelo seu PR e extraí-los nós mesmos :)

Também tivemos uma breve discussão ontem e tentamos identificar o que pode ter dado errado, para que possamos fazer melhor da próxima vez. Alguns pontos que identificamos foram:

  • O PR alterou uma área altamente sensível no código (prune, que finalmente remove os dados), por isso precisa de um escrutínio extra
  • @MichaelEischer e @aawsome tentaram revisar o PR e disseram que era muito grande
  • O PR foi apenas dois commits, um deles substituiu todo o código por outro, código completamente diferente, isso é muito difícil de revisar
  • O PR incluiu pelo menos 4-5 ideias e melhorias diferentes, o que dificulta ainda mais a revisão

Alguma outra coisa que eu perdi?

As alterações em cmd_prune.go de #2340 são, até onde posso ver, completamente substituídas por #2718 e #2842 por @aawsome . #3006 também substitui as alterações index/index.go.

Eu extraí a implementação de caminhada em árvore altamente paralelizada de checker.go (veja https://github.com/MichaelEischer/restic/tree/streamtrees), que permite implementar um paralelo FindUsedBlobs com alguns linhas de código adicionais. Também é reutilizável para o comando de cópia. Minha ramificação mencionada também unifica o código usado para paralelizar o carregamento de índice e instantâneo. Vou dividir o ramo em PRs menores.

Isso parece deixar o uso da contagem de conexão de back-end e GOMAXPROCS para se ajustar automaticamente ao paralelismo de IO/CPU como parte restante do #2340.

Percebi que nem o #2340 nem o outro prune PR atualmente paralelizam o upload do índice reescrito.

Esta página foi útil?
0 / 5 - 0 avaliações