# systemd 服务管理

URL: https://caijiao.org/rockylinux/systemd-service
Source: docs/rockylinux/systemd-service.md
Description: 详细介绍 Rocky Linux 中 systemd 系统和服务管理器的使用方法，包括服务管理、单元文件配置、系统控制等

在 Rocky Linux 中，systemd 是默认的系统和服务管理器，负责启动系统、初始化服务和管理进程生命周期。本教程将详细介绍如何使用 systemd 来管理系统服务、创建自定义服务单元、设置定时任务等。

## systemd 概述

systemd 是一个完整的系统和服务管理器，它替代了传统的 SysV init 系统。systemd 提供了以下核心功能：

- 并行启动服务，加快系统引导速度
- 基于依赖关系的服务启动顺序
- 服务状态监控和自动恢复
- 电源管理功能
- 日志管理集成
- 设备管理和挂载点管理

## systemd 基本概念

### 单元（Units）

systemd 使用"单元"（Unit）来表示各种系统资源，最常见的单元类型包括：

- **service**：系统服务
- **socket**：套接字
- **device**：设备文件
- **mount**：挂载点
- **automount**：自动挂载点
- **target**：目标（类似于传统的运行级别）
- **timer**：定时器（用于定时任务）
- **path**：路径触发器
- **slice**：进程组
- **scope**：外部创建的进程组

### 目标（Targets）

Targets 类似于传统的运行级别，但更灵活。常见的 targets 包括：

- **poweroff.target**：关机状态
- **rescue.target**：单用户救援模式
- **multi-user.target**：多用户文本模式
- **graphical.target**：多用户图形界面模式
- **default.target**：默认启动目标（通常链接到 multi-user.target 或 graphical.target）

## 服务管理基本命令

### 查看服务状态

```bash
# 查看特定服务的状态
systemctl status service_name.service

# 查看所有服务的状态
systemctl list-units --type=service

# 查看所有已加载但未激活的服务
systemctl list-units --type=service --state=inactive

# 查看所有服务（包括未加载的）
systemctl list-unit-files --type=service
```

### 控制服务

```bash
# 启动服务
systemctl start service_name.service

# 停止服务
systemctl stop service_name.service

# 重启服务
systemctl restart service_name.service

# 重新加载服务配置（不中断服务）
systemctl reload service_name.service

# 启动服务并使其在启动时自动运行
systemctl enable service_name.service

# 禁用服务的自动启动
systemctl disable service_name.service

# 检查服务是否已启用
systemctl is-enabled service_name.service

# 立即激活服务并在启动时启用
systemctl enable --now service_name.service
```

### 查看服务依赖关系

```bash
# 查看服务的依赖项
systemctl list-dependencies service_name.service

# 查看哪些服务依赖于特定服务
systemctl list-dependencies --reverse service_name.service
```

## 系统控制命令

### 系统重启和关机

```bash
# 重启系统
systemctl reboot

# 关机
systemctl poweroff

# 挂起系统
systemctl suspend

# 使系统进入休眠状态
systemctl hibernate

# 混合睡眠（同时休眠和挂起）
systemctl hybrid-sleep
```

### 切换目标（运行级别）

```bash
# 查看当前目标
systemctl get-default

# 设置默认目标
systemctl set-default graphical.target

# 临时切换到另一个目标
systemctl isolate multi-user.target
```

## 服务日志管理

```bash
# 查看服务日志
journalctl -u service_name.service

# 查看最近的服务日志
journalctl -u service_name.service -n 50

# 实时监控服务日志
journalctl -u service_name.service -f

# 查看特定时间范围的日志
journalctl -u service_name.service --since "2023-05-01" --until "2023-05-02"

# 查看启动日志
journalctl -b

# 查看上一次启动的日志
journalctl -b -1
```

## 服务单元文件

### 单元文件位置

systemd 单元文件存储在以下位置：

- `/usr/lib/systemd/system/`：系统安装的单元文件
- `/etc/systemd/system/`：用户或管理员创建的自定义单元文件
- `/run/systemd/system/`：运行时生成的单元文件

### 单元文件结构

一个典型的服务单元文件包含以下部分：

```ini
[Unit]
Description=服务描述
Documentation=文档URL
After=network.target sshd.service  # 依赖关系

[Service]
Type=服务类型（simple、forking、oneshot、dbus、notify、idle）
User=运行服务的用户
Group=运行服务的组
ExecStart=启动命令
ExecReload=重新加载命令
ExecStop=停止命令
Restart=何时重启服务（always、on-success、on-failure、on-abnormal、on-abort、on-watchdog）
RestartSec=重启前等待的秒数
TimeoutStartSec=启动超时时间
TimeoutStopSec=停止超时时间

[Install]
WantedBy=multi-user.target  # 此服务应该被哪些目标启用
```

## 创建自定义服务

### 示例：创建一个简单的服务

1. 创建服务单元文件：

```bash
sudo vim /etc/systemd/system/myapp.service
```

添加以下内容：

