拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

记一次真实 openEuler(欧拉)环境中 fstab / sysctl / limits 配置错误的连环排查与修复全过程

记一次真实 openEuler(欧拉)环境中 fstab / sysctl / limits 配置错误的连环排查与修复全过程

一、故障背景

环境信息:

  • 操作系统:openEuler 22.03 LTS SP4(内核5.10.0-216.12.3.0119.oe22003sp4.x86_64)

  • CPU 架构:x86_64(TaiShan 200 机型也有 aarch64 版本,排查命令通用)

  • 业务角色:MySQL 8.0 主库 + Redis 6.2 集群(6 节点)

  • 硬件:TaiShan 200 / 256GB 内存 / NVMe SSD × 4

  • 系统自带服务:A-Tune 已启用(atuned服务 running,profile 为database)——本次故障的隐藏主角

  • 故障起因:DBA 周末按「CentOS 7 优化文档」一次性改了fstab、sysctl.conf、limits.conf三个文件,周一重启后服务器进不了系统。

故障现象:

  1. 重启后卡在紧急模式(fstab 挂载失败)

  2. 紧急模式修复后能启动,但 MySQL 报Too many open files

  3. MySQL 启动后 Redis 报Cannot assign requested address(端口耗尽)

  4. 最诡异:sysctl -p明明设置成功的参数,过几分钟自己变回去了

  5. 整个集群连锁故障

三个配置文件互相独立但连环影响,还叠加了 openEuler 特有的A-Tune 自动调优回写,必须按「启动顺序 + 服务依赖」逐层修复。


二、排查与修复全过程

阶段 1:fstab 配置错误 → 系统无法启动

1.1 故障现象

重启后控制台输出:

[ OK ] Started Dispatch Password Requests to Console Directory Watch. [FAILED] Failed to mount /data. See 'systemctl status data.mount' for details. [DEPEND] Dependency failed for Local File Systems. [DEPEND] Dependency failed for MySQL 8.0 database server. ... Reloading system manager configuration Welcome to emergency mode! After logging in, type "journalctl -xb"... Give root password for maintenance: _
1.2 排查步骤
# ① 输入 root 密码进入紧急模式 shell,先确认系统版本(养成习惯,先定位发行版) cat /etc/os-release # 输出: # NAME="openEuler" # VERSION="22.03 LTS SP4" # ID="openEuler" # VERSION_ID="22.03" # PRETTY_NAME="openEuler 22.03 LTS SP4" # ANSI_COLOR="0;31" # ② 查看 systemd 挂载失败详情 systemctl status data.mount -l --no-pager # 关键输出: # ● data.mount - /data # Active: failed (Result: exit-code) # Process: 456 ExecMount=/usr/bin/mount /data (code=exited, status=32) # Aug 26 09:14:22 db01 mount[456]: mount: /data: wrong fs type, bad option, # bad superblock on /dev/mapper/vg_data-lv_data, missing codepage # or helper program, or other error. # ③ 查看 fstab 中 /data 行 grep "/data" /etc/fstab # 实际输出(DBA 添加): # /dev/mapper/vg_data-lv_data /data xfs defaults,noatime,nodiratime,discard 0 0 # ↑↑↑ 问题在这里 # ④ 确认实际文件系统类型 blkid /dev/mapper/vg_data-lv_data # 实际输出: # /dev/mapper/vg_data-lv_data: UUID="a1b2c3d4-..." TYPE="ext4" # ↑↑↑↑ 实际是 ext4! # ⑤ 为什么 DBA 会写 xfs?——因为 openEuler 22.03 安装器(Anaconda)默认根分区就是 xfs, # DBA 想当然认为所有分区都是 xfs,没核对这块手动建的 /data findmnt -no FSTYPE / # 输出:xfs ← 根分区确实是 xfs,误导了 DBA
1.3 根因分析
错误原因
xfs写成了 ext4 盘的文件系统类型DBA 看到 openEuler 根分区默认 xfs,就以为/data也是 xfs,没跑blkid核对
discard选项这块 NVMe 盘做了硬件 RAID(LSI 9460),RAID 卡未透传 UNMAP/TRIM,mount 时报 bad option

