scp -3:直接對兩個 remote host 複製檔案

剛剛找資料才發現的,scp 指令早就可以針對兩個遠端複製檔案了:「scp from one remote server to another remote server」。

可以加上 -3,像是這樣:

scp -3 src:/foo/bar/a.zip dst:/tmp/

不過依照說明可以不用加,因為這是 default 值:

Copies between two remote hosts are transferred through the local host. Without this option the data is copied directly between the two remote hosts. Note that, when using the legacy SCP protocol (via the -O flag), this option selects batch mode for the second host as scp cannot ask for passwords or passphrases for both hosts. This mode is the default.

看了 Stack Exchange 上的回答日期,是 2014 年十月回的,所以至少 Ubuntu 16.04 就有這個功能了?(沒有去查這個功能多早...)

之前一直都是查怎麼用 rsync 搬,然後發現做不到所以都還是傻傻的透過 jump server 轉運檔案,沒想到隔壁棚早就給了解法...

這樣有些情境搬檔案就簡單多了...

SQLite 官方自己搞的 Cloud Backed SQLite

SQLite 自己搞了一套使用雲端空間為儲存空間的技術:「Cloud Backed SQLite」,對應的 Hacker News 討論可以看「Cloud Backed SQLite (sqlite.org)」這邊。

他說目前支援 Azure Blob StorageGoogle Cloud Storage,這點比較有趣,沒有提到 Amazon S3

The system currently supports Azure Blob Storage and Google Cloud Storage. It also features an API that may be used to implement support to other cloud storage systems.

跟之前的 sql.js 專案不太一樣,sql.js 的作法是用 HTTP range 存取現有的 SQLite 資料庫檔案,而這次的這個專案則是改變底層架構,去配合雲端環境的特點。

雲端的 storage 因為每個 access 都會有很高的 latency (相比於本地的空間),所以要避免太多 random access,儘量以 sequential access 為主,這個特性像是以前在處理傳統磁頭硬碟時的技巧。

另外一個特點是雲端空間有多檔案的概念,所以也可以利用這個方式設計資料結構。

還蠻有趣的計畫,而且是官方搞的...

用 Perl 把 log 丟上 Slack

