2022 年我给一个项目做缓存层,用的是 Redis。我当时想:数据都在内存里,万一服务器重启不就全没了?所以得开持久化。第一版我做得很省事:在 redis.conf 里抄了一行 save 900 1,心想"这下数据就落到磁盘上了"。本地测试时我特意重启了一次 Redis——数据还在,我心里很踏实:"持久化嘛,不就是在配置里开一下,数据就落盘、永远不会丢了。"可等它真正上线、扛着真实的流量和真实的意外,一串问题冒了出来。第一种最先把我打懵:有一次服务器意外重启,起来之后我发现 Redis 里的数据少了一大半——明明开了持久化,怎么还丢?第二种:我换成了 AOF,以为"这下记的是每一条命令、一条都不会丢了",结果一次宕机后还是丢了几秒钟的写入。第三种:AOF 文件在一个月里悄悄涨到了几十 GB,磁盘直接报警。第四种最让我后背发凉:主库一次重启后,从库上的数据也跟着被清空了。我盯着这一连串问题想了很久才彻底想明白,第一版错在一个根本的认知上:我以为"持久化就是在配置里开一下,数据就落盘、永不丢失"。这句话把"开启持久化"和"数据绝对安全"当成了一回事。可它不是。Redis 本质是一个内存数据库,持久化是事后补上的一层机制,不是实时的、不是免费的、更不是配一行就万无一失的。RDB 是某个时间点的快照,两次快照之间的写入会全丢;AOF 是命令日志,但 fsync 策略决定了它到底能丢多少;AOF 不重写就会无限膨胀;持久化还藏着 fork 开销和主从复制的陷阱。真正用好 Redis 持久化,核心不是"在配置里开一下",而是理解 RDB 和 AOF 各自丢数据的窗口在哪、代价是什么,再按你的业务能容忍的丢失程度去选型和配齐。这篇文章就把 Redis 持久化梳理一遍:为什么"开一下"不等于数据不丢、RDB 快照丢的是哪段数据、AOF 的 fsync 三档怎么选、AOF 为什么必须重写、混合持久化和文件损坏怎么恢复,以及 fork 开销、主从持久化、容量规划这些把持久化真正做对要避开的坑。
问题背景
先把那串问题的现象和我的误判讲清楚,后面所有的配置选择都是冲着纠正这个误判去的。
现象:只在 redis.conf 里开了一行持久化配置之后,上线冒出一串问题:服务器意外重启后数据少了一大半(RDB 两次快照之间的写入全没了);换成 AOF 后宕机仍丢了几秒数据(appendfsync 策略决定的窗口);AOF 文件一个月涨到几十 GB(从没触发过重写);主库重启后从库数据也被清空(主库以空数据集启动并同步给了从库)。
我当时的错误认知:"持久化就是在 redis.conf 里开一下,数据就落盘、永远不会丢了。"
真相:Redis 本质是把数据放在内存里的数据库,内存断电即失。持久化是把内存里的数据"另存"到磁盘的机制,但它有两种完全不同的路子,而且都有各自丢数据的窗口:RDB 是定时给整个数据集拍一张快照,丢的是上一次快照之后到宕机之间的全部写入;AOF 是把每一条写命令记进日志,但命令写进日志缓冲、再 fsync 到磁盘之间有一个时间差,这个差由 appendfsync 决定,所以它也会丢——只是丢得少。可靠的持久化,是想清楚你的业务能容忍丢多少,再据此选 RDB、选 AOF、还是两者混合,并把重写、恢复、主从这些配套都配齐。
要把 Redis 持久化做对,需要几块认知:
- 为什么"开一下持久化"不等于数据不丢——Redis 是内存数据库,持久化是事后补丁;
- RDB 快照——它快、它小,但它丢的是两次快照之间的一整段数据;
- AOF 命令日志——
appendfsync的三档,决定了你最多丢多少; - AOF 重写——不重写,日志文件会无限膨胀直到撑爆磁盘;
- 混合持久化、文件损坏恢复、fork 开销、主从陷阱这些工程坑怎么处理。
一、为什么"开一下持久化"不等于数据不丢
先把这件最根本的事钉死:Redis 之所以快,正是因为它把所有数据都放在内存里——读写都不碰磁盘。可内存有一个致命特性:断电、进程被杀、机器重启,内存里的东西瞬间归零。持久化,就是 Redis 为了对抗这个特性,额外加的一层"把内存数据备份到磁盘"的机制。但你要看清三件事:第一,它不是实时的——内存里的数据变化,和磁盘上的备份,中间永远有一个时间差;第二,它不是免费的——备份这个动作本身要占 CPU、要占内存、要占磁盘 IO;第三,它不是配一行就万无一失的——你配的那一行,只决定了"什么时候备份",而"什么时候备份"直接决定了"你会丢多少"。
下面这行配置,就是我那个"上线就丢数据"的第一版:
# 反面教材:redis.conf 里只抄了这一行,就以为数据安全了
save 900 1
# 这一行的真实含义:每过 900 秒(15 分钟),
# 如果期间至少发生了 1 次写入,就触发一次 RDB 快照。
# 换句话说:两次快照之间最多可能积压 15 分钟的写入,
# 一旦在这 15 分钟里宕机,这段时间的数据全部丢失。
# 我却把它理解成了"数据会实时落盘"。
这行配置在本地测试时让我很安心,因为我测试的方式是:写入数据 → 手动正常重启 Redis → 发现数据还在。可这个测试有一个致命的盲区:Redis 正常关闭时,会主动做一次 RDB 快照再退出——所以我测出来的"数据还在",是正常关闭的功劳,根本不是 save 900 1 的功劳。而线上的意外重启、进程被 OOM Killer 杀掉、机器掉电,统统不会有这次"临别快照"。于是那串问题就有了解释:数据少了一大半,是因为意外宕机时,距上一次快照已经过去了十几分钟,这十几分钟的写入从来没进过磁盘。问题的根子清楚了:持久化配置的每一个参数,本质上都在回答同一个问题——"你能容忍丢多少数据"。你不搞清楚这个问题,随手抄一行,就等于随手决定了一个你根本没意识到的丢失窗口。先从 RDB 这种快照式持久化说起。
二、RDB:时间点快照,丢的是哪段数据
RDB(Redis DataBase)是 Redis 最早、也最简单的持久化方式。它的原理一句话:在某个时间点,把整个内存数据集,完整地 dump 成一个二进制文件(默认叫 dump.rdb)。重启时,Redis 把这个文件整个加载回内存。它的特点是文件紧凑、加载快,适合做备份和灾难恢复。下面是一份说清楚了的 RDB 配置:
# save <秒数> <修改次数>:满足任一条就触发一次 RDB 快照
save 900 1 # 15 分钟内有 1 次修改
save 300 100 # 5 分钟内有 100 次修改
save 60 10000 # 1 分钟内有 10000 次修改
# 多档一起配:写得越频繁,快照间隔越短,丢失窗口越小
dbfilename dump.rdb # RDB 文件名
dir /var/lib/redis # RDB 文件存放目录
rdbcompression yes # 对字符串做压缩,省磁盘但费一点 CPU
rdbchecksum yes # 文件尾部加 CRC64 校验,能发现损坏
# 快照失败时是否拒绝写入:yes 能让你立刻发现磁盘故障
stop-writes-on-bgsave-error yes
RDB 的快照可以自动触发(上面的 save 规则),也可以手动触发。理解手动命令,能帮你看清 RDB 的同步与异步之分:
# SAVE:在主线程里同步做快照 —— 期间 Redis 完全阻塞,线上禁用
redis-cli SAVE
# BGSAVE:fork 一个子进程在后台做快照,主线程几乎不受影响 —— 线上用这个
redis-cli BGSAVE
# 查看上一次成功落盘的时间戳,确认快照到底有没有在跑
redis-cli LASTSAVE
# 距上一次快照,已经积压了多少次未落盘的修改 —— 这个数字就是你的风险敞口
redis-cli INFO persistence | grep rdb_changes_since_last_save
这里的认知要点非常关键:RDB 是"时间点快照",它丢的,永远是"上一次快照成功之后、到宕机之前"的那一整段写入。你把 save 规则配得越密,这个窗口越小,但永远不可能是零——因为快照本身有间隔。所以 RDB 的适用场景是:能容忍丢失几分钟数据的业务,比如纯缓存(丢了大不了回源重建)、定时备份。如果你的数据丢几分钟都不能接受,RDB 单独用就不够,得看下一种:AOF。
三、AOF:命令日志,fsync 策略决定丢多少
AOF(Append Only File)走的是完全不同的思路:它不拍快照,而是把每一条"会改变数据的写命令",原样追加记录到一个日志文件里。重启时,Redis 把这些命令从头到尾重放一遍,数据就回来了。听起来"每条命令都记了,那一条都不会丢"——但关键的坑就在这:命令不是直接写进磁盘的。它先进操作系统的内核缓冲区,再由一个叫 fsync 的动作真正刷到磁盘盘片上。什么时候 fsync,由 appendfsync 决定:
appendonly yes # 开启 AOF
appendfilename "appendonly.aof" # AOF 文件名
# appendfsync 三选一 —— 这一行直接决定你最多丢多少数据:
#
# always:每执行一条写命令就 fsync 一次。最安全,几乎不丢,
# 但每条命令都等磁盘,吞吐量大幅下降。
#
# everysec:每秒钟 fsync 一次。最多丢 1 秒的数据,
# 性能和安全的平衡点 —— 绝大多数业务用这个。
#
# no:从不主动 fsync,完全交给操作系统(通常 30 秒一次)。
# 最快,但宕机可能丢掉几十秒的数据。
appendfsync everysec
所以"AOF 一条都不丢"是个误解——只有 appendfsync always 才接近"不丢",而它的代价是每条写命令都要等一次磁盘 IO,吞吐会掉得很厉害。绝大多数业务用的是 everysec,它的含义必须记牢:最多丢最近 1 秒的写入。我用一段 Python 压测脚本,把这个"丢 1 秒"实测出来:
import redis
import time
r = redis.Redis(host="127.0.0.1", port=6379)
def stress_write(duration=10):
"""持续写入,并记录"我以为已经成功写入"的最大序号。"""
n = 0
deadline = time.time() + duration
while time.time() < deadline:
n += 1
# set 返回成功,只代表命令进了内存和 AOF 缓冲区,
# 不代表它已经被 fsync 到磁盘 —— 这正是丢数据的窗口
r.set(f"item:{n}", n)
print(f"客户端认为已写入 {n} 条")
return n
# 跑这个脚本,在写入过程中用 kill -9 杀掉 redis-server 进程,
# 重启后再用下面的脚本数一数实际幸存多少 —— 差额就是丢失量
if __name__ == "__main__":
stress_write()
import redis
r = redis.Redis(host="127.0.0.1", port=6379)
# 模拟宕机重启后,核对实际幸存的数据量
survived = r.dbsize()
print(f"重启后实际幸存 {survived} 条")
# 用 everysec 时,survived 会比客户端认为的写入数少一点点,
# 这个差额对应的就是"最后那不到 1 秒、还没 fsync 的写入"。
# 把 appendfsync 换成 always 再测一次,差额会接近 0 —— 但写入会明显变慢。
这里的认知要点是:AOF 也会丢数据,它和 RDB 的区别不是"丢不丢",而是"丢多少"。RDB 的丢失窗口是快照间隔(分钟级),AOF everysec 的丢失窗口是 1 秒。你选哪个、配哪一档,本质上是在一个滑块上,在"丢得少"和"跑得快"之间选一个位置。但 AOF 有一个 RDB 没有的麻烦:它是只追加的,日志会越长越长。
四、AOF 重写:不重写,文件会撑爆磁盘
开头那个"AOF 文件一个月涨到几十 GB",根子就在 AOF "只追加"的本性上。想象一下:你对同一个 key counter 执行了 10 万次 INCR,AOF 文件里就老老实实记了 10 万条 INCR 命令——可这个 key 的最终状态,不过就是一个数字。这 10 万条命令里,99999 条都是"历史包袱"。AOF 重写(rewrite)就是来解决这个的:它不读旧的 AOF 文件,而是直接扫描当前内存里的数据,为每个 key 生成"用最少的命令把它恢复到现在这个状态"的指令,写成一个全新的、紧凑的 AOF 文件。
# AOF 自动重写的触发条件(两个条件要同时满足):
#
# 当前 AOF 文件大小,比"上一次重写后的大小"增长了百分之多少
auto-aof-rewrite-percentage 100
# 即:涨到上次的 2 倍时触发重写
#
# 但文件至少要大于这个值才考虑重写,避免文件很小时频繁重写
auto-aof-rewrite-min-size 64mb
# 手动触发一次 AOF 重写:同样是 fork 子进程在后台做,不阻塞主线程
redis-cli BGREWRITEAOF
# 重写前后对比文件大小,直观感受"历史包袱"被清掉了多少
redis-cli INFO persistence | grep -E "aof_current_size|aof_base_size"
# aof_current_size:当前 AOF 文件大小
# aof_base_size:上一次重写完成时的大小
# 两者差距越大,说明积压的待重写历史命令越多
我第一版把 auto-aof-rewrite 那两行整个删掉了(以为是"可选项"),结果 AOF 从不触发重写,只进不出,一路膨胀。这里的认知要点是:AOF 重写不是"优化项",而是"必需项"。一个开了 AOF 却不配重写的 Redis,它的 AOF 文件注定会无限增长——直到撑爆磁盘,或者重启时因为要重放天量命令而慢得无法忍受。重写让 AOF 文件始终维持在"恢复当前数据所需的最小体积"附近。理解了 RDB 的"快但丢得多"和 AOF 的"丢得少但文件大、重启慢",下一个问题自然就是:能不能两个一起用?
五、混合持久化与文件损坏恢复
RDB 和 AOF 各有长短:RDB 文件小、重启加载快,但丢数据多;AOF 丢数据少,但文件大、重启时要一条条重放命令,慢。Redis 4.0 之后给了一个"两者兼得"的方案——混合持久化:让 AOF 重写时,文件的头部用 RDB 的二进制格式写一份全量快照,尾部再用 AOF 的命令格式追加增量。重启时,头部 RDB 部分加载极快,尾部增量命令量很小,于是既快又丢得少:
appendonly yes
appendfsync everysec
# 开启混合持久化:AOF 重写产生的文件 = RDB 全量头 + AOF 增量尾
# Redis 7 默认就是 yes,老版本要手动开
aof-use-rdb-preamble yes
# 同时保留 RDB 的 save 规则也无妨:RDB 文件可单独留作冷备份
save 900 1
save 300 100
持久化文件本身也可能损坏——比如写盘到一半机器掉电,会留下一个尾部不完整的 AOF 文件。这种情况下 Redis 可能拒绝启动。Redis 自带了两个检查修复工具:
# 检查 RDB 文件是否完整(靠的就是 rdbchecksum 写入的那个校验和)
redis-check-rdb /var/lib/redis/dump.rdb
# 检查 AOF 文件;加 --fix 会把尾部那段不完整的命令"截断修复"
redis-check-aof --fix /var/lib/redis/appendonly.aof
# 注意:--fix 是"丢掉损坏的尾部命令"来换取能启动,
# 修复前务必先 cp 一份原文件备份,别让"修复"变成"二次破坏"
# 也可以在配置里让 Redis 启动时自动忽略 AOF 尾部的不完整内容
# aof-load-truncated yes
这里的认知要点是:持久化文件不是"写进去就绝对可靠"的,它也会损坏;一套完整的持久化方案,必须包含"文件坏了怎么检查、怎么修复、怎么从备份恢复"的预案。下面这张图,把"该怎么选持久化方案"的决策过程串起来:
六、工程坑:fork 开销、主从持久化与容量
五块设计之外,还有几个工程坑,不处理就会让持久化反过来拖垮线上。坑 1:持久化要 fork 子进程,写多时内存可能翻倍。无论 BGSAVE 还是 BGREWRITEAOF,都靠 fork 出一个子进程来做。fork 用的是写时复制(copy-on-write):子进程一开始和父进程共享内存页,但只要父进程改了某个页,这个页就要复制一份。所以持久化期间如果写入很猛,被复制的页越来越多,内存占用最坏会接近翻倍:
# 观察 fork 这个动作本身耗时多久(微秒)—— 数据集越大,fork 越慢
redis-cli INFO stats | grep latest_fork_usec
# 关键:给系统配置内存超分,否则 fork 时可能因内存不足而失败
# 写入 /etc/sysctl.conf 并执行 sysctl -p
echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf && sysctl -p
# 经验法则:为持久化预留出"约等于数据集大小"的空闲内存余量
坑 2:主从复制下,从库也必须开持久化——否则可能引发数据全清空。这就是开头第四个问题的真凶。设想:主库没开持久化,某次意外重启后,主库以一个空数据集启动;而主从复制的机制是"从库无条件向主库看齐"——于是从库会忠实地把自己的数据也清空,去和那个空主库同步。一次重启,主从数据一起没了:
# 主库:必须开持久化,否则重启后的空数据集会被同步给所有从库
appendonly yes
appendfsync everysec
# 从库:同样要开自己的持久化
# 并且强烈建议主库配合开启下面这条 ——
# 当持久化未开启时拒绝继续运行,从源头堵死"空数据集启动"的可能
# (在主库的配置里)
# 另外:从库默认 replica-read-only yes,只读,防止误写脏数据
replica-read-only yes
坑 3:磁盘容量要为持久化留足余量。持久化要占磁盘的,而且不止一份:RDB 文件、AOF 文件、AOF 重写时会先写一个临时文件再改名(重写过程中临时文件和旧文件同时存在)。所以磁盘可用空间,至少要能同时放下 RDB + 当前 AOF + 一份重写临时 AOF。磁盘一旦写满,持久化会失败,而你如果配了 stop-writes-on-bgsave-error yes,Redis 还会直接拒绝所有写入。坑 4:用 INFO persistence 把持久化状态监控起来。持久化是不是在正常跑、上一次有没有失败,不能靠猜,要靠监控:
redis-cli INFO persistence
# 上线后必须盯住这几个字段:
#
# rdb_last_bgsave_status 上一次 RDB 落盘成功还是失败
# rdb_changes_since_last_save 距上次落盘积压的修改数 —— 风险敞口
# aof_last_bgrewrite_status 上一次 AOF 重写成功还是失败
# aof_last_write_status 上一次 AOF 写盘成功还是失败
# aof_rewrite_in_progress 当前是否正在重写
#
# 任何一个 status 变成 err,都要立刻告警 —— 那意味着
# 你以为在保护你的持久化,其实早已悄悄停摆了
把这些坑收一收:持久化不是"开了就一劳永逸"的开关,它是一个需要预留内存、预留磁盘、需要监控、需要定期演练恢复的子系统。坑 5:别忘了真正演练一次恢复。你配了一堆持久化,但你真的拿持久化文件成功恢复过一次吗?很多人直到真出事那天才发现:RDB 文件因为目录权限根本没写成功、或者备份脚本copy 的是个空文件。一个没有被演练验证过的恢复方案,等于没有方案。
关键概念速查
| 概念 / 配置 | 说明 |
|---|---|
| RDB | 定时把整个数据集 dump 成二进制快照文件,加载快、文件小 |
| AOF | 把每条写命令追加进日志,重启时重放,丢数据少 |
| save 规则 | RDB 自动快照触发条件,间隔越短丢失窗口越小 |
| appendfsync | always 几乎不丢 / everysec 最多丢 1 秒 / no 丢几十秒 |
| BGSAVE | fork 子进程后台做 RDB 快照,不阻塞主线程 |
| AOF 重写 | 按当前数据生成最小命令集,防止 AOF 文件无限膨胀 |
| auto-aof-rewrite | AOF 自动重写触发条件,是必需项不是可选项 |
| 混合持久化 | AOF 文件用 RDB 全量头加 AOF 增量尾,兼顾快与少丢 |
| redis-check-aof | 检查并截断修复损坏的 AOF 文件,修复前先备份 |
| fork 写时复制 | 持久化期间写入猛,内存占用最坏接近翻倍 |
避坑清单
- 持久化不是实时落盘,RDB 和 AOF 都有各自丢数据的窗口。
- 本地正常重启数据还在,是正常关闭做了临别快照,不代表配置可靠。
- RDB 丢的是上次快照到宕机之间的整段写入,save 配密只能缩小不能归零。
- AOF 不是一条不丢,everysec 最多丢 1 秒,always 才接近不丢但慢。
- AOF 重写是必需项,不配重写文件会无限膨胀直到撑爆磁盘。
- 混合持久化让 AOF 文件兼顾重启快和丢数据少,新版默认开启。
- 持久化文件会损坏,要会用 redis-check-rdb / redis-check-aof 修复。
- 持久化靠 fork 子进程,写入猛时内存最坏接近翻倍,要留足余量。
- 主从复制下从库也要开持久化,否则主库空启动会清空从库数据。
- 用 INFO persistence 监控持久化状态,并真正演练一次恢复流程。
总结
回头看那串"意外重启丢一大半、换 AOF 还是丢几秒、AOF 文件涨到几十 G、主库重启清空从库"的问题,最该记住的不是某一个配置项,而是我动手前那个想当然的判断——"持久化就是在配置里开一下,数据就落盘、永不丢失"。这句话错在它把 Redis 当成了一个"数据天然就在磁盘上"的数据库。我以为我开了持久化,数据就像存进了一个保险箱。可 Redis 骨子里是一个内存数据库——它的快,正是用"数据只在内存里"换来的。持久化不是它的地基,而是它额外打的一块补丁:这块补丁有时间差(内存变化和磁盘备份永远不同步)、有成本(占 CPU、占内存、占磁盘 IO)、有窗口(总有一段最新的数据还没来得及落盘)。
所以做 Redis 持久化,真正的工程量不在"在 redis.conf 里开一下"那一行配置上。那一行,谁都会写。真正的工程量,在于你要先回答一个业务问题——"我这份数据,能容忍丢多少":能丢几分钟,RDB 就够,还省事;最多丢一两秒,就上 AOF 配 everysec;一条都不能丢,才用 always 拿性能去换。答案定了,再顺着它把配套全配齐:RDB 的 save 多档、AOF 的重写规则、混合持久化、从库的持久化、fork 的内存余量、磁盘的容量余量、INFO persistence 的监控告警。这篇文章的几节,其实就是顺着这条线展开的:先想清楚"开一下"为什么不算持久化,再讲 RDB 快照丢的是哪段、AOF 的 fsync 决定丢多少、AOF 为什么必须重写、混合持久化和损坏恢复怎么做,最后是 fork、主从、容量这几个把持久化做扎实的工程细节。
你会发现,给 Redis 配持久化,和现实里"给一屋子重要文件做备份"完全相通。一个不会做备份的人,会怎么做?他买了个移动硬盘,往那一放,就觉得"我备份了"(这就是抄一行 save 900 1 就安心)。可他从不知道这块硬盘多久才同步一次(这就是没搞清丢失窗口),硬盘满了也不知道(这就是不配重写、不留容量),硬盘悄悄坏了他也没发现(这就是不做监控),真到要恢复那天,才发现备份的是个空文件(这就是从不演练恢复)。而一个真懂备份的人怎么做?他先分清哪些文件丢了要命、哪些丢了无所谓(这就是按业务定丢失容忍度),按重要程度定不同的备份频率(这就是 RDB 与 AOF 的选型),定期检查备份盘还健不健康(这就是 INFO persistence 监控),而且每隔一阵真的拿备份还原一次,确认它真能用(这就是演练恢复)。
最后想说,持久化做没做对,差距永远不会在"本地重启一下数据还在"时暴露——本地你做的是温柔的、正常的重启,Redis 临走前还贴心地补了一张快照,你会觉得"开一行配置已经是全部"。它只在线上那次你毫无防备的意外宕机、那次 OOM Killer 的突然袭击、那次机房的瞬间掉电里才显形。那时候它会用最让人心碎的方式给你结账:做不好,你会像我一样,看着监控曲线断崖式掉下去——缓存里一大半数据凭空蒸发,大量请求瞬间击穿到数据库;你翻出持久化文件想恢复,却发现它停留在十几分钟前,甚至根本就是损坏的、空的;而做对了,同样一次意外宕机,你的 Redis 会从磁盘上从容地把数据加载回来,丢失的只是最后那不到一秒、无关痛痒的一点点,业务几乎无感。所以别等"那条断崖式下跌的曲线"找上门,在你写下那行 save 或 appendonly yes 的那一刻就该想清楚:我面对的不是一个数据天然在磁盘上的数据库,而是一个把数据放在内存里、靠一层有时间差的补丁来兜底的内存数据库——它的丢失窗口、它的文件膨胀、它的 fork 开销、它的主从同步,这一道道关口,我是不是每一道都想清楚、配明白了?这些问题有了答案,你的 Redis 才不只是一个"看起来开了持久化"的缓存,而是一个真正经得起一次意外宕机、能把数据稳稳交还给你的存储。
—— 别看了 · 2026