網頁大小 14KB 與 15KB 的速度差異

Hacker News 上看到「Why your website should be under 14kB in size」這篇,對應的討論在「A 14kb page can load much faster than a 15kb page (endtimes.dev)」,在講網頁大小 14KB/15KB 的速度差異比 15KB/16KB 大很多的問題:

What is surprising is that a 14kB page can load much faster than a 15kB page — maybe 612ms faster — while the difference between a 15kB and a 16kB page is trivial.

原因是 TCP slow start 造成的:

This is because of the TCP slow start algorithm.

而網頁這邊 TCP slow start 目前大多數的實做都是 10 packets 後發動:

Most web servers TCP slow start algorithm starts by sending 10 TCP packets.

然後再組合 1500 bytes/packet 以及 overhead,就差不多是 14KB 了:

The maximum size of a TCP packet is 1500 bytes.

This this maximum is not set by the TCP specification, it comes from the ethernet standard

Each TCP packet uses 40 bytes in its header — 16 bytes for IP and an additional 24 bytes for TCP

That leaves 1460 bytes per TCP packet. 10 x 1460 = 14600 bytes or roughly 14kB!

然後 HTTP/3 也可以看到類似的設計 (出自「QUIC Loss Detection and Congestion Control」:

Sending multiple packets into the network without any delay between them creates a packet burst that might cause short-term congestion and losses. Implementations MUST either use pacing or limit such bursts to the initial congestion window, which is recommended to be the minimum of 10 * max_datagram_size and max(2* max_datagram_size, 14720)), where max_datagram_size is the current maximum size of a datagram for the connection, not including UDP or IP overhead.

算是一個小知識... 但對於現在肥滋滋的網頁效果來說就沒辦法了,而且考慮到大一點的網站會在一個 TCP 連線裡面可能會傳很多 request,其實早就超過 TCP slow start 的門檻了。

TCP 標準被整理到 RFC 9293

看到「RFC 9293: Transmission Control Protocol (TCP)」這篇,主要是把本來分散在各個 RFC 的文件 (從 RFC 793 開始) 全部整理成一份,另外把一些已知的勘誤表放進來:

This document specifies the Transmission Control Protocol (TCP). TCP is an important transport-layer protocol in the Internet protocol stack, and it has continuously evolved over decades of use and growth of the Internet. Over this time, a number of changes have been made to TCP as it was specified in RFC 793, though these have only been documented in a piecemeal fashion. This document collects and brings those changes together with the protocol specification from RFC 793. This document obsoletes RFC 793, as well as RFCs 879, 2873, 6093, 6429, 6528, and 6691 that updated parts of RFC 793. It updates RFCs 1011 and 1122, and it should be considered as a replacement for the portions of those documents dealing with TCP requirements. It also updates RFC 5961 by adding a small clarification in reset handling while in the SYN-RECEIVED state. The TCP header control bits from RFC 793 have also been updated based on RFC 3168.

然後淘汰掉 (obselete) 一卡車 RFC 文件 XD

翻資料發現 2014 的時候 HTTP/1.1 被幹過一次類似的事情,不過是反過來被拆開:「HTTP/1.1 的更新」,這次把 RFC 2616 幹掉分成 RFC 7230RFC 7235

然後今年因為 HTTP 的關係又被幹了一次,這次 HTTP/1.1 又被整回來變成一份文件,但是把裡面的一些概念拆開:「HTTP 標準的翻新」。

其中 RFC 9110 定義 HTTP Semantics,RFC 9111 定義 HTTP Caching,然後 RFC 9112RFC 9113 拿來定義了 HTTP/1.1 與 HTTP/2,另外先把 HTTP/3 的號碼保留下來的 RFC 9114

不斷 refactor 以及加新功能的文件...

DOS 下的 TCP/IP 程式組

Hacker News 上看到「mTCP: TCP/IP applications for DOS PCs (brutman.com)」這個有趣的東西,在 DOS 環境下的 TCP/IP 程式組,原網站在「TCP/IP applications for your PC compatible retro-computers」這邊。

不過我覺得比較神奇的是,他的測試環境是真的包括一堆老機器跟網卡耶 XDDD

