关于BBR的介绍参见 BBR (很久以前写过详细文档,后来丢了,只找到了一小部分……)
在一些比较老的OpenVZ的vps(宿主机内核低于4.9版本)上,是无法开启bbr的。tcp的拥塞控制,在网络链路存在严重丢包时,会将拥塞窗口乘性减少,所以进行文件传输时,速度会越来越慢。以下介绍一下我面临scp速度慢的问题的解决办法
haproxy-lkl代理ssh端口
市面上有很多代替BBR的方案,大多都大差不差,都是使用lkl(linux kernal library)内核库绕过内核协议处理网络数据,再使用端口代理,实现在某几个端口的传输层能达到bbr的效果。
参考了ovz架构安装bbr内核一文,很方便,一建安装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 恭喜!BBR 安装完成并成功启动
已加速的端口: 22
你可以通过修改文件: /usr/local/haproxy-lkl/etc/port-rules
来配置需要加速的端口或端口范围。
请使用 systemctl {start|stop|restart} haproxy-lkl 来 {开启|关闭|重启} 服务
服务已自动加入开机启动,请放心使用。
如果这个脚本帮到了你,你可以请作者喝瓶可乐: https://blog.kuoruan.com/donate
享受加速的快感吧!
|
但也有缺点,这个端口代理只能影响外部访问该端口的,不能影响由内向外的。我尝试过打开某个本地端口,再通过以下代码将文件scp到外面,但是并没有用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
def transfer_and_delete_file_using_key_and_local_port(local_file_path, remote_host, remote_user, private_key_path, remote_file_path, local_port): private_key = paramiko.RSAKey.from_private_key_file(private_key_path) local_host = "0.0.0.0"
ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((local_host, local_port)) sock.connect((remote_host, 22)) transport = paramiko.Transport(sock) try: transport.start_client() transport.auth_publickey(remote_user, private_key) sftp = paramiko.SFTPClient.from_transport(transport) remote_dir = os.path.dirname(remote_file_path) try: sftp.listdir(remote_dir) except IOError: sftp.mkdir(remote_dir) sftp.put(local_file_path, remote_file_path) sftp.close() logging.info(f"local file scp finish, {local_file_path}") os.remove(local_file_path) logging.info(f"local file deleted: {local_file_path}") except Exception as e: traceback.print_exc() logging.error(f"exception on {local_file_path} with error {e}") finally: transport.close()
|
http请求呼叫远端pull
我干脆就不push了,让远端pull。这里面只有一个问题,就是网络链路不稳定容易导致('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
错误
解决方案是pull接口幂等+重试
本地:
1 2 3 4 5 6 7 8 9 10 11
| def ask_remote_scp_local_file_and_remote(): while True: try: resp = session.post("http://xxx", json=req,timeout=3600) if resp: break except Exception as e: logging.error("ask remote scp fail," + e.__str__()) if resp.status_code == 200 and resp.text == 'success': os.remove(file_path) return
|
远端:
使用python-redis-lock包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| def scp_from_remote_using_key(local_file_path, remote_host, remote_user, private_key_path, remote_file_path, port): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: private_key = paramiko.RSAKey.from_private_key_file(private_key_path) ssh.connect(remote_host, port=port, username=remote_user, pkey=private_key) sftp = ssh.open_sftp() local_dir = os.path.dirname(remote_file_path) try: os.listdir(local_dir) except IOError: os.mkdir(local_dir)
sftp.get(remote_file_path, local_file_path) sftp.close() logging.info(f"remote file scp finish, {remote_file_path}") except Exception as e: logging.error(f"exception on {remote_file_path} with error {e}") finally: ssh.close() def lock_and_scp(local_file_path, remote_host, remote_user, private_key_path, remote_file_path, port): m2 = hashlib.md5() m2.update(remote_file_path.encode('utf-8')) md5 = m2.hexdigest() lock = redis_lock.Lock(redis_connect, "lock_" + md5, expire=600)
if lock.acquire(blocking=True): if redis_connect.get("finished_" + md5) is None: scp_from_remote_using_key(local_file_path, remote_host, remote_user, private_key_path, remote_file_path, port) redis_connect.set("finished_" + md5, "1") redis_connect.expire("finished_" + md5, 600) lock.release()
|