/images/logo.jpg

[Network] 1. 文件传输优化分享

[Network] 1. 文件传输优化分享

背景(敏感数据已脱敏)

  • 由于种种要求,需要将数据上传到海外的 oss 上进行存储。所以开发了一个代理服务维护数据并进行加密等操作。期间内部发现数据上传下载非常慢,经过一系列排查,最终定位到问题根源,并给出解决方案。现将排查过程进行分享。
  • 当然了,前提之一是内网打通,通过专线网络接入,才能做到理论上的物理极限。使用复杂漫长的公共网络既不适合文件安全,也不适合大文件长时间传输。

服务本身问题

描述
  • 最初怀疑是数据落盘导致的太慢。因为上传必须落盘,防止文件过大。下载直接流式传输,非常合理。唯一的改进是上传进行流式加密和传输,但是当前问题不大。

现象

  • 使用编写的脚本上传 1M 的加密数据,耗时接近 2s
1
2
3
4
5
import requests
requests.post(f"{url}/upload/files", files={
    "data": ('', upload_data, "application/json"),
    "file": transfer_data
})
1
2
3
4
5
6
7
$ python oss.py --file_input=./1M.data --region=us --model=3 --range=5
encrypted_upload
upload ./1M.data, encrypt cost 4.714599609375, upload cost 1788.95849609375
upload ./1M.data, encrypt cost 10.140625, upload cost 1945.90087890625
upload ./1M.data, encrypt cost 9.924560546875, upload cost 1756.984130859375
upload ./1M.data, encrypt cost 8.694580078125, upload cost 1930.31201171875
upload ./1M.data, encrypt cost 8.279296875, upload cost 1739.38623046875

抓包

  • 与运维进行沟通,运维怀疑是网络问题,进行抓包一探究竟。

抓包演示

ping 包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ sudo tcpdump -i bond0 | grep x.x.x.x1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bond0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:21:19.255718 IP public2.alidns.com.domain > domain1.36590: 43190 1/0/1 A x.x.x.x1 (88)
16:21:19.256404 IP domain1 > x.x.x.x1: ICMP echo request, id 32590, seq 1, length 64
16:21:19.456754 IP x.x.x.x1 > domain1: ICMP echo reply, id 32590, seq 1, length 64
16:21:20.257688 IP domain1 > x.x.x.x1: ICMP echo request, id 32590, seq 2, length 64
16:21:20.458076 IP x.x.x.x1 > domain1: ICMP echo reply, id 32590, seq 2, length 64
16:21:21.259088 IP domain1 > x.x.x.x1: ICMP echo request, id 32590, seq 3, length 64
16:21:21.459506 IP x.x.x.x1 > domain1: ICMP echo reply, id 32590, seq 3, length 64
16:21:22.260538 IP domain1 > x.x.x.x1: ICMP echo request, id 32590, seq 4, length 64
16:21:22.460976 IP x.x.x.x1 > domain1: ICMP echo reply, id 32590, seq 4, length 64
1
2
3
4
5
6
7
8
9
$ ping domain1
PING domain1 (x.x.x.x1) 56(84) bytes of data.
64 bytes from x.x.x.x1 (x.x.x.x1): icmp_seq=1 ttl=58 time=200 ms
64 bytes from x.x.x.x1 (x.x.x.x1): icmp_seq=2 ttl=58 time=200 ms
64 bytes from x.x.x.x1 (x.x.x.x1): icmp_seq=3 ttl=58 time=200 ms
^C
--- domain1 ping statistics ---
4 packets transmitted, 3 received, 25% packet loss, time 3004ms
rtt min/avg/max/mdev = 200.395/200.419/200.456/0.517 ms

三次握手

1
2
3
16:54:06.286416 IP domain1.33666 > x.x.x.x1.http: Flags [S], seq 2682796272, win 64240, options [mss 1460,sackOK,TS val 2595135963 ecr 0,nop,wscale 7], length 0
16:54:06.486797 IP x.x.x.x1.http > domain1.33666: Flags [S.], seq 2198055866, ack 2682796273, win 62643, options [mss 1460,sackOK,TS val 2062390218 ecr 2595135963,nop,wscale 7], length 0
16:54:06.486840 IP domain1.33666 > x.x.x.x1.http: Flags [.], ack 1, win 502, options [nop,nop,TS val 2595136163 ecr 2062390218], length 0

四次挥手

1
2
3
16:54:28.356723 IP domain1.54028 > x.x.x.x1.http: Flags [F.], seq 1746, ack 215, win 501, options [nop,nop,TS val 2595158034 ecr 2062412087], length 0
16:54:28.557169 IP x.x.x.x1.http > domain1.54028: Flags [F.], seq 215, ack 1747, win 477, options [nop,nop,TS val 2062412289 ecr 2595158034], length 0
16:54:28.557222 IP domain1.54028 > x.x.x.x1.http: Flags [.], ack 216, win 501, options [nop,nop,TS val 2595158234 ecr 2062412289], length 0