因為想在 Raspberry Pi 上面把一些 log 丟上 Slack,本來看到「Stream Any Log File to Slack Using curl」這篇,但發現裡面在把字串包進 JSON object 的方法太髒 (直接把 " 換成 '),另外一方面是 Slack 已經在宣導不要用舊版的 Incoming Webhooks,所以決定用其他方式來處理。

選擇 Perl 主要是因為有一陣子沒有用 Perl 寫東西了,倒不是什麼特別的原因 (如果考慮到 Raspberry Pi 上資源有限的話,應該用 C 或是 Rust 或是 Go,但我的 Raspberry Pi 還沒忙到這種程度...),所以決定用 Perl 來實做這個程式,把 log 檔案丟上 Slack:

這邊有些比較不太常見的選擇:

  • 不用 File::Tail 而反而是用 pipe 的方式取得 tail -F 的輸出,是因為 File::Tail 非常舊了 (2015),實做上沒有用到 inotify 類的界面監控檔案的變化,反而是系統的 tail 有做。
  • JSON::PP (pure perl 版本) 而不是 JSON 是因為 JSON::PP 在 Perl 5.14+ 後內建了,我沒有太在意效能,這也是上面放 use v5.14 的原因。
  • 這邊的 API 呼叫還是選擇了 WWW::Mechanize 是因為沒有內建的套件可以處理 HTTPS 連線 (可以參考 Perl core modules 這邊),既然要另外安裝,就裝個支援度比較完整的 libwww-mechanize-perl 來用。

然後查了一下 // 的用法在 Perl 5.10+ 就支援了,好早...

Content Defined Chunking (CDC)

前幾個禮拜在 Hacker News Daily 上看到「CDC File Transfer (github.com/google)」這則,連結是指到 GoogleGitHub 專案上,裡面實做了 FastCDC 演算法,另外說明他們為什麼要解這個問題以及對應的成果:「google/cdc-file-transfer」。

Google 的人看起來像是是在 CI/CD 階段遇到頻寬上的問題 (從「The builds are 40-45 GB large.」這邊猜),用 scprsync 看起來都不能解,所以他們自己刻了 FastCDC 演算法來解。

但我對 Content Defined Chunking (CDC) 不熟,所以先查一下 CDC 是什麼東西,就查到 restic 這篇講得很清楚:「Foundation - Introducing Content Defined Chunking (CDC)」。

要計算 delta 很直覺的作法就是要切 chunk,而接著的直覺就是固定大小的 chunk 切開,像是這樣每 16 bytes 切一個 chunk:

0123456789abcdef 0123456789abcdef 0123456789abcdef 0123456789abcdef

如果其中一個地方有變化,但其他沒變化的話就可以透過 cryptographic hash function (像是 SHA-256) 確認 chunk 內容一樣,進而省下很多傳輸的頻寬:

0123456789abcdef 0123456789ABCDEF 0123456789abcdef 0123456789abcdef

但可以馬上看出來這個方法的大缺點是只能處理 replacement,很難處理 insert & delete 的部份,舉例來說,如果變更是在開頭的地方加上 ABC,就會造成 chunk 會完全不一樣,而導致全部都要再傳一次:

ABC0123456789abc def0123456789abc def0123456789abc def0123456789abc def

這邊其實是個經典的演算法問題:想要找出兩個 string 的差異 (把舊的內容當作一個 string,新的內容也當作一個 string)。

這個問題算是 Edit distance 類型的題目,但你會發現解 Edit distance 的演算法會需要先傳輸完整個 string 才能開始跑演算法,這就本末倒置了。

而另外一個想法是,放棄固定的 chunk 大小,改用其他方式決定 chunk 的邊界要切在哪裡。而 CDC 就是利用一段 sliding window + hash 來找出切割的點。

文章裡面提到的 sliding window 是 64 bytes,這邊就可以算出對應的 HASH(b0, b1, ..., b63),然後往右滑動變成 HASH(b1, b2, ..., b64),再來是 HASH(b2, b3, ..., b65),一直往右滑動計算。

接下來 restic 會看 hash 值,如果最低的 21 bits 都是 0 就切開,所以 chunk 大小的期望值應該是 2MB?(這邊不確定,好像不能直接用 2^21 算,應該用積分之類的方法...)

For each fingerprint, restic then tests if the lowest 21 bits are zero. If this is the case, restic found a new chunk boundary.

而這個演算法可以適應新增與刪除的操作,不會造成從新增或刪除後的資料都要重傳,只有自己這個 chunk 需要重傳 (可能前或後的 chunk 也會要)。

然後挑一下 hash function 的特性,就可以讓計算的速度也很快。這邊提到了 hash function 可以用 Rolling hash,可以很快的從 HASH(b0, b1, ..., b63) 算出 HASH(b1, b2, ..., b64),而不需要全部重算。

有了 chunk 後,再用 cryptographic hash function 比較 chunk 的內容是否一樣,這樣就可以大幅降低傳輸所需要的頻寬了。

Xfce 4.18 出版

看到「Xfce 4.18 released」這個消息,可以放一個月讓 bug 飛一飛改一改再來更新...

看起來 thunar (Xfce 的檔案總管?) 改了不少東西,可以看到花了很多篇幅在介紹。看起來對我來說最有改變的是 undo 與 redo 的部份:

It is now possible to undo basic file operations and to redo them. Undo and Redo can be used for 'move', 'rename', 'trash', 'link' and 'create' operations. Per default, a history of the last 10 operations is stored, though the history length is configurable. Whenever an Undo/Redo is triggered, a notification with few details will be shown.

其他的應該是還好...

Amazon EFS 的 file lock 限制

看到「Amazon EFS now supports a larger number of concurrent file locks」這篇提到:

This Amazon EFS update increases the number of simultaneous file locks an NFS mount can acquire to 65,536 (from 8,192 previously), enabling Amazon EFS to be used for a broader set of applications that heavily leverage file locking (including message broker and distributed analytics applications).

所以 NFS 的部份先前有 8192 個的上限在,現在則是拉 65536 個了。

不過提到 message broker,應該是以前的應用利用 NFS file lock 來做一些事情?

Amazon EFS 效能提昇的一些討論

上一篇「Amazon EFS 的效能提昇」提到 Amazon EFS 的效能提昇,在 Hacker News 上看到 Amazon EFS 團隊的 PMT (Product-Manager-Technical) 出來回一些東西:「Amazon Elastic File System Update – Sub-Millisecond Read Latency (amazon.com)」,搜尋 geertj 應該就可以看到他回的東西了...

像是即使是 Jeff Barr 發表這篇文章,也還是經過 legal team 的同意才能發表:

(PMT on the EFS team).

Yes, the wordings are carefully formulated as they have to be signed off by the AWS legal team for obvious reasons. With that said, this update was driven by profiling real applications and addressing the most common operations, so the benefits are real. For example, a simple WordPress "hello world" is now about 2x as fast as before.

另外這次的效能提昇是透過 cache 層達成的:

I'm the PMT for this project in the EFS team. The "flip the switch" part was indeed one of the harder parts to get right. Happy to share some limited details. The performance improvement builds on a distributed consistent cache. You can enable such a cache in multiple steps. First you deploy the software across the entire stack that supports the caching protocol but it's disabled by configuration. Then you turn it for the multiple components that are involved in the right order. Another thing that was hard to get right was to ensure that there are no performance regressions due to the consistency protocol.

然後在每個 AZ 都有 cache:

The caches are local to each AZ so you get the low latency in each AZ, the other details are different. Unfortunately I can't share additional details at this moment, but we are looking to do a technical update on EFS at some point soon, maybe at a similar venue!

另外看起來主要就是 metadata cache 的幫助:

NFS workloads are typically metadata heavy and highly correlated in time, so you can achieve very high hit rates. I can't share any specific numbers unfortunately.

還是有很多細節數字不能透漏,但知道是透過 cache 達成的就已經可以大致上想像後面是怎麼弄出來的了...

Amazon EFS 的效能提昇

AWS 宣佈他們將 Amazon EFS 的 latency 大幅降低以提昇效能:「Amazon Elastic File System Update – Sub-Millisecond Read Latency」。

Linux 上一般是用 NFS 掛 EFS,個位數的 ms 的確對於效能影響超大,現在宣稱讀取的部份降到 0.6ms,應該會有蠻明顯的感覺:

Up until today, EFS latency for read operations (both data and metadata) was typically in the low single-digit milliseconds. Effective today, new and existing EFS file systems now provide average latency as low as 600 microseconds for the majority of read operations on data and metadata.

然後不另外收費:

This performance boost applies to One Zone and Standard General Purpose EFS file systems. New or old, you will still get the same availability, durability, scalability, and strong read-after-write consistency that you have come to expect from EFS, at no additional cost and with no configuration changes.

另外就是過去幾個禮拜他們把現有的 EFS 都轉移過去了:

We “flipped the switch” and enabled this performance boost for all existing EFS General Purpose mode file systems over the course of the last few weeks, so you may already have noticed the improvement. Of course, any new file systems that you create will also benefit.

不過 EFS 另外一個問題就是貴炸,用錢換方便...

OpenSSH 的 scp 改用 SFTP 協定

在「By default, scp(1) now uses SFTP protocol」這邊看到的,OpenSSH 的 scp 改用 SFTP 協定了,原因也有附在文章裡:

SFTP offers more predictable filename handling and does not require expansion of glob(3) patterns via the shell on the remote side.

要注意這是 BC-break change,有些之前會動的 case 在改用 SFTP 後會爛掉,但這算是前進了一大步,scp 因為 spec 的關係很難維護安全性。

在「Deprecating scp」這邊也有提到相關的問題,另外也給出了一些範例。

rsync 的預設值是傳整個檔案,不是 delta

剛好最近工作上需要透過 4G 網路傳大檔案,但希望大檔案傳到一半斷掉後可以續傳,而不要浪費頻寬整個重傳,所以查了資料並且測了一些東西...

其中一個比較特別的是發現 rsync 的預設是傳整個檔案 (當檔案有變化時),而不是傳 delta (有變更的部份),不過還好,可以透過指令強制使用 delta。

在「Does rsync --inplace write to the entire file, or just to the parts that need to be updated? (for btrfs+rsync backups)」這邊有提到幾個需要設定的指令。

首先是標題就有提到的 --inplace,在 manpage 裡面有提到是直接更新檔案,而非建立一個新檔案再 rename,這樣做的缺點是其他的應用程式可能會讀到改到一半的檔案:

update destination files in-place

另外一個提到的是 --no-whole-file,這個要看 --whole-file 的說明來理解,後者就是不開 delta:

copy files whole (w/o delta-xfer algorithm)

第三個是 -c,強制使用 checksum 比對:

skip based on checksum, not mod-time & size

不過我的應用裡面不太想管這個,就沒設定 -c 了,基本上是靠 ssh 的保護,不會有收到錯誤封包的問題。

整體來說,這個方法對兩邊的機器都比較吃資源,而且會遇到應用程式在還在傳輸時讀到檔案的問題,但如果可以克服,而且目標是省頻寬的話,算是個還不錯的方法...