📌openEuler 与 CentOS 差异提示:openEuler 22.03 根分区默认xfs(CentOS 7 也是 xfs,但 Ubuntu 默认 ext4);硬件 RAID 卡后面discard基本都不可用,云盘/直通盘才有效。

1.4 修复
# ① 先用正确的类型手动挂载验证 mount -t ext4 /dev/mapper/vg_data-lv_data /data echo $? # 0 → 挂载成功 # ② 修正 fstab(备份后编辑) cp /etc/fstab /etc/fstab.bak.$(date +%F) # 修正后的行(用 UUID 更稳健): # UUID=a1b2c3d4-e5f6-7890-abcd-ef1234567890 /data ext4 defaults,noatime,nodiratime 0 2 # ③ 验证 fstab 语法(不验证直接重启会再次进紧急模式) findmnt --verify--verbose # 必须全部输出 "SUCCESS",不能有 "FATAL" 或 "ERROR" # ④ 重新挂载所有 fstab 项 mount -a && echo $? # 0 → 全部成功 # ⑤ 验证挂载选项生效 mount | grep /data # 输出应包含 rw,noatime,nodiratime

阶段 2:sysctl 配置错误 + A-Tune 回写(openEuler 特有坑)

2.1 故障现象

fstab 修复后系统正常启动,但:

  • Redis 报错:Cannot assign requested address(端口耗尽)

  • 业务报错:nf_conntrack: table full, dropping packet

  • 最诡异:sysctl -p设置成功的参数,几分钟后自己变回去了

2.2 排查步骤
# ① 查看 Redis 报错 tail -50 /var/log/redis/redis-6379.log # 关键行: # # Error condition on socket for UPDATE: Cannot assign requested address # ↑ 可用端口耗尽的经典症状 # ② 查看当前端口范围与 conntrack sysctl net.ipv4.ip_local_port_range net.netfilter.nf_conntrack_max # 实际输出: # net.ipv4.ip_local_port_range = 32768 60999 ← 还是默认值 # sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max: No such file or directory # ↑↑↑ 模块没加载,路径不存在 # ③ 检查模块加载状态 lsmod | grep conntrack # 输出:(空)→ nf_conntrack 没加载! # ④ 查看 DBA 改的 sysctl 配置 cat /etc/sysctl.conf | grep -v "^#" | grep -v "^$" # DBA 添加的内容: # net.ipv4.ip_local_port_range = 1024 65535 ← 问题1:和 22/3306/6379 等服务端口冲突 # net.netfilter.nf_conntrack_max = 1048576 ← 问题2:模块没加载时此行报错被忽略 # net.core.somaxconn = 1024 # fs.file-max = 2000000 # ⑤ 手动执行看真实报错 sysctl -p2>&1 # 输出: # net.ipv4.ip_local_port_range = 1024 65535 # sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max: No such file or directory # net.core.somaxconn = 1024 # fs.file-max = 2000000 # ⑥ 加载模块后设置成功 modprobe nf_conntrack sysctl -p 2>&1 echo "nf_conntrack" > /etc/modules-load.d/conntrack.conf # 开机自动加载 # ⑦ 5 分钟后验证 —— 诡异现象出现了! sysctl net.core.somaxconn # 输出:net.core.somaxconn = 128 ← ❌ 又变回去了!! sysctl fs.file-max # 输出:fs.file-max = 98840 ← ❌ 也变回去了!!
2.3 深挖:为什么参数会「自己变回去」?

这是openEuler 独有的坑:A-Tune 自动调优服务会根据负载 profile 动态回写 sysctl 参数。

