Hidekichi| →

LinuxとWindowsのアップデートの違い

聞いたこともないトランザクションとかLinuxは何をしているのでしょうか?

まずはシステムアップデートの流れから復習

私が使用しているディストリビューションがCachyOS(Arch Linux系)ということもあり、その標準パッケージマネージャーpacmanを例に書いていこうかと思います。Debian/Ubuntu系で使われるaptにしろ、Fedoraなどで使われるdnfにしろその見た目や、各サーバーのデータベースや構造は違ってもどれもLinuxという枠組みで見ると同じようなことをしています。

Arch系のシステムアップデートはsudo pacman -Syu(パッケージのデータベースの同期とシステム全体のアップデート)をターミナルやGUIのパッケージマネージャで(システムのアップデートとして)実行すると、システム内部では以下のような感じでトランザクションが処理されます。

  1. データベースの更新(Sync Database)
    • アップデート前の事前準備
    • リポジトリから最新のパッケージ一覧をダウンロードします。どのパッケージに更新があるかを調べるためです
  2. 依存関係の解決と計算(Dependency Resolution)
    • 矛盾がないかのチェック
    • アップグレード対象のパッケージと、それに必要な依存ライブラリの整合性を検証します。競合や不整合(パッケージの衝突)が発生しないか、この段階で事前に計算します。
  3. パッケージのダウンロード(Fetch Archives)
    • 更新に必要な.pkg、.tar、.zstパッケージファイルをローカルキャッシュ(/var/cache/pacman/pkg)へダウンロードし、署名(PGP)を検証します
  4. トランザクションの初期化(Transaction Initialize)
    • ここから変更フェーズ
    • ユーザーの確認(Y/n)後、pacman内部でトランザクションが作成されます
      • システムデータベースのロック(/var/lib/pacman/db.lckの作成)
      • インストール前のフック処理の実行
  5. 変更コミット・適用(Commit Transaction)
    • ダウンロードしたパッケージを展開し、古いファイルを新しいファイルへと置き換えていきます。
      • ファイルの展開中にエラーが発生した場合、pacmanは未完了の変更をロールバックし、壊れた状態が残らないように安全中断しようと試みます
  6. トランザクションの完了・解放(Release Transaction)
    • すべてのファイルの配置とインストール後のフック処理が完了したらロックファイルを削除して、トランザクションを正常完了させます。

流れとしてはこういうことです。

トランザクションをわかりやすく

トランザクションという言葉が何をしているのかがわかりにくくさせていると思います。トランザクションは「取引・商売」というような意味ですが、ITやコンピューターの世界では単にそれらの単語からイメージするものとは少し異なります。

例えば、「銀行を例にしてAさんの口座からBさんの口座へ1万円振り込む」という流れでいうと、

  1. Aさんの口座から1万円を減らす
  2. Bさんの口座に1万円増やす

こういう処理が行われます。もし「1」の減らした状態直後にシステムエラーや停電が起きたらAさんのお金だけが消えてBさんには届かないと言うことになります。そのためシステムでは、この2つの処理を1セットとして両方ともが成功したら初めて完了とするとするわけです。途中で失敗したら「1」の作業も取り消して最初の状態に戻します。

この全て成功するか、全く処理されないかを保証する一連の処理の事を銀行の取引にちなんでトランザクションと呼ぶようになりました。

これはどこかで聞いた覚えがあるかも知れませんが、FedoraでいうAtomicというものとそっくりです。Fedora Atomic各種スピンなどのImmutable(不変)更新というのは、この仕組みをシステム全体、OSのルートレベルまで拡張した仕組みです。成功するか、失敗して前の状態のまま留まるかのいずれかしかないという状態の事をAtomic(不可分 = これ以上分解できない)と冠しているわけです。

トランザクションフックとは何をしているか

