news 2026/10/22 8:20:24

Kubernetes Deployment故障排查:从三层结构到根因定位

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kubernetes Deployment故障排查:从三层结构到根因定位

1. 故障排查的底层逻辑设计——先给大脑装一张“地图”

先说个我一直坚持的观点:排查 Kubernetes Deployment 故障,真正难的不是某个具体命令不会敲,而是面对一坨报错时不知道从哪里下手。Kubernetes 的报错信息天生就“分层”,有时候问题明明出在 Deployment,报错却先出现在 Pod 上;有时候 Pod 一切正常,流量却进不来。如果脑子里没有一张“故障地图”,很容易被表象带偏,在错误的方向上浪费几个小时。

所以这篇指南不打算只教你几条命令,而是想把排查过程“可视化”:把 Deployment 从声明到运行的全链路拆开,让每个故障都对应到链路上的一个节点。这样你下次遇到问题,不是“猜”哪坏了,而是顺着链路“定位”哪坏了。

这篇文章适合谁?刚接触 Kubernetes、被 Deployment 各种状态搞晕的新手,也适合已经上手了一段时间、但排查仍然靠“重启大法”的开发者。我会把关键命令、事件解读、状态判断全部串起来,给你一套能直接抄作业的排查路径。

1.1 Deployment 的“三层结构”决定了排查顺序

要理解故障,先理解结构。一个 Deployment 往下拆,其实有三层:

Deployment(声明期望状态) └── ReplicaSet(管理 Pod 副本数) └── Pod(真正跑容器的最小单元)

这个层级关系不是摆设,它直接决定了排查顺序。Deployment 本身不直接创建 Pod,它只负责声明“我想要几个副本”,然后由控制器创建出对应的 ReplicaSet,再由 ReplicaSet 负责把 Pod 拉起来。

所以很多新手犯的第一个错误是:看到 Pod 报错,就去查 Deployment 的 YAML,改一通,发现没用。为什么?因为 Deployment YAML 只是“蓝图”,Pod 才是“施工结果”。要搞清楚施工为什么失败,你得先看 Pod,再看 Deployment。

我推荐的排查顺序是固定的:

  1. 先看 Deployment 是否 Ready,确认 ReplicaSet 是否存在;
  2. 再看 ReplicaSet 的状态,确认它是否成功创建了 Pod;
  3. 最后看 Pod 的具体状态和事件,定位容器层的故障。

这个顺序就像查水管漏水:先看总阀门开没开,再看分阀门,最后看漏水点。跳层排查,大概率会被表象误导。

1.2 故障排查的“可视化思维”

标题里说“可视化”,并不只是画几张图那么简单。我理解的可视化,是把抽象的集群状态转化成人类容易理解的“信号灯”思维。

Kubernetes 本身已经给出了一套信号灯,就是各种状态字段:

  • Deployment 的Available字段,绿了就是副本数足够且可用;
  • ReplicaSet 的FullyLabeledReplicas,绿了就是 Pod 的标签匹配没问题;
  • Pod 的Status字段,Running就是运行中,Pending就是还没调度成功。

你不需要记住每一个字段的含义,但你要养成一个习惯:每次排查前,先用一条命令把这三个对象的状态同时拉出来,像看仪表盘一样扫一遍。

kubectl get deploy,rs,pods -o wide

这一条命令输出 Deployment、ReplicaSet、Pod 的全部状态。我几乎所有排查都是从这一行开始的。它会把“红绿灯”一次性摆在你面前,哪个环节亮红灯,就从哪里往下挖。

2. 可视化排查第一站:Deployment 与 ReplicaSet

从 Deployment 开始排查,不是因为它最容易出问题,而是因为它是“第一道信号灯”。Deployment 的状态直接告诉你:期望状态和实际状态是否一致。

2.1 版本发布失败的信号灯

先看一个最常见的场景:你更新了 Deployment 的镜像版本,发现滚动更新一直没完成。这时候kubectl get deploy的输出很可能长这样:

NAME READY UP-TO-DATE AVAILABLE myapp 0/1 1 0

这几个字段我把它们翻译成人话:

  • READY表示实际就绪的副本数 / 期望副本数;
  • UP-TO-DATE表示已经更新到新版本的副本数;
  • AVAILABLE表示正在对外提供服务的副本数。

