unixforum.org
Всем привет!
Я написал не большую программку, которая копирует файлы из одной директории в другую.
Цель: продемонстрировать преимущества многопоточности.
Но вот результаты не радуют.
Копирую 445 файлов из одной директории в другую. Общий вес файлов — 842,9 метра.
Время выполнения программы:
1 поток:
real 1m16.085s
user 0m9.097s
sys 0m3.708s
2 потока:
real 1m17.756s
user 0m9.037s
sys 0m4.208s
3 потока:
real 1m27.259s
user 0m9.141s
sys 0m4.152s
#include #include #include #include #include #include #define MAX_NAME_LEN 100 #define MAX_DATA_LEN 100 #define THREADS_COUNT 3 struct fileAttr< char fileName[MAX_NAME_LEN]; char dataFromFile[MAX_DATA_LEN]; >; struct dirAttr< DIR *dp; char copyFromDir[MAX_NAME_LEN]; char copyToDir[MAX_NAME_LEN]; >; pthread_mutex_t blockMutex = PTHREAD_MUTEX_INITIALIZER; void *beginCopy(void *); void setPathAndFileName(char *, const char *, const char *); int main(int argc, char *argv[]) < struct dirAttr dAttr; pthread_t threads[THREADS_COUNT]; int i; if(argc != 3)< printf("Usage: %s \n", argv[0]); exit(1); > strncpy(dAttr.copyFromDir, argv[1], sizeof(dAttr.copyFromDir)); strncpy(dAttr.copyToDir, argv[2], sizeof(dAttr.copyToDir)); // Открываем директорию от куда копировать dAttr.dp = opendir(dAttr.copyFromDir); if(dAttr.dp == NULL) < printf("[ERROR] Can't open dir %s\n", dAttr.copyFromDir); exit(1); >// Проверяем, существует ли директория, куда копировать // Если нет, создаём её if(opendir(dAttr.copyToDir) == NULL) if(mkdir(dAttr.copyToDir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) < printf("[ERROR] Can't make dir %s\n", dAttr.copyToDir); exit(1); >else printf("[INFO] Directory %s does not exists. I was make it\n", dAttr.copyToDir); for(i = 0; i < THREADS_COUNT; i++) if(pthread_create(&threads[i], NULL, beginCopy, (void *)&dAttr) != 0) perror("[ERROR] Can't create thread"); for(i = 0; i < THREADS_COUNT; i++) pthread_join(threads[i], NULL); closedir(dAttr.dp); exit(0); >void *beginCopy(void *arg)< struct fileAttr fAttr; struct dirent *dirp; FILE *copyFrom, *copyTo; struct dirAttr *dAttr = (struct dirAttr *)arg; pthread_mutex_lock(&blockMutex); // Просматриваем файлы в указанной директории while((dirp = readdir(dAttr->dp)) != NULL)< if(!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) continue; pthread_mutex_unlock(&blockMutex); printf("[INFO] thread id %u\n", pthread_self()); fflush(stdout); setPathAndFileName(fAttr.fileName, dAttr->copyFromDir, dirp->d_name); printf("copy from: %s\n", fAttr.fileName); fflush(stdout); copyFrom = fopen(fAttr.fileName, "r"); if(copyFrom == NULL) < printf("[ERROR] Can't open file %s to read\n", fAttr.fileName); continue; >setPathAndFileName(fAttr.fileName, dAttr->copyToDir, dirp->d_name); printf("copy to : %s . ", fAttr.fileName); fflush(stdout); copyTo = fopen(fAttr.fileName, "w"); if(copyFrom == NULL) < printf("[ERROR] Can't open file %s to write\n", fAttr.fileName); continue; >// Копирование данных while(fgets(fAttr.dataFromFile, MAX_DATA_LEN, copyFrom) != NULL) fputs(fAttr.dataFromFile, copyTo); printf("Done\n\n"); fflush(stdout); fclose(copyFrom); fclose(copyTo); > > void setPathAndFileName(char *fName, const char *path, const char *name)< bzero(fName, sizeof(fName)); strncpy(fName, path, MAX_NAME_LEN); strncat(fName, "/", 1); strncat(fName, name, MAX_NAME_LEN); >
Мьютексом блокируется лишь получение имени последующего файла, но копирование не блокируется.
Системный монитор показывает, что во время работы программы, кол-во открытых ею файлов = кол-во потоков * 2, т.к. каждый поток открывает файл «копировать из» и «копировать в».
По идее, при увеличении числа потоков, программа должна выполняться быстрее, но на деле происходит иначе.
Подскажите, почему так?
Многопотоковый rsync
Что нужно: скопировать много-много данных из Новосибирска в Москву, много-много тут 4 ТБ.
Проблема: rsync через ssh выдаёт примерно 0.5 МБ/сек, что страшно грустно.
Неожиданность: 10 параллельно запущенных rsync дают примерно в 10 раз большую производительность.
Пока все, с кем я поговорил из ответственных за связь, отнекиваются на предмет ограничения пропускной способности одного соединения. Хотя не все ещё из отпусков повыходили — возможно найду причину.
Я могу конечно на коленке запускать пачку rsync и выдавать каждому свою группу файлов, но если есть многопоточный rsync, то мне кажется проблему будет решить проще.
проще всего будет сделать один тар, порезать его на куски и каждому rsync-у отдать свой кусок.
утилита для разрезания и собирания блобов не помню как называется, но она точно есть.
В этом нет необходимости, так как скопировать нужно много больших файлов размером примерно по 1 ГБ, имеющих в имени уникальный номер. То есть всё уже порезано и собрано.
почему rsync, а не ftp?
так ли необходимо шифрование?
Доступ только через ssh. Шифрование не тормозит процесс вообще.
Кстати, подумалось, что lftp многопоточный и может sftp, так что хоть и не rsync, но имеет смысл попробовать.
Q: Are there any plans that would allow one to set a parameter, like ‘number_of_threads’ and rsync will ship multiple files at the same time?
A: Not at present. That would be a pretty big protocol change, and is probably something that would be best left to a new-protocol rewrite. It would be quite interesting to have separate connections for the hierarchy traversal code versus one or more file transfer connections that were controlled by the traversal process, but that is not something that I’m working on, nor have I heard about anyone else doing that.
Wayne Davison — rsync developer, 2009-October
rsync+ssl,rsync+ipsec. Скорее всего таки тормоза из-за ssh, если их в параллель куча работает быстрее.
Либо в сети и не позволяет быстро один поток выдавать.
Как быстро скопировать большое количество файлов между двумя серверами
Мне нужно передать огромное количество mp3 файлов между двумя серверами (Ubuntu). Под огромным я подразумеваю около миллиона файлов, которые в среднем имеют размер 300K. Я пытался использовать scp, но это заняло бы в районе недели (на скорости около 500 KB/s). Если я передаю один файл по HTTP, я получаю 9-10 MB/s, но я не знаю, как передать их все.
Есть ли способ быстро передать их все?
Ответ 1
Я бы рекомендовал tar. Когда структуры файлов похожи, rsync работает очень хорошо. Однако поскольку rsync выполняет несколько проходов анализа каждого файла, а затем копирует изменения, он намного медленнее tar для начального копирования. Эта команда, скорее всего, сделает то, что вы хотите. Она скопирует файлы между машинами, а также сохранит разрешения и права доступа пользователей/групп.
tar -c /path/to/dir | ssh remote_server ‘tar -xvf — -C /absolute/path/to/remotedir’
Вот команда, которую вы будете использовать для rsync:
rsync -avW -e ssh /path/to/dir/ remote_server:/path/to/remotedir
Ответ 2
Я бы использовал rsync.
Если вы экспортировали их по HTTP с доступными списками каталогов, вы можете использовать wget и аргумент —mirror. Вы понимаете, что HTTP быстрее, чем SCP, потому что SCP все шифрует (и, следовательно, нагружает процессор). HTTP и rsync будут работать быстрее, потому что они не шифруют.
Вот некоторые документы по настройке rsync на Ubuntu: https://help.ubuntu.com/community/rsync.
В этих документах говорится о туннелировании rsync через SSH, но, если вы просто перемещаете данные по частной локальной сети, вам не нужен SSH (я предполагаю, что вы находитесь в частной локальной сети).
Ответ 3
При перемещении 80 Т б данных (миллионы крошечных файлов), переход от rsync к tar оказался намного быстрее.
# медленный способ
rsync -av —progress /mnt/backups/section01/ /mnt/destination01/section01
и переключившись на tar.
# быстрый способ
cd /mnt/backups/
tar -cf — section01 | tar -xf — -C /mnt/destination01/
Поскольку эти серверы находятся в одной локальной сети, место назначения смонтировано по NFS на исходной системе, которая выполняет push. Чтобы сделать это еще быстрее, мы решили не сохранять время хранения файлов:
mount -o remount,noatime /mnt/backups
mount -o remount,noatime /mnt/destination01
Ответ 4
При копировании большого количества файлов я обнаружил, что такие инструменты, как tar и rsync, работают менее эффективн о , чем нужно, из-за накладных расходов на открытие и закрытие множества файлов. Я написал инструмент с открытым исходным кодом под названием fast-archiver, который быстрее tar для таких сценариев; он работает быстрее за счет выполнения нескольких одновременных операций с файлами.
Вот пример сравнения fast-archiver с tar на резервной копии более двух миллионов файлов; fast-archiver выполняет архивацию за 27 минут, а tar — за 1 час 23 минуты.
$ time fast-archiver -c -o /dev/null /db/data
пропуск символической ссылки /db/data/pg_xlog
1008.92user 663.00system 27:38.27elapsed 100%CPU (0avgtext+0avgdata 24352maxresident)k
0inputs+0outputs (0major+1732minor)pagefaults 0swaps
$ time tar -cf — /db/data | cat > /dev/null
tar: Удаление ведущих ‘/’ из имен пользователей
tar: /db/data/base/16408/12445.2: файл изменился при чтении
tar: /db/data/base/16408/12464: файл изменен по мере чтения
32.68user 375.19system 1:23:23elapsed 8%CPU (0avgtext+0avgdata 81744maxresident)k
0inputs+0outputs (0major+5163minor)pagefaults 0swaps
Для передачи файлов между серверами вы можете использовать fast-archiver с помощью ssh, как показано ниже:
ssh postgres@10.32.32.32 «cd /db; fast-archive -c data —exclude=data/\*.pid» | fast-archiver -x
Ответ 5
- Сетевая файловая система (NFS), и затем скопируйте их чем угодно, например , Midnight Commander (mc), Nautilus (от gnome). Я использовал NFS v3 с хорошими результатами.
- Samba (CIFS), и затем скопируйте файлы с чем угодно, но неизвестно, насколько это эффективно.
- HTTP с , wget —mirror или любой другой клиент HTTP. Будьте осторожны, чтобы не иметь неприятных символических ссылок или вводящих в заблуждение индексных файлов. Если все, что у вас есть, — это MP3, тогда все должно нормально сработать.
- rsync . Я использовал его с довольно хорошими результатами, и одна из его приятных особенностей — то, что вы можете прервать и возобновить передачу позже.
Ответ 6
Я могу предложить следующее улучшение (если bash — ваша оболочка). Это добавит параллельное сжатие, индикатор выполнения и проверку целостности по сетевому каналу:
tar c file_list |
tee >(sha512sum >&2) |
pv -prab |
pigz -9 |
ssh [user@]remote_host ‘
gunzip |
tee >(sha512sum >&2) |
tar xC /directory/to/extract/to
‘
pv — это хорошая программа просмотра прогресса для ваше го соединения, а pigz — параллельная программа gzip, которая использует столько потоков, сколько есть у вашего процессора по умолчанию (я думаю, до 8 максимум). Вы можете настроить уровень сжатия, чтобы лучше соответствовать соотношению процессора и пропускной способности сети, и поменять его местами с pxz -9e и pxz -d, если у вас намного больше процессоров, чем пропускной способности. Вам нужно только проверить, что две контрольные суммы совпадают после завершения.
Эта опция полезна для очень больших объемов данных, а также для сетей с высокой задержкой, но не очень полезна, если связь нестабильна и падает. В таких случаях лучшим выбором будет rsync, поскольку он может возобновить работу.
Пример вывода:
6c1fe5a75cc0280709a794bdfd23d7b8b655f0bbb4c320e59729c5cd952b4b1f84861b52d1eddb601259e78249d3e6618f8a1edbd20b281d6cd15f80c8593c3e — ]
176MiB [9.36MiB/s] [9.36MiB/s] [ ]
6c1fe5a75cc0280709a794bdfd23d7b8b655f0bbb4c320e59729c5cd952b4b1f84861b52d1eddb601259e78249d3e6618f8a1edbd20b281d6cd15f80c8593c3e —
Для блочных устройств:
dd if=/dev/src_device bs=1024k |
tee >(sha512sum >&2) |
pv -prab |
pigz -9 |
ssh [user@]remote_host ‘
gunzip |
tee >(sha512sum >&2) |
dd of=/dev/src_device bs=1024k
‘
Также убедитесь, что они одинакового размера , или ограничьте их с помощью count=, skip=, seek= и т. д.
Когда я копирую файловые системы таким образом, я часто сначала делаю :
dd if=/dev/zero of=/thefs/zero.dat bs=64k && sync && rm /thefs/zero.dat && umount /thefs
чтобы обнулить большую часть неиспользуемого пространства, что ускоряет перенос.
Ответ 7
Вы не упомянули, находятся ли эти две машины в одной локальной сети, а также является ли канал безопасным, т. е. с использованием SSH, или другим инструментом, который вы можете использовать, например , netcat.
Я бы использовал следующее на принимающей машине:
cd
netcat -l -p | gunzip | cpio -i -d -m
Затем на передающей стороне:
cd
find . -type f | cpio -o | gzip -1 | netcat .
Это имеет следующие преимущества:
Отсутствие нагрузки на процессор при шифровании, которое есть в ssh.
gzip -1 обеспечивает легкое сжатие без загрузки процессора, так что это хороший компромисс, дающий небольшое сжатие при сохранении максимальной пропускной способности ( в озможно, это не так выгодно для данных MP3). Если вы можете разделить файлы на группы, вы можете запустить два или более каналов параллельно и действительно обеспечить насыщение пропускной способности сети.
Например,
find -type f | cpio -o | gzip -1 | netcat
find -type f | cpio -o | gzip -1 | netcat
Примечания:
Независимо от способа передачи, я бы, вероятно, запустил rsync или unison после этого, чтобы убедиться, что передача прошла успешно.
Вы можете использовать tar вместо cpio, если хотите.
Даже если вы используете ssh, я бы убедился, что он сам не использует сжатие, и вместо этого передавал бы через gzip -1 самостоятельно, чтобы избежать перегрузки процессора ( и ли, по крайней мере, установите CompressionLevel , равным 1).
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.