「トランザクションフックを実行しています(Running transaction hooks…)」という表示は、パッケージのファイル展開(置き換え)が完了した直後または直前に、「システムを正しく動作させるための仕上げ処理」を自動で実行している状態です。

ダウンロードして展開しただけではシステムはそれを認識できないので、特定のタイミング(イベント)に引っ掛けて自動実行するプログラムスクリプトの事をフック(Hook)と呼びます。

トランザクションフック…というような表示が出ている時、次のような仕上げ作業が順番に行われています。

  1. カーネルと初期応答機能の更新(mkinitcpio)
    • Linuxカーネルが更新された場合、パソコン起動時に必要な初期イメージ(initramfs)を再生成します。
  2. 共有ライブラリのキャッシュ更新(ldconfig)
    • 追加・更新された新しいライブラリ(.so ファイル)をシステムが即座に見つけられるよう、リンク情報を更新します。
  3. デスクトップやアイコンのデータベース更新
    • 新しいアプリを入れた際、アプリ一覧にアイコンや名前(.desktop)が正しく表示されるようキャッシュを再構築します。
  4. フォントキャッシュの更新(fc-cache)
    • 新しいフォントを追加した際、文字化けせずに使えるようシステムに認識させます。
  5. 不要な設定ファイルや古い一時ファイルのクリーンアップ

システムファイルだけでなく、GIMPや様々なアプリを更新したとしても同様に処理が行われます。1回ごとに処理するのではなくまとめて処理したあと、仕上げ処理を1回で行うための方法です。

トランザクションの初期化中などとあった場合は、銀行で言うと「誰から誰へ、いくらのやり取りをするか」というような計画(伝票)を作成して、取引を安全に行うための整備を事前準備しているというようなこととなります。そのため、何かのトラブルでトランザクションが失敗した時に備え、前の状態に戻れるように、「取引中」といったロックファイルを作り、第三者からの処理が入らないようにしたり、処理が行われる前にどういう状態であったかを記録してメモにしておくというようなことが行われます。

この辺りは言われてみれば「それはそうだ」と思われることだと思います。けれどもどこにも説明なく、その単語をそのままカタカナにして書かれても意味がわからないとなるのは当然のことです。

「トランザクションフックを実行しています」の最中は、すでにシステムファイルが書き換わっており、最後の仕上げ段階にいます。ここで強制終了(電源オフやターミナルの閉鎖)をすると、カーネルイメージの生成が途中で止まるなどして次回OSが起動しなくなる危険性が高いため、処理が完了するまで必ず待つ必要があります。

他のディストリビューションではどうなっているのか?

本質的にやっていることは、どのパッケージマネージャでも全く同じです。Arch系以外のディストリビューションでも、コマンド名やファイル構成こそ異なりますが、内部のロジックや処理の流れはほぼ統一されています。

  1. メタデータの同期
    • リモートサーバー(リポジトリ)の最新リストをダウンロードしてローカル情報と比較する。
  2. 依存関係の計算
    • どのパッケージが必要か、バージョン衝突が起きないかを判定し、変更リスト(トランザクション)を作成する。
  3. アーカイブの取得
    • 更新に必要なファイル群(.deb や .rpm など)をローカルキャッシュに一括ダウンロードする。
  4. 展開・適用
    • 旧ファイルを削除し、新ファイルを配置する。途中で失敗した場合は安全に中断・変更を破棄する。
  5. フック処理
    • キャッシュ再構築、サービスの再起動、カーネルイメージ(initramfs)の再生成などを一括実行する。
項目 ArchLinux(pacman) Debian/Ubuntu(apt) Fedora(dnf)
パッケージ形式 .pkg.tar.zst .deb .rpm
同期・更新コマンド pacman -Syu apt update && apt upgrade dnf upgrade
データベースの場所 /var/lib/pacman /var/lib/apt /var/lib/dnf
ダウンロードキャッシュ /var/cache/pacman/pkg/ /var/cache/apt/archives var/cache/dnf
フックの仕組み alpm-hook(/usr/share/libalpm/hooks/) DPkg::Post-Invoke などのスクリプト DNF Plugin / RPM trigger
低階層の処理実行ツール libalpm(pacmanに内蔵) dpkg rpm