如果READY一直卡在0/1,说明新版本 Pod 根本没起来。如果UP-TO-DATE是 1 但READY是 0,说明 Pod 创建了但不健康,大概率是启动探针失败或者容器启动崩溃。

这时候要做的不是盯着 Deployment 看,而是顺着链路往下查 ReplicaSet:

kubectl rollout status deployment/myapp

这条命令会阻塞并等待滚动更新完成,但更好用的其实是加一个--timeout参数,比如:

kubectl rollout status deployment/myapp --timeout=60s

如果 60 秒内没完成,命令会超时退出,告诉你“再等下去也是浪费时间,快去看事件吧”。这比干等着强多了。

2.2 ReplicaSet 状态的可视化排查

Deployment 下面是 ReplicaSet。看起来多了一层很麻烦,但其实这是个很好的“回溯机制”。

举个例子:有一次我把某个服务的镜像版本从 v1 升级到 v2,部署之后发现服务异常。我怀疑是 v2 镜像的问题。怎么验证?我先看 ReplicaSet 列表:

kubectl get rs

输出里会同时存在两个 ReplicaSet:一个对应 v1,一个对应 v2。如果 v2 的 ReplicaSet 下面 Pod 一直报错,我立刻就能通过修改 Deployment 的镜像版本回滚到 v1,整个过程不到一分钟。

ReplicaSet 相关的排查,我建议重点关注两个字段:

  • DESIRED——期望的副本数;
  • CURRENT——当前创建的副本数。

如果CURRENT一直小于DESIRED,说明 Pod 创建失败了。Pod 创建失败的原因,常见的有:资源配额不足、镜像拉取失败、存储卷挂载失败。这些具体原因,单看 ReplicaSet 是看不出来的,必须进一步看 Pod。

所以 ReplicaSet 阶段的排查诀窍是:把 ReplicaSet 当作“分赃不均”的信号灯,它亮红灯的瞬间,就是 Pod 往下走的初始状态。

2.3 事件的可视化排序

Kubernetes 里几乎所有重要操作都会产生事件(Event)。但事件是个“实时流”,过一段时间就被清理了。如果你等 Pod 已经 Crash 了好几个小时才去看事件,大概率什么都看不到。

所以我给自己定了一个规矩:任何异常,第一件事就是拉事件,不要先查日志。

kubectl describe deploy myapp kubectl describe pod myapp-xxxx

describe输出的底部就是事件列表。事件是倒序排列的,最新的在最上面。我习惯把事件从下往上读,相当于把整个生命周期倒着播放一遍,看它是怎么一步步走到现在这个状态的。

可视化指南里,事件列表就像飞机上的“黑匣子记录仪”。你不需要记住每个事件的编号,只需要关注两种事件:Warning类型的事件,以及带有Failed关键字的描述。

3. 可视化排查第二站:Pod 生命周期状态全解码

Pod 是 Kubernetes 里最核心的排查对象,也是故障的“重灾区”。Pod 的状态字段就像人的“体温指标”,不同状态对应不同的病因。我把常见状态整理成一张速查表,排查时对照着看,效率能翻倍。

3.1 Pod 状态的“八字”速查表

状态含义常见原因下一步操作
Pending等待中,未调度成功资源不足、节点不可调度、亲和性不满足kubectl describe pod查看事件
Running容器已启动正常状态进一步看 Ready 是否 1/1
CrashLoopBackOff启动后崩溃,反复重启镜像启动命令错误、环境变量缺失、配置错误查看日志kubectl logs
ImagePullBackOff镜像拉取失败镜像不存在、仓库认证失败、网络不通检查镜像名和拉取策略
ErrImageNeverPull镜像拉取策略拒绝imagePullPolicy设置为Never检查 YAML 中拉取策略
ContainerCreating容器创建中正在拉镜像或挂载卷等待,或查看事件判断卡在哪
Terminating终止中正在删除,或卡在优雅终止检查terminationGracePeriodSeconds
Unknown节点异常节点宕机或网络分区检查节点状态

这张表怎么看?我推荐的做法是“先定位状态,再找原因”。不要一上来就去翻日志,日志和状态其实是两回事:状态告诉你“现状是什么”,日志告诉你“为什么会这样”。先看状态,再决定要不要看日志。

