Bilibiliの動画をyt-dlpでダウンロードしていると、特定のCDNから配信される場合だけ、ダウンロード途中で速度が極端に低下したり、The read operation timed outが発生したりすることがあった。
Got error: Downloaded 87390979 bytes, expected 195457749 bytes. Retrying (1/10)...とか続いて、結局失敗する。
-vで詳細なログを出しながら何度か試しているうちに、少し不思議な挙動が見えてきた。
結論から言うと今回の現象は、Bilibili側のCDNアクセス時に一部データの遅延によりエラー発生。一度動画を最後まで取得すればその後のダウンロードが安定するという可能性が高そう。
ただしCDN内部のキャッシュ状態は外部から直接確認できないため、これはあくまで観測結果からの推測となります。
発生した現象:Got error. Retrying (1/10)…
yt-dlpで動画をダウンロードしていると、以下のようなログが出ることがあった。
Got error: Downloaded 87390979 bytes, expected 195457749 bytes. Retrying (1/10)...
つまり、約195MBのデータを受信するはずだったHTTPリクエストが、約87MB受信したところで途中終了している。
その後、何度かリトライされるも、結局完全なファイルとはならずに終了。
CDNによって挙動が違う
興味深かったのは、同じ動画でも配信されるCDNによって挙動が違ったこと。
今回問題が発生したのは、
upos-sz-mirrorcosov.bilivideo.com
一方、別のCDNである、
upos-hz-mirrorakam.akamaized.net
から配信された場合は、ダウンロード速度は遅いものの、途中で止まることなく最後まで完走した。
つまり、
bilivideo.com の場合、
速度は比較的速い
↓
途中で速度低下・タイムアウト
↓
リトライ
akamaized.net の場合、
速度は遅い
↓
しかし安定して完走
という違いがあった。
この時点で、動画ファイルそのものの破損や、yt-dlpの基本的なダウンロード処理が原因である可能性は低そうだと考えた。
socket-timeout を延長してみる
yt-dlpにはソケット通信のタイムアウトを指定する--socket-timeoutオプションがある。
そこで、タイムアウトをすこし長くして試してみた。
yt-dlp --socket-timeout 60 URL
すると、約27~30%付近で止まっていたダウンロードが、少し先まで進むようになった。
約27.9%
↓
タイムアウト
タイムアウト時間を延長(--socket-timeout設定)
↓
さらに先まで進む
やはり、動画ファイルのデータが特定の場所で壊れているわけではなさそう。
まぁこのような状況が発生するのは1つだけじゃないからね、それはそう。
http-chunk-size を小さくしてみる
次に、HTTPダウンロードのチャンクサイズを小さくして試した。
例えば、
yt-dlp --socket-timeout 60 --http-chunk-size 5M URL
のような設定。
すると、さらにダウンロードが先まで進むようになった。
最終的には、
27.9%付近で停止
↓
44.7%付近で停止
↓
86.4%付近で停止
↓
93%付近、速度低下しながらも・・・
↓
100% 完走
という状態になった。
最初は27~30%付近でおかしくなっていたものが、設定を変更すると44%、86%、93%と、徐々に先へ進んでいった。
つまり、その時々で通信が詰まったりしている?けれど一応最後までダウンロードはできる、ということ。
一度100%までダウンロードすると、次はスムーズに
そして今回の検証で最も重要だったのがここ。
まず、タイムアウト時間を延長し、HTTPチャンクサイズを小さくすることで、何度か詰まりながらも最終的に100%までダウンロードした。
そして、その直後に同じURLを、今度はオプションを付けずに再度ダウンロードしてみた。
結果は、
最初から最後までスムーズにダウンロード完了!
bilivideo.comだったのにも関わらず。
この結果から、
一度100%まで取得したことでCDN側のキャッシュ状態が変化し、2回目以降のダウンロードではデータが安定して配信されるようになった
のではないかと思う。
初回アクセス
↓
一部のデータ取得が遅い
↓
タイムアウトしながらもリトライ
↓
徐々にデータ取得
↓
100%まで完走
↓
(CDN側のキャッシュ状態が改善した可能性)
2回目のアクセス
↓
キャッシュから安定して配信
まとめ
ということで CDNのキャッシュが問題 なのだと思う。多分。
(プロのネットワークエンジニアでもなんでもないので勝手な推測ですが)
そしてそれがわかったところでユーザー側にできることはあまりないかもしれない。
ただタイムアウトを長くしたり、チャンクサイズを小さくしたりすることで、途中で失敗せず最後まで取得できる可能性を高めることはできるかもしれないので、思ったことを簡単にまとめてみました。
重ねて言いますが、あくまでもこれは今回観測した環境での結果、推測であり、すべての状況に当てはまるとは限らないので悪しからず。

コメント