と言う感じですが、かなり似通っていることがわかると思います。「リポジトリからリストを取ってきて、依存関係を計算し、取ってきて適用し、最後に後始末(フック)をする」 という思想・設計はLinuxの世界で完全に標準化されています。

NixOSでは、例えばPythonでもバージョン違いが共存できるじゃないかと言われる方がいるかも知れません。NixOSは同じアプリのバージョン違いは、それぞれにハッシュを付与してハッシュ管理しているため、Pythonのバージョンが違っても別物として共存できるようになっています。違うバージョンというのはハッシュの違いでしかないので、従来のトランザクションが抱えていた上書きによる破損のリスクはそもそも存在しないのです(そう言う処理をしないため)。そんなにNixOSが優れているなら、他のディストリビューションも追従するはずでは?とも思われるかも知れませんが、従来のトランザクションは無駄ができにくくストレージの節約にも繋がります。なのでメリットがないわけでもないのです。NixOSが超特殊だと考えるほうが良いと思います。

Windowsではどうなっているのだろうか?

Windowsのアップデートってダウンロードも勝手にして、勝手に再起動が入ってその間何もできなくて面倒が過ぎますよね。LinuxとWindowsとの最大の違いは使用中のファイル(実行中のプログラムやライブラリ)を上書きできるかどうかにあります。

項目 Linux(pacman、apt、dnfなど) Windows(Update)
使用中のファイルの上書き 可能(Linuxファイルシステムの特性) 不可(Windowsがファイルを厳重にロックする)
アップデート中の作業 そのままPCを使用継続可能 再起動時・電源オフ時に待たされる
再起動のタイミング 好きなタイミングでok 強制、または強く強要

Linuxの場合

Linuxでは、プログラムがファイルを実行中でも、ディスク上のファイルを新しいものに差し替えることができます。実行中のアプリは「メモリ上の古いファイル」を参照し続け、次にアプリを起動した時から新しいファイルが使われるため、再起動なしでアプデが完了します。

Linuxは中央集権型と言えます。

今回のトランザクションの話でもそうですが、ターミナル上にログが残ります。これはシステムファイルでも、サードパーティーアプリでも同様です。今、裏で何が起きているかがログとしてすべてリアルタイムに画面に可視化されます。ユーザーがコマンドを打った時だけ更新が走り、勝手に再起動されることはありません。

Windowsの場合

Windowsでは、実行中のDLLやシステムファイルはOSレベルで固くロックされます。そのため、アップデート時は「次回起動時にファイルを置き換える指示(予約)」だけを記録し、OSが停止・起動するタイミングでしか実際のファイル置換ができません。

Windowsは分散型(基本はOS+一部マイクロ製品)です。

Windowsでは更新内容は公開されているとは言え、画面には「○% 完了しました」や「準備しています」といった抽象的な表示しか出ず、裏で具体的にどのファイルが置換されているかは隠蔽されています。バックグラウンドでは勝手にダウンロードが進み、予期せぬタイミングで再起動を要求されることがあります。

アップデートのまとめ

Linuxは、走行中の電車(OS)のパーツを、乗客を乗せたまま1つずつ新しいものに組み替えていく」ようなアプローチ。フックを使ってその場で整合性を整えます。Windowsでは、一度電車(OS)を完全に駅に止めて乗客を全員降ろし、工場に引き込んでパーツを一括交換してから再発車する」ようなアプローチ。

Linuxは停止時間をできるだけ作らずに、最小限の時間でシステム・アプリの更新ができるようなサーバー・エンジニア向けの設計となっており、Windowsは一般ユーザーがファイルを壊さないようにOSが確実に整合性を保てる状態(作業中以外・停止時)に処理する設計を取っているという違いがあります。

