麒麟系统服务精简实战:禁用冗余服务提升性能
1. 为什么要对麒麟系统做服务精简很多人拿到预装麒麟系统的机器后第一反应是“能用就行”直到某天发现开机要一分半、内存莫名其妙被吃掉一大块、后台还总有不明进程在跑才开始琢磨是不是系统本身太臃肿了。其实问题往往不在系统本身而在于默认开启了一大堆普通用户根本用不到的服务。这些服务有些是给特定硬件准备的有些是给企业级场景预留的还有些纯粹是历史遗留——它们安安静静躺在后台单个占用不大但十几个叠加起来对老机器或者资源受限的环境就是实打实的负担。所谓“禁用不必要的服务”核心思路就一句话只保留维持系统基本运行和你实际工作所需的那些其余全部关掉。这件事听起来简单但真动手时会遇到几个现实问题哪些算“必要”关错了会不会导致系统起不来禁用和停止有什么区别我该用 systemctl 还是别的工具这些问题不搞清楚很容易从“优化”变成“搞崩”。这篇文章面向的是有一定 Linux 基础、正在使用麒麟系统无论是桌面版还是服务器版的运维人员或技术爱好者。我会把整个服务精简的完整思路、判断标准、实操步骤、参数选择依据以及我自己踩过的坑全部摊开讲清楚。你照着做至少能省下 30% 到 50% 的常驻内存开机速度也会有肉眼可见的提升。更重要的是你会建立起一套自己的判断逻辑以后遇到任何 Linux 系统都能套用。2. 动手之前必须搞清楚的底层逻辑2.1 麒麟系统的服务管理机制到底怎么回事麒麟系统底层用的是 systemd 作为初始化系统和服务管理器这一点和大多数现代 Linux 发行版一致。systemd 的核心概念是unit每个服务、挂载点、定时任务都是一个 unit。跟服务最相关的是.service文件它们通常放在/usr/lib/systemd/system/和/etc/systemd/system/这两个目录下。前者是软件包安装时自带的后者是管理员自定义或者覆盖用的。这里有个关键点很多人会忽略systemd 的服务状态和“是否开机自启”是两回事。一个服务可以当前正在运行但开机不会自动启动也可以当前没运行但开机时会自动拉起来。所以“禁用”这个词在 systemd 语境下其实对应两个不同操作systemctl stop xxx立刻停止当前运行的服务但下次开机还会启动。systemctl disable xxx取消开机自启但当前如果正在运行它不会停。systemctl disable --now xxx两个一起做既停止又取消自启。我见过太多人只做了 disable 就以为万事大吉结果当前会话里服务还在跑内存该占还是占。所以正确的做法是disable 和 stop 同时执行用--now参数一步到位。2.2 哪些服务算“必要”哪些算“可有可无”这是整个精简过程中最难的部分因为“必要”是相对的。对一台跑数据库的服务器来说网络管理服务是命根子对一台只用来写文档的桌面机来说蓝牙服务可能一辈子用不上。所以我不打算给你一个万能清单而是给你一套判断方法。第一类绝对不能动的核心服务。这类服务停了系统直接出问题比如systemd-journald日志、systemd-udevd设备管理、dbus进程间通信、NetworkManager或systemd-networkd网络。这些你连查都不用查直接跳过。第二类取决于使用场景的服务。比如bluetooth蓝牙、cups打印、avahi-daemon局域网设备发现、ModemManager移动宽带。如果你确定不用这些功能关掉完全没问题。我自己的桌面机上这几个全关了从来没出过事。第三类大概率用不到但容易误判的服务。比如firewalld防火墙、sshd远程登录、chronyd时间同步。防火墙关了确实省一点资源但安全风险你自己掂量sshd 如果你不需要远程登录可以关但关了之后想远程连都连不上时间同步服务占用极小关了可能导致时间漂移反而带来麻烦。这类服务我的建议是保留因为它们带来的收益远大于那一点点资源节省。第四类明显冗余的服务。比如各种getty虚拟终端、postfix邮件服务桌面机根本用不到、rpcbindNFS 相关不用 NFS 就关、abrt自动错误报告。这些是精简的主要目标。2.3 精简之前必须做的安全措施在动手之前有一件事比什么都重要确保你有退路。我吃过一次亏把某个看起来无关紧要的服务关了结果图形界面起不来又因为没留后路只能重装。从那以后我养成了三个习惯第一操作前先做快照或备份。如果是虚拟机直接打快照出问题秒回滚。如果是物理机至少把/etc/systemd/system/目录备份一份命令是cp -r /etc/systemd/system/ /root/systemd-backup-$(date %Y%m%d)。第二保留一个 root 终端不关。你在图形界面里操作的时候万一关了某个服务导致桌面崩溃至少还有一个 tty 可以进去救。按CtrlAltF2切到第二个虚拟终端用 root 登录就能把服务重新启用。第三每次只改一两个服务改完重启验证。不要一口气关二十个然后重启出了问题你根本不知道是哪个导致的。我一般是一次关三到五个重启确认没问题再继续下一批。提示如果你是在远程 SSH 连接下操作千万不要禁用sshd和网络相关服务否则你会直接失联只能去机房插显示器。3. 服务排查与筛选的完整实操流程3.1 先把当前运行的服务全部列出来第一步永远是摸清现状。systemd 提供了几个非常实用的命令我按使用频率从高到低排列# 列出所有正在运行的服务按内存占用排序 systemctl list-units --typeservice --staterunning --no-pager # 列出所有已启用的服务开机自启的 systemctl list-unit-files --typeservice --stateenabled --no-pager # 查看某个服务的详细信息包括依赖关系 systemctl status 服务名 # 查看服务占用的内存 systemd-cgtop -msystemctl list-units这条命令输出的信息量很大我一般会配合grep过滤。比如我想看看有哪些跟打印相关的服务在跑systemctl list-units --typeservice --staterunning --no-pager | grep -i -E cups|print|avahi|bluetooth还有一个更直观的方式是用systemd-analyze看启动耗时# 查看整体启动时间 systemd-analyze # 查看每个服务的启动耗时排名 systemd-analyze blame | head -30systemd-analyze blame这个命令特别有用它会按耗时从高到低列出所有服务。我实测下来麒麟桌面版默认启动时NetworkManager-wait-online.service经常排在前三这个服务的作用是等待网络完全就绪对桌面机来说完全可以禁用能省好几秒开机时间。3.2 用依赖关系判断服务能不能关光看服务名字有时候判断不准因为很多服务之间存在依赖关系。你关了一个可能连带影响另一个。systemd 提供了查看依赖的命令# 查看某个服务依赖了谁它需要谁才能运行 systemctl list-dependencies --reverse 服务名 # 查看谁依赖了这个服务关了它会影响谁 systemctl list-dependencies 服务名举个例子假设我想关掉avahi-daemon先查一下谁依赖它systemctl list-dependencies avahi-daemon.service如果输出里只有它自己那就可以放心关。如果发现cups依赖它而你又需要打印功能那就得斟酌一下。我自己的经验是大部分独立服务之间的依赖关系并不复杂真正需要小心的是那些被多个服务共同依赖的基础组件比如dbus、systemd-logind这些。判断方法很简单如果一个服务被三个以上的其他服务依赖那它大概率是基础设施不要动。3.3 我实际精简掉的服务清单与理由下面这张表是我在一台麒麟桌面版机器上实际禁用掉的服务以及每个服务的用途和禁用理由。注意这不是让你照抄的清单而是给你一个判断参考。服务名用途禁用理由风险等级cups.service打印服务没有打印机低cups-browsed.service网络打印机发现同上低avahi-daemon.service局域网设备发现不需要发现局域网设备低bluetooth.service蓝牙台式机没有蓝牙低ModemManager.service移动宽带管理没有移动网卡低postfix.service邮件传输桌面机不发邮件低abrtd.service自动错误报告不需要上报低abrt-journal-core.service错误报告日志同上低rpcbind.serviceNFS 端口映射不用 NFS低nfs-client.targetNFS 客户端同上低NetworkManager-wait-online.service等待网络就绪拖慢开机桌面机不需要中gettytty2.service到gettytty6.service虚拟终端只保留 tty1中kdump.service内核崩溃转储桌面机不需要中firewalld.service防火墙视安全需求决定高sshd.service远程登录不需要远程连接高关于getty服务我要多说一句。默认情况下麒麟系统会开六个虚拟终端tty1 到 tty6每个都跑一个 getty 进程等着你登录。但实际上你最多用一两个剩下的纯属浪费。我一般只保留 tty1图形界面和 tty2应急用其余全部禁用。每个 getty 大概占 1 到 2 MB 内存六个就是 10 MB 左右虽然不多但积少成多。kdump这个服务也值得说一下。它的作用是在内核崩溃时把内存内容转储到磁盘方便事后分析。对服务器来说这很重要但对桌面机来说内核崩溃的概率极低而且转储文件动辄几个 GB还不如直接重启。关掉它能省下不少内存预留空间。4. 禁用服务的标准操作与参数详解4.1 单服务禁用的标准命令组合对于确认要禁用的服务我推荐的标准操作是# 一步到位停止并禁用 sudo systemctl disable --now 服务名.service # 验证状态确认已停止且已禁用 systemctl status 服务名.service systemctl is-enabled 服务名.servicesystemctl status的输出里如果看到Active: inactive (dead)说明已经停止看到Loaded: ...; disabled说明已经取消自启。两个都满足才算真正禁用成功。有时候你会遇到一种情况disable执行了但status里显示的还是enabled。这通常是因为有另一个服务或 target 依赖它把它又拉起来了。这时候需要用mask命令# mask 比 disable 更彻底它会创建一个指向 /dev/null 的符号链接 sudo systemctl mask 服务名.servicemask的效果是这个服务彻底无法启动连手动启动都不行。除非你unmask否则它永远起不来。我一般只在遇到顽固服务时才用 mask因为它的副作用比较大容易忘记自己屏蔽过什么。4.2 批量禁用的脚本化方法如果你要禁用的服务比较多一个个敲命令太慢可以写个简单的脚本。我常用的做法是把服务名写到一个文本文件里然后循环处理#!/bin/bash # 批量禁用服务脚本 # 用法将服务名每行一个写入 service-list.txt然后执行此脚本 SERVICE_LISTservice-list.txt LOG_FILEdisable-services-$(date %Y%m%d-%H%M%S).log while IFS read -r service; do # 跳过空行和注释行 [[ -z $service || $service ~ ^# ]] continue echo 正在处理: $service | tee -a $LOG_FILE if systemctl list-unit-files --typeservice | grep -q ^${service}; then sudo systemctl disable --now $service 21 | tee -a $LOG_FILE echo --- | tee -a $LOG_FILE else echo 服务不存在跳过: $service | tee -a $LOG_FILE fi done $SERVICE_LIST echo 处理完成日志保存在: $LOG_FILE这个脚本有几个细节值得注意。第一它会先检查服务是否存在避免因为拼写错误报一堆无意义的错。第二它把操作过程记录到日志文件方便事后回溯。第三它跳过了空行和以#开头的注释行这样你可以在列表文件里写注释。注意批量操作有风险建议第一次运行时先注释掉disable --now那行改成echo只打印不执行确认列表没问题后再真正执行。4.3 禁用后如何验证效果禁用完一批服务后怎么知道有没有效果我一般从三个维度验证内存占用对比。用free -h看总内存变化用systemd-cgtop -m看具体哪些服务还在占内存。我实测下来精简十几个服务后常驻内存能从 1.2 GB 降到 700 MB 左右效果还是很明显的。开机时间对比。用systemd-analyze看总启动时间用systemd-analyze blame看排名变化。我之前那台机器从 48 秒降到了 26 秒主要贡献就是NetworkManager-wait-online和几个 getty。运行状态确认。用systemctl --failed看有没有服务启动失败。如果有 failed 的服务说明可能关错了东西需要排查。# 查看所有启动失败的服务 systemctl --failed # 查看系统整体状态 systemctl status如果systemctl --failed输出为空说明系统运行正常没有因为你的操作导致服务异常。5. 常见问题与排查技巧实录5.1 关了服务之后系统起不来怎么办这是最让人心慌的情况但只要你之前留了后路处理起来并不难。首先按CtrlAltF2切到虚拟终端用 root 登录。如果连虚拟终端都进不去那就需要进入救援模式或者用 Live USB 启动。进入系统后第一步是查看哪些服务启动失败了systemctl --failed找到可疑的服务后重新启用它sudo systemctl enable --now 服务名.service然后重启验证。如果还是起不来可以查看系统日志找线索# 查看本次启动的完整日志 journalctl -b # 只看错误级别的日志 journalctl -b -p errjournalctl -b会显示本次启动的所有日志-p err过滤出错误级别以上的信息。我遇到过一次图形界面起不来就是通过journalctl -b -p err发现是display-manager.service依赖的某个服务被误关了。5.2 服务显示 disabled 但还在运行这种情况通常有两个原因。第一个原因是服务被其他服务或 target 依赖systemd 为了满足依赖关系把它拉起来了。排查方法是# 查看谁依赖了这个服务 systemctl list-dependencies --reverse 服务名.service第二个原因是服务被 socket 激活。有些服务平时不运行但有对应的.socket文件监听端口一旦有请求就自动启动。这种情况下你需要同时禁用 socketsudo systemctl disable --now 服务名.socket我遇到过cups就是这种情况禁用了cups.service但cups.socket还在监听结果一有打印请求服务又被拉起来了。后来把 socket 也禁用才彻底解决。5.3 如何判断一个服务是否真的“没用”这个问题没有标准答案但我有一套自己的判断流程。首先看服务描述systemctl status 服务名.service | grep -i description然后看它属于哪个软件包rpm -qf $(systemctl show -p FragmentPath 服务名.service | cut -d -f2)知道软件包名字后就能大致判断它的用途。比如cups开头的肯定是打印相关bluetooth肯定是蓝牙nfs肯定是网络文件系统。还有一个实用技巧是看服务的依赖链。如果一个服务只被自己依赖而且没有其他服务依赖它那它大概率是独立的关掉影响面小。反之如果它被多个服务依赖就要谨慎。5.4 常见问题速查表问题现象可能原因排查命令解决方法系统起不来误关关键服务systemctl --failed重新 enable 相关服务服务显示 disabled 但仍在运行被依赖或被 socket 激活systemctl list-dependencies --reverse禁用依赖服务或对应 socket图形界面异常显示管理器依赖被关journalctl -b -p err恢复 display-manager 相关服务网络不通网络服务被误关systemctl status NetworkManager重新启用网络服务开机仍然很慢有其他耗时服务systemd-analyze blame继续排查耗时服务内存没明显下降服务被重新拉起systemd-cgtop -m检查是否有服务自动重启5.5 我踩过的三个坑第一个坑只 disable 没 stop。刚开始做精简的时候我以为disable就够了结果重启后发现内存没怎么降。后来才明白disable只影响下次开机当前运行的服务还在。必须用disable --now才能立即生效。第二个坑关了firewalld导致远程连接异常。有一次我在服务器上关了防火墙结果某些端口规则失效导致一个内部服务连不上。后来我学乖了服务器上的防火墙服务一律保留只在桌面机上考虑关闭。第三个坑批量操作没留日志。有一次我一次性关了十几个服务结果系统出了点小问题但我完全不记得关了哪些。从那以后我养成了写日志的习惯每次操作都记录到文件里方便回溯。6. 进阶技巧让服务精简更安全更高效6.1 用 systemd 的 drop-in 机制做精细控制有时候你不想完全禁用某个服务只是想调整它的行为。比如某个服务你还需要但希望它延迟启动或者限制它的资源占用。这时候可以用 systemd 的 drop-in 机制在/etc/systemd/system/服务名.service.d/目录下创建一个覆盖文件sudo mkdir -p /etc/systemd/system/NetworkManager-wait-online.service.d/ sudo tee /etc/systemd/system/NetworkManager-wait-online.service.d/override.conf EOF [Service] # 将超时时间从默认的 30 秒改为 5 秒 TimeoutStartSec5 EOF sudo systemctl daemon-reload这种方式的优势是不修改原始服务文件升级软件包时不会冲突而且可以随时删除覆盖文件恢复默认行为。我一般用这种方式来调整那些“不能关但可以优化”的服务。6.2 建立自己的服务白名单与其每次装新系统都重新判断哪些服务该关不如建立一份自己的白名单。我的做法是维护一个essential-services.txt文件里面列出所有我认为必须保留的服务。每次精简时先用systemctl list-unit-files --stateenabled列出所有自启服务然后跟白名单对比不在白名单里的就考虑禁用。# 生成当前自启服务列表 systemctl list-unit-files --typeservice --stateenabled --no-pager | awk {print $1} | sort current-enabled.txt # 跟白名单对比找出不在白名单里的服务 comm -23 current-enabled.txt essential-services.txtcomm -23的作用是找出第一个文件中有但第二个文件中没有的行也就是“当前启用了但不在白名单里”的服务。这些就是你的候选禁用对象。6.3 定期复查与动态调整服务精简不是一劳永逸的事。系统更新、软件安装都可能引入新的自启服务。我一般每个月会跑一次复查看看有没有新增的不必要服务。复查命令很简单# 查看最近安装的软件包引入的服务 systemctl list-unit-files --typeservice --stateenabled --no-pager | wc -l如果这个数字比你上次检查时多了就说明有新服务被启用了需要重新评估。另外如果你发现某个服务被禁用了但系统运行一切正常而且过了很长时间都没出问题那就可以放心把它加入永久禁用列表。反之如果某个服务禁用后你经常需要手动启动它那就说明它对你来说是必要的应该重新启用。6.4 一个实用的服务审计脚本最后分享一个我自己写的服务审计脚本它会输出当前所有自启服务的列表、内存占用和启动耗时方便你快速判断哪些值得关注#!/bin/bash # 服务审计脚本列出所有自启服务及其资源占用 echo 当前开机自启的服务 systemctl list-unit-files --typeservice --stateenabled --no-pager | head -50 echo echo 启动耗时排名前 20 systemd-analyze blame | head -20 echo echo 内存占用排名前 20 systemd-cgtop -m --ordermemory -n 1 | head -25 echo echo 启动失败的服务 systemctl --failed --no-pager这个脚本我放在/usr/local/bin/service-audit.sh每个月跑一次几分钟就能完成复查。我个人在实际操作中的体会是服务精简这件事收益最大的往往不是那些占用资源最多的服务而是那些你根本不知道它存在、但它一直在后台跑的服务。把它们找出来关掉不仅省资源更重要的是让系统变得透明可控。你清楚每一个在跑的东西是干什么的这种掌控感比省下来的那几百兆内存更有价值。