tcpdump Flags

  • Tcpdump flags 是指示 TCP 连接状态或动作的标志。它们通常在 tcpdump 输出中用方括号表示。Tcpdump 输出中有多种 flags,输出也可能包含多个 TCP flags 的组合 1。一些常见的 flags 有:
    • S (SYN): 这个 flag 用于在两个主机之间建立连接。它在三次握手的第一个包中设置。
    • . (No flag): 这意味着在包中没有设置任何 flag。它通常用于数据传输或确认包。
    • P (PUSH): 这个 flag 用于表示发送方希望尽快发送数据,而不等待缓冲区填满。
    • F (FIN): 这个 flag 用于终止两个主机之间的连接。它在四次挥手的最后一个包中设置。
    • R (RST): 这个 flag 用于重置处于无效状态或遇到错误的连接。它也用于拒绝不想要的连接尝试。
    • W (ECN CWR): 这个 flag 用于表示发送方已经根据网络的显式拥塞通知 (ECN) 减小了其拥塞窗口大小。
    • E (ECN-Echo): 这个 flag 用于表示接收方已经收到了一个带有 ECN 位的包,这意味着网络中存在拥塞。
  • 例如,一个带有 flags [S.] 的包意味着它是一个 SYN 包,是建立 TCP 连接的第一步。一个带有 flags [P.] 的包意味着它是一个 PUSH 包,包含了发送方想要快速传送的数据。一个带有 flags [F.] 的包意味着它是一个 FIN 包,是关闭 TCP 连接的最后一步 2。

为什么 tcpdump 四次挥手只有三个包

  • Tcpdump 四次挥手只有三个包的原因可能有以下几种:
    • 一种可能是被动关闭方(收到 FIN 的一方)在回复 ACK 的同时,也发送了自己的 FIN,将第二次和第三次挥手合并为一个报文,节省了一个包 1。这种情况下,被动关闭方已经没有数据要发送了,所以可以直接进入 LAST_ACK 状态,等待主动关闭方的最后一个 ACK。
    • 另一种可能是主动关闭方(发送 FIN 的一方)在收到被动关闭方的 FIN 后,没有及时回复 ACK,而是在一段时间后才发送 ACK,并且在 ACK 中设置了 RST 标志,表示强制重置连接 2。这种情况下,主动关闭方可能遇到了异常或超时,所以不再等待 2MSL 的时间,而是直接进入 CLOSE 状态。
    • 还有一种可能是 tcpdump 没有抓到所有的包,因为网络延迟或丢包的原因,导致某个挥手的报文没有被捕获到 3。这种情况下,可以尝试重新抓包或增加抓包的时间范围,看是否能够看到完整的四次挥手过程。

实际数据

1
2
3
$ python oss.py --file_input=./1K.data --file_output=./download-1M.data --region=us --model=3 --range=5
encrypted_upload
http://domain1 upload ./1K.data, encrypt cost 1.530029296875, upload cost 408.5546875
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ sudo tcpdump -i bond0 | grep x.x.x.x1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bond0, link-type EN10MB (Ethernet), capture size 262144 bytes

16:54:06.286416 IP domain1.33666 > x.x.x.x1.http: Flags [S], seq 2682796272, win 64240, options [mss 1460,sackOK,TS val 2595135963 ecr 0,nop,wscale 7], length 0
16:54:06.486797 IP x.x.x.x1.http > domain1.33666: Flags [S.], seq 2198055866, ack 2682796273, win 62643, options [mss 1460,sackOK,TS val 2062390218 ecr 2595135963,nop,wscale 7], length 0
16:54:06.486840 IP domain1.33666 > x.x.x.x1.http: Flags [.], ack 1, win 502, options [nop,nop,TS val 2595136163 ecr 2062390218], length 0
16:54:06.486930 IP domain1.33666 > x.x.x.x1.http: Flags [P.], seq 1:292, ack 1, win 502, options [nop,nop,TS val 2595136164 ecr 2062390218], length 291: HTTP: POST /upload/files HTTP/1.1
16:54:06.486960 IP domain1.33666 > x.x.x.x1.http: Flags [P.], seq 292:1746, ack 1, win 502, options [nop,nop,TS val 2595136164 ecr 2062390218], length 1454: HTTP
16:54:06.687234 IP x.x.x.x1.http > domain1.33666: Flags [.], ack 292, win 488, options [nop,nop,TS val 2062390419 ecr 2595136164], length 0
16:54:06.687279 IP x.x.x.x1.http > domain1.33666: Flags [.], ack 1746, win 477, options [nop,nop,TS val 2062390419 ecr 2595136164], length 0
16:54:06.690277 IP x.x.x.x1.http > domain1.33666: Flags [P.], seq 1:215, ack 1746, win 477, options [nop,nop,TS val 2062390422 ecr 2595136164], length 214: HTTP: HTTP/1.1 200 OK
16:54:06.690314 IP domain1.33666 > x.x.x.x1.http: Flags [.], ack 215, win 501, options [nop,nop,TS val 2595136367 ecr 2062390422], length 0
16:54:06.692023 IP domain1.33666 > x.x.x.x1.http: Flags [F.], seq 1746, ack 215, win 501, options [nop,nop,TS val 2595136369 ecr 2062390422], length 0
16:54:06.892401 IP x.x.x.x1.http > domain1.33666: Flags [F.], seq 215, ack 1747, win 477, options [nop,nop,TS val 2062390624 ecr 2595136369], length 0
16:54:06.892448 IP domain1.33666 > x.x.x.x1.http: Flags [.], ack 216, win 501, options [nop,nop,TS val 2595136569 ecr 2062390624], length 0
  • 实际是上传 1M 数据,进行分析,此处简化。
  • 因为时间跳跃增长全部发生在服务端返回的数据包。此时问题已经很明了了,由于深圳和美东现实的物理距离,200ms 的来回已经做到了极限。所以其实是合理的。

