为什么我的ansible copy模块非常慢?!

最近用ansible来做一些初始化的操作,其中有用到copy模块来拷贝一些东西,结果发现速度慢到哭,经网络监测,2G的带宽它才给我跑了10MB,百度依旧是没有好答案,只能谷歌,第一条stack overflow就给出解决方案(这里吐槽下某朝最近的严打活动。。。,没有了谷歌我们怎么活)

原文如下:

I’m using Ansible to copy a directory (900 files, 136MBytes) from one host to another:

---
- name: copy a directory
  copy: src={{some_directory}} dest={{remote_directory}}

This operation takes an incredible 17 minutes, while a simple scp -r <src> <dest> takes a mere 7 seconds.

I have tried the Accelerated mode, which according to the ansible docs “can be anywhere from 2-6x faster than SSH with ControlPersist enabled, and 10x faster than paramiko.”, but to no avail.

答案:

TLDR:

use synchronize instead of copy.

use synchronize instead of copy.

use synchronize instead of copy.

重要的事情说三遍!!!

Here’s the copy command I’m using:

- copy: src=testdata dest=/tmp/testdata/

As a guess, I assume the sync operations are slow. The files module documentation implies this too:

The “copy” module recursively copy facility does not scale to lots (>hundreds) of files. For alternative, see synchronize module, which is a wrapper around rsync.

Digging into the source shows each file is processed with SHA1. That’s implemented using hashlib.sha1. A local test implies that only takes 10 seconds for 900 files (that happen to take 400mb of space).

So, the next avenue. The copy is handled with module_utils/basic.py’s atomic_move method. I’m not sure if accelerated mode helps (it’s a mostly-deprecated feature), but I tried pipelining, putting this in a local ansible.cfg:

[ssh_connection]
pipelining=True

It didn’t appear to help; my sample took 24 minutes to run . There’s obviously a loop that checks a file, uploads it, fixes permissions, then starts on the next file. That’s a lot of commands, even if the ssh connection is left open. Reading between the lines it makes a little bit of sense- the “file transfer” can’t be done in pipelining, I think.

So, following the hint to use the synchronize command:

- synchronize: src=testdata dest=/tmp/testdata/

That took 18 seconds, even with pipeline=False. Clearly, the synchronize command is the way to go in this case.

Keep in mind synchronize uses rsync, which defaults to mod-time and file size. If you want or need checksumming, add checksum=True to the command. Even with checksumming enabled the time didn’t really change- still 15-18 seconds. I verified the checksum option was on by running ansible-playbook with -vvvv, that can be seen here:

ok: [testhost] => {"changed": false, "cmd": "rsync --delay-updates -FF --compress --checksum --archive --rsh 'ssh  -o StrictHostKeyChecking=no' --out-format='<<CHANGED>>%i %n%L' \"testdata\" \"user@testhost:/tmp/testdata/\"", "msg": "", "rc": 0, "stdout_lines": []}

E文不好的我给翻一下:

其实就是用synchronize替代copy模块,另外,在ansible.cfg文件中改如下:

[ssh_connection]
pipelining=False

然后去感受替换后的奇迹吧,骚年~

发表评论

电子邮件地址不会被公开。 必填项已用*标注