本来であればWindowsの方が確実に思われるでしょうが昨今のアップデートの不具合から考えると、何をしたからおかしくなったがわかるほうが、最初に試して問題が起きた人が即座にフィードバックできるという点を考えると何をしているのかが隠蔽されるのはある意味問題です。Macのように一社でしか作っていない場合は、現行のWindowsのような方法でいいと思うのです。しかし様々な環境や使い方が想定を超えているようなWindowsだと、本来は問題ないはずだけども何かしらで問題が起こることが多くなると思うのです。フィードバックを多く得られた方がより安定したアップデートが可能になるとも言えます。そうしないのであればマニュアルインストールとドキュメント、ロールバックを確実にできる環境が必要になると思うのです。

Windowsでは、それらは一応あるので問題があるファイルを配信して色んな人に怒られている現状があります。

おまけ pacmanあれこれ

pacmanの更新時にはpacman -Syuとしますが、他にもいくつか便利なものをかいておきます。

オプション文字 意味 役割
-S Sync(Synchronize) 同期モード。リポジトリ(サーバー)からパッケージを取得・同期して操作する大枠のモード。
y refresh データベースの更新。 ローカルにある「サーバーのパッケージ一覧リスト」を最新に更新(refresh)します。
u sysupgrade(システムアップグレード) パッケージの更新。 システム全体(インストール済みアプリ)を最新バージョンへアプデ(upgrade)します。

本来ならrefreshなのでrなどを使いたいところですが、既に他で使用されている(予約されている)ためキーボードで押しやすい位置にもあること、Syncという意味からもyが選ばれたと言う経緯があるそうです。pacman -Syでリポジトリのリスト(DB)を1回更新すると言う事ですが、pacman -Syyとすると「リストが最新に見えても、強制的にもう一度完全にダウンロードし直す」と、文字を重ねることでより強く「強制的に(Force状態)で動作させる」というルールがあります。

ローカルスクリプト(.pkg.tar.zst)をインストールする際にはpacman -Uと大文字のUになっています。小文字のuとは意味が異なり、Upgrade/Install local packageとなります。インストールスクリプトはcURLなどを使用してダイレクトにできるものもあるのにどうしてpacman -U <スクリプト>等としてわざわざ入れるのかは、アンインストールする時にpacmanでさっくりと削除するためです。

これらはオプションを全部覚えておく必要があるのではなく、「そういう機能があったな」と理解しておき、必要に迫ったらArch Wikiなどで調べて使用すればよいと思います。さらに細かい情報が記載されています。

Wait/Download only

sudo pacman -Syuw

ダウンロードだけ先に済ませておいて、後から時間ができたときに、sudo pacman -Suとすると一瞬でインストールを終わらせると言った使い方ができます。wはwaitで、Wait/Download onlyという意味になります。

ダウングレードを許可する更新

sudo pacman -Syyuu

配信側が配信した後、何かの問題で配信自体をロールバックしてしまって、それらをダウンロードしたPCでローカルの方が新しいとなった場合に、たいていは数日で更新されると思うので「ローカルの方が新しい」のは放置しておいても良いと思いますが、(サウンド系の配信等で)音が出なくなったとかとシステムがおかしくなるほどではないが問題が出た場合にそれでは困るので、ダウングレードを許可する更新をして、以前の正常だったバージョンに強制的に戻すと言う事が可能です。

Search

pacman -Ss <keyword>

リポジトリにあるパッケージをキーワード検索します。Searchです。

Query Search

pacman -Qs <keyword>

「自分のPCにすでにインストールされているパッケージ」の中から検索します。自分が入れたかどうか確認したい時に便利です。

Search Info

pacman -Si <package>

未インストールのパッケージの「説明、依存関係、ダウンロードサイズ」などの詳細情報を確認します。Search Infoになります。

Query Info