裡面提到的 NE1000ISA 界面的卡,這樣聽起來保養的都還不錯...

Tor 0.4.7.7 支援 congestion control

Tor 首度在協定內支援了 congestion control:「Congestion Control Arrives in Tor 0.4.7-stable!」。

這個新功能會帶來效能的提昇:

Tor has released 0.4.7.7, the first stable Tor release with support for congestion control. Congestion control will eliminate the speed limit of current Tor, as well as reduce latency by minimizing queue lengths at relays. It will result in significant performance improvements in Tor, as well as increased utilization of our network capacity.

之所以沒有辦法直接利用 packet loss 的方式讓 TCP network stack 直接判斷 congestion control,是因為這樣會產生 side channel:

Crucially, we rejected mechanisms to provide congestion control by allowing packet drops, due to the ability to introduce end-to-end side channels in the packet drop pattern.

所以 Tor 得自己實做 congestion control 演算法,選擇的演算法是結合了 Vegas 的 Tor-Vegas,可以看到在實驗中,德國與香港的 exit node 效率大幅提昇:

另外也因為 0.4.7.7 也出來一個禮拜了,也可以看到 Advertised Bandwidth (算是 Tor network 觀察到的 bandwidth) 開始成長:

另外一個重要的點是 UDP 的支援計畫,看起來在這次改善後也比較有可行性了:

The astute reader will note that we rejected datagram transports. However, this does not mean that Tor will never carry UDP traffic. On the contrary, congestion control deployment means that queue delay and latency will be much more stable and predictable. This will enable us to carry UDP without packet drops in the network, and only drop UDP at the edges, when the congestion window becomes full. We are hopeful that this new behavior will match what existing UDP protocols expect, allowing their use over Tor.

用 iptables 擋特定國家的封包

這兩天發現 ubuntu-20.04.3-live-server-amd64.iso 這個 BitTorrent 的 ISO image 有大量來自 CN 的連線在狂抓,導致整個上傳頻寬都被吃滿:

沒想到第一次用 iptables 的 xt_geoip 居然是這個用途... 主要是參考「GeoIP Blocking Ubuntu 20.04LTS」這邊的方法,不過因為我的 rtorrent 是跑在 Docker 裡面的,有另外要注意的地方。

首先是安裝軟體,這邊要裝 xtables-addons-commonlibtext-csv-xs-perl

sudo apt install -y libtext-csv-xs-perl xtables-addons-common

再來是建立目錄,並且下載一包 GeoIP 的資料 (從 DBIP 下載) 並且轉成 xt_geoip 可以用的格式:

sudo mkdir /usr/share/xt_geoip
cd /usr/share/xt_geoip
sudo /usr/lib/xtables-addons/xt_geoip_dl
sudo /usr/bin/perl /usr/lib/xtables-addons/xt_geoip_build

然後就是加到 iptables 的條件裡面了,我加到兩個地方,一個是 INPUT chain,另外一個是 DOCKER-USER chain (參考「Docker and iptables」這邊的說明),假設你是用 port 6991 的話就這樣加:

sudo iptables -I INPUT -p tcp -m geoip --source-country CN -m tcp --dport 6991 -j DROP
sudo iptables -I DOCKER-USER -p tcp -m geoip --source-country CN -m tcp --dport 6991 -j DROP

然後可以考慮每個禮拜更新一次資料庫。

另外在找資料的時候發現「Free updated GeoIP legacy databases」這邊有人放出 MaxMind 的版本,不過免費版的應該都差不多,這邊就用 xtables-addons-common 內預設的。

弄完以後就正常多了...

Amazon EC2 的網路效能

前一篇「在 AWS 上面的 OpenVPN Server 效能」最後的問題就是 EC2 instance 本身的網路效能,畢竟是公司要用的,還是實際測一下數字,之後有人接手的時候也比較清楚是怎麼選這個大小的...

這邊拿的是 AWSap-southeast-1 (Singapore) 的 EC2 測試,直接在同一個 subnet 裡面開兩台一樣的機器跑 iperf 測試。