```ini
[Unit]
Description=My Custom Application
After=network.target

[Service]
Type=simple
User=myuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

2. 重新加载 systemd 配置：

```bash
sudo systemctl daemon-reload
```

3. 启动并启用服务：

```bash
sudo systemctl enable --now myapp.service
```

### 不同类型的服务

#### simple 类型

最常见的服务类型，systemd 会启动 ExecStart 中指定的进程，并将其视为主要服务进程。

```ini
[Service]
Type=simple
ExecStart=/usr/bin/application
```

#### forking 类型

当服务启动后会通过 fork 创建子进程并在后台运行，父进程则退出。

```ini
[Service]
Type=forking
ExecStart=/usr/bin/application --daemon
PIDFile=/run/application.pid
```

#### oneshot 类型

适用于只需执行一次并退出的服务。

```ini
[Service]
Type=oneshot
ExecStart=/usr/bin/script.sh
RemainAfterExit=yes
```

#### dbus 类型

服务启动后会获取一个特定的 D-Bus 名称。

```ini
[Service]
Type=dbus
BusName=org.example.MyService
ExecStart=/usr/bin/myservice
```

#### notify 类型

服务启动后会通过 sd_notify() 函数发送通知。

```ini
[Service]
Type=notify
ExecStart=/usr/bin/application
NotifyAccess=all
```

## 定时器（Timers）

systemd 定时器提供了比传统 cron 更强大的定时任务功能。

### 创建定时器

1. 创建服务单元文件 `/etc/systemd/system/backup.service`：

```ini
[Unit]
Description=Backup Service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
```

2. 创建定时器单元文件 `/etc/systemd/system/backup.timer`：

```ini
[Unit]
Description=Run backup daily

[Timer]
OnCalendar=*-*-* 02:00:00  # 每天凌晨 2 点运行
Persistent=true  # 系统启动时，如果错过了预定时间，立即执行一次

[Install]
WantedBy=timers.target
```

3. 启用并启动定时器：

```bash
sudo systemctl enable --now backup.timer
```

### 管理定时器

```bash
# 查看定时器状态
systemctl list-timers

# 查看特定定时器状态
systemctl status backup.timer

# 手动触发定时器对应的服务
systemctl start backup.service
```

## 路径触发器（Paths）

路径触发器用于监控文件或目录的变化，并在变化发生时启动服务。

### 创建路径触发器

1. 创建服务单元文件 `/etc/systemd/system/process-file.service`：

```ini
[Unit]
Description=Process file when changed

[Service]
Type=oneshot
ExecStart=/usr/local/bin/process-file.sh
```

2. 创建路径触发器单元文件 `/etc/systemd/system/process-file.path`：

```ini
[Unit]
Description=Monitor file changes

[Path]
PathModified=/path/to/monitor/file.conf  # 监控文件修改
# 或监控目录：PathChanged=/path/to/monitor/

[Install]
WantedBy=multi-user.target
```

3. 启用并启动路径触发器：

```bash
sudo systemctl enable --now process-file.path
```

## systemd 资源控制

### 控制进程资源限制

可以在服务单元文件中使用 `Limit*` 指令来控制服务的资源使用：

```ini
[Service]
# 其他配置...
LimitCPU=10s  # 限制 CPU 使用时间
LimitNOFILE=1000  # 限制最大打开文件数
LimitNPROC=100  # 限制最大进程数
LimitAS=1G  # 限制地址空间（内存）
```

### 使用 cgroups 进行资源管理

可以使用 `MemoryLimit`、`CPUQuota` 等指令控制服务的资源使用：

```ini
[Service]
# 其他配置...
MemoryLimit=500M  # 限制内存使用为 500MB
CPUQuota=50%  # 限制 CPU 使用为 50%
```

## 系统状态分析

### 系统启动时间分析

```bash
# 查看系统启动时间
systemd-analyze

# 查看各个服务的启动时间
systemd-analyze blame

# 生成启动时间图表
systemd-analyze plot > bootplot.svg
```

### 系统日志分析

```bash
# 查看系统日志概览
journalctl -p err..emerg  # 只查看错误和紧急日志
journalctl --since "1 hour ago"  # 查看过去一小时的日志
journalctl --disk-usage  # 查看日志占用的磁盘空间
```

## systemd 常见问题与解决方案

### 服务无法启动

- **问题**：服务启动失败
- **解决方案**：
  - 检查服务状态获取详细错误信息：`systemctl status service_name`
  - 查看服务日志：`journalctl -u service_name`
  - 验证 ExecStart 路径是否正确
  - 检查服务依赖项是否已启动

### 服务无法自动启动

- **问题**：系统启动后服务未自动运行
- **解决方案**：
  - 确保服务已启用：`systemctl enable service_name`
  - 检查 WantedBy 设置是否正确
  - 检查依赖项是否满足

### 服务频繁重启

- **问题**：服务频繁重启
- **解决方案**：
  - 检查 Restart 和 RestartSec 设置
  - 查看服务日志找出崩溃原因
  - 考虑调整超时设置

## 最佳实践

1. **使用标准路径**：将自定义服务单元文件放在 `/etc/systemd/system/`
2. **正确设置依赖关系**：使用 After= 和 Requires= 指令
3. **设置适当的用户权限**：不要以 root 运行不需要 root 权限的服务
4. **配置资源限制**：使用 MemoryLimit、CPUQuota 等限制资源使用
5. **设置重启策略**：根据服务的性质选择合适的 Restart 选项
6. **启用日志**：确保服务输出被正确记录
7. **定期检查**：定期查看服务状态和日志，确保服务正常运行

## 总结

systemd 是 Rocky Linux 中强大的系统和服务管理器，通过本文介绍的命令和技术，您可以有效地管理系统服务、创建自定义服务、设置定时任务等。掌握 systemd 的使用对于系统管理员来说至关重要，它可以帮助您更好地控制和监控系统资源和服务。

systemd 的功能远不止本文所介绍的内容，随着您使用经验的积累，您将能够充分利用 systemd 的强大功能来优化系统管理。