# ① 检查 A-Tune 服务状态 systemctl status atuned --no-pager # 输出: # ● atuned.service - A-Tune daemon # Active: active (running) since Mon 2026-08-26 09:20:11 CST; 2h ago # ← 在运行! # ② 查看 A-Tune 当前应用的 profile atune-adm list # 输出: # ++++++++++++++++ System Info ++++++++++++++++ # os_info: openEuler 22.03 LTS SP4 # kernel: 5.10.0-216.12.3.0119.oe22003sp4.x86_64 # platform: x86_64 # ++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++ Profile ++++++++++++++++++++ # active_profile : database ← ❗ 当前激活了 database profile! # ++++++++++++++++++++++++++++++++++++++++++++ # ③ 查看 database profile 都会改什么 atune-adm info database # 输出(节选,重点关注 sysctl 相关): # [sysctl] # vm.dirty_ratio = 20 # vm.dirty_background_ratio = 10 # vm.swappiness = 10 # kernel.sched_autogroup_enabled = 0 # net.core.somaxconn = 128 ← 💥 找到了!profile 里的 somaxconn=128 # fs.file-max = 98840 ← 💥 file-max 也被 profile 锁定 # net.ipv4.tcp_max_syn_backlog = 128 # # [disk] # dataMountPoint = queue/scheduler = mq-deadline # ← 连磁盘调度器都会被改! # ④ 查看 A-Tune 日志确认回写动作 journalctl -u atuned --since"1 hour ago"--no-pager | grep-iE"sysctl|apply|exec" | tail -20 # 输出(节选): # Aug 26 10:42:15 db01 atuned[1234]: [INFO] [engine/sysctl.go:120] Apply sysctl config for profile: database # Aug 26 10:42:15 db01 atuned[1234]: [INFO] [engine/sysctl.go:135] Set kernel param: net.core.somaxconn = 128 # Aug 26 10:42:15 db01 atuned[1234]: [INFO] [engine/sysctl.go:135] Set kernel param: fs.file-max = 98840 # ↑↑↑ 石锤:atuned 每 5 分钟(负载评估周期)把 profile 值写回去
2.4 修复:sysctl 正确配置 + 与 A-Tune 共存策略
# === 第一步:重写 /etc/sysctl.conf(针对 256GB 内存 + MySQL/Redis 场景) === cp /etc/sysctl.conf /etc/sysctl.conf.bak.$(date +%F) cat > /etc/sysctl.conf << 'EOF' # === 网络参数 === # 端口范围:避开 1-10000(特权端口 + 常见服务端口 22/80/443/3306/6379) net.ipv4.ip_local_port_range =10000 65535 # TCP 连接相关 net.core.somaxconn = 32768 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.tcp_max_tw_buckets = 1048576 net.ipv4.tcp_fin_timeout = 15 net.ipv4.tcp_tw_reuse = 1 # 缓冲区(256GB 内存场景) net.core.rmem_max = 67108864 net.core.wmem_max = 67108864 net.ipv4.tcp_rmem = 4096 87380 67108864 net.ipv4.tcp_wmem = 4096 65536 67108864 # === conntrack(前提:modprobe nf_conntrack 已加载) === net.netfilter.nf_conntrack_max = 2621440 net.netfilter.nf_conntrack_tcp_timeout_established = 1800 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 # === 文件描述符 === fs.file-max = 2097152 # === 内存参数 === vm.swappiness =1 vm.overcommit_memory =1 # === INOTIFY(容器/多实例场景必备) === fs.inotify.max_user_instances =8192 fs.inotify.max_user_watches =1048576 EOF # === 第二步:处理 A-Tune 冲突(三选一,生产推荐方案 B) === # ── 方案 A:直接停用 A-Tune(不适合,会失去欧拉调优能力)── # systemctl disable --now atuned # ── 方案 B(推荐):自定义 profile,把 DBA 参数固化进 A-Tune ── # ① 基于 database profile 导出现有配置做模板 atune-adm info database > /tmp/database-profile.txt # ② 在 /etc/atk/conf.d/ 下创建自定义 profile(A-Tune 支持自定义 profile 目录) mkdir -p /etc/atk/conf.d cat > /etc/atk/conf.d/mysql-redis.yaml << 'EOF' mysql-redis: schedule_policy: performance sysctl: net.core.somaxconn: -32768 fs.file-max: -2097152 net.ipv4.ip_local_port_range: -"10000 65535" net.netfilter.nf_conntrack_max: -2621440 vm.swappiness: -1 vm.dirty_ratio: -10 vm.dirty_background_ratio: -3 disk: /dev/mapper/vg_data-lv_data: queue/read_ahead_kb: -1024 queue/scheduler: - mq-deadline EOF # ③ 加载并激活自定义 profile atune-adm list # 确认 mysql-redis 出现在 profile 列表 atune-adm profile mysql-redis # 激活 atune-adm list | grep active_profile # 输出:active_profile : mysql-redis ← 以后 A-Tune 回写的就是我们自己的值了 # ── 方案 C:只关掉 A-Tune 的定时回写,保留服务 ── # 编辑 /etc/ata/ata.ini,把 period 相关采集间隔调大或禁用 sysctl 引擎 # (细节随 A-Tune 版本变化,不如方案 B 可控) # === 第三步:验证长效性 === sysctl -p sleep 360 # 等过 A-Tune 的回写周期 sysctl net.core.somaxconn fs.file-max net.ipv4.ip_local_port_range # 输出: # net.core.somaxconn = 32768 ← ✅ 不再被改回 # fs.file-max = 2097152 ← ✅ # net.ipv4.ip_local_port_range = 10000 65535 ← ✅
2.5 openEuler sysctl 与 CentOS 的差异速查
差异点CentOS 7openEuler 22.03
内核版本3.105.10(参数面更宽,如bpf、cgroup v2相关)
A-Tune无有,且会动态回写 sysctl(最大坑点)
sysctl.d 加载顺序/usr/lib→/run→/etc相同,但自带/usr/lib/sysctl.d/内置文件更多
nf_conntrack手动 modprobe相同,需手动加载 + 写modules-load.d
调优框架tunedA-Tune(默认启用),tuned 也可用但双调优框架并存易冲突