3.2 CrashLoopBackOff 的深入排查

在所有状态里,CrashLoopBackOff可能是出现频率最高的。这个状态的中文直译是“崩溃循环退避”,意思是容器启动后立刻崩溃,Kubernetes 会按指数退避策略反复重启它,比如第一次等 10 秒,第二次等 20 秒,第三次 40 秒,上限 5 分钟。

排查这个状态,我有一套固定的“三连”操作:

  1. 看启动日志和上一个实例的日志:
kubectl logs myapp-xxxx # 当前实例日志 kubectl logs myapp-xxxx --previous # 上一个崩溃实例的日志
  1. 看事件里有没有具体报错:
kubectl describe pod myapp-xxxx
  1. 如果症状是“进程启动了但马上退出”,还要看启动命令是否正确:
kubectl get pod myapp-xxxx -o yaml

在 YAML 里spec.containers[].command和args是否写对了?最常见的一个坑是:基础镜像默认没有你要执行的命令,或者 entrypoint 被覆盖了。

我有一次排查一个 Java 应用,日志里反复出现“Unrecognized option: -jar”,折腾了很久才发现是启动命令写错了。command写成了java -jar app.jar,但实际应该拆成command: ["java"]和args: ["-jar", "app.jar"]。这个知识点很重要,因为在 Dockerfile 里这种写法没问题,但在 Kubernetes YAML 里,command和args的优先级和拼接逻辑跟 Docker 不一样。

3.3 Pod 调度失败的可视化诊断

另一个高频状态是Pending卡住不动。这个状态的本质是“调度器找不到合适的节点”,或者“调度器找到了节点但条件不满足”。

可视化排查的思路是这样:把节点想象成一个停车场,Pod 是一辆车。车停不进来,要么是停车场满了(资源不足),要么是管理员不让停(Taint 容忍问题),要么是车位条件不匹配(节点亲和性、标签选择器问题)。

实际排查命令:

kubectl describe pod myapp-xxxx

看 Events 部分,通常会有这样一条信息:

0/3 nodes are available: 1 Insufficient cpu, 2 Insufficient memory.

翻译一下:一共 3 个节点,1 个 CPU 不够,2 个内存不够。这基本就是资源配额的问题。

如果看到的是:

0/3 nodes are available: 3 node(s) had taint {node-role.kubernetes.io/control-plane: }, that the pod didn't tolerate.

这是说 3 个节点都有污点(Taint),但 Pod 没有对应的容忍(Toleration)。这种情况通常发生在你往控制平面节点上调度任务时。

遇到 Pending,我的建议是:先describe,再根据事件里的关键词分方向。资源不足就调大节点或者缩小 request;污点问题就在 YAML 里加tolerations字段。切忌盲目把节点删了重加。

4. 从状态到根因:三种经典故障的可视化拆解

光看状态还不够,状态只是“现象”,真正的排查价值在于透过现象找到“根因”。这一节我挑三个出现频率最高的故障场景,从事件、日志、根因三个维度完整拆一遍。

4.1 镜像拉取失败的完整链路

镜像拉取失败,对应的状态是ImagePullBackOff或ErrImagePull。很多人一看到这个状态,第一反应是“镜像不存在”。但实际排查下来,原因五花八门:

  • 私有仓库认证失败(最常见);
  • 镜像仓库地址写错了;
  • 镜像 tag 不存在;
  • 集群无法访问外网仓库(网络策略限制);
  • imagePullSecrets配置缺失。

排查路径我建议这样走:先看 Webhook 层面有没有拉取凭证的问题。

kubectl get pod myapp-xxxx -o yaml | grep -A4 imagePullSecrets

如果imagePullSecrets是空的,而你的镜像在私有仓库里,那一定拉取失败。解决方法是先创建 Secret:

kubectl create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=user \ --docker-password=pass

然后在 Deployment 的spec.template.spec下加上:

imagePullSecrets: - name: regcred

如果imagePullSecrets已经配置了还是失败,再看事件描述,通常会有明确提示,比如401 Unauthorized说明凭证错了,404 Not Found说明镜像不存在,connection refused说明网络不通。

这一条链路走完,基本能把镜相关故障隔离到具体环节。我统计过自己遇到的镜像问题,大概 60% 是认证问题,25% 是 tag 打错,15% 是网络问题。先把认证检查完,能少走很多弯路。

