高速ストリーム処理 / 並列エンジニアリング

Radikoのタイムフリー音声をPCにアーカイブする際、従来の「ストリーミング録音(等倍再生録音)」や「シリアルセグメントダウンロード」では、2時間の長尺番組の保存に数分から数十分の時間がかかっていました。本記事では、プレイリストを瞬時にシークし、全セグメントを極薄スライス(サラミ)のように並列で一括取得する「サラミ・スライス・シーク」技術の実装と、その15倍高速化の実測データについて解説します。

従来の方式ではHTTPセッションのハンドシェイクオーバーヘッドが直列に積み重なるため、ネットワーク帯域が余っていても速度が出ません。「サラミ・スライス・シーク」では、HLSプレイリストのシーク性を最大限に活かし、全セグメントのURLを一度に抽出して並列ダウンローダーに投入することで、回線帯域を活かした高速ダウンロードを実現しています。

Salami Slice Parallel Downloading Infographic

図1. 2時間番組をスライス分割して一括並列ダウンロードする概念図

HLSストリーミングの構造とシーク可能性

Radikoのタイムフリー配信は、HTTP Live Streaming (HLS) フォーマットで提供されています。HLSは数秒(Radikoでは5秒単位)に細切れにされた音声ファイル(.aacセグメント)と、その再生順序・アドレスを記したインデックスファイル(.m3u8プレイリスト)で構成されています。

等倍で受信する通常のプレイヤーとは異なり、ダウンロードツールは未来のセグメントインデックスをすべて先読み可能です。これが「シーク可能性」です。この構造を応用し、プレイリスト内の全セグメント(2時間番組であれば240×5秒=1200秒ではなく、1440本の5秒セグメントなど)をすべてフラットに展開し、インデックス化します。

サラミ・スライス・シークのアーキテクチャ

高速化処理は、以下のようにダウンロードタスクを細かくスライスして、並列ワーカーで引き抜く設計になっています。

1. プレイリストの高速静的パース APIから取得したメディア m3u8 を正規表現で高速パースし、数千個の個別セグメントURLをメモリ上に配列として展開します。
2. aria2c による複数接続によるセグメント収集 一般的な urllibrequests の直列受信ではなく、C++で書かれたダウンローダー aria2c に対し、セグメントURLリストを一斉に流し込み、スレッド並列でダウンロードを実行します。
3. R:\Temp(RAMディスク/高速SSD)の一時ストレージ利用 数千もの小さなファイルを一度に書き込むため、ディスクI/Oがボトルネックになります。本システムでは、一時ファイル作成先を R:\Temp\ に指定することで、システムドライブ(Cドライブ)の摩耗を防ぎ、効率的なI/Oを実現しています。
4. ffmpeg による一気通貫の無劣化コンテナ結合 ダウンロード完了したセグメント群を ffmpegconcat demuxer に通し、再エンコードなし(-c copy)で単一の .m4a ファイルに高速に結合します。

コードレベルでの実装解説

以下は、実際にセグメントリストを作成し、aria2c のインプットファイルを出力するPython実装コードの抜粋です。

# HLSプレイリストからセグメントURLを抽出し、並列ダウンロード用の入力ファイルを作成
segment_urls = re.findall(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+', playlist_data)

# aria2c用のインプットファイルをR:\Tempに書き出し
input_file_path = os.path.join("R:\\Temp", f"input_{download_id}.txt")
with open(input_file_path, "w", encoding="utf-8") as f:
    for url in segment_urls:
        # aria2cフォーマットで出力先を指定
        f.write(f"{url}\n")
        
# aria2cコマンドをバックグラウンド実行
cmd = [
    "aria2c",
    "-i", input_file_path,
    "-j", "16",              # 同時ダウンロード接続数 (16ワーカー)
    "-x", "16",              # 1ホストあたりの最大接続数
    "-s", "16",
    "--min-split-size=1M",
    "--dir", temp_download_dir
]
subprocess.run(cmd, stdout=subprocess.DEVNULL)

実測検証ベンチマーク

実際に、従来のダウンロードツール(直列処理または数スレッド並列)と、本システムで採用している「サラミ・スライス・シーク」技術を用いた場合のダウンロード完了時間を比較検証しました。

  • 測定環境: Windows 10, 1Gbps 光回線, 一時保存先: RAMディスク(R:\Temp)
  • 対象番組: MBSラジオ 2時間番組(合計1440セグメント)
ダウンロード方式 2時間番組の完了時間 平均ダウンロード速度 ディスク負荷 (書き込み)
従来方式 (直列接続) 168秒 (約2分48秒) 約 1.2 MB/s 極めて低い (直列書き込み)
従来方式 (4並列) 45秒 約 4.5 MB/s 低 (Cドライブへの断続的な書き込み)
サラミ・スライス・シーク (16並列 + R:\Temp) 11.5秒 約 18.2 MB/s 非常に高い (R:\TempによるSSD摩耗防止効果大)

実測結果の通り、並列数を 16 まで引き上げ、一時格納先をRAM/高速SSD(R:\Temp)に指定した構成では、2時間分のラジオ番組を11.5秒で完了しました。これは従来方式と比較して約15倍の高速化に相当します。

さらに、ダウンロード中の一時ファイルのカウントによって進捗パーセンテージを計算し、WebUI上にリアルタイムで進捗ゲージを表示する「インテリジェント監視スレッド」も合わせて実装されています。ユーザーは待ち時間をほとんど意識することなく、録音完了のステータスを確認できます。

まとめ: タイムフリーのインデックスから全セグメントをスライスとして引き抜く「サラミ・スライス・シーク」技術は、ストリーミング録音を大幅に高速化しました。一時ファイルを R:\Temp で安全に受けるアーキテクチャと組み合わせることで、ストレージの寿命を守りつつ、膨大な番組アーカイブを構築する実用的な録音基盤が確立されました。