Назад | Перейти на главную страницу

Чрезмерный размер инкрементной резервной копии в BareOS

У меня есть установка BareOS с очень небольшими изменениями в файлах конфигурации по умолчанию. Выполняется полное, инкрементное и дифференциальное резервное копирование. Похоже, что для большинства клиентов выполняется резервное копирование, как и ожидалось.

Однако один из моих клиентов, похоже, неоднократно выполняет резервное копирование более 10% всей файловой системы в каждом инкрементном цикле.

Как найти самые большие файлы и папки, резервные копии которых выполняются повторно?

BAT, по-видимому, здесь не очень полезен, поскольку он перечисляет только размер самого узла файла, а не весь размер папки. Я действительно ищу du команда, которая работает в рамках BareOS для конкретной попытки резервного копирования.

Хотя я ценю усилия @damiano-verzulli, обсуждение на IRC-канале BareOS на FreeNode ускользнуло от этого ответа:

Оказывается, Кьетил Торгрим Хомме уже написал для этого скрипт под названием bacula-du. (Наряду с множеством других полезных скриптов!)

Все они перечислены и доступны здесь:

http://heim.ifi.uio.no/kjetilho/hacks/

В частности bacula-du объясняется так:

Usage: bacula-du [OPTIONS] -j JOBID 
       Summarize disk usage of directories included in the backup JOBID

Main options are:   
    -a, --all             write counts for all files, not just directories
    -S, --separate-dirs   do not include size of subdirectories   
    -t, --threshold=SIZE  skip output for files or directories with usage below SIZE.  default is 1 octet.   
    -L, --largest=NUM     only print NUM largest directories/files 

There is also an alternate mode which can be useful as a faster alternative to a verify job.

Usage: bacula-du --md5sum -j JOBID   --md5sum              
       output list of all files in job in md5sum format 

bacula-du (версия 1.4)

Я должен добавить сюда одну небольшую заметку. Чтобы это работало, он должен иметь доступ к базе данных (очевидно). В конфигурации по умолчанию он использует механизм безопасности на основе пользователя, поэтому вы должны запустить команду как пользователь bareos, чтобы она работала, например

$ sudo -u bareos ./bacula-du -j 1429
done reading database.
   807160 /log/
     6372 /var/openldap-data/
     6372 /var/
   813532 /admin/
...
119983392 /

Обратите внимание, что важный добавлено обновление в конце первой части


К сожалению, даже если очень легко проверить, что именно произошло с конкретной резервной копией, получить размер файла резервной копии не так просто.

Давайте рассмотрим несколько примеров глубже.

В моем случае от bconsole Я могу получить список последних вакансий:

*list jobs
 Automatically selected Catalog: CatalogoBareos
 Using Catalog "CatalogoBareos"
 +-------+------------------------+---------------------+------+-------+------------+-------------------+-----------+
 | JobId | Name                   | StartTime           | Type | Level | JobFiles   | JobBytes          | JobStatus |
 +-------+------------------------+---------------------+------+-------+------------+-------------------+-----------+
 [...]
 | 7,060 | backup-XXXXXXXX        | 2016-01-02 16:00:50 | B    | I     |          2 |        74,225,116 | T         |
 | 7,062 | backup-YYY             | 2016-01-02 16:04:47 | B    | F     |    890,482 |   181,800,839,481 | T         |
 [...]
 +-------+------------------------+---------------------+------+-------+------------+-------------------+-----------+

Из приведенного выше вы можете увидеть две вакансии:

  • Задание 7060: инкрементное резервное копирование, 2 интересных файла, всего 74 МБ данных;
  • Задание 7062: резервное копирование "F", интересный файл 890492, всего 181 ГБ данных;

Давайте сосредоточимся на задании 7060, так как оно является дополнительным. Давай проверим который файлы были скопированы:

*list files jobid=7060 
 c:/allXXX_Backup/PLONE/Backup_Plone.bkf
 c:/allXXX_Backup/PLONE/
+-------+-----------------+---------------------+------+-------+----------+------------+-----------+
| JobId | Name            | StartTime           | Type | Level | JobFiles | JobBytes   | JobStatus |
+-------+-----------------+---------------------+------+-------+----------+------------+-----------+
| 7,060 | backup-XXXXXXXX | 2016-01-02 16:00:50 | B    | I     |        2 | 74,225,116 | T         |
+-------+-----------------+---------------------+------+-------+----------+------------+-----------+
*

Итак, Job 7060 интересует один файл (Backup_Plone.bkf) и один каталог (содержащая папка).

К сожалению, как видите, вывод list files jobid=7060 делает НЕ представьте нужный вам размер файла ... Надеюсь, он полезен, но не решить вашу проблему.