4.2 资源不足引发的连环故障

资源不足(Insufficient memory/Insufficient cpu)是 Kubernetes 集群最常见的问题,常常表现为 Pod 刚启动就被 OOM Kill,或者一直 Pending 无法调度。

可视化排查的第一步,是看集群的整体资源水位:

kubectl top nodes kubectl top pods

top nodes会显示每个节点的 CPU 和内存占用率。如果某个节点内存占用已经到了 90% 以上,那么新 Pod 很可能调度不进来。

这时如果你硬要调度,可以临时把节点上的其他 Deployment 副本数降一降,或者直接扩容节点。但我不建议长期靠扩容解决问题,压根问题在于 Deployment 的 request 可能设置得太高或太低。

关于 request 和 limit,我在这里分享一个很重要的实操经验:

  • request 是“最低保障”,调度器按它来分配节点资源;
  • limit 是“最高上限”,超出会被强制杀掉(OOM Kill);
  • 如果 Pod 里跑的进程有内存尖峰,request 设置过低会导致多个 Pod 挤在同一节点,互相抢内存,最终集体 OOM。

排查时如果发现容器反复 OOM Kill,登录节点看内核日志,能确认内存是否被打满:

journalctl -k | grep -i oom

如果内核日志显示某进程被 OOM Killer 杀掉,那就说明内存确实不够。这种问题靠调代码不一定立刻生效,最直接的缓解方式是调大 limit 或者减少副本数。

4.3 CrashLoopBackOff 的根因可视化

CrashLoopBackOff 我已经提过一次,这里展开讲根因。这个状态本质上是一个“症状”,不是独立的一个病。我在实际项目里发现,CrashLoopBackOff 最常见的根因有四种:

  1. 启动命令或参数错误,导致应用启动即退出;
  2. 配置缺失,应用读取不到环境变量或配置文件;
  3. 探针配置过于激进,容器虽然启动了,但健康检查失败;
  4. 依赖服务(如数据库)未就绪,应用连接失败后主动退出。

排查顺序我推荐“由近及远”:先看应用自身的启动日志,再看探针配置,最后检查依赖服务。

启动日志这个步骤很多人会漏掉--previous参数,导致看到的是“当前正在重启的实例日志”,这个实例可能根本没来得及打印任何日志就退出了。正确姿势是上一个实例的日志。

kubectl logs myapp-xxxx --previous --tail=200

--tail=200只看最近 200 行,避免日志刷屏。

如果日志显示“connect: connection refused”,那说明依赖服务没起来或地址不对。这里有个很容易踩的坑:在本地开发时服务间调用用的是localhost,但进了 Kubernetes,你得改用 Service 名称,比如mysql或redis。如果你忘了改,应用在容器里永远连不上。

探针问题我会在 5.3 单独讲,这里先提醒一句:livenessProbe和readinessProbe的periodSeconds不要设置得太小,否则应用启动稍有波动就会被误杀。

5. 运维环境故障排查的“可视化工具包”

看完前几节,你可能已经有了排查思路,但距离“高效”还差一步:工具。Kubernetes 自带的kubectl是最基础的,但有些信息光靠kubectl很难看清。这一节分享几个我在实战中常用的工具和技巧,它们能让故障排查真正“可视化”。

5.1 让事件实时可见:kubectl 的插件生态

先推荐一个最基础的组合拳:

kubectl get events --sort-by='.lastTimestamp' -A

这个命令按时间排序显示所有命名空间的事件。但在事件较多时,输出会非常杂乱。所以我更喜欢用一个开源小工具kubectl-tree,它能把 Deployment、ReplicaSet、Pod 之间的从属关系画成一棵“树”,层次一目了然。

安装方式也很简单(某开源项目,读者可自行检索):

kubectl krew install tree kubectl tree deploy myapp

输出类似:

NAMESPACE NAME READY STATUS default deploy/myapp 1/1 Ready └─ default rs/myapp-7d8f9c 1/1 Ready └─ default pod/myapp-7d8f9c-x2k3l 1/1 Running

这个输出让我一眼就能看到三层结构的对应关系。相比传统的get deploy,rs,pods,它多了“谁是爸爸谁是儿子”的视觉呈现,排查层级问题时非常友好。

