1. 为什么"看一眼版本和位数"在 Solaris 上值得单开一篇
Solaris 系统版本查询与位数判定,听起来像是运维入门第一课的内容,一个uname -a敲下去似乎什么都解决了。但真在机房里待过的人都知道,这台跑着 Solaris 的机器给出的答案往往比想象中模糊:uname -r告诉你5.10,可业务方问你的是"是 Solaris 10 还是 Solaris 11";uname -p显示sparc,但你要装的那个中间件只认 64 位;getconf LONG_BIT返回32,你又不敢确定内核到底是不是 64 位的。三个命令三种口径,最后谁也没说服谁。
这篇内容就是冲着这个混乱来的。我会把 Solaris 上"版本"和"位数"这两件事彻底拆开:版本信息到底分几层、每层由哪个命令或文件负责、位数判定为什么必须区分内核位数和用户态位数、SPARC 与 x86 两条产品线的差异在哪里、批量化巡检时怎么写脚本才不会踩坑。适合刚接手一批老 Solaris 机器的新手,也适合需要给升级方案做评估、必须把"确切版本号"写进报告的老手。
先把结论摆前面:Solaris 的版本号存在"内核版本号"和"产品版本号"两套体系,位数也存在"内核支持位数"和"当前进程运行位数"两个层面,任何单一命令都只能回答其中一个问题。这不是设计缺陷,而是这套系统从 32 位时代一路演进到 64 位时代留下的历史层次。理解了这层历史,后面所有的命令输出就都能对号入座了。
2. 版本信息:五类入口,各管一段
2.1 uname 家族:最基础,也最容易被误读
uname是所有人第一个会敲的命令,但它在 Solaris 上的输出有一套自己的命名规则,不熟悉的人第一眼容易懵。先看一个典型的全量输出:
$ uname -a SunOS dbnode01 5.10 Generic_147440-25 sun4u sparc SUNW,SPARC-Enterprise这一行拆开看,字段依次是:系统名(SunOS)、主机名、内核版本号(5.10)、内核补丁级别(Generic_147440-25)、硬件平台类名(sun4u)、处理器类型(sparc)、整机平台标识。
关键在于第三段那个5.10。它不是你口头说的"Solaris 10",而是这套系统的内核版本号。Solaris 的版本命名在历史上换过一次体系:早期是SunOS 5.x对应Solaris 2.x,从 Solaris 2.6 之后,两者开始分道扬镳——Solaris 7 对应的内核是 5.7,Solaris 8 对应 5.8,Solaris 9 对应 5.9,Solaris 10 对应 5.10,Solaris 11 对应 5.11。Solaris 11 后续的 11.1、11.2、11.3、11.4 全部共用5.11这个内核版本号,靠额外的标识区分。
这就带来第一个大坑:看到5.11你只知道是 Solaris 11 系列,但不知道是小版本几。而 11.0 到 11.4 之间的差异相当大,尤其是 11.4 引入了大量变更,靠uname -r是完全分不出来的。判断小版本必须去读/etc/release,这个后面细说。
uname的常用参数我整理成一张表,方便对照:
| 参数 | 输出内容 | 典型值 | 用途 |
|---|---|---|---|
-s | 系统名 | SunOS | 基本无变化 |
-n | 主机名 | dbnode01 | 巡检归档 |
-r | 内核版本 | 5.10 / 5.11 | 判断大版本 |
-v | 内核补丁级别 | Generic_147440-25 | 判断补丁状态 |
-m | 硬件类名 | sun4u / sun4v / i86pc | 判断架构族 |
-p | 处理器类型 | sparc / i386 | 判断指令集族 |
-i | 平台实现 | SUNW,Sun-Fire-V240 | 精确机型 |
-X | 综合信息 | 多行键值对 | 快速概览 |
其中uname -X是 Solaris 独有的,输出一串键值对,非常适合脚本解析:
$ uname -X System = SunOS Node = dbnode01 Release = 5.10 KernelID = Generic_147440-25 Machine = sun4u BusType = <unknown> Serial = <unknown> Users = <unknown> OEM# = 0 Origin# = 1 NumCPU = 8这个输出的好处是格式稳定、字段名明确,awk -F'=' '/Release/'一把就能抓到版本号,比切割uname -a的空格安全得多。我在批量巡检脚本里优先用uname -X,原因就在这里——uname -a的字段数量在不同平台版本上会有细微差异,而-X的键名是固定的。
注意:
uname -X在部分精简安装的最小化系统上可能不可用,做脚本时要加兜底判断,不要假定它一定存在。
2.2 /etc/release:产品版本的唯一权威出处
如果只能记住一个文件,记住这个:/etc/release。这是判断"这台机器装的到底是哪个产品版本"的权威来源,uname回答不了的小版本问题,这里都有答案。
Solaris 10 上的典型内容:
$ cat /etc/release Solaris 10 8/11 s10s_u10wos_17b SPARC Copyright (c) 1983, 2011, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Assembled 23 August 2011关键信息全在第一行:Solaris 10 8/11表示这是 Solaris 10 的 2011 年 8 月发布的更新版本(即 Update 10),后面跟的是构建号s10s_u10wos_17b和架构SPARC。
Solaris 11.4 上的内容形态不同:
$ cat /etc/release Oracle Solaris 11.4 X86 Copyright (c) 1983, 2020, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Assembled 24 July 2020第一行明确写出11.4,架构标注X86。相比uname -r的5.11,这个信息精确得多。
所以实际操作里我的习惯是:uname -r用来做快速判断和脚本分支,/etc/release用来做最终确认和报告填写。两者缺一不可,前者适合机器读,后者适合人读。
有个细节值得说:这个文件的格式在不同版本之间并不统一,Solaris 8/9 时代的输出格式又不一样,做跨版本脚本解析时要非常小心。我的做法是只提取第一行的非空内容,然后用关键字匹配Solaris\s+[0-9]+(\.[0-9]+)?这样的模式,而不是按固定列位置切割。按固定位置切的老脚本,换一个版本就崩。
2.3 showrev:老派工具,信息最全
showrev是 Solaris 上的一个传统命令,输出信息相当全面,尤其是需要一次性拿到主机、版本、内核、架构、补丁等全部信息时,它比敲五六个命令高效。
$ showrev Hostname: dbnode01 Hostid: 83a1c2f4 Release: 5.10 Kernel architecture: sun4u Application architecture: sparc Hardware provider: Sun_Microsystems Domain: Kernel version: SunOS 5.10 Generic_147440-25这里有两个字段特别值得注意:Kernel architecture和Application architecture。前者是内核跑的架构(sun4u表示 64 位 SPARC 硬件平台),后者是应用程序默认运行的架构(sparc表示 32 位用户态)。这两个字段并列出现,本身就是对"位数要分两层看"这个观点的最好注解。
加-a参数会输出所有已安装补丁的列表,加-p只输出补丁信息。补丁列表这块内容量很大,实际使用中我一般只在排查特定补丁时才用showrev -p | grep。
showrev有一个小缺陷:部分新版本系统上它的输出格式有微调,而且它依赖一些底层服务,在极简环境里偶尔会报错。所以它适合做人工核对,不适合做脚本主解析源。
2.4 包管理侧留下的版本痕迹
Solaris 有两套包管理工具,Solaris 10 及更早用pkginfo(SVR4 包体系),Solaris 11 引入了pkg(IPS 体系)。这两套工具都能反查出系统的版本脉络。
在 Solaris 10 上查核心包:
$ pkginfo -l SUNWcsr PKGINST: SUNWcsr NAME: Core Solaris, (Root) CATEGORY: system ARCH: sparc VERSION: 11.10.0,REV=2011.01.28.20.02 BASEDIR: / VENDOR: Sun Microsystems, Inc. DESC: core software for a specific hardware platform group PSTAMP: on10-20110129074805 INSTDATE: Apr 12 2012 09:33 HOTLINE: Please contact your local service provider STATUS: completely installed这里的VERSION: 11.10.0其实就是 Solaris 10 Update 10 的内部版本号,on10前缀也对应了 Update 10。这种内部版本号和产品版本号的映射关系,如果手上没有对照表,很容易看走眼。
在 Solaris 11 上则是:
$ pkg list entire NAME (PUBLISHER) VERSION IFO entire 0.5.11-0.175.3.0.0.30.2 i--这个0.5.11-0.175.3.0.0.30.2就是 Solaris 11.3 的构建版本,175.3中的3对应小版本号。这个编号体系比较绕,实际判断时我一般直接比对构建号前缀,或者干脆去读/etc/release。
提示:不要用
pkginfo或pkg list来判断系统大版本,它们反映的是包数据库状态,可能因为升级残留或包冻结而与实际运行版本不一致。判断系统版本永远以/etc/release和uname -r为准。
2.5 补丁与更新级别:容易被忽略的第四维度
版本号之外还有一层:补丁级别。两台都写着Solaris 10的机器,可能因为补丁集不同而行为完全不一样。这在排查"同样的配置为什么一台好一台坏"时是高频原因。
判断补丁级别的方法:
# 看内核补丁级别 $ uname -v Generic_147440-25 # 看已装补丁总数与最近补丁 $ showrev -p | wc -l $ showrev -p | tail -5 # Solaris 11 上查看系统更新级别 $ pkg list -H entireuname -v输出里的Generic_147440-25就是内核补丁的标识,斜杠后面的数字越大表示内核补丁越新。这个值和/etc/release里的构建号是两回事,前者反映的是内核二进制被打过哪些补丁,后者反映的是安装介质的原始构建。做过现场补丁的机器,两者会明显不一致,这是正常现象。
我在做升级前评估时,会把uname -v和/etc/release里的组装日期两个信息都记下来,因为很多中间件厂商的支持矩阵是按"Solaris 10 Update 9 及以上"这种粒度来划的,光看5.10根本判断不了是否在支持范围内。
3. 位数判定:内核、用户态、二进制文件,三件事别混
3.1 isainfo:Solaris 上位数的标准答案
如果有人让我只用一个命令说清楚位数,我会答isainfo。这是 Solaris 上专门用来查询指令集架构信息的工具,语义最清晰,没有歧义。
最核心的用法是isainfo -b:
$ isainfo -b 64这个输出回答的是:当前运行的内核能够支持的最大应用程序位数。返回64意味着这个系统可以运行 64 位应用,返回32意味着只能跑 32 位应用。
再看isainfo -v,输出更详细:
$ isainfo -v 64-bit sparcv9 applications 32-bit sparc applications这个输出直接把两个层级都摊开了:内核支持 64 位sparcv9应用,同时也兼容 32 位sparc应用。这是 Solaris 10 在 SPARC 平台上的典型状态。
再看一个 x86 平台上的例子:
$ isainfo -v 64-bit amd64 applications avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr mmx cmov sep cx8 tsc fpu 32-bit i386 applications avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr mmx cmov sep cx8 tsc fpu可以看到 x86 线上的 64 位架构名是amd64,这个命名在 Solaris 上一直沿用,与具体处理器品牌无关,纯粹是架构约定。
isainfo的参数我整理一下:
| 参数 | 含义 | 典型输出 |
|---|---|---|
-b | 支持的最大应用位数 | 32 / 64 |
-k | 内核自身位数 | 32 / 64 |
-n | 原生指令集名 | sparcv9 / amd64 |
-v | 详细架构列表 | 多行 |
-m | 支持的机器架构 | sun4u / i86pc |
这里-k和-b的区别非常关键,很多人会把两者搞混。-k说的是内核自己是几位,-b说的是内核能跑几位的应用。在 Solaris 10 上这两者可以不一致:32 位内核也能通过 64 位库跑一部分 64 位应用,isainfo -b返回64而isainfo -k返回32的机器是真实存在的。这种状态在规划内存密集型应用时是个大坑,后面会细讲。
3.2 isalist 与 uname -p / uname -m 的分工
isalist输出的是当前进程可以运行的指令集列表,按优先级从高到低排列:
$ isalist sparcv9+vis2 sparcv9+vis sparcv9 sparcv8plus+vis2 sparcv8plus+vis sparcv8plus sparcv8 sparcv7 sparc这个列表的顺序表达了一个搜索顺序:系统在找库文件或可执行文件时,会按这个顺序依次尝试。排在最前的是它能支持的最高指令集。判断"这台机器能不能跑某个 64 位程序",看列表里有没有sparcv9或amd64就够了。
要特别注意isalist的结果受当前进程环境影响。在 32 位 shell 里执行和在 64 位 shell 里执行,输出可能不同。这就是为什么同一条命令在不同终端里跑出不同结果,让人怀疑人生。
uname -p和uname -m的定位则更偏"硬件标识":
uname -p返回处理器类型,SPARC 平台返回sparc,x86 平台返回i386。注意它不区分 32/64 位,SPARC 上无论 32 位还是 64 位程序都返回sparc。uname -m返回硬件类名,sun4u是较老的 SPARC 平台,sun4v是支持虚拟化的 SPARC 平台,i86pc是 x86 平台。
这两个字段的价值在于判断架构族,而不是判断位数。很多老脚本用uname -p来判断 64 位,这是错的——在 SPARC 上它永远返回sparc,看不出位数。这个坑我在接手别人脚本时踩过一次,一段巡检逻辑在 SPARC 上永远走 32 位分支,导致内存参数算错,折腾了大半天才定位到。
3.3 getconf LONG_BIT 的陷阱
getconf LONG_BIT是通用类 Unix 系统上的常用手段,返回32或64。在 Solaris 上它也能用,但语义和在 Linux 上不一样,必须小心。
$ getconf LONG_BIT 32 $ /usr/bin/isainfo -b 64同一台机器,两条命令给出不同答案。原因在于getconf LONG_BIT反映的是当前执行这个命令的进程所处的用户态位数,也就是 C 库的long类型宽度。Solaris 为了保证兼容性,默认的用户态环境是 32 位的,即使用 64 位内核也一样。所以getconf LONG_BIT大部分时候返回32。
那什么时候会返回64?在 64 位编译的程序里调用时,或者在某些明确切换到 64 位环境的 shell 中。比如:
$ /usr/bin/amd64/getconf LONG_BIT 64Solaris 上 64 位版本的二进制通常放在/usr/bin/<arch>/这样的子目录里,amd64或sparcv9是目录名。这个路径约定本身就是位数判断的一个辅助手段,后面会讲。
结论:判断系统支持位数用isainfo -b,判断当前 shell 环境位数用getconf LONG_BIT,两者回答的是不同问题。报告里写"系统是 64 位"没问题,写"当前环境是 64 位"就要谨慎,可能只是指 shell。
3.4 从二进制文件反推位数
有时候系统层面的信息不足以回答业务问题,因为业务方真正关心的是"我这个可执行文件能不能跑"。这时候就得看文件本身了。
Solaris 自带file和elfdump两个工具,都能识别 ELF 文件的位数。
$ file /usr/bin/ls /usr/bin/ls: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped $ file /usr/bin/sparcv9/ls /usr/bin/sparcv9/ls: ELF 64-bit MSB executable SPARC Version 1, dynamically linked, strippedfile的输出里直接写了32-bit或64-bit,一眼可辨。这个方法在排查"为什么某个程序启动报cannot execute binary file"时最直接——十有八九是拿 64 位二进制往 32 位环境里塞。
elfdump更底层一些:
$ elfdump -e /usr/bin/sparcv9/ls | head -20 ELF Header ei_magic: { 0x7f, E, L, F } ei_class: ELFCLASS64 ei_data: ELFDATA2MSB ei_version: EV_CURRENT ...ei_class: ELFCLASS64就是答案。elfdump的好处是可以精确检查e_machine、e_flags字段,判断是否包含特定的硬件能力标记,这在做兼容性核查时很有用。
还有一个更实用的场景:检查动态库依赖链里有没有混入错误位数的库。用ldd配合位数检查:
$ ldd /opt/app/bin/myserver libc.so.1 => /lib/64/libc.so.1 libsocket.so.1 => /lib/64/libsocket.so.1路径里出现/lib/64/就说明走的是 64 位库。如果同一个程序在一台机器上走/lib/,在另一台上走/lib/64/,那说明两台机器的运行时环境配置有差异,值得追一追。这个现象在升级迁移中很常见,尤其是从 Solaris 10 迁移到 Solaris 11 时,默认库路径策略发生了变化。
4. 实操:从一条命令到一套巡检流程
4.1 手工三步走:最快拿到完整答案
现场排查时间紧的时候,我一般按这个顺序敲三条命令,三十秒内心里有数:
第一步,确认产品版本:
cat /etc/release | head -1第二步,确认内核版本与平台:
uname -X第三步,确认位数能力:
isainfo -v三条命令的信息叠加起来,就能回答"这台机器是什么版本、什么架构、能跑几位的程序"这三个问题。如果业务方还追问具体补丁,再加一条uname -v和showrev -p | wc -l。
我把这套组合拳叫"三看":看文件、看内核、看指令集。看文件得到产品语义,看内核得到运行语义,看指令集得到能力语义。这三层信息互不替代,只取其一都会留下盲区。
实际操作中有一个小技巧:把这三条命令写成一行,一次执行:
cat /etc/release | head -1 && uname -X && isainfo -v输出虽然有点长,但是一次粘贴就能拿到全部信息,在只能通过带外控制台操作的场景里特别省事。带外控制台的粘贴限制、响应延迟都是真实存在的麻烦,能少一次交互就少一次。
4.2 脚本化批量采集:一次跑完全机房
单机排查靠手感,批量巡检就得靠脚本。我手上这套脚本经过几轮迭代,主要解决三个问题:输出格式统一、异常情况有兜底、结果可直接导入表格。
#!/bin/bash # solaris_inventory.sh - 采集 Solaris 版本与位数信息 # 输出以 | 分隔,便于后续 awk / csv 处理 HOST=$(uname -n) # 产品版本:取 /etc/release 首个非空行 PRODUCT=$(grep -v '^[[:space:]]*$' /etc/release 2>/dev/null | head -1 | sed 's/^[[:space:]]*//') # 内核版本 KREL=$(uname -r) # 内核补丁级别 KVER=$(uname -v) # 硬件平台类 KMACH=$(uname -m) # 处理器类型 PTYPE=$(uname -p) # 支持位数(内核能力) ABITS=$(isainfo -b 2>/dev/null || echo "NA") # 内核自身位数 KBITS=$(isainfo -k 2>/dev/null || echo "NA") # 原生指令集名 NISA=$(isainfo -n 2>/dev/null || echo "NA") # 当前用户态位数 LONGBIT=$(getconf LONG_BIT 2>/dev/null || echo "NA") # CPU 数量 NCPU=$(psrinfo -p 2>/dev/null || echo "NA") printf "%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s\n" \ "$HOST" "$PRODUCT" "$KREL" "$KVER" "$KMACH" "$PTYPE" \ "$ABITS" "$KBITS" "$NISA" "$LONGBIT" "$NCPU"这个脚本有几个设计考虑值得说明。
为什么用grep -v '^[[:space:]]*$'而不是head -1?因为/etc/release的第一行通常是空行或者只有空格,直接取第一行会拿到空字符串。这个细节在不同版本上表现不一致,加上这个过滤就稳了。我最早写的版本就是直接head -1,结果在 Solaris 11.4 上采出来一片空白,排查了半天才发现是空行问题。
为什么isainfo要加2>/dev/null || echo "NA"?因为极少数裁剪过的系统上isainfo不存在或者路径不在PATH里,脚本不能因为这个崩掉。整批采集最怕的就是一台机器出错中断全部流程。
为什么输出用|分隔?因为版本信息里可能包含空格(比如Solaris 10 8/11),用空格分隔会导致字段错位。|在版本信息里几乎不会出现,是安全的定界符。
批量执行的时候,配合一个主机列表文件循环:
while read H; do ssh -o ConnectTimeout=5 -o BatchMode=yes "$H" 'bash -s' < solaris_inventory.sh done < hostlist.txt > inventory_$(date +%Y%m%d).txt这里BatchMode=yes是必须的,避免脚本卡在交互式密码提示上。ConnectTimeout=5也是必须的,否则一台失联的机器会让整批采集卡住几分钟。这两条在无人值守场景下是硬要求。
4.3 判断矩阵:把输出翻译成结论
采集回来的原始信息要变成可用的结论,需要一张映射表。下面这张表覆盖了主流 Solaris 版本的典型输出组合,可以直接对照使用:
| 场景 | /etc/release首行特征 | uname -r | isainfo -b | isainfo -k | 结论 |
|---|---|---|---|---|---|
| Solaris 8 SPARC 32位 | Solaris 8 x/xx | 5.8 | 32 | 32 | 32位内核,仅跑32位应用 |
| Solaris 8 SPARC 64位内核 | Solaris 8 x/xx | 5.8 | 64 | 64 | 64位内核,兼容32位应用 |
| Solaris 9 SPARC | Solaris 9 x/xx | 5.9 | 64 | 64 | 64位内核,用户态默认32位 |
| Solaris 10 SPARC 32位内核 | Solaris 10 x/xx SPARC | 5.10 | 64 | 32 | 32位内核,支持部分64位应用 |
| Solaris 10 SPARC 64位内核 | Solaris 10 x/xx SPARC | 5.10 | 64 | 64 | 64位内核,完整64位支持 |
| Solaris 10 x86 32位内核 | Solaris 10 x/xx X86 | 5.10 | 64 | 32 | 32位内核,可跑64位应用 |
| Solaris 10 x86 64位内核 | Solaris 10 x/xx X86 | 5.10 | 64 | 64 | 64位内核 |
| Solaris 11 任意小版本 | Solaris 11.x | 5.11 | 64 | 64 | 仅64位内核 |
| Solaris 11.4 | Solaris 11.4 | 5.11 | 64 | 64 | 仅64位,x86侧取消32位内核 |
这张表里最容易让人困惑的是isainfo -b返回 64 但isainfo -k返回 32 的那一行。这种组合在 Solaris 10 上大量存在,因为 Solaris 10 允许安装 32 位内核,但同时又提供了 64 位的用户态库和对 64 位应用的支持。这种机器上跑一个内存需求超过 4GB 的程序,会撞上 32 位内核的地址空间限制,表现为进程被强制终止或内存分配失败。这是升级评估时最该优先识别出来的情况。
还有一个需要单独提的:Solaris 11 起,32 位内核完全消失,isainfo -k永远返回 64。这意味着从 Solaris 10 迁移到 Solaris 11 时,原本依赖 32 位内核特性的配置(比如某些老驱动、特定的内核参数调整)会失效。这是迁移评估的重点项,不是简单的"版本号变了"。
5. 常见问题速查与避坑心得
5.1 十个高频问题对照表
下面这些问题是我在实际支持和交流中反复遇到的,整理成表方便查阅:
| 问题现象 | 可能原因 | 排查方法 | 处理建议 |
|---|---|---|---|
uname -r显示 5.11,不知道具体小版本 | 11 系列共用内核版本号 | cat /etc/release看首行 | 用/etc/release作为版本判定依据 |
getconf LONG_BIT返回 32,但系统号称 64 位内核 | 用户态默认 32 位 | isainfo -k确认内核位数 | 明确区分两个概念,报告分开写 |
装了 64 位程序却报cannot execute binary file | 内核不支持或库路径缺失 | isainfo -v、file查二进制 | 确认isainfo -b返回 64,检查/lib/64 |
| 同一条命令在不同终端输出不同 | isalist受进程环境影响 | 分别在两个终端跑isalist | 以isainfo -b为准 |
uname -p在 SPARC 上永远返回 sparc | 该字段不区分位数 | 用isainfo -b替代 | 修正脚本里的错误判断逻辑 |
两台机器/etc/release首行格式不同 | 不同版本组装格式不一致 | 对比完整文件内容 | 脚本用正则匹配而非固定列切 |
| 补丁级别和发行版版本对不上 | 现场打过补丁 | uname -v与/etc/release对比 | 分别记录,不要合并成一个字段 |
pkginfo查到的版本与系统版本不符 | 包数据库残留或冻结 | 交叉验证/etc/release | 系统版本以/etc/release为准 |
| 升级到 11 后原 32 位驱动失效 | 11 起取消 32 位内核 | 查驱动兼容性列表 | 升级前做驱动兼容性盘点 |
| 批量脚本在某几台机器上输出空白 | /etc/release首行为空 | 加grep -v过滤空行 | 补上兜底逻辑 |
这里我特别想展开说说第二条和第三条,因为这两个是最容易引发误判的。
关于getconf LONG_BIT。我见过不止一次,有人拿这个命令的输出写进升级报告,写着"S系统为 32 位,需升级到 64 位",结果被业务方追问"可我们买的就是 64 位机器啊"。这个锅不在业务方,在于getconf LONG_BIT的语义被误读了。它回答的是"我这个命令自己跑在几位环境里",而不是"这个系统支持几位"。Solaris 为了向后兼容,默认把用户态钉在 32 位,这本身是个合理的设计决策——大量老程序假设 32 位环境,贸然切换会大面积崩溃。但代价就是新人一看这个数字就慌。
关于cannot execute binary file。这个报错的成因有好几种,需要分层排查。第一层看二进制本身是不是 64 位(file命令);第二层看内核支不支持 64 位(isainfo -b);第三层看动态库路径对不对(ldd)。我遇到过一种情况:二进制是 64 位的,内核也支持 64 位,但LD_LIBRARY_PATH被老脚本硬编码指向了 32 位库目录,导致运行时加载失败。这种问题光看版本信息永远查不出来,必须追到环境变量。
5.2 几条只有踩过才懂的经验
经验一:不要相信任何"单一来源"的版本信息。
系统版本至少有四个来源:uname -r、/etc/release、showrev、包管理工具。它们在正常情况下应当一致,但一旦做过升级、打过补丁、做过克隆部署,就可能不一致。我处理过一次事故,一台机器uname -r是 5.10,/etc/release里写的却是 Solaris 11.3,原因是系统盘做过某种迁移操作,/etc/release被遗留文件覆盖了。最终以pkg list entire和实际行为验证为准。这件事教会我:多源交叉验证不是多余的谨慎,而是必要的流程。
经验二:把采集结果和采集时间一起记。
版本信息是会变的。今天采的是 Solaris 10 Update 9,三个月后可能就打完补丁变成 Update 11 了。如果巡检报告里只有版本号没有时间戳,半年后这份报告就失去了参考价值。我的习惯是每次采集都带上date +%Y-%m-%d\ %H:%M:%S和主机名,形成"谁、什么时候、什么状态"的完整三元组。
经验三:isalist的输出顺序有意义,不要只做有无判断。
很多人用isalist | grep sparcv9判断支不支持 64 位,这没错,但丢掉了顺序信息。顺序反映的是优先级,排在前面的指令集是系统首选。在做性能调优时,如果发现某个应用的库被加载成了低优先级版本,可能就是因为库文件放置位置不对,导致搜索顺序没命中最高优先级。这个细节在排查"同样的程序在不同机器上性能差 20%"时非常关键。
经验四:老脚本里的架构判断逻辑一定要重新审一遍。
接手历史系统时,最危险的不是缺工具,而是有工具但用错了。uname -p判位数、getconf LONG_BIT判系统能力、uname -m判处理器架构,这三类错误在老脚本里出现的频率高得惊人。我的做法是拿到任何一份巡检脚本,先把所有涉及架构判断的行拉出来单独过一遍,逐条验证在当前环境下的输出是否符合预期。这个动作花不了十分钟,但能避免后面几个小时的误判排查。
经验五:位数和内存的关系要在评估阶段就摆到桌面上。
32 位进程的地址空间上限是 4GB 量级,这是硬约束,跟机器物理内存多大无关。很多业务方看到机器有 64GB 内存,就认为应用能用到 64GB,结果应用进程一超过 3GB 多就崩。这时候要回答的不是"系统是不是 64 位",而是"这个进程跑在几位模式、编译时是不是 64 位、内核地址空间限制是多少"。这三者任何一个不满足,物理内存再大也用不上。所以在做容量规划时,我会把版本和位数信息与内存规划放在同一张表里评估,而不是等到出问题再回头查。
6. 版本与架构信息在下游场景里的实际用法
6.1 升级路径评估:版本信息是第一道闸门
拿到一批机器的版本清单之后,第一步要做的是判定升级路径是否可行。这里有三条硬规则:
规则一:内核版本号决定跨越几个大版本。从5.10到5.11是跨大版本升级,中间可能涉及文件系统、启动机制、包管理的全面更换,不能按小版本升级的思路处理。而 11.1 到 11.4 之间是同一内核版本内的小版本推进,路径相对平滑。
规则二:位数能力决定应用改造量。Solaris 11 只提供 64 位内核,如果原系统是 32 位内核且上面跑着依赖 32 位内核特性的应用,升级就意味着应用层改造。这个评估要在动手之前完成,不能边升边看。
规则三:补丁级别决定是否需要中间步骤。有些升级路径要求先打到某个补丁级别才能继续,这个信息在uname -v里。跳过这步直接升级,会在中途失败并留下半成品状态,恢复起来很麻烦。
把这三条规则做成一张评估表,每台机器一行,填完就知道哪些可以直接升、哪些需要先做中间步骤、哪些需要应用层配合。这个表在项目启动会上比任何口头说明都有说服力。
6.2 软件包适配:位数信息决定下载哪个版本
第三方软件的分发页面上,通常按"平台 + 位数"分栏。Solaris 的下载选项往往是SPARC 64-bit、SPARC 32-bit、x86 64-bit、x86 32-bit这样的组合。选错的后果不是装不上,而是装上了跑不起来或者跑起来性能诡异。
判断该选哪个,看两个字段就够了:uname -p定架构族(sparc 还是 i386),isainfo -b定位数能力。两个一组合,答案唯一。
但有个细节:isainfo -b返回 64 不代表应该装 64 位版本。如果这台机器上运行的其他组件都是 32 位的,塞一个 64 位的新组件进去,可能出现库冲突或者进程间通信问题。正确的做法是先盘点现有组件的位数分布,让新组件与它们保持一致。这个判断需要的信息比单纯的"系统支持几位"多一层,得多花点功夫。
6.3 归档记录:让信息能穿越时间
最后说一个容易被轻视的环节:信息归档。版本和位数这类信息,采集一次的成本很低,但事后回溯的价值很高。我的做法是维护一份简单的台账,包含这些字段:
| 字段 | 来源 | 说明 |
|---|---|---|
| 主机名 | uname -n | 唯一标识 |
| 采集时间 | date | 必须有,否则失去时效 |
| 产品版本 | /etc/release首行 | 用于对业务方说明 |
| 内核版本 | uname -r | 用于技术判断 |
| 内核补丁级别 | uname -v | 用于支持矩阵比对 |
| 平台架构 | uname -m | 硬件族 |
| 处理器类型 | uname -p | 指令集族 |
| 支持位数 | isainfo -b | 能力上限 |
| 内核位数 | isainfo -k | 内核实际状态 |
| CPU 数量 | psrinfo -p | 容量参考 |
这份台账看起来枯燥,但在三种场景下会救急:一是换人接手时的知识传递,二是升级方案评审时的数据支撑,三是故障复盘时判断"是不是环境差异导致的"。我见过太多团队在接手老系统时连基本的版本分布都不清楚,第一周全花在登录各台机器敲命令上,有了这份台账,第一天就能进入实质工作。
这套台账的维护成本其实很低,前面那个采集脚本跑一遍就齐了,关键是要有坚持跑的习惯。我一般在每次变更前后各跑一次,前后对比就能看出变更的实际影响范围——有时候一次"小改动"会牵动十几台机器的版本状态,这个发现本身就很有价值。