⚠️重要:如果系统同时启用了tuned和atuned,两者都会改内核参数。生产建议二选一,欧拉环境优先 A-Tune + 自定义 profile。


阶段 3:limits.conf 配置错误 → MySQLToo many open files

3.1 故障现象

sysctl 稳定后,MySQL 启动失败:

systemctl status mysqld --no-pager-l # 输出: # ● mysqld.service - MySQL 8.0 database server # Active: failed (Result: exit-code) # Aug 26 09:35:12 db01 mysqld[9876]: 2026-08-26T01:35:12.438678Z 0 [ERROR] # [MY-010191] Can't open dir '/data/mysql/', errno: 24, error: Too many open files
3.2 排查步骤
# ① 当前会话 fd 限制 ulimit -n # 输出:1024 # ② 查看 DBA 改的 limits.conf grep -v "^#" /etc/security/limits.conf | grep -v "^$" # DBA 添加: # * soft nofile 2000000 # * hard nofile 2000000 # * soft nproc 65535 # * hard nproc 65535 # mysql soft nofile 2000000 # mysql hard nofile 2000000 # ③ 新开 SSH 会话验证(limits.conf 只对新 PAM 会话生效) ssh root@db01 'ulimit -n' # 输出:2000000 ← ✅ SSH 会话生效了! # ④ 但 MySQL 是 systemd 启动的 —— 查看 systemd 服务的实际限制 systemctl show mysqld | grep-iE"^LimitNOFILE|^TasksMax" # 输出: # LimitNOFILE=1024 ← ❌ limits.conf 对 systemd 服务无效! # TasksMax=480 ← ❌ 还有进程数限制(systemd 默认 15% 的 pids.max)! # ⑤ 确认 MySQL 进程的真实限制(如果进程已拉起) MYSQL_PID=$(pgrep -x mysqld 2>/dev/null) [ -n"$MYSQL_PID" ] && grep-E"Max open files|Max processes" /proc/$MYSQL_PID/limits # Max open files 1024 1024 files # Max processes 480 480 processes
3.3 根因分析
层次原因
直接原因systemd 启动的 mysqld 的LimitNOFILE默认 1024
配置原因DBA 只改了limits.conf(PAM 会话层),systemd 服务不读它
openEuler 加重因素openEuler 22.03 的 systemdDefaultTasksMax默认 15%(本机 256GB/128核 → pids.max≈480),DBA 想改nproc 65535但 systemd 侧根本没放开
3.4 修复
# === 第一步:systemd override(核心修复) === # ① 创建 override systemctl edit mysqld # 在打开的编辑器中写入: # [Service] # LimitNOFILE=2000000 # LimitNPROC=65535 # TasksMax=infinity # LimitMEMLOCK=infinity # 或者直接写文件(等价): mkdir -p /etc/systemd/system/mysqld.service.d cat > /etc/systemd/system/mysqld.service.d/limits.conf << 'EOF' [Service] LimitNOFILE=2000000 LimitNPROC=65535 TasksMax=infinity LimitMEMLOCK=infinity EOF # ② 重载并重启 systemctl daemon-reload systemctl restart mysqld # ③ 验证 systemctl show mysqld | grep -E "^LimitNOFILE|^TasksMax" # LimitNOFILE=2000000 # TasksMax=infinity MYSQL_PID=$(pgrep -x mysqld) grep -E "Max open files|Max processes" /proc/$MYSQL_PID/limits # Max open files 2000000 2000000 files ✅ # Max processes 65535 65535 processes ✅
# === 第二步:修正 limits.conf(保持 SSH 会话层正确) === cat > /etc/security/limits.conf << 'EOF' # root root soft nofile 2000000 root hard nofile 2000000 root soft nproc 65535 root hard nproc 65535 # mysql mysql soft nofile 2000000 mysql hard nofile 2000000 mysql soft nproc 65535 mysql hard nproc 65535 # 通配(优先级最低,放最后) * soft nofile 1048576 * hard nofile 1048576 * soft nproc 65535 * hard nproc 65535 EOF # === 第三步:确认 PAM 加载了 pam_limits(openEuler 路径与 CentOS 略有不同) === grep -rn "pam_limits" /etc/pam.d/system-auth /etc/pam.d/postlogin 2>/dev/null # 必须输出: # /etc/pam.d/system-auth:session required pam_limits.so # /etc/pam.d/postlogin:session required pam_limits.so # 缺哪行补哪行: # echo 'session required pam_limits.so' >> /etc/pam.d/system-auth # === 第四步:检查 limits.d 目录有没有覆盖(openEuler 默认无 20-nproc.conf, # 但如果有人抄过 CentOS 的配置可能多出来) === ls -l /etc/security/limits.d/ # 如果存在 20-nproc.conf 且值较小(如 4096),通配符 * 会被它覆盖: # cat /etc/security/limits.d/20-nproc.conf → 建议删除或调大 # === 第五步:全机 systemd 服务统一兜底(可选,谨慎) === # /etc/systemd/system.conf 与 user.conf 中: # DefaultLimitNOFILE=1048576 # DefaultTasksMax=80% # 改完 systemctl daemon-reexec 生效(不影响运行中服务,新服务生效)
3.5 limits 排查速查表(openEuler 版)
错误现象根因修复
SSH 会话ulimit -n还是 1024limits.conf 只对新会话生效新开 SSH 验证
systemd 服务不生效服务不读 limits.confsystemctl edit <svc>写LimitNOFILE
LimitNOFILE设了没生效忘了daemon-reloadreload 后restart(restart 才重新 fork)
nproc放开仍报进程数不够systemdTasksMax限制override 里TasksMax=infinity
通配符*不生效limits.d/*.conf优先级更高检查/etc/security/limits.d/
Docker 容器内不生效容器有独立 ulimitdocker run --ulimit nofile=...
MySQL 里show variables like 'open_files_limit'仍 1024MySQL 自身变量没跟上my.cnf加open_files_limit=2000000,或直接依赖 systemd 值

三、三方联动验证脚本(openEuler 版)

#!/bin/bash # === openEuler 配置体检:fstab + sysctl + limits + A-Tune 四项全检 === echo "========================================" echo " 0. 系统信息" echo "========================================" grep PRETTY_NAME /etc/os-release uname -r systemctl is-active atuned && atune-adm list | grep active_profile echo "" echo "========================================" echo " 1. FSTAB 检查" echo "========================================" findmnt --verify--verbose2>&1 | grep-E"FATAL|ERROR" \ && echo"❌ fstab 有错误" || echo"✅ fstab 语法正确" mount -a -v --fake 2>&1 | grep -v "^$" | head -20 # 干跑一次全部挂载 echo "" echo "========================================" echo " 2. SYSCTL 检查" echo "========================================" declare -AEXPECTED=( ["net.ipv4.ip_local_port_range"]="1000065535" ["net.core.somaxconn"]="32768" ["net.netfilter.nf_conntrack_max"]="2621440" ["fs.file-max"]="2097152" ["vm.swappiness"]="1" ) lsmod | grep -q nf_conntrack && echo"✅ nf_conntrack 已加载" || echo"❌ nf_conntrack 未加载" for param in "${!EXPECTED[@]}"; do actual=$(sysctl -n "$param" 2>/dev/null || echo "NOT_FOUND") if [ "$actual"="${EXPECTED[$param]}" ]; then echo"✅ $param = $actual" else echo"❌ $param: expected=[${EXPECTED[$param]}] actual=[$actual]" fi done echo "" echo "========================================" echo " 3. A-TUNE 冲突检查(openEuler 特有)" echo "========================================" if systemctl is-active --quiet atuned; then PROFILE=$(atune-adm list 2>/dev/null | grep active_profile | awk -F: '{print $2}' | xargs) echo"⚠️ atuned 运行中,当前 profile: $PROFILE" # 检查 profile 是否包含与 /etc/sysctl.conf 冲突的键 atune-adm info "$PROFILE"2>/dev/null | grep-A50"\[sysctl\]" | \ grep-oE"^[a-z].*=" | sed's/ =//' | while read -r key; do ifgrep-q"^$key" /etc/sysctl.conf 2>/dev/null; then echo"⚠️ 冲突参数:$key 同时存在于 profile[$PROFILE] 和 /etc/sysctl.conf" fi done echo" 建议:把冲突参数固化进自定义 profile(见文档阶段2方案B)" else echo "✅ atuned 未运行,无回写冲突" fi echo "" echo "========================================" echo " 4. LIMITS 检查" echo "========================================" echo "当前会话: nofile=$(ulimit -n) nproc=$(ulimit -u)" for svc in mysqld redis redis-6379; do systemctl is-active --quiet"$svc"2>/dev/null || continue echo"[$svc] systemd 视角:" systemctl show "$svc" | grep-E"^LimitNOFILE|^LimitNPROC|^TasksMax" | \ awk'{printf " %s\n", $0}' PID=$(systemctl show -p MainPID --value "$svc") if [ "$PID" !="0" ] && [ -n"$PID" ]; then echo"[$svc] 进程(PID $PID)视角:" grep-E"Max open files|Max processes" /proc/$PID/limits | \ awk'{printf " %-16s soft=%-12s hard=%s\n", $1" "$2, $4, $5}' fi done echo "" echo "========================================" echo " 检查完成" echo "========================================"

四、根因总结

配置文件错误后果根因
/etc/fstabxfs 写成 ext4 盘 + RAID 后 discard 失效系统进紧急模式没用blkid核对;没确认 RAID 卡是否透传 TRIM
/etc/sysctl.confnf_conntrack 模块未加载conntrack 参数静默失败没先modprobe+modules-load.d
/etc/sysctl.conf端口范围含服务端口Redis 端口耗尽没避开 1-10000
A-Tune(openEuler 独有)profile 定期回写默认值参数「自己变回去」手动 sysctl 与 A-Tune profile 冲突,未做 profile 固化
/etc/security/limits.conf只改了 PAM 层MySQL fd 限制 1024systemd 服务走LimitNOFILE/TasksMax,不读 limits.conf
三个文件一次性全改连环故障难定位违反「单变量迭代」原则

五、最佳实践 SOP(openEuler 版)

  1. 改前必备份:cp file file.bak.$(date +%F);sysctl 类变更同时记录sysctl -a > /tmp/sysctl-before.txt

  2. 先弄清发行版特性:openEuler 上改内核参数前必查atune-adm list,冲突参数一律固化进自定义 profile,而不是裸改 sysctl.conf

  3. 单变量迭代:一次只改一个文件,验证通过再改下一个

  4. 改后必验证 + 等一个回写周期:A-Tune 环境下sysctl -p后至少等 10 分钟再复查一遍

  5. 重启前干跑:findmnt --verify、mount -a --fake、sysctl -p、systemctl daemon-reload全绿再 reboot

  6. systemd 服务永远用 override:systemctl edit <service>,同时关注LimitNOFILE / LimitNPROC / TasksMax三件套

  7. limits.conf 与 systemd 双轨都要改:SSH 会话靠 limits.conf,服务靠 unit override,缺一个都是坑。

返回列表