5.2 一键收集现场信息:kubectl describe 的批量用法

出故障的时候,时间和现场同样重要。人手不够的时候,我会用一行命令把关键对象的describe一次性导出来:

kubectl describe deploy,rs,pods -l app=myapp > debug-$(date +%s).txt

这个命令的好处有三个:

  1. 用-l app=myapp只导出目标应用的对象,不刷屏;
  2. 输出带时间戳的文件名,方便事后对比;
  3. describe自带事件,相当于把黑匣子下载下来。

曾经有两次我在排查线上问题时,都是先跑了这条命令存档,然后才慢慢分析。事后复盘时,档案里的事件时间线帮了大忙——因为你永远不知道自己会不会在排查过程中把现场搞乱。

5.3 探针与滚动更新相关的可视化避坑指南

探针(Probe)配置是 Kubernetes 里最容易被低估的“故障制造机”。它不像镜像问题那么显眼,但它一旦配置不当,就会让 Pod 状态反复在Running和CrashLoopBackOff之间横跳,非常隐蔽。

我的建议是三种探针分开理解:

  • livenessProbe:问“容器还活着吗?”如果挂了就杀掉重启;
  • readinessProbe:问“容器能对外服务了吗?”如果没准备好,就从 Service 端点列表里摘除;
  • startupProbe:问“应用启动完成了吗?”特别适合启动慢的应用,配合前两者可以避免启动期间被误杀。

有一次排查一个启动需要 30 秒的 Java 应用,它反复被 livenessProbe 杀死。后来我在启动阶段加了startupProbe,并把initialDelaySeconds设成 20 秒,问题就彻底解决了。

startupProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 20 periodSeconds: 10 failureThreshold: 30 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 45 periodSeconds: 15

failureThreshold: 30,periodSeconds: 10,意味着最多给 300 秒的启动时间。这是确保启动慢的应用不被误杀的关键。还有一个小细节:httpGet探测的路径一定要选择应用本身提供的健康检查接口,不要随便拿一个静态页面糊弄,否则探针会失真。

滚动更新相关的避坑也值得一提。kubectl rollout restart deployment/myapp在需要强制重新拉取镜像时很有用,但如果你用的是latest标签,即使执行了 restart,Kubelet 也可能因为本地已经有镜像而跳过拉取。这种情况下,把imagePullPolicy改成Always,或者换一个明确的版本号 tag,都能避免“改了镜像却不生效”的假象。

6. 故障速查表与实操心得

最后这部分,我把前面所有内容浓缩成一张故障速查表,并且分享几个我自己踩过的坑。这些坑不是什么高端技巧,但它们确实能节省排查时间。

6.1 高频故障速查表

故障现象排查命令最可能的原因处理建议
Deployment 死循环更新kubectl rollout status deploy/xxx新版本 Pod 一直不 Ready查看新 RS 对应的 Pod 事件
Pod Pending 超时kubectl describe pod xxx资源不足/污点未容忍扩节点或调整 request
Pod 反复 Crashkubectl logs pod xxx --previous启动命令/环境变量错误对比上个实例日志
副本数不足kubectl get rsReplicaSet 创建 Pod 失败看 ReplicaSet 的事件
流量异常但 Pod 正常kubectl get endpointsService 标签选择器不匹配确认 Service 的 selector
服务 DNS 解析失败kubectl exec pod -- nslookup svcService 未创建/命名空间不对检查 Service 名称和命名空间

这张表我打印出来贴在自己工位上。排查的时候先对照一圈,能覆盖 80% 的日常故障。

6.2 我踩过的三个坑

第一个坑:kubectl logs看不到日志,不代表容器没日志。很多时候应用把日志写到文件而不是标准输出,你需要先kubectl exec进容器看文件。还有一种情况是容器崩溃太快,logs来不及抓到输出,这时--previous参数比什么都管用。

第二个坑:错误地修改旧版本的 ReplicaSet。Deployment 滚动更新后,旧 ReplicaSet 会保留一定数量的副本用于快速回滚。有人觉得这些旧 Pod 占资源,手动把旧的 ReplicaSet 删了或者把副本数改成 0。结果下次回滚时发现找不到旧版本,只能痛苦地重新构建镜像。后来我在团队里立了一条规矩:除非确认永远不需要回滚,否则不手动删 ReplicaSet。

