看了大佬提升SCP传输速度的文章

使用tar+lz4/pigz+ssh更快的数据传输:

http://www.orczhou.com/index.php/2013/11/tranfer-data-faster-on-the-fly/

加速scp传输速度:

http://www.orczhou.com/index.php/2013/11/make-scp-faster-with-cipher-and-compression/

[root@mysql141 binlog]# time scp -r mysql-bin.000214 172.25.2.142:/opt/soft/test_scp/
mysql-bin.000214                                                                 100% 1024MB 126.0MB/s   00:08    
real    0m8.331s
user    0m6.597s
sys     0m2.721s
[root@mysql141 binlog]# time scp -r -c aes192-cbc mysql-bin.000214 172.25.2.142:/opt/soft/test_scp/
mysql-bin.000214                                                                 100% 1024MB 177.4MB/s   00:05    
real    0m5.959s
user    0m4.444s
sys     0m2.825s
[root@mysql141 binlog]# time tar -c mysql-bin.000214|lz4 -B4|ssh -c aes192-cbc 172.25.2.142 "lz4 -d |tar -xC /opt/soft/test_scp"
using blocks of size 64 KB 
real    0m4.024s
user    0m5.049s
sys     0m2.634s


闲来无事,想着scp为串行方式,可否使用并行方式再进一步提升速度,做了如下实验:

192.168.11.81读:

dd if=20210331.txt of=/dev/null bs=1M count=1000

1.8 GB/s

scp传输:

scp -c aes192-cbc 20210331.txt 192.168.11.82:~/

20210331.txt                     100% 1000MB 114.2MB/s   00:08

192.168.11.82写:

dd if=/dev/zero of=20210331.txt bs=1M count=1000

892 MB/s

整体流程

磁盘读取--------->scp传输--------->落盘

>1.8 GB/s       >114.2MB/s       >892 MB/s

瓶颈还是在scp传输上,看看iperf测试带宽情况,114.2MB/s 明显没达到带宽极限

ethtool eth0|grep Speed

 Speed: 1000Mb/s 

iperf -c 192.168.11.82 -t 60 -f M

[ ID] Interval       Transfer     Bandwidth

[  3]  0.0-60.0 sec  28010 MBytes   467 MBytes/sec

iperf -c 192.168.11.82 -P 10 -t 60 -f M 

[ ID] Interval       Transfer     Bandwidth

[SUM]  0.0-60.0 sec  29660 MBytes   494 MBytes/sec

现在想办法把scp传输这一过程速度发挥到极致,对比串行和并行的速度情况

造测试数据,10个1000M的文件:

for i in {1..10}
do
 dd if=/dev/zero of=${i}_20210331.txt bs=1M count=1000
done

常规串行执行:

time scp -r -c aes192-cbc *_20210331.txt 192.168.11.82:~/
10_20210331.txt                   100% 1000MB  70.1MB/s   00:14    
1_20210331.txt                    100% 1000MB  75.7MB/s   00:13    
2_20210331.txt                    100% 1000MB  83.3MB/s   00:12    
3_20210331.txt                    100% 1000MB  76.6MB/s   00:13    
4_20210331.txt                    100% 1000MB  78.1MB/s   00:12    
5_20210331.txt                    100% 1000MB  76.6MB/s   00:13    
6_20210331.txt                    100% 1000MB  76.8MB/s   00:13    
7_20210331.txt                    100% 1000MB  83.2MB/s   00:12    
8_20210331.txt                    100% 1000MB  77.3MB/s   00:12    
9_20210331.txt                    100% 1000MB  83.3MB/s   00:12

real    2m11.144s

user    1m2.778s

sys     1m20.256s

编写并行执行脚本parallel_scp.sh,内容和执行方式如下:

#脚本传值依次是:文件名(支持通配符) 目标IP 目标路径 scp并发数

sh parallel_scp.sh '*_20210331.txt' 192.168.11.82 '/root/' 10

cat parallel_scp.sh
#!/bin/bash
fileName=$1
remoteHost=$2
remoteDir=$3
maxScp=$4
ls ${fileName} > filelist.lst
cat filelist.lst | while read line
do
scpNum=`ps -ef| awk '{print $8}' |grep ^scp|egrep -v 'grep|tail'|wc -l`
while [ ${scpNum} -ge ${maxScp} ]
do
  sleep 5
  scpNum=`ps -ef| awk '{print $8}' |grep ^scp|egrep -v 'grep|tail'|wc -l`
done
scpFileName=`echo ${line}| awk '{print "scp_"$0".sh"}'`
echo "scp -r -c aes192-cbc ${line} ${remoteHost}:${remoteDir}" >  ${scpFileName}
time nohup sh ${scpFileName} > ${scpFileName}.out 2>&1 &
#echo "当前进度:nohup sh ${scpFileName} > ${scpFileName}.out &"
done
#echo "传输完成。"


sh parallel_scp.sh '*_20210331.txt' 192.168.11.82 '/root/' 10

real    1m12.449s

user    0m5.911s

sys     0m5.150s

通过理论和测试实验的执行时间来看,并行的scp会比串行时间快。


以上都是基于文件大小相同,若需要传输的文件大小不一,要是并行执行时,同一批并行的都是大文件,或者都是小文件,传输速度肯定是不均衡的,下面考虑把同一批并行的文件组合成大小差不多

ls -lS /root/*_20210331.txt|awk '{print $9}' > 123456.txt--按文件大小排序,由大到小倒序排

123456.txt 存在100行,内容为

/root/1_20210331.txt --10G

/root/2_20210331.txt --9G

....

/root/100_20210331.txt --1MB


awk '{lines[NR]=$0} END{i=50; while(i>0){print lines[i];--i}}' 123456.txt >p1.txt  --倒序排列文件,100个文件中前50大小的文件倒序排

awk '{lines[NR]=$0} END{j=51; while(j<101){print lines[j];++j}}' 123456.txt >p2.txt --顺序排列文件,100个文件中前50大小的文件顺序排

方法一:

paste -d "\n" p1.txt p2.txt >c.txt --逐行交叉合并两文件,c.txt的内容为均分大小后的文件排序

方法二(unix环境不一定存在paste命令):

将两个文件的内容按行交叉合并

for ((i=1;i<=$line;i++));do

cat a.txt | tail -n +$i |head -n 1 >>c.txt  #提取p1.txt的第i行,追加到c.txt

cat b.txt | tail -n +$i |head -n 1 >>c.txt  #提取p2.txt的第i行,追加到c.txt

done

这里最后的c.txt,替换到脚本里面的filelist.lst,就可以调用parallel_scp.sh执行了。


总结:

1、这里采用并行把scp速度发挥到极致,并未考虑性能影响,生产环境需要谨慎使用。

2、对于很大的二进制文件(data类型),考虑使用tar+lz4/pigz+ssh数据传输。

3、类比,对于相同串行执行的ftp、sftp等传输工具,也可考虑使用该方式,脚本稍微改一下就行。