Сделаем шаг вперед.

Я путешествовал по официальная документация bareos невозможность найти правильный способ получить "размер файла" из bconsole. Поэтому я решил пойти по тяжелому пути: прямой SQL-доступ к каталогу.

Примечание: будьте предельно осторожны при работе с прямым доступом к каталогу, так как каждое некорректное действие может привести к серьезным повреждениям и связанной с этим потере данных!

После подключения к DB-движку (MySQL, в моем случае .... но это мелочь, как и с PostgreSQL, это то же самое), я увидел, что метаданные файлов с резервным копированием хранятся (... среди прочего) в:

  • File table: в нем хранятся в основном все метаданные, за исключением ...
  • Filename таблица: в нем хранится имя файла с резервной копией
  • Path таблица: хранит полный путь к файлу с резервной копией

С большим удивлением я обнаружил, что File таблица делает не включать size поле. Поэтому с помощью простого запроса получить то, что нам нужно, невозможно. Во всяком случае, я нашел интересный LStat поле (подробнее об этом позже).

Итак, я запустил следующий SQL-запрос:

select 
  f.JobId,f.LStat,f.MD5, fn.Name, p.Path
from
  Filename fn,
  File f,
  Path p
where
  f.JobId=7060 and
  fn.FilenameId = f.FilenameId and 
  p.PathId = f.PathId

и получил следующие результаты:

mysql> select f.JobId,f.LStat,f.MD5, fn.Name, p.Path
    -> from
    -> Filename fn,
    -> File f,
    -> Path p
    -> where
    -> f.JobId=7060 and
    -> fn.FilenameId = f.FilenameId and 
    -> p.PathId = f.PathId
    -> ;
+-------+------------------------------------------------------+------------------------+------------------+-------------------------+
| JobId | LStat                                                | MD5                    | Name             | Path                    |
+-------+------------------------------------------------------+------------------------+------------------+-------------------------+
|  7060 | A A IH/ B A A A EbJQA A A BWheFw BWheFw BTD/En A A L | 8ZuPGwdo9JYJileo+sVlfg | Backup_Plone.bkf | c:/all***_Backup/PLONE/ |
|  7060 | A A EH/ B A A A A A A BWhRjY BWgz4o BTD/En A A L     | 0                      |                  | c:/all***_Backup/PLONE/ |
+-------+------------------------------------------------------+------------------------+------------------+-------------------------+
2 rows in set (0.00 sec)

Для LStat поле, в Официальное руководство разработчика BareOS Я видел:

> Column Name   Data Type   Remark
> [...]
> LStat         tinyblob    File attributes in base64 encoding

Итак, теперь проблема в следующем:

  • Включает ли LStat размер файла?

и, как я бы поставил на «ДА! Определенно!»:

  • Как можно получить FileSize из строки LStat?

Быстрый поиск «BareOS LStat» привел меня к нескольким результатам. Через несколько секунд я получил этот поток, включая несколько комментариев о поле LStat, включая небольшой скрипт PERL для его правильного декодирования. Вот (*любезно предоставлено Брайаном Макдональдом, 2005 *), слегка измененный, чтобы лучше соответствовать вашим потребностям:

#!/usr/bin/perl

