为什么更新正在运行的Linux系统没有问题?


25

多年以来,我每天都使用Linux系统,并且在运行时更新系统从来没有遇到重大问题,但是我仍然想知道为什么这是可能的。

让我举一个例子。

假设某个软件包中的程序“ A”正在系统上运行。在某些时候,此程序需要打开同一程序包中的另一个文件(“ B”)。之后,程序“ A”关闭“ B”,因为它不再需要它。假设现在我更新包“ A”和“ B”所属的包。至少在目前,“ A”不受此操作的直接影响,因为它在RAM中运行并且更新仅替换了硬盘上的“ A”。假设文件系统上的“ B”也已被替换。现在,由于某种原因,“ A”需要再次读取“ B”。问题是:“ A”是否有可能找到“ B”的不兼容版本并以其他方式崩溃或故障?

为什么没有人通过使用实时CD或类似方法重新引导来更新系统?


我倾向于避免这样的更新,不是因为更新的机制(可以很好地做到这一点),而是因为首先要根据更改对我的应用程序和配置进行测试的偏好。然后,我将有一个单独的现在更新的系统可以切换到该系统。但是除此之外,用户区中的更新通常不是问题,对于小型补丁程序或安全修复程序,我只会这样做。
Skaperen 2012年

Answers:


23

更新Userland很少有问题

您通常可以在实时系统上更新软件包,因为:

  1. 共享库存储在内存中,而不是在每次调用时从磁盘读取,因此旧版本将一直使用,直到重新启动应用程序为止。
  2. 打开的文件实际上是从文件描述符读取的,而不是文件名,因此即使移动/重命名/删除文件,文件内容仍可用于运行的应用程序,直到扇区被覆盖或文件描述符关闭为止。
  3. 如果软件包设计合理,则通常需要由软件包管理器正确处理需要重新加载或重新启动的软件包。例如,每当libc6升级时,Debian将重新启动某些服务。

通常,除非您要更新内核且未使用ksplice,否则可能需要重新启动程序或服务才能利用更新。但是,很少需要重新启动系统以更新用户空间中的所有内容,尽管在台式机上有时比重新启动单个服务要容易。

也可以看看

http://en.wikipedia.org/wiki/Ring_%28computer_security%29#Supervisor_mode


但是,如果您需要所有缓存内存,将会发生什么?在这种情况下,共享库将不得不再次从磁盘加载...
Nils

3
实际上,对#1的描述不是很清楚。旧库文件的内容仍保留在单独的(原始)inode下,即使链接到该文件的所有名称都消失了,只要某个进程打开了文件或映射了其内容,数据也保持不同(并且文件系统无法重新安装r / o,直到文件的取消链接完成为止。映射原始文件的过程仍然具有到原始内容的内存映射。
Skaperen 2012年

@Nils我不是专家,但是如果您用尽了缓存,会不会将其写入交换并从那里重新读取?如果已满,则某个进程可能会被阻塞,然后才能从已经在使用该进程的另一个进程中夺走内存。

@Joe no-swap也是ram。Skaperen描述了会发生什么:文件句柄保持不变。因此,基本上,该程序对旧的(已用)库有一个麻烦,直到再次释放该句柄之后,该库才会被删除-这全部在文件系统级别上-不在RAM级别上。
尼尔斯2012年

4

是的,您所描述的是可能的,但是大多数情况下,如果文件包含在软件包中,它将是一个库或其他文件,该文件只能被读取一次(因为它没有变化,因此没有理由多次阅读)。同样,如果长期需要该文件,则应用程序可能会将文件句柄保持打开状态,即使在实际的文件系统上替换了该文件句柄,打开的文件句柄也会使旧版本保持打开状态。

在大多数情况下,在流程有效期内多次读取的任何数据都是用户/可变数据,并且在程序包升级期间不会更改。另外,由于数据是可变的,因此任何程序员都可以确保自己的程序能够处理从一次读取到下一次读取的更改。