第三个坑:忽略命名空间。这个坑最基础但也最隐蔽。排查时命令里忘了加-n 指定命名空间,结果看的是 default 命名空间的对象,而你实际部署的应用在另一个命名空间。你会看到“一切正常”的假象,然后陷入无限迷茫。现在我执行任何命令前都会先在脑子里过一遍:这个对象在哪个命名空间?

6.3 最后一招:理清楚事件时间线再动刀

排查故障最忌讳“边看边改”。我见过不少同事看到 Pod 报错,立刻就去改 Deployment 配置,改完发现还不行,再改回来,来回折腾几小时。真正高效的排查顺序应该是:

  1. 先获取全局状态(get deploy,rs,pods);
  2. 再拉事件(describe),理清时间线;
  3. 根据时间线和状态锁定一个可疑点;
  4. 针对可疑点查看日志或 YAML;
  5. 确认根因后,一次性修复,再观察一段时间。

这个顺序看起来简单,但真正做到的人不多。它最大的价值在于避免了“瞎改碰运气式”的排查,让每一次操作都有依据。

我个人在实际操作中的体会是,Kubernetes 的故障排查与其说是技术活,不如说是“流程活”。只要顺着 Deployment → ReplicaSet → Pod 这条链路一层层往下看,把每个对象的状态当作信号灯,大多数故障都能在十分钟内定位。真正难的从来不是命令,而是你能不能忍住不跳过中间层、不凭感觉去猜。按这套可视化路径走,我自己的线上故障平均修复时间,从刚开始接触 Kubernetes 时的两三个小时,已经压缩到了二十分钟以内。希望你也能养成自己的排查节奏,少踩一些我曾经踩过的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 8:20:24

AI辅助学术专著写作:从框架推演到成稿的实战指南

前阵子帮一位做社会学研究的老师整理手头的专著资料,他跟我抱怨:书稿拖了快三年,目录改了四版,每章开头写起来都特别费劲,资料堆了一桌子但不知道从哪下笔。后来我建议他试试用AI专著撰写工具做"预写"和&quo…

作者头像 李华
网站建设 2026/10/22 8:19:40

家庭财务管理系统源码实战:从解压到本地部署的完整指南

简介:这是一套完整可用的家庭财务管理系统源码,面向软件开发初学者、课程设计学生及个人开发者,解决家庭收支记录、预算控制与财务分析等实际需求。资源共200个文件,包含66个C#后端逻辑文件(.cs)、27个ASPX…

作者头像 李华
网站建设 2026/10/22 8:18:27

Spring Boot + Vue构建医疗用品商城:全栈开发实战指南

做医疗用品销售商城这个项目,最初并不是因为有多宏大的规划,纯粹是朋友那边需要一个能跑起来的电商系统,要求不复杂:能上架商品、用户能注册登录、能加购物车、能下单,后台能管订单和库存。技术选型他们没硬性规定&…

作者头像 李华
网站建设 2026/10/22 8:18:27

Flutter实战:三国杀身份攻略App开发与OpenHarmony适配

1. 从身份局玩家的真实痛点说起 先说结论:我做这个App不是一时心血来潮,而是被朋友问烦了。三国杀身份局里,主公、忠臣、反贼、内奸四类身份,每局的胜负目标完全不同,但绝大多数玩家——尤其是刚入坑的新手——根本不知…

作者头像 李华
网站建设 2026/10/22 8:18:25

SpringBoot+Vue前后端分离医疗用品商城系统实战拆解

做医疗用品销售商城这个项目,前后折腾了大半年。本身是个前后端分离的小商城,但医疗用品的特殊业务属性,让它比普通电商系统多了不少隐藏要求:商品需要资质审核、库存要管批次和效期、订单要能查溯源……光这些点,就够…

作者头像 李华
网站建设 2026/10/22 8:18:23

SpringBoot短视频推荐系统毕业设计完整复盘

记一次SpringBoot短视频推荐系统毕业设计的完整复盘 每年到毕业季前后,总有同学拿着“Java后端 Vue前端”的技术栈来问我,做什么题目既好落地、又能讲出点东西来。短视频推荐系统是我这几年看来性价比很高的一个方向。它表面上是“做一个视频App后台”&…

作者头像 李华