灵魂拷问

  • 此时,一个灵魂拷问出现了,为什么之前走公网反而更快?
  • 与兄弟部门同事沟通,模拟他们的代码,使用 aws 的 sdk 进行测试
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import boto3
from boto3.s3.transfer import TransferConfig

def download():
    s3_client = client(access_key, access_secret, host)
    GB = 1024 ** 3
    config = TransferConfig(multipart_threshold=2 * GB, max_concurrency=10, use_threads=True)
    s3_client.download_file(Bucket="bucket", Key="name-100.jpg", Filename="name-100.jpg", Config=config)

if __name__ == '__main__':
    download()
    # ...
    download()

结果

[Github] 1. 部署 GitHub 博客站点

[Github] 1. 部署 GitHub 博客站点

简介

  • GitHub Pages 是一个静态网站托管服务,它直接从 GitHub 仓库中获取 HTML、CSS 和 JavaScript 文件,可选地通过构建过程运行这些文件,然后发布网站。

准备工作

创建仓库

  • 创建一个名为 your_github_username.github.io 的仓库,其中 your_github_username 是你的 GitHub 用户名。例如,如果你的 GitHub 用户名是 octocat,那么仓库名应该是 octocat.github.io

安装 Hugo

创建博客站点

初始化 Hugo 站点

1
2
3
4
5
6
7
8
# 创建目录
mkdir your_github_username.github.io
# 进入目录
cd your_github_username.github.io
# 初始化站点
hugo new site .
# git 初始化,确保这是一个 git 仓库
git init

添加主题

1
2
3
4
5
6
7
8
9
# 添加主题,这里我们使用 LoveIt 主题
git submodule add https://github.com/dillonzq/LoveIt.git themes/LoveIt
# 现在 git 在 main 分支上,这个分支不稳定,我们需要切换到最新的稳定版本
cd themes/LoveIt
git checkout v0.3.0
cd ../..
# 现在,你的目录中应该有一个 .gitmodules 文件。如果没有,你需要先运行 `git init`
# 复制示例站点配置文件到根目录
cp themes/LoveIt/exampleSite/hugo.toml .

修改配置文件

  • 修改配置文件 hugo.toml

基础 URL

1
baseURL = "https://gooddayday.github.io"

主题目录

1
2
3
# themes directory
# 主题目录
themesDir = "./themes"

网站标题

1
2
3
# website title
# 网站标题
title = "GoodyHao's Blog"

网站图片

1
2
3
# website images for Open Graph and Twitter Cards
# 网站图片, 用于 Open Graph 和 Twitter Cards
images = ["/logo.jpg"]

网站图标

  • 将图标文件放在 static 目录中

Git 仓库

  • 修改 gitRepo 为你的公共 git 仓库 URL
1
2
3
# public git repo url only then enableGitInfo is true
# 公共 git 仓库路径,仅在 enableGitInfo 设为 true 时有效
gitRepo = "https://github.com/GOODDAYDAY/GOODDAYDAY.github.io"

GitHub 部署

创建工作流文件

  • 创建文件 .github/workflows/deploy.yaml,并添加以下内容:
 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
40
41
42
name: Deploy Hugo to GitHub Pages
on:
  push:  # 触发条件:推送代码到master分支
    branches:
      - master
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest  # 使用Ubuntu环境
    steps:
      # 1. 检出仓库代码(递归拉取主题submodule)
      - uses: actions/checkout@v4
        with:
          submodules: true

      # 2. 安装Hugo(使用extended版本,支持SASS)
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'  # 或指定版本(如'0.147.2')
          extended: true

      # 3. 缓存依赖(加快后续构建速度)
      - uses: actions/cache@v3
        with:
          path: |
            resources/_gen
            public
          key: ${{ runner.os }}-hugo-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-hugo-

      # 4. 构建Hugo站点(开启压缩)
      - name: Build Hugo site
        run: hugo --minify

      # 5. 部署到GitHub Pages(自动推送public目录到gh-pages分支)
      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN  }}  # GitHub自动提供的Token(无需手动创建)
          publish_dir: ./public  # 指向Hugo生成的静态文件目录
          force_orphan: true  # 强制创建新提交(避免分支历史混乱)
  • GitHub 仓库设置 -> Pages -> Source -> 选择 gh-pages 分支和 / (root) 文件夹 -> 保存
    • 如果 gh-pages 分支不存在,需要先将代码推送到 GitHub

/images/1.%20deploy%20github%20blog%20site.md/1.%20github-page-setting.png