機器開機後會先跑這串指令 (除了安裝 iperf 的指令,其他的是出自我自己 wiki 上的 Ubuntu 這頁),然後再重開機:

sudo fallocate -l 512M /swapfile; sudo chmod 600 /swapfile; sudo mkswap /swapfile; sudo swapon /swapfile; echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab; echo -e "net.core.default_qdisc=fq\nnet.ipv4.tcp_congestion_control=bbr" | sudo tee /etc/sysctl.d/99-tcp.conf; sudo sysctl -p /etc/sysctl.d/99-tcp.conf; sudo apt update; sudo apt dist-upgrade -y; sudo apt install -y apache2-utils apt-transport-https build-essential curl dnsutils dstat git jq locales moreutils most mtr-tiny net-tools p7zip-full pigz prometheus-node-exporter rsync sharutils software-properties-common sysstat unrar unzip vim-nox wget zsh zsh-syntax-highlighting zstd; sudo apt install -y iperf; sudo apt clean

接下來就是一台跑 iperf -s,另外一台跑 iperf -c 10.x.x.x -i 1 -t 3600 讓他跑一個小時看結果了。

我都有跑 tmux 再連到這些機器上,這樣可以捲回去看每一秒的傳輸速度,就可以看出來變化了,不過這邊還是簡單的只列出最高速度 (burstable) 與穩定輸出的速度 (baseline):

EC2 instance Baseline Burstable vCPU RAM Pricing (USD$)
c6g.medium 500Mbps 10Gbps 1 2GB 0.0392
c6g.large 750Mbps 5Gbps (claimed 10Gbps) 2 4GB 0.0784
c6g.xlarge 1.25Gbps 10Gbps 4 8GB 0.1568
t4g.small 125Mbps 5Gbps 2 2GB 0.0212
t4g.medium 255Mbps 5Gbps 2 4GB 0.0424
t4g.large 510Mbps 5Gbps 2 8GB 0.0848
t4g.xlarge 1Gbps 5Gbps 4 16GB 0.1696

這邊沒列出來的是 burstable 可以持續的時間,但這跟你機器吃的網路資源有關,我就決定只用 baseline 來做決策了,這樣可能會多花一點錢,但會少很多麻煩。

另外這次在處理的過程有被同事提醒各種 bandwidth overhead,所以就順便查了一下資料:

  • OpenVPN 本身的 overhead 大約是 5% (跑 UDP 的時候):「OpenVPN performance」。
  • SSH 也有些 overhead,大約是 6% (把來回的封包都算進去):「What is the overhead of SSH compared to telnet?」。
  • rsync 的部份鐵定也有 overhead,但這邊就沒找到現成的文章有統計過了。
  • 另外我自己之前做實驗發現 TCP BBR 的 retransmission algorithm 還蠻激進的,會有 10% packet loss,改用預設的 CUBIC 會好很多,大約 1% 到 2% 左右。

綜合這些測試,我自己抓了 35% 的 overhead 來推估,最後是用 c6g.large 來養 VPN server。750Mbps 的實際流量大約可以包進 550Mbps 的原始流量,大約是 68MB/sec。

不過新加坡與印尼之間的 internet bandwidth 好像還是不太夠,有時候深夜跑也跑不滿... 不過之後 VPN 上的 client 會愈來愈多,應該是不需要降...

Mitmproxy 7 支援 TLS over TCP 的分析了

Hacker News 首頁上看到 Mitmproxy 7 的消息:「Mitmproxy 7」。

比較重要的功能應該就是可以針對任意的 TLS 連線攔截分析了:

不過像是 STARTTLS 這類先在 plaintext 溝通,然後送出指令進入 TLS 的方式,目前就還沒支援:

Opportunistic TLS (STARTTLS) is not supported yet, but regular TCP-over-TLS just works!

另外是可以分析 WebSocket 內的傳輸資料:

應該是跑個 pip install -U mitmproxy 就可以升級了... (如果先前是用 pip 安裝的話)

HP 印表機的 Port 與 Prometheus...

Twitter 上看到這個,HP 印表機的 Port 9100 跟 Prometheus 撞到,再加上 mistype,於是就出事了:

找了一下 HP 的文件,「HP Jetdirect Print Servers - HP Jetdirect Port Numbers for TCP/IP (UDP) Connections」:

9100 TCP port is used for printing. Port numbers 9101 and 9102 are for parallel ports 2 and 3 on the three-port HP Jetdirect external print servers.

翻了一下「Service Name and Transport Protocol Port Number Registry」這邊,看起來 HP 在很久前就登記了 9100/tcp 與 9100/udp...

不過這沒有誰對誰錯的問題,只是很好笑:Printer 在收到不認識的指令時會直接當做 text 印出來,加上 Prometheus 的 HTTP request 打進去...

Google Meet 可以走 443/tcp 了

Work from home 期間開會基本上就是幾個視訊軟體換來換去,Zoom 的話公司有買,自己開免費版的時候是 40mins 限制,另外 Slack 的畫面品質不怎麼樣,而 Google Meet 在疫情期間不限制時間,拿來聊天還蠻好用的。

看到「TLS support for Google Meet」這篇,文章裡面提到先前 Google Meet 是用 443/udp 跑 SRTP,這對很多公司的 firewall 需要另外開 (看到這個 UDP port 想到 QUIC 好像也是走這個 UDP port),在家裡的話應該還好,對於公司的電腦就會麻煩一些。

文章裡提到,這次支援了 TLS (over 443/tcp):

Some network setups do not work with SRTP over 443 which was preventing Meet calls from connecting. Meet now encapsulates SRTP in TLS which increases overall compatibility. This change will initially be available on the web, and will be available for mobile soon. We’ll announce it on the Google Workspace Updates blog when it’s available.

可以 fallback 回 443/tcp 走 TLS 的話穿透力應該就更好了,不過不知道免費版的有沒有也一起上,這邊只題到了 G Suite 系列會上:

Available to all Google Workspace customers, as well as G Suite Basic and Business customers

上次用 Google Meet 是在雲端聚餐聊天...

關閉 GitLab 的 nginx,使用自己裝的 nginx

我自己架設的 GitLab 是透過「Install self-managed GitLab」這邊的方法裝進 Ubuntu 系統內的 (我在自己的 wiki 上也有整理:「GitLab」),他會自己下載所有對應的套件,包括了 nginx

但這樣就直接把 TCP port 80/443 都吃掉了,同一台機器要放其他的 virtual host 就比較麻煩,所以找了些方法讓 GitLab 不要佔用 TCP port 80/443。

首先是找到這篇,資料有點舊,但裡面關掉 nginx 的方法還算是有用:「How to setup gitlab without embedded nginx」。

現在只要把 /etc/gitlab/gitlab.rb 裡面的:

  • nginx['enable'] 改成 false
  • web_server['external_users'] 改成 ['www-data']

然後跑 gitlab-ctl reconfigure 讓他更新設定檔,接下來停掉整個 GitLab 再打開 (或是重開機) 讓 nginx 完全失效就可以了。

接下來弄好自己的 nginx 以及 HTTPS 設定,這個部份我自己偏好用 dehydrated,其他人會有不同的偏好設法。

在弄完 nginx 後再來是 proxy_pass 類的資訊要帶進去,這個部份可以參考本來 GitLab 的 nginx 設定檔 (在 /var/opt/gitlab/nginx/conf/ 這下面),其中最重要的就是 GitLab 本身,我們會在 /etc/nginx/conf.d/upstream.conf 裡面寫入對應的 upstream 資訊 (沒這個檔案就自己生一個):

upstream gitlab-workhorse {
    server unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket;
}

接下來是在對應的 virtual host 下設定 proxy_pass

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://gitlab-workhorse;
    }

另外我有啟用 GitLab 提供的 Mattermost,所以也要翻設定導進去:

#
upstream gitlab_mattermost {
    server 127.0.0.1:8065;
}

與:

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://gitlab_mattermost;
    }

都弄好後叫 nginx 重讀設定,接下來應該就會動了... 然後 TCP port 80/443 也算自由了,要掛其他的網域上去應該都 OK。