集群信息显示 Kubernetes 版本：kubectl version显示集群信息：kubectl cluster-info列出集群中的所有节点：kubectl get node查看一个具体的节点详情：kubectl describe node <node-name>5.列出所有命名空间：kubectl get namespaces列出所有命名空间中的所有 pod：kubectl get pods --all-namespacesPod信息列出特定命名空间中的 pod：kubectl get pods -n <namespace>查看一个 Pod 详情：kubectl describe pod <pod-name> -n <namespace>查看 Pod 日志：kubectl logs <pod-name> -n <namespace>尾部 Pod 日志：kubectl logs -f <pod-name> -n <namespace>在 pod 中执行命令：kubectl exec -it <pod-name> -n <namespace> -- <command>Pod 亲和性和反亲和性列出 pod 的 pod 亲和性规则：kubectl get pod <pod-name> -n <namespace> -o=jsonpath='{.spec.affinity}'列出 pod 的 pod 反亲和性规则：kubectl get pod <pod-name> -n <namespace> -o=jsonpath='{.spec.affinity.podAntiAffinity}'节点污点 列出节点污点：kubectl describe node <node-name> | grep TaintsPod 优先级和抢占 列出优先级：kubectl get priorityclassesPod 开销 列出 pod 中的开销：kubectl get pod <pod-name> -n <namespace> -o=jsonpath='{.spec.overhead}'Pod 健康检查检查 Pod 准备情况：kubectl get pods <pod-name> -n <namespace> -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'检查 Pod 事件：kubectl get events -n <namespace> --field-selector involvedObject.name=<pod-name>服务信息Service信息列出命名空间中的所有服务：kubectl get svc -n <namespace>查看一个服务详情：kubectl describe svc <service-name> -n <namespace>更改和验证 Webhook 配置列出变异 webhook 配置：kubectl get mutatingwebhookconfigurations列出验证 Webhook 配置：kubectl get validatingwebhookconfigurationsPod 网络策略 列出命名空间中的 pod 网络策略：kubectl get networkpolicies -n <namespace>部署相关Deployment信息列出命名空间中的所有Deployment：kubectl get deployments -n <namespace>查看一个Deployment详情：kubectl describe deployment <deployment-name> -n <namespace>查看滚动发布状态：kubectl rollout status deployment/<deployment-name> -n <namespace>查看滚动发布历史记录：kubectl rollout history deployment/<deployment-name> -n <namespace>作业和 CronJob列出命名空间中的所有作业：kubectl get jobs -n <namespace>查看一份工作详情：kubectl describe job <job-name> -n <namespace>列出命名空间中的所有 cron 作业：kubectl get cronjobs -n <namespace>查看一个 cron 作业详情：kubectl describe cronjob <cronjob-name> -n <namespace>StatefulSet信息列出命名空间中的所有 StatefulSet：kubectl get statefulsets -n <namespace>查看一个 StatefulSet详情：kubectl describe statefulset <statefulset-name> -n <namespace>ConfigMap 和Secret信息列出命名空间中的 ConfigMap：kubectl get configmaps -n <namespace>查看一个ConfigMap详情：kubectl describe configmap <configmap-name> -n <namespace>列出命名空间中的 Secret：kubectl get secrets -n <namespace>查看一个Secret详情：kubectl describe secret <secret-name> -n <namespace>命名空间信息查看一个命名空间详情：kubectl describe namespace <namespace-name>资源使用情况检查 pod 的资源使用情况：kubectl top pod <pod-name> -n <namespace>检查节点资源使用情况：kubectl top nodes持久卷和持久卷声明列出PV：kubectl get pv查看一个PV详情：kubectl describe pv <pv-name>列出命名空间中的 PVC：kubectl get pvc -n <namespace>查看PVC详情：kubectl describe pvc <pvc-name> -n <namespace>容量信息列出按容量排序的持久卷 (PV)：kubectl get pv --sort-by=.spec.capacity.storage查看PV回收策略：kubectl get pv <pv-name> -o=jsonpath='{.spec.persistentVolumeReclaimPolicy}'列出所有存储类别：kubectl get storageclasses存储卷快照列出存储卷快照：kubectl get volumesnapshot -n <namespace>查看存储卷快照详情：kubectl describe volumesnapshot <snapshot-name> -n <namespace>资源反序列化 反序列化并打印 Kubernetes 资源：kubectl get <resource-type> <resource-name> -n <namespace> -o=json网络信息显示命名空间中 Pod 的 IP 地址：kubectl get pods -n <namespace> -o custom-columns=POD:metadata.name,IP:status.podIP --no-headers列出命名空间中的所有网络策略：kubectl get networkpolicies -n <namespace>查看一个网络策略详情：kubectl describe networkpolicy <network-policy-name> -n <namespace>Ingress和服务网格列出命名空间中的所有Ingress：kubectl get ingress -n <namespace>查看一个Ingress详情：kubectl describe ingress <ingress-name> -n <namespace>列出命名空间中的所有 VirtualServices (Istio)：kubectl get virtualservices -n <namespace>查看一个 VirtualService (Istio)详情：kubectl describe virtualservice <virtualservice-name> -n <namespace>节点诊断获取特定节点上运行的 Pod 列表：kubectl get pods --field-selector spec.nodeName=<node-name> -n <namespace>Pod 网络故障排除运行网络诊断 Pod（例如 busybox）进行调试：kubectl run -it --rm --restart=Never --image=busybox net-debug-pod -- /bin/bash测试从 Pod 到特定端点的连接：kubectl exec -it <pod-name> -n <namespace> -- curl <endpoint-url>跟踪从一个 Pod 到另一个 Pod 的网络路径：kubectl exec -it <source-pod-name> -n <namespace> -- traceroute <destination-pod-ip>检查 Pod 的 DNS 解析：kubectl exec -it <pod-name> -n <namespace> -- nslookup <domain-name>资源使用情况资源配额和限制列出命名空间中的资源配额：kubectl get resourcequotas -n <namespace>查看一个资源配额详情：kubectl describe resourcequota <resource-quota-name> -n <namespace>自定义资源定义 (CRD)列出命名空间中的自定义资源：kubectl get <custom-resource-name> -n <namespace>查看自定义资源详情：kubectl describe <custom-resource-name> <custom-resource-instance-name> -n <namespace>使用这些命令时，请记住将<namespace>, <pod-name>, <service-name>, <deployment-name>, <statefulset-name>, <configmap-name>, <secret-name>, <namespace-name>, <pv-name>, <pvc-name>, <node-name>, <network-policy-name>, <resource-quota-name>, <custom-resource-name>, 和替换为你的特定值。<custom-resource-instance-name>这些命令应该可以帮助你诊断 Kubernetes 集群以及在其中运行的应用程序。资源伸缩和自动伸缩Deployment伸缩：kubectl scale deployment <deployment-name> --replicas=<replica-count> -n <namespace>设置Deployment的自动伸缩：kubectl autoscale deployment <deployment-name> --min=<min-pods> --max=<max-pods> --cpu-percent=<cpu-percent> -n <namespace>检查水平伸缩器状态：kubectl get hpa -n <namespace>配置和资源验证验证 Kubernetes YAML 文件而不应用它：kubectl apply --dry-run=client -f <yaml-file>验证 pod 的安全上下文和功能：kubectl auth can-i list pods --as=system:serviceaccount:<namespace>:<serviceaccount-name>安全和授权RBAC和安全性列出命名空间中的角色和角色绑定：kubectl get roles,rolebindings -n <namespace>查看角色或角色绑定详情：kubectl describe role <role-name> -n <namespace>Pod 安全策略 (PSP) 列出所有 Pod 安全策略（如果启用）：kubectl get psp事件：查看最近的集群事件：kubectl get events --sort-by=.metadata.creationTimestamp按特定命名空间过滤事件：kubectl get events -n <namespace>Pod 安全标准（PodSecurity 准入控制器） 列出 PodSecurityPolicy (PSP) 违规行为：kubectl get psp -A | grep -vE 'NAME|REVIEWED'服务帐户列出命名空间中的服务帐户：kubectl get serviceaccounts -n <namespace>查看一个服务帐户详情：kubectl describe serviceaccount <serviceaccount-name> -n <namespace>清空节点和解除封锁清空节点以进行维护：kubectl drain <node-name> --ignore-daemonsets解除对节点的封锁：kubectl uncordon <node-name>资源清理强制删除 pod（不推荐）：kubectl delete pod <pod-name> -n <namespace> --grace-period=0 --force节点故障排除检查节点情况：kubectl describe node <node-name> | grep Conditions -A5列出节点容量和可分配资源：kubectl describe node <node-name> | grep -E "Capacity|Allocatable"临时容器 运行临时调试容器：kubectl debug -it <pod-name> -n <namespace> --image=<debug-image> -- /bin/sh资源指标 获取 Pod 的 CPU 和内存使用情况：kubectl top pod -n <namespace>kuelet诊断 查看节点上的kubelet日志：kubectl logs -n kube-system kubelet-<node-name>使用Telepresence 进行高级调试 使用 Telepresence 调试 pod：telepresence --namespace <namespace> --swap-deployment <pod-name>Kubeconfig 和上下文列出可用的上下文：kubectl config get-contexts切换到不同的上下文：kubectl config use-context <context-name>Pod 中断预算 (PDB)列出命名空间中的所有 PDB：kubectl get pdb -n <namespace>查看一个PDB详情：kubectl describe pdb <pdb-name> -n <namespace>资源锁诊断（如果使用资源锁）列出服务的服务端点：kubectl get endpoints <service-name> -n <namespace>检查 Pod 中的 DNS 配置：kubectl exec -it <pod-name> -n <namespace> -- cat /etc/resolv.conf自定义指标（Prometheus、Grafana） 查询Prometheus指标：用于kubectl port-forward访问Prometheus和Grafana服务来查询自定义指标。节点条件 自定义查询输出：kubectl get nodes -o custom-columns=NODE:.metadata.name,READY:.status.conditions[?(@.type=="Ready")].status -l 'node-role.kubernetes.io/worker='审核日志 检索审核日志（如果启用）：检查 Kubernetes 审核日志配置以了解审核日志的位置。节点操作系统详细信息获取节点的操作系统信息：kubectl get node <node-name> -o jsonpath='{.status.nodeInfo.osImage}'这些命令应该涵盖 Kubernetes 中的各种诊断场景。确保将、、等占位符替换为集群和用例的实际值。其他诊断命令
journalctl是systemd日志系统的查询工具。当你某个服务启动失败或出现错误时，系统会提示你使用这个工具来排查。使用grep、awk这类工具对日志进行处理时，可能遇到下面的情况导致排查困难。日志文件太大，grep半天没反应想看某个时间段的日志，结果要写一堆复杂的正则表达式系统重启后，之前的日志找不到了想看某个服务的完整日志链路，结果要翻好几个不同的文件基础用法直接使用journalctl命令，会看到系统从启动开始的所有日志。不过这样看起来会很乱，而且信息量巨大。加个-f参数，就像tail -f一样，可以实时显示最新的日志。当怀疑某个服务有问题的时候，开着这个命令，然后去操作一下，立马就能看到相关的日志输出。按时间查看日志#查看今天的日志 journalctl --since today #或者看昨天的： journalctl --since yesterday #看某个时间段的 journalctl --since "2024-01-15 14:00:00" --until "2024-01-15 15:00:00"按服务查看日志#只看nginx服务的日志 journalctl -u nginx #实时监控某个服务： journalctl -u nginx -f #有时候一个服务重启了好几次，你想看它的历史记录： journalctl -u nginx --since "1 hour ago"进阶技巧按优先级过滤#只显示错误级别的日志 journalctl -p err查看内核日志journalctl -k该命令等同于dmesg，但是journalctl的输出格式更友好，而且可以结合其他参数使用。按进程ID查看 有时候你知道某个进程有问题，可以直接按PID查看：journalctl _PID=1234查看启动信息 想看系统启动过程中发生了什么：journalctl -b如果系统重启过多次，你想看上一次启动的日志：journalctl -b -1这个功能在排查系统启动异常时特别有用。高级功能JSON格式输出 有时候你需要程序化处理日志，可以用JSON格式：journalctl -u nginx -o json这样输出的每一行都是一个JSON对象，方便后续处理。查看磁盘使用情况 journal日志会占用磁盘空间，你可以查看当前使用情况：journalctl --disk-usage如果空间不够，可以清理旧日志：journalctl --vacuum-time=7d只保留最近7天的日志。导出日志 有时候需要把日志发给其他人分析：journalctl -u myapp --since today > app_logs.txt反向查看日志 从最新的日志开始看：journalctl -r这个在查看最近发生的问题时很有用。配置优化持久化存储 默认情况下，有些系统的journal日志是存储在内存中的，重启后就丢失了。要启用持久化存储：sudo mkdir -p /var/log/journal sudo systemd-tmpfiles --create --prefix /var/log/journal sudo systemctl restart systemd-journald限制日志大小 编辑/etc/systemd/journald.conf：SystemMaxUse=1G SystemMaxFileSize=100M这样可以避免日志占用太多磁盘空间。常见问题和解决方案日志查看权限问题 有时候普通用户看不到某些日志，需要加入systemd-journal组：sudo usermod -a -G systemd-journal username日志时间显示问题 如果时间显示不对，可能是时区设置问题：journalctl --utc使用UTC时间显示。性能问题 如果journalctl查询很慢，可能是因为日志文件太大。可以考虑：清理旧日志调整日志级别使用更精确的过滤条件一些小技巧# 查看最近的错误日志，按时间倒序 journalctl -p err -r --since "1 hour ago" # 查看某个用户的所有日志 journalctl _UID=1000 # 查看系统启动耗时 systemd-analyze blame
curl简介全称是"Client URL"，顾名思义就是一个URL客户端工具。它最大的特点就是支持的协议特别多，HTTP、HTTPS、FTP、FTPS、SCP、SFTP、LDAP等等，基本上你能想到的网络协议它都支持。curl测试API接口非常方便。比如说要测试一个REST API，用curl简直不要太方便：[root@webtest ~]# curl -X GET https://v2.jinrishici.com/token {"status":"success","data":"5w1dZp7lNh+NpR0Ws6OG6TGCqp/2UgMf"}这样就能快速看到接口返回的数据，比打开浏览器或者用Postman要快多了。curl还有个很牛的地方就是它的参数特别丰富，几乎可以模拟任何HTTP请求。想要发送POST请求？没问题：curl -X POST -H "Content-Type: application/json" -d '{"name":"张三","age":25}' https://api.example.com/users需要带认证信息？也很简单：curl -u username:password https://api.example.com/protected 或者用Bearer token： curl -H "Authorization: Bearer your_token_here" https://api.example.com/datawgetwget简介wgetwget的全称是"Web Get"，它主要是用来从网络上获取文件的。相比curl，wget更专注于下载这一件事，在下载方面它做得确实很出色。wget有个递归下载功能。有一次需要备份一个静态网站，用wget一条命令就搞定了：wget -r -np -k -L -p https://example.com/这条命令会把整个网站都下载下来，包括CSS、JS、图片等所有资源，而且还会自动调整链接，下载完直接就能在本地打开。wget还有个很实用的功能就是断点续传。下载大文件的时候网络断了不用担心，加个-c参数就能接着下载：wget -c https://example.com/bigfile.zip 这个功能在网络不稳定的时候简直是救命稻草。两者的主要区别在哪里？最大的区别就是设计理念不同。curl更像是一个瑞士军刀，什么都能干，但是每样都不是最专业的；wget就像是一个专业的下载工具，在下载这件事上做得特别精细。从使用场景来说，一般是这样选择的：需要测试API、发送复杂HTTP请求的时候用curl单纯下载文件，特别是大文件或者需要递归下载的时候用wget需要在脚本里处理HTTP响应数据的时候用curl需要镜像整个网站或者批量下载的时候用wgetcurl的高级用法说到curl的高级用法，那可真是太多了。我经常用到的几个技巧分享给大家：保存响应头信息有时候需要查看服务器返回的头信息，可以用-I参数：curl -I https://www.baidu.com或者既要响应体又要响应头：curl -i https://api.example.com/data 跟随重定向默认情况下curl不会跟随重定向，需要加-L参数：curl -L https://short.url/abc123 设置超时时间网络不好的时候设置个超时时间很有必要：curl --connect-timeout 10 --max-time 30 https://slow.server.com使用代理需要通过代理访问的时候：curl --proxy http://proxy.server:8080 https://example.com 上传文件curl还能上传文件，这个功能很多人不知道：curl -X POST -F "file=@/path/to/file.txt" https://upload.example.com保存和使用Cookie处理需要登录的网站时，Cookie管理很重要：#保存cookie curl -c cookies.txt -d "username=admin&password=123456" https://example.com/login # 使用cookie curl -b cookies.txt https://example.com/protectedwget的实用技巧wget虽然看起来简单，但是用好了也很强大。限制下载速度在服务器上下载大文件的时候，为了不影响其他服务，可以限制下载速度：wget --limit-rate=200k https://example.com/bigfile.zip后台下载下载大文件时可以放到后台运行：wget -b https://example.com/hugefile.iso下载进度会保存在wget-log文件里，可以用tail命令查看： tail -f wget-log批量下载有个URL列表文件的话，可以批量下载：wget -i urls.txturls.txt文件里每行一个URL就行。设置重试次数网络不稳定的时候可以设置重试：wget --tries=3 --waitretry=2 https://unstable.server.com/file.zip递归下载的高级选项递归下载网站的时候，有很多参数可以控制行为：wget -r -np -nd -A "*.pdf" -R "*.html" https://example.com/documents/这条命令会递归下载所有PDF文件，但是排除HTML文件，而且不创建目录结构。实际工作中的应用场景监控网站可用性写个简单的脚本监控网站是否正常：#!/bin/bash response=$(curl -s -o /dev/null -w "%{http_code}" https://mywebsite.com) if [ $response -eq 200 ]; then echo "网站正常" else echo "网站异常，状态码：$response" fi自动化部署脚本部署的时候经常需要下载最新的安装包：#!/bin/bash # 获取最新版本号 latest_version=$(curl -s https://api.github.com/repos/user/project/releases/latest | grep tag_name | cut -d '"' -f 4) # 下载最新版本 wget https://github.com/user/project/releases/download/${latest_version}/project-${latest_version}.tar.gz API接口测试 测试POST接口的时候，curl特别方便： # 测试用户注册接口 curl -X POST \ -H "Content-Type: application/json" \ -d '{ "username": "testuser", "email": "test@example.com", "password": "123456" }' \ https://api.example.com/register文件备份定期备份重要文件到远程服务器：#!/bin/bash # 打包文件 tar -czf backup-$(date +%Y%m%d).tar.gz /important/data/ # 上传到远程服务器 curl -T backup-$(date +%Y%m%d).tar.gz ftp://backup.server.com/backups/ --user username:password常见问题和解决方案用这两个工具的时候，经常会遇到一些问题，常见的几个：SSL证书问题有时候遇到自签名证书或者证书有问题的网站，可以跳过证书验证：# curl跳过证书验证 curl -k https://self-signed.example.com # wget跳过证书验证 wget --no-check-certificate https://self-signed.example.com/file.zip不过这样做有安全风险，生产环境要谨慎使用。中文文件名乱码下载中文文件名的文件时可能会乱码，可以设置编码：wget --restrict-file-names=nocontrol https://example.com/中文文件.zip大文件下载超时下载大文件时经常会超时，可以调整超时设置：# curl设置超时 curl --connect-timeout 30 --max-time 3600 -O https://example.com/bigfile.zip # wget设置超时 wget --timeout=30 --read-timeout=3600 https://example.com/bigfile.zip
资源估算很关键，既关系到成本控制，也影响业务稳定性。CPU资源估算公式和方法CPU的估算相对来说比较复杂，因为不同类型的应用对CPU的需求差别很大。我总结了一套比较实用的计算方法。基础CPU需求计算公式CPU核心数 = (并发用户数 × 单用户CPU消耗 × 安全系数) / CPU利用率目标关键参数说明并发用户数：同时在线并产生请求的用户数单用户CPU消耗：每个用户请求平均消耗的CPU时间安全系数：通常取1.5-2.0CPU利用率目标：建议控制在70%以下不同应用类型的CPU需求参考表应用类型单用户CPU消耗(ms)推荐配置(1000并发)备注静态网站5-102-4核主要是文件读取简单Web应用20-504-8核基础CRUD操作复杂业务系统100-2008-16核复杂查询和计算实时计算200-50016-32核大量数据处理图像/视频处理500-100032核以上CPU密集型任务实际计算示例假设我们有一个电商网站：预期并发用户：2000人应用类型：复杂业务系统单用户CPU消耗：150ms安全系数：1.8CPU利用率目标：70%计算过程：CPU核心数 = (2000 × 0.15 × 1.8) / 0.7 = 771 / 0.7 ≈ 11核 建议配置：12-16核CPU内存需求精确计算内存的估算相对简单一些，但也有一套科学的计算方法。内存需求计算公式总内存需求 = 系统基础内存 + 应用内存 + 连接内存 + 缓存内存 + 预留内存各组件内存需求详细表格组件类型基础占用计算公式说明操作系统1-2GB固定值Linux系统基础占用Java应用512MB-2GB堆内存 + 非堆内存JVM参数配置Node.js应用100-500MB根据代码复杂度相对轻量Python应用50-200MB根据框架和库Django/Flask差异较大Go应用10-100MB编译型语言内存占用很小MySQL128MB起InnoDB缓冲池大小建议总内存的70%Redis根据数据量数据大小 × 1.2包含持久化开销Nginx2-10MB连接数 × 2KB反向代理占用连接内存计算公式连接内存 = 最大连接数 × 单连接内存占用不同服务的单连接内存占用：HTTP连接：2-8KB数据库连接：1-4MBWebSocket连接：4-16KB实际内存计算案例以电商网站为例：并发用户：2000人技术栈：Java + MySQL + Redis数据量：用户数据50万条，商品数据10万条组件计算过程内存需求操作系统固定2GBJava应用堆内存4GB + 非堆1GB5GBHTTP连接2000 × 8KB16MBMySQL数据量约2GB，缓冲池设置8GBRedis热点数据500MB × 1.2600MB预留空间总量的20%3GB总计 约19GB建议配置：24GB或32GB内存存储空间规划计算存储的估算看起来简单，实际上坑也不少。我整理了一套比较完整的计算方法。存储需求计算公式总存储需求 = 业务数据 + 日志文件 + 备份空间 + 系统文件 + 增长预留不同数据类型的存储需求表数据类型单条记录大小增长系数备注用户基础信息1-2KB1.5包含索引开销订单记录2-5KB2.0关联数据较多商品信息5-20KB1.8包含图片路径等日志记录200-500B1.2压缩后存储图片文件100KB-2MB1.0原始大小视频文件10MB-1GB1.0原始大小日志文件存储计算日志存储需求 = 日请求量 × 单条日志大小 × 保留天数日志类型单条大小保留期压缩比访问日志300-500B30天0.3应用日志200-800B7天0.4错误日志500-2KB90天0.5数据库日志100-300B7天0.3存储计算实例电商网站存储需求计算：数据类型数量单条大小小计增长系数最终需求用户数据50万1.5KB750MB1.51.1GB商品数据10万15KB1.5GB1.82.7GB订单数据100万3KB3GB2.06GB访问日志100万/天400B400MB/天30天12GB应用日志50万/天600B300MB/天7天2.1GB图片文件20万张500KB100GB1.0100GB备份空间业务数据×3 33GB系统文件固定 20GB 20GB总计 约177GB建议配置：250GB SSD + 500GB HDD的组合网络带宽需求计算网络带宽经常被忽视，但其实很重要。带宽需求计算公式所需带宽(Mbps) = 并发用户数 × 平均页面大小(MB) × 8 × 安全系数 / 页面加载时间(秒)不同业务场景的带宽需求表业务类型平均页面大小目标加载时间安全系数单用户带宽需求企业官网2-5MB3秒1.520-42Kbps电商平台3-8MB2秒2.048-128Kbps视频网站10-50MB5秒1.829-144Kbps直播平台持续流量实时2.52-8Mbps游戏平台小数据包<100ms3.0100-500Kbps带宽计算实例电商网站带宽需求：并发用户：2000人平均页面大小：5MB目标加载时间：2秒安全系数：2.0计算过程：所需带宽 = 2000 × 5 × 8 × 2.0 / 2 = 40,000 Mbps = 40 Gbps优化建议：使用CDN减少源站压力图片压缩和懒加载静态资源缓存优化后实际需求可能只需要200-500Mbps数据库资源专项计算数据库的资源需求和应用服务器不太一样，需要单独考虑。数据库CPU计算公式数据库CPU需求 = (QPS × 平均查询时间 × CPU使用率) / 1000不同数据库的资源需求对比表数据库类型CPU效率内存需求存储IO适用场景MySQL中等中等高通用OLTPPostgreSQL高中等中等复杂查询MongoDB中等高中等文档存储Redis高高低缓存/会话Elasticsearch低高高全文搜索数据库内存分配建议表组件MySQLPostgreSQLMongoDB缓冲池70-80%25%50%连接缓存5-10%10%10%查询缓存5-10%25%20%系统预留10-20%40%20%数据库性能基准测试表配置MySQL QPSPostgreSQL QPSMongoDB QPSRedis QPS2核4GB1,000-2,000800-1,5002,000-4,00050,000-80,0004核8GB3,000-5,0002,500-4,0006,000-10,000100,000-150,0008核16GB8,000-12,0006,000-10,00015,000-25,000200,000-300,00016核32GB15,000-25,00012,000-20,00030,000-50,000400,000-600,000注：QPS数据基于标准OLTP场景，实际性能会因查询复杂度而变化容器化环境资源计算现在容器化部署越来越流行，资源计算方式也有所不同。容器资源计算公式容器总资源 = Σ(单容器资源 × 副本数 × 资源超分比)Kubernetes资源配置参考表服务类型CPU RequestCPU LimitMemory RequestMemory Limit副本数建议Web前端100m500m128Mi512Mi3-5API服务200m1000m256Mi1Gi3-10数据库1000m2000m2Gi4Gi1-3缓存服务100m500m512Mi2Gi2-3消息队列200m800m512Mi2Gi2-3容器资源超分配比例表资源类型开发环境测试环境生产环境说明CPU4:12:11.5:1超分比例内存2:11.5:11.2:1相对保守存储3:12:11:1生产不超分ROI计算公式投资回报率 = (收益增长 - 成本增长) / 成本增长 × 100%示例：通过性能优化，响应时间从3秒降到1秒，转化率提升20%，月收入增加10万，而优化成本只有2万，那么ROI就是400%监控指标和告警阈值设置监控系统一定要做好，这是运维的眼睛。我总结了一套完整的监控指标体系。核心监控指标阈值表指标类型正常范围警告阈值严重阈值监控频率CPU使用率<60%70%85%1分钟内存使用率<70%80%90%1分钟磁盘使用率<70%80%90%5分钟磁盘IO等待<10%20%40%1分钟网络带宽<60%70%85%1分钟响应时间<500ms1s3s实时错误率<0.1%1%5%实时连接数<1000根据配置根据配置1分钟应用层监控指标表指标Java应用Node.js应用Python应用Go应用堆内存使用<80%N/A<80%<80%GC频率<10次/分钟N/A<5次/分钟<1次/分钟线程数<500N/A<200<1000连接池<80%<80%<80%<80%性能测试和容量规划光有理论计算还不够，性能测试是验证估算准确性的重要手段。性能测试场景设计表测试类型并发用户数持续时间目标指标测试目的基准测试10-5010分钟建立基线了解基础性能负载测试预期并发30分钟响应时间<1s验证正常负载压力测试1.5×预期15分钟系统不崩溃找到性能瓶颈峰值测试3×预期5分钟快速恢复验证突发处理稳定性测试0.8×预期24小时无内存泄漏长期稳定性性能测试工具对比表工具适用场景并发能力学习成本报告质量JMeter通用Web测试中等中等好wrk简单HTTP测试高低一般LoadRunner企业级测试很高高很好ArtilleryNode.js友好中等低好Gatling高性能测试很高中等很好实际案例：电商平台完整资源规划下面用一个完整的案例来演示整个资源估算过程。业务需求分析某电商平台预期指标：注册用户：100万日活用户：10万峰值并发：5000人商品数量：50万日订单量：1万单图片文件：100万张详细资源计算过程1. Web服务器资源计算CPU需求：并发用户：5000人单用户CPU消耗：100ms（复杂业务）安全系数：1.8CPU利用率目标：70%CPU核心数 = (5000 × 0.1 × 1.8) / 0.7 = 1286核 考虑到单机限制，建议配置：8台 × 16核 = 128核内存需求：组件计算需求系统基础8台 × 2GB16GBJava应用8台 × 8GB64GB连接内存5000 × 8KB40MB预留20%16GB总计 96GB2. 数据库服务器资源计算预估QPS：查询QPS：2000写入QPS：500总QPS：2500根据性能基准表，需要8核16GB配置，考虑到安全系数，建议配置：16核32GB3. 缓存服务器资源计算Redis内存需求：用户会话：10万 × 2KB = 200MB商品缓存：5万 × 10KB = 500MB查询缓存：预估1GB总计：1.7GB × 1.5 = 2.6GB建议配置：4核8GB4. 存储需求计算数据类型计算过程存储需求用户数据100万 × 2KB × 1.53GB商品数据50万 × 20KB × 1.818GB订单数据365万 × 5KB × 2.036GB图片文件100万 × 800KB800GB日志文件计算得出50GB备份空间业务数据 × 3171GB总计 1078GB5. 带宽需求计算使用CDN优化后：动态内容：5000用户 × 100KB × 8 / 2秒 = 2Gbps考虑安全系数：2Gbps × 1.5 = 3Gbps实际配置：500Mbps（CDN分担大部分流量）最终配置方案服务器类型配置数量月成本Web服务器16核32GB8台10.8万数据库服务器16核32GB SSD2台3.2万缓存服务器4核8GB2台0.8万负载均衡标准配置2台0.4万CDN服务500GB流量-0.5万总计 15.7万/月动态扩容策略静态配置往往无法应对业务的快速变化，动态扩容策略很重要。自动扩容触发条件表指标扩容阈值缩容阈值冷却时间扩容步长CPU使用率>70%<30%5分钟+1台内存使用率>80%<40%5分钟+1台响应时间>1秒<300ms3分钟+2台队列长度>100<102分钟+1台错误率>1%<0.1%10分钟+2台扩容成本效益分析扩容方式响应时间成本增加适用场景垂直扩容5-10分钟50-100%短期突发水平扩容2-5分钟20-50%持续增长预热扩容即时10-30%可预期峰值写在最后服务器资源估算确实是个技术活，需要综合考虑业务需求、技术架构、成本预算等多个因素。通过这些公式和表格，可以更科学地进行资源规划：核心要点回顾CPU估算：基于并发用户数和单用户消耗计算内存估算：分组件计算，预留20%安全空间存储估算：考虑数据增长和备份需求带宽估算：结合CDN优化，避免过度配置成本控制：对比不同方案，选择最优性价比实用建议基于实际业务需求估算，不要拍脑袋决定预留适当的扩容空间，但不要过度设计重视监控和性能测试，数据说话根据实际运行情况及时调整优化考虑动态扩容，应对业务变化最重要的是，要有持续优化的意识。系统上线只是开始，后续的监控、调优、扩容才是重头戏。技术在发展，业务在变化，资源配置也要跟着调整。没有完美的架构，只有合适的架构。资源估算也是一样，关键是要找到性能、成本、可靠性之间的平衡点。
执行free -h命令时，通常会看到这样的输出其中：total是总内存，这个最直观used包括了应用程序和缓存使用的内存free是完全空闲的内存，通常很小buff/cache是可以释放的缓存内存available是真正可用的内存，这个最重要shared是共享内存，通常不用太关注total：系统总内存total就是系统的总物理内存大小，比如8G内存条，这里显示的就是8G（会扣掉一些被内核占用的部分）。used：已使用内存used包括了：应用程序实际使用的内存内核使用的内存缓冲区和缓存使用的内存有时看到used很高，不代表应用程序真的用了那么多内存。很可能是Linux把大量内存用作了文件缓存。具体查看内存使用情况/proc/meminfo看详细分解cat /proc/meminfo | grep -E "(MemTotal|MemFree|MemAvailable|Buffers|Cached|SReclaimable)"Buffers就是缓冲区使用的内存Cached就是页面缓存使用的内存SReclaimable是可回收的内核数据结构把这几个加起来，基本就是free命令里buff/cache那一列的值。如果Cached特别大，说明系统缓存了很多文件；如果Buffers很大，可能是有大量的磁盘IO操作。ps命令查看进程内存使用# 按内存使用量排序显示进程 ps aux --sort=-%mem | head -10 # 或者用这个更直观的格式 ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -10 # 某个应用的总内存使用,比如统计所有java进程的内存使用 ps aux | grep java | awk '{sum+=\$6} END {print "Total memory: " sum/1024 " MB"}'free：真正空闲的内存free显示的是完全没有被使用的内存。注意，这里不包括被用作缓冲区和缓存的内存，因为这些内存在需要的时候是可以立即释放给应用程序使用的。如果经常看到free的值很小，这是正常现象。Linux的设计哲学就是"空闲的内存是浪费的内存"，系统会尽可能地把空闲内存用作文件缓存，提高系统性能。shared：共享内存shared显示的是被多个进程共享的内存大小。这部分内存主要包括：共享内存段（System V shared memory）tmpfs文件系统使用的内存一些其他的共享内存区域在日常运维中，一般特别关注这个数值。除非某个应用大量使用了共享内存，否则这个值通常不会很大。比如一些使用Redis的系统，如果Redis配置了大量的共享内存，这个值会比较高。但大多数情况下，这个数字都不是重点关注对象。buff/cache：缓冲区和缓存这个是Linux内存管理的精髓所在。buff/cache包括：缓冲区（buffers）：用于缓存磁盘块设备的数据页面缓存（page cache）：用于缓存文件内容Linux会把空闲内存用作文件缓存，这样当程序再次读取相同文件时，就可以直接从内存中获取，而不需要再次访问磁盘。这大大提高了系统的IO性能。关键是，这部分内存在应用程序需要时可以立即释放。所以虽然它们被标记为"已使用"，但实际上是可用的。buff/cache的调整和优化手动清理缓存（谨慎使用）注意：生产环境别随便清理，会影响性能。# 清理页面缓存 echo 1 > /proc/sys/vm/drop_caches # 清理所有缓存 sync && echo 3 > /proc/sys/vm/drop_caches调整缓存策略控制swap使用倾向# 查看当前值 cat /proc/sys/vm/swappiness # 调整为10（让系统优先回收缓存而不是使用swap） echo "vm.swappiness = 10" >> /etc/sysctl.conf控制缓存回收压力# 调整目录和inode缓存回收 echo "vm.vfs_cache_pressure = 50" >> /etc/sysctl.conf不同场景的优化建议数据库服务器vm.swappiness = 1 vm.vfs_cache_pressure = 150文件服务器vm.swappiness = 10 vm.vfs_cache_pressure = 50调整完要用sysctl -p生效，然后观察系统表现。大多数情况下默认设置就够用了，没事别瞎调。available：真正可用的内存这个是最重要的指标！available显示的是应用程序可以使用的内存总量，包括：free的内存可以立即释放的buff/cache内存一些其他可回收的内存简单来说，available = free + 可回收的buff/cache这个数值才是真正需要关注的。只有当available很低的时候，才说明系统内存真的不够用了。判断系统内存是否充足，主要就看这个available值。只要它保持在一个合理的水平，就不用担心内存问题。
公网测试工具：speedtest-cli安装# CentOS/RHEL系列 yum install epel-release yum install python-pip pip install speedtest-cli # Ubuntu/Debian系列 apt update # 安装 pipx sudo apt install pipx pipx ensurepath # 安装应用 pipx install speedtest-cli运行speedtest-cli使用该命令会自动选择服务器进行测速。不过有时候自动选择的服务器不太理想，你可以手动指定。先看看附近有哪些服务器：speedtest-cli --list | grep -i China [root@node1 ~]# speedtest-cli --list | grep -i China 71313) 中国电信 (Xuzhou, China) [1301.96 km] 16204) JSQY - Suzhou (Suzhou, China) [1576.10 km] 选一个延迟比较低的：speedtest-cli --server 71313iperf3：内网测试工具speedtest-cli虽然方便，但有个问题就是测试的是到公网的速度。如果想测试内网带宽，或者两台服务器之间的带宽，那就得用iperf3了。安装iperf3# CentOS/RHEL yum install iperf3 # Ubuntu/Debian apt install iperf3测试iperf3需要一台服务器做服务端，一台做客户端。在服务端运行：iperf3 -s在客户端运行： iperf3 -c 192.168.99.100客户端结果服务端结果默认测试10秒钟，也可以指定时间：iperf3 -c 服务端IP -t 30测试UDP带宽：iperf3 -c 192.168.99.100 -u -t 15客户端结果服务端结果仔细观察上面的测试结果可以看到，测试udp的速度时网速反而比tcp的要慢很多，而正常情况是udp速度要比tcp的块。出现这种状况的原因是iperf3 中 UDP ​默认带宽只有1Mbps，而TCP会自动尝试使用所有可用带宽。解决这一现象的方案是测UDP时手动设置UDP带宽。iperf3 -u -b 1G -l 1400 -c 192.168.99.100客户端服务端wget/curl - 简单实用的下载测试如果想快速测一下下载速度，不想装额外的工具，那wget和curl就够用了。下载一个100MB的文件到/dev/null（相当于丢弃），然后显示下载速度。 wget :wget -O /dev/null http://speedtest.tele2.net/100MB.zipcurlcurl -o /dev/null http://speedtest.tele2.net/100MB.zip #查看更详细的信息 curl -o /dev/null -w "下载速度: %{speed_download} bytes/sec\n总时间: %{time_total}s\n" http://speedtest.tele2.net/100MB.zip 这种方法的好处是可以测试到特定服务器的速度，比如CDN节点或者合作伙伴的服务器。nload - 实时监控网络流量安装nload# CentOS/RHEL yum install nload # Ubuntu/Debian apt install nload运行nload它会显示一个实时的图表，显示当前的上传和下载速度。如果你有多个网卡，可以用左右箭头键切换。iftop - 看看谁在占用带宽iftop比nload更进一步，它不仅能显示总的流量，还能显示每个连接的流量情况。安装CentOS/RHEL yum install iftop # Ubuntu/Debian apt install iftop运行（需要root权限）iftopiftop的界面有点像top命令，显示当前所有网络连接的流量情况。可以看到每个IP地址的上传下载速度，这对于排查网络问题特别有用。nethogs - 进程级别的网络监控安装# CentOS/RHEL yum install nethogs # Ubuntu/Debian apt install nethogs运行（需要root权限）nethogsnethogs会显示每个进程的网络使用情况，包括进程名、PID、用户等信息。这对于排查哪个应用程序占用带宽特别有用。实用的测试技巧选择合适的测试时间网络带宽测试最好在不同时间段多测几次，因为网络状况会随时间变化。我一般会在早上、中午、晚上各测一次，这样能得到比较全面的数据。注意测试方向很多人只测下载速度，忽略了上传速度。但对于服务器来说，上传速度同样重要，特别是如果你的服务器需要向用户推送大量数据的话。考虑并发连接单线程测试得到的带宽可能不能反映真实情况。可以试试多线程测试：iperf3 -c 服务端IP -P 4这个命令会启动4个并行连接进行测试。记录测试结果把测试结果记录下来，建立一个基线。这样以后出现问题的时候，你就能快速判断是不是网络带宽的问题了。如果测试结果不理想，可以按这个顺序排查：先确认是不是测试方法的问题，换个工具再测一次检查服务器的网卡配置，看看是不是限速了联系网络管理员或者运营商，确认线路状况检查防火墙和安全组设置，看看是不是有限制
500错误其实就是服务器内部错误，说白了就是服务器遇到了意外情况，不知道怎么处理了。但是这个"意外情况"可能的原因太多了，从代码bug到服务器资源不足，从数据库连接问题到配置文件错误，每一个都可能是罪魁祸首。500错误虽然让人头疼，但是只要有系统的排查思路，大部分问题都能快速定位和解决。一般的排查步骤是：快速定位影响范围分析各种日志检查系统资源根据应用类型进行专项排查检查数据库连接排查配置和环境问题检查网络和依赖服务不同技术栈的应用有不同的排查重点，Java应用重点关注JVM内存和GC，PHP应用重点关注进程和权限，Python应用重点关注模块导入和WSGI服务器，Go应用重点关注goroutine泄漏，Node.js应用重点关注事件循环阻塞。排查问题的时候要保持冷静，按照步骤一步步来。不要一上来就乱改配置，那样可能会让问题变得更复杂。最重要的是，要从每次故障中学习，不断完善监控和预防措施。第一步：快速定位问题范围遇到500错误，首先搞清楚影响范围。这个很重要，因为它决定了你处理问题的优先级和方式。是所有页面都500还是只有特定页面（可以通过浏览器f12查看报错接口）是所有用户都受影响还是部分用户错误是突然出现的还是逐渐增多的案例：某个业务网站突然开始报500错误。先测试几个不同的页面，发现只有特定页有问题，首页和其他功能页面都正常。这就大大缩小了排查范围，基本可以确定是相关的功能出了问题。如果使用了负载均衡，还要检查一下是不是某台服务器的问题。一般可用直接访问每台服务器的IP，看看是不是所有服务器都有问题。有时候可能只是其中一台服务器出了状况。第二步：深入日志分析确定了影响范围之后，就该看日志了。日志是我们排查问题最重要的线索，但是看日志也有技巧。Web服务器日志先看Web服务器的错误日志，比如Nginx的error.log或者Apache的error_log。这里通常能看到最直接的错误信息。tail -f /var/log/nginx/error.log经常遇到的错误类型有：连接超时：upstream timed out连接被拒绝：connect() failed (111: Connection refused)文件权限问题：Permission denied配置语法错误：nginx configuration test failed案例：Nginx日志显示"upstream timed out"，但是应用服务器看起来运行正常。后来发现是因为某个接口的处理时间突然变长了，超过了Nginx设置的超时时间。调整了一下proxy_read_timeout就解决了。第三步：系统资源检查有时候500错误不是代码问题，而是服务器资源不够用了。这种情况下，即使代码没问题，服务器也处理不了请求。内存使用情况free -h如果可用内存很少，或者swap使用率很高，那很可能就是内存不足导致的问题。特别是在流量突然增大的时候,因为内存不足导致500错误发生的几率会高很多。还可以用top或者htop看看哪个进程占用内存最多：top -o %MEMCPU使用率topCPU使用率持续100%也会导致服务器响应缓慢或者直接返回500错误。有些服务器因为某个进程死循环，CPU占用率一直是100%，导致整个网站都访问不了。磁盘空间df -h磁盘空间不足也是一个常见原因，特别是日志文件增长太快的时候。比如因为某个日志文件疯狂增长，把磁盘空间占满了，导致应用无法写入临时文件而报500错误。不同应用类型的专项排查不同技术栈的应用出现500错误时，排查重点还是有些区别的。Java应用排查Java应用的500错误排查，一般从这几个方面入手：JVM内存问题 Java应用最容易出现的就是内存问题，特别是OutOfMemoryError。jstat -gc <pid> jmap -histo <pid>某次一个Spring Boot应用突然开始频繁500，通过jstat发现老年代内存使用率一直在99%以上，明显是内存泄漏了。后来用MAT分析heap dump，发现是某个缓存没有设置过期时间，导致对象越积累越多。线程池状态jstack <pid>线程池满了也会导致请求无法处理。有些应用因为某个接口响应特别慢，把线程池都占满了，新的请求进来就直接500了。GC问题jstat -gc <pid> 1s如果Full GC频繁或者GC时间过长，也会影响应用响应。如果应用每隔几分钟就会卡顿几秒钟，用户访问就会超时报500，原因就是Full GC时间太长了。应用日志 Java应用的日志通常在logs目录下，或者通过logback、log4j配置的路径：tail -f /app/logs/application.log grep "ERROR" /app/logs/application.log | tail -20常见的错误类型：数据库连接池耗尽空指针异常类加载失败配置文件读取失败PHP应用排查PHP应用的排查相对简单一些，但也有自己的特点。PHP-FPM进程状态systemctl status php-fpm ps aux | grep php-fpmPHP-FPM进程数不够或者进程死掉了，都会导致500错误。有时是因为php-fpm配置的max_children太小，高并发时进程不够用的情况。PHP错误日志tail -f /var/log/php/error.logPHP的错误日志通常能直接告诉你问题所在：Fatal error: 致命错误，比如内存不足、语法错误Parse error: 语法解析错误Warning: 警告，可能导致功能异常内存限制PHP有memory_limit限制，如果脚本占用内存超过这个值就会报Fatal error：php -i | grep memory_limit有些数据导入脚本，处理大文件时内存不够用，直接就500了。文件权限 PHP应用对文件权限比较敏感，特别是上传目录、缓存目录等：ls -la /var/www/html/Python应用排查Python应用的排查重点又不太一样。WSGI服务器状态 如果用的是Gunicorn或者uWSGI：ps aux | grep gunicorn systemctl status gunicornPython进程内存 Python应用也容易出现内存泄漏，特别是使用了某些C扩展的时候：ps -o pid,ppid,cmd,%mem,%cpu --sort=-%mem | headDjango/Flask应用日志tail -f /var/log/django/error.log tail -f /var/log/flask/app.logPython应用常见的500错误：模块导入失败数据库连接问题模板渲染错误第三方库版本冲突案例：服务器上同时跑着Python 2和Python 3的应用，结果某次系统更新后，Python 2的一些依赖包出问题了，导致应用启动失败。Go应用排查Go应用相对来说比较稳定，但也有自己的问题。Goroutine泄漏curl http://localhost:6060/debug/pprof/goroutine?debug=1如果开启了pprof，可以通过这个接口查看goroutine数量。goroutine泄漏会导致内存占用越来越高。应用日志 Go应用的日志格式比较自由，通常在应用目录或者系统日志里：journalctl -u your-go-app -f tail -f /var/log/your-app.logpanic恢复 Go应用如果没有正确处理panic，就会导致整个程序崩溃：defer func() { if r := recover(); r != nil { log.Printf("Recovered from panic: %v", r) } }()Node.js应用排查Node.js应用的排查也有自己的特点。进程管理器状态 如果用的是PM2：pm2 status pm2 logs内存泄漏检查 Node.js应用容易出现内存泄漏，特别是事件监听器没有正确移除的时候：node --inspect your-app.js然后用Chrome DevTools连接进行内存分析。事件循环阻塞const blocked = require('blocked-at'); blocked((time, stack) => { console.log(`Blocked for ${time}ms, operation started here:`, stack); });数据库连接问题排查数据库问题是导致500错误的一个大头。我遇到的数据库相关的500错误主要有几种：连接数耗尽SHOW PROCESSLIST; SHOW STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';如果连接数接近max_connections的值，就说明数据库连接池满了。这时候新的请求就会因为无法获取数据库连接而报500错误。一次双11活动，流量突然暴增，数据库连接数瞬间就满了。当时紧急调整了max_connections的值，同时优化了应用的连接池配置，才解决了问题。慢查询SHOW PROCESSLIST;如果看到很多查询处于"Sending data"或者"Copying to tmp table"状态，说明有慢查询在拖累整个数据库性能。可以开启慢查询日志来定位具体是哪些SQL语句有问题：SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2;锁等待SHOW ENGINE INNODB STATUS;这个命令可以看到InnoDB的详细状态，包括是否有死锁或者锁等待的情况。配置文件和环境问题配置文件的问题也经常导致500错误，而且这种问题通常比较隐蔽。Web服务器配置 检查Nginx或Apache的配置文件语法：nginx -t apache2ctl configtest我见过有人修改配置文件后忘记检查语法，重启服务后直接就500了。还有一种情况是配置文件的路径写错了，或者权限设置不对。应用配置 应用程序的配置文件也要检查，比如数据库连接配置、缓存配置等。有时候可能是配置文件被意外修改了，或者环境变量没有正确设置。一次很坑的情况：开发同事在测试环境修改了数据库配置，结果不小心把生产环境的配置也改了，导致应用连不上数据库，全站500。环境变量 很多现代应用都依赖环境变量来配置：env | grep APP_ printenv特别是容器化部署的应用，环境变量配置错误是常见的500错误原因。网络和依赖服务问题 有时候500错误不是应用本身的问题，而是依赖的外部服务出了问题。第三方API 现在的应用很少是完全独立的，通常都会调用各种第三方API。如果这些API出问题了，也可能导致应用报500错误。我建议在调用第三方API的时候一定要做好异常处理和超时设置：import requests from requests.exceptions import RequestException, Timeout try: response = requests.get(api_url, timeout=5) response.raise_for_status() except Timeout: # 处理超时，返回默认值或降级处理 return default_response except RequestException as e: # 处理其他请求异常 logger.error(f"API调用失败: {e}") return error_response内部服务依赖 如果是微服务架构，要检查各个服务之间的调用是否正常：curl -I http://internal-service:8080/health telnet internal-service 8080案例：用户服务突然开始报500，排查了半天发现是依赖的订单服务挂了。这种情况下，最好是有熔断机制，避免级联故障。DNS解析 有时候DNS解析出问题也会导致服务调用失败：nslookup your-service-domain dig your-service-domain比如内部DNS服务器不稳定，偶尔会解析失败，导致应用无法连接到数据库或者其他服务。实战案例分享案例一：Java应用内存泄漏有一次一个Spring Boot应用开始间歇性500错误，刚开始以为是偶发问题，但是随着时间推移，错误频率越来越高。排查过程是这样的：检查了应用日志，发现有OutOfMemoryError用jstat查看GC情况，发现老年代内存使用率持续上升生成heap dump进行分析，发现某个Map对象占用了大量内存代码review发现是缓存没有设置过期策略最后给缓存添加了LRU策略和过期时间，问题就解决了。这个案例告诉我们，缓存虽然能提高性能，但是一定要合理设置过期策略。案例二：PHP-FPM进程不足这是一个WordPress网站，在某次营销活动后开始频繁500错误。排查步骤：检查Nginx日志，发现大量"upstream timed out"查看PHP-FPM状态，发现进程数已经达到上限检查PHP-FPM配置，max_children设置得太小了调整配置后重启服务，问题解决这个案例说明容量规划很重要，要根据实际业务量来调整配置。案例三：Python应用模块导入失败某次一个Django应用突然开始500，但是重启后又正常了，过一段时间又开始500。最后发现是某个Python包的版本有问题，在特定条件下会导入失败。这种间歇性的问题最难排查，需要仔细分析日志中的错误模式。案例四：Go应用goroutine泄漏这是一个Go写的API服务，运行一段时间后开始出现500错误。通过pprof发现goroutine数量异常增多，最后定位到某个HTTP客户端没有正确设置超时，导致goroutine一直阻塞。案例五：Node.js事件循环阻塞一个Node.js应用，用户反馈页面加载很慢，有时候会500。用blocked模块检测发现事件循环被阻塞，原因是某个同步文件操作阻塞了事件循环。改为异步操作后问题解决。工具推荐最后推荐一些常用的排查工具：系统监控htop: 更好用的topiotop: 磁盘IO监控nethogs: 网络流量监控dstat: 综合系统监控日志分析ELK Stack: Elasticsearch + Logstash + KibanaFluentd: 日志收集Loki: 轻量级日志系统应用监控Prometheus: 指标收集Grafana: 可视化Jaeger: 分布式追踪APM工具: New Relic、DataDog、Skywalking数据库监控pt-query-digest: MySQL慢查询分析pgbadger: PostgreSQL日志分析Redis监控: redis-cli --latency工具只是辅助，关键还是要有正确的排查思路。
进程假死其实就是进程还在，但是不干活了。用ps命令看，进程确实存在，但就是不处理请求。PHP-FPM作为FastCGI进程管理器，负责管理PHP进程池。当它出现假死时，表现就是：进程存在但不响应新请求CPU使用率可能很低或者异常高内存占用可能持续增长日志可能停止更新或者出现异常快速定位和解决进程假死问题,关键是要：建立完善的监控体系，及时发现问题熟练掌握各种排查工具的使用针对常见场景做好预防措施特别要重视磁盘IO问题，这个经常被忽略但影响很大保持冷静，按照既定流程逐步排查磁盘IO问题特别值得重视，因为它往往比较隐蔽，不像CPU或内存问题那么明显。很多时候系统看起来资源充足，但就是响应慢，这时候就要想到是不是磁盘IO的问题了。快速判断是否为进程假死看进程状态ps aux | grep php-fpm正常情况下的输出如下：如果看到进程状态是D（不可中断睡眠）或者Z（僵尸进程），那基本就是有问题了。STAT: 进程状态码S: 睡眠状态s: 会话领导者l: 多线程+: 前台进程组R: 运行中D 状态的进程通常是在等待 I/O 操作完成，如磁盘读写Z 状态 (僵尸进程)，僵尸进程是已经终止但父进程尚未调用 wait() 获取其退出状态的进程检查进程响应# 查看PHP-FPM状态页面（需要先配置） curl http://localhost/status # 或者直接测试PHP页面响应 curl -w "@curl-format.txt" -o /dev/null -s "http://your-site.com/test.php"如果curl一直卡住不返回，或者返回时间特别长，那就很可能是假死了。观察系统资源# 查看CPU使用情况 top -p `pgrep php-fpm | tr '\n' ',' | sed 's/,$//'` # 查看内存使用 free -h # 查看磁盘IO iostat -x 1深入分析假死原因strace可以实时查看进程在做什么系统调用：# 找到问题进程PID ps aux | grep php-fpm | grep -v master # 追踪系统调用 strace -p 进程PID -f -e trace=all查看进程调用栈如果strace信息太多看不过来，可以用gdb查看调用栈gdb -p 进程PID (gdb) bt (gdb) info threads (gdb) thread apply all bt分析PHP-FPM慢日志PHP-FPM有个很有用的功能就是慢日志，可以记录执行时间超过阈值的请求：在php-fpm.conf中配置 slowlog = /var/log/php-fpm/slow.log request_slowlog_timeout = 5s慢日志会记录详细的调用栈，比如： [26-Oct-2024 15:30:45] [pool www] pid 12345 script_filename = /var/www/html/index.php [0x00007f8b8c0c8000] curl_exec() /var/www/html/api.php:45 [0x00007f8b8c0c8100] api_call() /var/www/html/index.php:23 通过慢日志能很快定位到是哪个函数卡住了。常见的假死场景和解决方案数据库连接问题这个真的太常见了。数据库连接池满了，或者网络抖动，都可能导致PHP进程卡在数据库操作上。解决方案：设置合理的数据库连接超时时间使用连接池，避免频繁建立连接监控数据库连接数设置MySQL连接超时 $pdo = new PDO($dsn, $user, $pass, [ PDO::ATTR_TIMEOUT => 5, PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION wait_timeout=30"外部API调用超时调用第三方API时没设置超时，对方服务挂了你也跟着挂。我见过太多这种情况了，一个支付接口的问题导致整个网站瘫痪。#使用curl时一定要设置超时 $ch = curl_init(); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);文件锁竞争多个进程同时操作同一个文件，可能导致死锁：#使用flock时要注意超时 $fp = fopen('data.txt', 'w'); if (flock($fp, LOCK_EX | LOCK_NB)) { // 获得锁，执行操作 fwrite($fp, $data); flock($fp, LOCK_UN); } else { // 获取锁失败，记录日志或者返回错误 error_log('Failed to acquire file lock'); } fclose($fp);磁盘IO问题导致的假死这个问题特别隐蔽，经常被忽略。磁盘IO性能差或者磁盘故障，会导致进程卡在文件读写操作上。#快速检测磁盘IO问题 # 查看磁盘IO使用率 iostat -x 1 5重点关注这几个指标：%util - 磁盘使用率，接近100%说明磁盘很忙await - 平均等待时间，超过20ms就要注意了svctm - 平均服务时间案例：服务器磁盘的%util一直在99%以上，但是通过top看CPU使用率很低。后来发现是磁盘坏道导致的，读写特别慢。找出占用IO的进程 # 安装iotop工具 apt install iotop -y # 实时查看IO使用情况 iotop -o -d 1 # 或者使用pidstat pidstat -d 1iotop的输出类似这样：Total DISK READ : 0.00 B/s | Total DISK WRITE : 12.34 M/s Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 15.67 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 1234 be/4 www 0.00 B/s 10.23 M/s 0.00 % 85.67 % php-fpm: pool www如果看到某个PHP-FPM进程的IO使用率特别高，那就要重点关注了。分析具体的文件操作# 使用lsof查看进程打开的文件 lsof -p 进程PID # 或者查看进程的文件描述符 ls -la /proc/进程PID/fd/案例：PHP程序在写日志时没有正确关闭文件句柄，导致同一个日志文件被打开了几千次，磁盘IO直接爆炸。磁盘空间不足的问题# 检查磁盘使用情况 df -h # 查找大文件 find /var/log -type f -size +100M -exec ls -lh {} \; # 查看目录大小 du -sh /var/log/*磁盘空间不足时，写操作会变得特别慢，甚至失败。PHP-FPM进程可能会卡在日志写入或者临时文件创建上。内存泄漏导致的假死PHP进程内存使用过多，触发系统的OOM机制，进程就卡住了。可以通过以下方式监控：# 查看进程内存使用 cat /proc/进程PID/status | grep VmRSS # 或者用ps ps -o pid,vsz,rss,comm -p 进程PID应急处理方案重启PHP-FPM服务# CentOS/RHEL systemctl restart php-fpm # Ubuntu/Debian systemctl restart php7.4-fpm # 或者直接kill掉重启 pkill php-fpm /usr/sbin/php-fpm -D不过重启会中断正在处理的请求，生产环境要慎重。平滑重启PHP-FPM支持平滑重启，不会中断现有连接：# 发送USR2信号进行平滑重启 kill -USR2 `cat /var/run/php-fpm.pid` # 或者使用systemctl systemctl reload php-fpm预防措施监控日志记录开启详细的日志记录，方便问题排查：php-fpm.conf log_level = notice access.log = /var/log/php-fpm/access.log access.format = "%R - %u %t \"%m %r\" %s %f %{mili}d %{kilo}M %C%%"定期重启一些老项目可能存在内存泄漏问题，可以设置定期重启# 添加到crontab，每天凌晨3点重启 0 3 * * * /usr/bin/systemctl reload php-fpm注意事项不要随便kill -9很多人遇到进程假死第一反应就是kill -9，但这样可能会导致数据不一致。最好先尝试kill -TERM让进程优雅退出。注意PHP-FPM版本差异不同版本的PHP-FPM配置参数可能不一样，升级时要注意兼容性。我就遇到过从PHP 7.2升级到7.4后，原来的配置不生效的情况。监控指标要合理设置监控阈值时不要太敏感，否则会产生很多误报。我之前设置响应时间超过1秒就告警，结果每天收到几十条告警消息，后来调整到5秒才比较合理。磁盘IO监控容易被忽略很多人只关注CPU和内存，忽略了磁盘IO。其实磁盘IO问题导致的服务假死非常常见，特别是那些有大量文件操作的应用。建议在监控系统中加入这些磁盘相关的指标：磁盘使用率（%util）平均等待时间（await）磁盘空间使用率inode使用率日志轮转PHP-FPM的日志文件会越来越大，一定要配置logrotate进行日志轮转，否则磁盘满了又是另一个问题。# /etc/logrotate.d/php-fpm /var/log/php-fpm/*.log { daily missingok rotate 7 compress delaycompress notifempty postrotate /bin/kill -USR1 `cat /var/run/php-fpm.pid 2>/dev/null` 2>/dev/null || true endscript }临时文件清理PHP会在/tmp目录下创建临时文件，如果程序异常退出，这些临时文件可能不会被清理。时间长了会占用大量磁盘空间和inode。# 定期清理PHP临时文件 find /tmp -name "php*" -type f -mtime +1 -delete # 清理session文件 find /var/lib/php/session -name "sess_*" -type f -mtime +1 -delete可以把这些命令加到crontab里定期执行。高级排查技巧使用perf分析性能对于复杂的性能问题，可以使用perf工具进行深入分析：# 安装perf工具 yum install perf -y # 对指定进程进行采样 perf record -p 进程PID -g -- sleep 30 # 查看报告 perf reportperf可以告诉你进程把时间都花在哪里了，对于定位性能瓶颈很有帮助。使用systemtap进行动态追踪systemtap是个更强大的工具，可以动态插入探针：# 监控文件IO操作 stap -e 'probe syscall.read, syscall.write { if (pid() == target()) printf("%s: %s\n", name, argstr) }' -x 进程PID不过systemtap比较复杂，一般情况下用strace就够了。分析core dump文件如果进程崩溃了，可以通过core dump文件分析崩溃原因：# 启用core dump ulimit -c unlimited echo '/tmp/core.%e.%p' > /proc/sys/kernel/core_pattern # 使用gdb分析core文件 gdb /usr/sbin/php-fpm /tmp/core.php-fpm.12345 (gdb) bt (gdb) info registers
在Linux系统中，网络连接是文件，设备是文件，管道也是文件，一切皆文件。而lsof的全称是"list open files"，即列出打开的文件。因此lsof就像是系统的"透视镜"，能让你看到系统内部正在发生什么。哪个进程打开了哪些文件，哪个端口被哪个程序占用，哪些文件被删除了但还在被进程使用着，这些信息lsof都能告诉你。基础用法最简单的用法就是直接输入lsof，不过这样会输出所有打开的文件，信息量太大了，一般不会这么用。输出的每一行代表一个打开的文件，包含了这些信息：COMMAND：进程名称PID：进程IDUSER：用户名FD：文件描述符TYPE：文件类型DEVICE：设备号SIZE/OFF：文件大小或偏移量NODE：inode号NAME：文件名或网络连接信息网络相关用法查看端口占用情况# 查看80端口被哪个进程占用 lsof -i:80 # 查看所有TCP连接 lsof -i tcp # 查看所有UDP连接 lsof -i udp # 查看指定IP和端口的连接 lsof -i@192.168.1.100:22查看网络连接状态# 查看所有网络连接 lsof -i # 查看指定状态的连接 lsof -i -sTCP:LISTEN # 查看监听状态的TCP连接 lsof -i -sTCP:ESTABLISHED # 查看已建立的TCP连接 #这个在排查网络问题的时候特别有用。比如怀疑某个服务连接数过多，就可以用这个命令来确认。进程相关的用法查看进程打开的文件 # 查看指定PID打开的文件 lsof -p 1234 # 查看指定进程名打开的文件 lsof -c nginx # 查看指定用户打开的文件 lsof -u www-data查看文件被哪些进程使用# 查看指定文件被哪些进程打开 lsof /var/log/nginx/access.log # 查看指定目录下的文件被哪些进程使用 lsof +D /var/log/文件系统相关找出被删除但未释放的文件 经常遇到这种情况：明明删除了大文件，但是df显示磁盘空间没有释放。这通常是因为文件被删除了，但还有进程在使用这个文件。# 查找被删除但未释放的文件 lsof | grep deleted # 或者更精确的查找 lsof +L1查看挂载点使用情况# 查看指定挂载点被哪些进程使用 lsof /mnt/data # 查看所有挂载点的使用情况 lsof -f -- /dev/sda1案例分享排查文件句柄泄漏 某个Python应用运行一段时间后就会报"Too many open files"的错误。怀疑是文件句柄泄漏。# 先找到进程PID ps aux | grep python_app # 查看进程打开的文件数量 lsof -p 12345 | wc -l # 查看具体打开了哪些文件 lsof -p 12345发现进程打开了大量的临时文件，而且数量一直在增长。最后定位到是代码里创建临时文件后没有正确清理。磁盘空间异常问题 服务器磁盘使用率突然飙升到95%，但是找不到大文件。后来用lsof发现有个日志轮转脚本有问题。排查发现有个进程打开了一个几GB的文件，但是这个文件在文件系统里找不到，原来是被删除了但进程还在写入。# 查找大文件 lsof | awk '$7 ~ /^[0-9]+$/ && $7 > 1000000 {print $2, $7, $9}' | sort -k2 -nr高级用法和技巧组合条件查询 lsof支持多种条件的组合，默认是OR关系，可以用-a参数改为AND关系。# 查看用户www-data打开的网络连接（OR关系） lsof -u www-data -i # 查看用户www-data打开的网络连接（AND关系） lsof -a -u www-data -i输出格式控制# 不显示主机名，直接显示IP lsof -n -i # 不显示端口名，直接显示端口号 lsof -P -i # 组合使用 lsof -nP -i:80这个在脚本里特别有用，因为解析主机名和端口名会比较慢。持续监控# 每2秒刷新一次 lsof -r 2 -i:80 # 监控到没有输出就退出 lsof +r 1 -i:80这个功能在调试网络连接问题的时候很有用，可以实时看到连接的变化。性能优化lsof虽然强大，但是在大型系统上运行可能会比较慢，特别是不加任何参数的时候。有几个优化技巧：尽量使用具体的参数，避免全量扫描使用-n和-P参数避免DNS和端口名解析在脚本中使用时，考虑缓存结果# 这样比较快 lsof -nP -i:80 # 这样会很慢 lsof | grep :80常见问题和注意事项使用lsof的时候有几个坑需要注意：权限问题：有些信息需要root权限才能看到系统负载：在高负载系统上运行lsof可能会影响性能输出解读：要理解各个字段的含义，特别是FD字段FD字段的含义比较复杂：cwd：当前工作目录txt：程序代码mem：内存映射文件数字：文件描述符号r、w、u：读、写、读写模式lsof的输出信息比较敏感，包含了很多系统内部的信息。在分享排查过程或者截图的时候，记得做好脱敏处理，避免泄露重要的系统信息。
当服务出现故障时，比如服务不可达，无法远程访问，应用程序报错等故障时，常用的排查思路整理如下。确定故障和检查硬件当发现服务器出现故障时，应详细记录故障发生的具体情况。包括：故障发生时间，故障发生规律，故障是否具有规律性等故障的具体表现，如服务器无法连接，应用程序报错，端口未开放等故障发生前是否有特殊操作，如系统更新，软件安装，修改配置等如果使用的不是云服务器而是自有硬件，还需要检查硬件设置状态查看服务器电源指示灯是否正常，硬盘指示灯是否有异常闪烁，cpu风扇是否正常运转，是否有异响或异味。检查交换机、路由器等常用网络设备是否存在异常，检查网络设备的指示灯状态，确认网线连接是否牢固。若服务器配备硬件监控系统，登录查看硬件健康状态报告，排查是否有硬盘故障，内存报错，电源问题等。验证是否存在网络问题本地网络测试：在服务器本地使用ping命令测试与网关、DNS服务器的连通性，检查防火墙。远程连接测试：从客户端尝试ping服务器ip，使用traceroute命令追踪路由，判断故障节点。端口状态检查：在服务器上使用netstat或者ss命令查看端口的监听状态，确认应用程序所需端口是否正常开放。查看、分析日志查看系统生成的各种日志文件，定位故障发生的原因，比如/var/log/messages（系统通用日志），/var/log/auth.log（认证相关日志）等，使用grep筛选关键词（如error、fail）快速定位问题。针对服务器上运行的应用程序（如web服务，数据库。中间件等），查看其专属日志。如，web服务，Nginx日志通常在/var/log/nginx/access.log和error.log，apache日志在/var/log/apache2/目录下。或者去配置文件中查看日志路径，在对日志文件进行排查。数据库，mysql日志包括错误日志，慢查询日志等。尝试重启服务或设备重启服务：若定位到某一服务异常，先尝试重启该服务观察是否恢复正常。重启服务器：排除掉硬件故障风险后，可以尝试重启服务器，在重新启动服务来观察是否恢复正常。（需提前通知相关用户，避免数据丢失）。