my $base64_digits =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
my $base64_values = { };
my $val = 0;
foreach my $letter ( split(//, $base64_digits ) )
    { $base64_values->{ $letter } = $val++; }

print "Please, enter your LSTAT string:";
my $lstat = <STDIN>;

my $vals = decode_stats($lstat);

print "Here are the results:\n";
foreach my $key (keys %{$vals}) {
   printf("%15s: %s\n",$key, $$vals{$key}) ;
}
exit;

sub decode_stats
{
  my $stats = shift;
  my $hash = { };

  # The stats data is in base64 format.  Yuck! - I mean Yay!
  # Each value is base64 encoded incorrectly, a deficiency we have
  # to correct here.  In particular, some values are encoded with a single
  # base64 character.  This results in a 6 bit value, and you have to
  # understand how bacula padded and manipulated those values before storing
  # them in the DB.

  # the fields are, in order:
  my @fields = qw(
    st_dev st_ino st_mode st_nlink st_uid st_gid st_rdev st_size
    st_blksize st_blocks st_atime st_mtime st_ctime LinkFI st_flags data
  );

  # Decoding this mess is based on reading src/lib/base64.c in bacula, in
  # particular the to_base64 function, which is how these got in the DB in
  # the first place.
  my $field_idx = 0;
  foreach my $element ( split( /\s+/, $stats ) )
  {
    my $result = 0;
    for ( my $i = 0; $i<length($element); $i++ )
    {
        if ($i) { $result <<= 6; }
        my $r = substr($element, $i, 1 );
        $result += $base64_values->{$r};
    }
    $hash->{ $fields[$field_idx] } = $result;
    $field_idx++;
  }

  return $hash;
}

При запуске и получении строки LSTAT он сообщает много данных, включая размер файла (st_size, последнее поле вывода):

verzulli@iMac-Chiara:/tmp$ perl pp.pl 
Please, enter your LSTAT string:A A IH/ B A A A EbJQA A A BWheFw BWheFw BTD/En A A L
Here are the results:
     LinkFI: 0
   st_atime: 1451614576
     st_ino: 0
   st_flags: 0
   st_mtime: 1451614576
     st_dev: 0
   st_nlink: 1
 st_blksize: 0
  st_blocks: 0
       data: 11
     st_gid: 0
    st_mode: 33279
     st_uid: 0
    st_rdev: 0
   st_ctime: 1393553703
    st_size: 74224640

Итак, теперь у нас есть размер файла, но, к сожалению, он не легко получить доступ с помощью одного запроса, чтобы найти самый большой файл в одном задании резервного копирования.

Существует несколько решений:

  • если вы используете MySQL 5.6.1 или новее, или механизм СУБД, поддерживающий кодирование / декодирование BASE_64, вы можете запросить SUBSTR LSTAT, а затем попросить механизм БД декодировать его значение как Base64. Например, см. Вот

  • вы можете написать СОХРАНЕННУЮ ПРОЦЕДУРУ. На самом деле он должен быть уже в PostgreSQL, что касается этот (кто заявляет: "... Добавлены образцы хранимых процедур postgresql для поля lstat ....");

  • вы можете написать небольшой скрипт PERL, запрашивая каталог и выполняя декодирование

  • ...

Надеюсь, этого будет достаточно ;-)


Обновление 1

Я только что обнаружил существование BVFS API, явно "... предназначен в основном для разработчиков, которые хотят разработать новый графический интерфейс для Bareos ...".

Эти API-интерфейсы предоставляют новый набор команд (так называемый "точечные команды"), в том числе интересный .bvfs_lsfiles который показывает на консоли некоторые метаданные, включая LSTAT поле. Так:

  1. определенно можно получить поле LSTAT без прямого доступа к базовой БД / каталогу.

Кроме того, с BareOS 15.2 был введен новый «режим API 2», добавляющий поддержку вывода JSON. Я только что это проверил:

  1. с включенным API V.2 объекты JSON, возвращаемые .bvfs_lsfiles, содержит правильно декодированное поле размера файла.

Вот пример:

*.bvfs_update
Using Catalog "MyCatalog"
*.bvfs_lsfiles path=/var/log/2016/01/06/ jobid=79
107131  34080   3614785 79  P0A CCMR IGA B A A A H1V BAA BI BWjIkK BWjJAx BWjJAx A A C  shorewall.log
107131  34081   3614786 79  P0A CCMQ IGA B A A A BT1 BAA Q BWjIkK BWjI7p BWjI7p A A C   system.log
*.api 2
{
  "jsonrpc": "2.0",
  "id": null,
  "result": {
    "api": 2
  }
}*
*.bvfs_lsfiles path=/var/log/2016/01/06/ jobid=79
{
  "jsonrpc": "2.0",
  "id": null,
  "result": {
    "files": [
      {
        "type": "F",
        "stat": {
          "dev": 64768,
          "nlink": 1,
          "mode": 33152,
          "ino": 533265,
          "rdev": 0,
          "user": "root",
          "group": "root",
          "atime": 1452050698,
          "size": 32085,
          "mtime": 1452052529,
          "ctime": 1452052529
        },
        "pathid": 107131,
        "name": "shorewall.log",
        "fileid": 3614785,
        "filenameid": 34080,
        "jobid": 79,
        "lstat": "P0A CCMR IGA B A A A H1V BAA BI BWjIkK BWjJAx BWjJAx A A C",
        "linkfileindex": 0
      },
      {
        "type": "F",
        "stat": {
          "dev": 64768,
          "nlink": 1,
          "mode": 33152,
          "ino": 533264,
          "rdev": 0,
          "user": "root",
          "group": "root",
          "atime": 1452050698,
          "size": 5365,
          "mtime": 1452052201,
          "ctime": 1452052201
        },
        "pathid": 107131,
        "name": "system.log",
        "fileid": 3614786,
        "filenameid": 34081,
        "jobid": 79,
        "lstat": "P0A CCMQ IGA B A A A BT1 BAA Q BWjIkK BWjI7p BWjI7p A A C",
        "linkfileindex": 0
      }
    ]
  }
}*

Итак, в конце концов, с последней версией BareOS исходная проблема кажется решаемой. без прямой доступ к каталогу.