pacman -Qi <package>

インストール済みパッケージの詳細情報(「いつ入れたか」「どのパッケージに依存されているか」など)を確認できます。Query Infoになります。

Query Dependencies True Orphans

pacman -Qdt

以前別のソフトを入れた際についでにインストールされ、現在はどのソフトからも必要とされていない「孤立したパッケージ」を一覧表示します。Query Dependencies True Orphansと言う意味になります。

Remove Nosave Recursive

sudo pacman -Rns <package>

パッケージを消す際、単に消す(-R)だけでなく、「そのアプリしか使っていなかった不要な依存ライブラリ」や「設定ファイルのバックアップ」もまとめて綺麗に削除します。アプリをアンインストールする時は基本これを使います。Remove Nosave Recursiveと言う意味です。

インストールあれこれ

インストールする際に、sudo pacman -S firefox等とすることはよくあります。firefox自体はそれでよいのですが、共用されているライブラリが最新でない可能性というのはあったりします。特にCachyOS(Arch系)などローリングリリースタイプのディストリビューションでは部分的なアップデート(Partial Upgrade)と呼ばれる特有の罠があったりします。

pacmanは最新のFirefoxと、そのfirefoxが使用する最新のライブラリをダウンロードして配置しようとします。この時、もしpacmanが必要なライブラリの一部しか更新しなかったり、あるいはローカルの古いライブラリと噛み合わなくなると依存関係の不整合が起こる可能性が発生します。そのため毎日システムアップデートしている人ならいざ知らず、たまにしかシステムのアップデートをしていない場合はsudo pacman -Syu firefoxとその時の最新にシステムもしておく方が間違いがないとされるのです。

sudo pacman -Sy firefoxなどは特に危険これはデータベースだけ更新することになり、アプリは最新が入りますが、周りの古いライブラリが放置されるため一番危険な「部分更新(Partial Upgrade)」の状態になります。

他にもたくさんのオプションがありますが、探して入れて削除するということができれば何でもできるのではないかと思う次第です。

まとめ

主にトランザクション中心に書きました。これらは「そう言われたらわかる」となると思いますが、それに合うような日本語がない、あるいはパッと思いつかない程度に逆に難しい単語となるならトランザクションでいいかとなるのもわかるとも言えます。

またWindowsのアップデート(特にメジャーアップデート)は、裏でOS丸ごと入れ替え大作戦を実行しています。現在のWindowsを残したまま、バックグラウンドで巨大なOSイメージを展開・構築し、再起動時に古いOS(Windows.old)からユーザーデータや設定を新しいOSへ引き継ぐ(移行・移動する)ため、膨大なディスクI/Oと処理時間がかかります。Windowsはシステムの更新時、OSが強固にロックするため、停止中あるいは再起動中にしか更新作業ができないと書きましたが、入れ替えて正常ファイルが動くように確認しながら書き換えるのにとにかく時間がかかります。

一方Linuxでは、作業中にでもファイルの更新はでき、更には好きなタイミングで更新作業に入れるので、余裕を持ちながら更新作業ができます。新しいファイルは再起動してから使えるようになるのは変わりないですが、古いファイルのまま作業をキリの良いところまで進めて好きなタイミングで作業できる賢い方法だと思います。

良いことばかりのLinuxではありませんが、はじめて更新をされた人はその更新作業の速さに驚かれることかと思います。

システムの設定などは色んなところで書かれているのである程度は分かるものの、どう使用していけばよいのかはあまり書かれていないので、本来は問題ないけれども間違った方法で運用すると不具合が出てしまう事があります。「それを直せる者だけが使うべきだ」と言われることもありますが、決してそんな事はないと思っています。

WindowsはそれらをOSができるだけやっているだけで、どっちもどっちなのです。Linuxでもログは見れますがGUIでアップデートやアプリのインストールをすればWindowsと変わりません。

blogカテゴリ内のタグ一覧