如果文件的映射未在内存中进行任何更改,则仍可以将其重新读取为“后备存储”(否则,将后备存储切换为交换(如果可用)),并且由于使用其他需求的压力,该内存中的副本也将被丢弃记忆。但这不是问题,因为原始文件仍处于打开或映射状态。替换库是一个新的不同文件,旧进程尚未打开。
Skaperen 2012年

1
@Skaperen我假设您正在谈论内存映射文件。升级软件包时,这些不是问题。所有程序包管理器都创建新文件来替换旧文件,而不是覆盖它们。实际上,这是唯一的方法,因为无法修改正在运行的可执行文件,只能将其取消链接。
Patrick

4

假设文件系统上的“ B”也已被替换。现在,由于某种原因,“ A”需要再次读取“ B”。问题是:“ A”是否有可能找到“ B”的不兼容版本并以其他方式崩溃或故障?

这是可能的,但在大多数情况下是不可能的。如果“ B”是代码库,则通常不会关闭原始版本。“ A”将继续使用“ B”的原始版本。如果在更新后运行“ A”,则将使用新版本的“ B”。在更新过程中,存在加载不兼容版本的风险。但是,由于代码库的加载方式,仅当“ A”需要的功能在其加载的“ B”版本中不存在时,这才是问题。

良好的编码习惯会使接口的功能保持不变。因此,加载哪个版本并不重要,除了新版本中已修复的错误之外。

配置文件稍有不同,但是通常在启动期间读取。在这种情况下,除非更改了配置的重载,否则“ A”将不会显示为“ B”。同样,更改配置文件的格式或含义也将是不好的编码习惯。配置文件的不兼容版本应使用其他名称,因此不会造成问题。

为什么没有人通过使用实时CD或类似方法重新引导来更新系统?

从其他版本关闭并重新启动会导致服务中断。对于服务器,通常不希望这样做。无论如何,正在运行的系统上的程序包管理器都知道其已安装的软件和版本。实时CD拥有自己的已安装软件列表,可能具有不同的版本。这使得很难从实时CD可靠地升级正在运行的系统。

当安装新版本的O / S时,有时会使用Live CD。在这种情况下,通常要进行操作系统的干净安装。这可以限制保留以前版本的未使用文件的数量。比升级实时系统要付出更多的努力。但是,如果使用不同的根分区,则可以限制卡在无法引导的部分更新的系统中的风险。


0

在某些情况下,这是一个问题:

  • 在运行Java VM的同时进行JDK升级:我向myselv询问了您遇到的相同问题-我有一个运行java的tomcat。现在,在对JDK进行补丁更新后,它仍然可以毫无问题地运行-看上去如此。

现在的解释是缓存内存。好的-我启动了一个内存占用程序,用完了所有可用的RAM-然后tomcat崩溃了(在我访问了在那里运行的applicaton之后)。

  • SuSE系统上的内核升级:在SuSE上,在内核的补丁程序升级后立即删除了旧内核及其模块。如果您随后要使用需要内核模块且尚未加载的新功能,则该服务将失败。

2
听起来有些Tomcat重启了,或者在Java级别以下使用了动态库(例如dlopen()等),最终可能会混合使用实时API。
Skaperen 2012年

@Skaperen甚至在使用共享库时-如果它们在使用后关闭,如果缓存变得稀疏,则任何程序都应该遇到麻烦...
Nils 2012年

1
打开的文件描述符具有将数据保留在磁盘上作为目录中文件名的功能。只要磁盘上有硬链接打开的文件描述符,就不会删除原始inode 。缓存与它无关。现在,某些程序在不使用它们时会关闭其文件描述符,会使数据消失。
dmckee 2012年

@dmckee对。我们越来越接近核心。那么,对于“正常”程序而言,正常的情况是:打开库并保持打开状态,或者加载库然后关闭它?
尼尔斯2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.