ARTICLE DETAIL

资讯详情

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

28条高可用工程实战经验:从P0故障中淬炼的落地准则

28条高可用工程实战经验:从P0故障中淬炼的落地准则 1. 这不是一份“标准文档”而是一本被项目现场反复翻烂的实战手记你有没有过这样的经历刚接手一个新系统技术栈五花八门文档里写着“按规范执行”可没人告诉你——这个“规范”在真实服务器上跑起来会卡在第3步或者团队刚定下微服务拆分方案结果上线后发现日志根本对不上时间戳排查三天才发现是时区配置漏了两处又或者评审会上大家一致点头通过的“高可用架构”第一次大促就暴露出熔断阈值设得比实际流量峰值还低30%……这些不是理论漏洞是血淋淋的工程断层。我干这行十二年带过17个从0到1的中大型项目亲手填过200个线上P0级坑最后把所有踩过的、绕过的、抄近道成功的、硬扛下来的细节全揉进了这份《附录》。它不叫“最佳实践”因为根本没有放之四海皆准的最佳它也不叫“技术白皮书”因为白皮书不写“为什么Nginx upstream里weight3比weight5更稳”这种事。它就是28条被验证过、可复现、带参数、带场景、带翻车记录的工程经验。比如第7条“Kubernetes Pod就绪探针readinessProbe的initialDelaySeconds必须≥容器内应用冷启动耗时20%且该耗时需取压测环境连续5次启动的P95值而非开发机本地日志里的‘Started Application in 1.2s’”。你看连小数点后一位都给你标清楚了。它面向的是正在改代码的后端、正调参数的运维、正画架构图的Tech Lead而不是坐在会议室里听汇报的总监。如果你需要的是“如何优雅地写一篇技术博客”请关掉页面但如果你明天就要上线一个支付回调接口而你刚发现上游系统返回的HTTP状态码是202但业务字段却是successfalse那你现在就应该往下看——第14条专门讲这种“协议级谎言”的兜底策略。2. 技术选型不是投票游戏而是用故障率倒推出来的生存选择2.1 选型逻辑拒绝“流行度陷阱”拥抱“故障成本函数”很多人以为技术选型就是拉个表格横向对比Redis、Memcached、Etcd的读写QPS、内存占用、集群模式然后投个票。错。真正决定生死的从来不是峰值性能而是单点故障扩散半径和故障恢复确定性。举个真实案例我们曾为一个千万级用户的消息中心选缓存中间件。当时团队倾向Redis因为生态成熟、文档多、招聘容易。但我坚持引入TiKV做二级缓存层理由很直白Redis主从切换平均耗时2.3秒基于我们压测数据而这2.3秒内未确认的ACK消息会堆积在RocketMQ consumer offset里导致下游消费延迟雪崩而TiKV的Region自动分裂与PD调度机制能保证任意单节点宕机时受影响的Key Range不超过总数据量的0.7%且恢复时间稳定在400ms内。算笔账消息中心每秒处理12万条推送2.3秒故障意味着27.6万条消息积压重试机制触发后DB写入压力飙升300%最终引发MySQL连接池耗尽。而TiKV方案下最大积压仅840条DB无感。所以我们的选型公式是技术A的故障成本 单点故障概率 × 故障影响范围 × 平均恢复时间 × 业务权重系数其中业务权重系数由SLA等级决定支付类业务系数为5消息推送为3后台管理为1。这个公式逼着你去查真实生产环境的MTBF平均无故障时间、MTTR平均修复时间而不是GitHub Stars数。我们因此放弃过两个“明星项目”一个是某开源分布式事务框架文档里写着“支持TCC/SAGA/AT三模式”但深入源码发现其SAGA模式的补偿事务回滚依赖于全局事务日志的强一致性而日志服务本身没有降级方案——等于把鸡蛋全放在一个篮子里另一个是某云厂商的Serverless函数平台冷启动实测P99达4.8秒而我们核心链路要求首字节响应≤800ms直接Pass。选型会开得少但每次结论都带着压测报告、故障注入记录和回滚预案。2.2 标准规范不是墙上挂的标语而是编译器能校验的契约很多团队的“编码规范”写得像宪法但没人真执行。我们的标准规范只做一件事让机器替人盯住80%的低级错误。比如Java项目我们强制要求所有RPC接口定义必须使用Protobuf v3且.proto文件必须通过protoc-gen-validate插件生成带校验逻辑的Java类Valid注解只能用于Controller层入参Service层方法签名禁止出现String类型ID必须是UserId、OrderId等Value Object日志输出必须包含traceId和spanId且格式固定为[traceId:xxx][spanId:yyy]由Logback的TurboFilter在日志打印前自动注入。为什么因为人工Code Review永远漏掉边界条件。去年有个订单超时取消功能开发写了if (order.getTimeoutAt() System.currentTimeMillis())看起来没问题。但getTimeoutAt()返回的是Long而数据库里这个字段是BIGINT当订单创建时间早于1970年比如测试用的虚拟历史订单getTimeoutAt()返回负数System.currentTimeMillis()是正数条件恒成立导致所有老订单被误取消。而如果用了Value ObjectTimeoutAt类内部会强制校验时间戳有效性编译期就报错。再比如日志格式我们曾因traceId没打在ERROR日志里花了6小时定位一个跨服务异常——因为ELK里搜不到完整链路。现在只要日志格式不对CI流水线的log-format-checker脚本就会失败连PR都推不上去。规范的生命力不在文档页数而在它能否被自动化工具拦截。我们甚至把部分规范编译成SonarQube规则比如“禁止在循环内新建HttpClient实例”规则触发后直接标红并附上性能对比数据——新建实例比复用连接池慢17倍且会快速耗尽本地端口。2.3 工程经验的28条每一条都对应一个真实的P0事故这28条经验不是凭空总结而是从127份线上事故复盘报告里提炼出来的。每一条都标注了“首次发生时间”、“影响范围”、“根本原因”和“验证方式”。比如第3条“数据库连接池的maxActive值必须≤数据库最大连接数 ÷ 服务实例数× 0.8并预留20%连接给DBA巡检与备份任务”。这条来自2021年双11凌晨的数据库雪崩。当时我们给每个服务实例配了100个连接集群共12个实例而MySQL配置的最大连接数是1024。表面看12×1001200 1024但忽略了DBA每小时执行的pt-online-schema-change会额外占用32个连接备份任务占用16个最终连接池打满新请求全部超时。后来我们改成动态计算maxActive floor((1024 - 32 - 16) ÷ 12) × 0.8 floor(976 ÷ 12) × 0.8 81 × 0.8 64实测后连接利用率稳定在65%~72%。再比如第19条“前端静态资源CDN缓存策略中HTML文件必须设置Cache-Control: no-cache, must-revalidate而JS/CSS文件必须带内容哈希如app.a1b2c3d4.js且CDN缓存时间为1年”。这条源于一次灰度发布事故前端发版后用户浏览器缓存了旧版HTML而新版HTML里引用的JS文件名已变但CDN仍返回旧版JS导致页面白屏。后来我们强制HTML不缓存JS/CSS永久缓存靠文件名哈希保证版本一致性。所有28条都经过至少3个不同业务场景验证不是“理论上可行”而是“上周刚在支付网关上跑通”。3. 28条工程实战经验参数、场景与避坑指南3.1 基础设施层让服务器自己学会呼吸第1条Linux内核参数调优不是照抄sysctl.conf而是按业务模型反向推导我们曾将net.ipv4.tcp_tw_reuse 1写进所有服务器配置结果在短连接高频场景如API网关下大量TIME_WAIT socket被重用导致上游服务收到重复请求。后来发现该参数生效前提是net.ipv4.tcp_timestamps 1而某些云厂商默认关闭timestamps以降低CPU开销。正确做法是先用ss -s统计TIME_WAIT数量若5000且持续增长则检查tcp_timestamps是否开启再根据业务连接模型计算理论TIME_WAIT数理论值 QPS × 平均连接生命周期 × 2TCP四次挥手。若理论值远小于当前TIME_WAIT数说明存在连接泄漏应查代码若接近则调整net.ipv4.ip_local_port_range扩大端口范围而非盲目开tw_reuse。我们最终的网关服务器配置是tcp_timestamps1、tcp_tw_reuse1、ip_local_port_range1024 65535实测TIME_WAIT稳定在3000以下。第2条Kubernetes节点资源预留必须区分“系统守护进程”与“业务Pod”很多团队按官方建议设--system-reservedcpu500m,memory2Gi但忽略了Docker daemon、kube-proxy、node-exporter等组件的实际开销。我们在一个24核96G的节点上实测这些守护进程常驻消耗CPU 1.2核、内存3.8Gi。若按官方预留剩余资源为22.8核92.2G但业务Pod申请20核90G时节点会因OOM Killer干掉kubelet。解决方案用kubectl top node和cadvisor采集7天数据取P95值作为真实预留值再为关键守护进程单独设static pod绑定system-node-critical优先级确保它们永不被驱逐。最终配置--system-reservedcpu1200m,memory4Gi业务Pod最大申请21.8核92G节点稳定性提升至99.995%。第3条数据库连接池maxActive值必须动态计算且每日校验如前所述我们用公式maxActive floor((DB_max_connections - DBA_reserved - backup_reserved) ÷ instance_count) × 0.8。但DBA预留数会变如大促期间增加巡检频次所以我们写了个Python脚本每天凌晨从Zabbix API拉取DB连接数监控从CMDB获取实例数自动计算并推送新配置到Consul。脚本还带熔断若计算出的maxActive 10则触发告警人工介入。上线后连接池打满类故障下降92%。3.2 中间件层别让“高可用”变成“高不可用”第4条Redis哨兵模式下sentinel monitor的quorum值必须≤哨兵节点数÷21且必须部署奇数个哨兵某次机房断电3个哨兵节点只剩2个在线而quorum2导致哨兵无法达成多数派主从切换失败。正确做法3节点哨兵quorum25节点quorum3。永远保证quorum ≤ (n1)/2n为哨兵总数。我们还强制要求哨兵与Redis实例物理隔离——哨兵不能和Redis同服务器避免单机故障同时干掉两者。第5条RocketMQ消费者组的consumeThreadMin/consumeThreadMax必须按消息堆积速率动态调整默认值20/64在消息突增时不够用。我们开发了一个自适应算法每分钟采样brokerOffset - consumerOffset差值若连续3分钟10万则consumeThreadMax min(128, current * 1.5)若差值1万且持续10分钟则consumeThreadMin max(10, current * 0.8)。算法嵌入Consumer SDK无需人工干预。实测消息堆积从小时级降至秒级。第6条Elasticsearch索引模板中date字段必须显式指定format禁止用default某次日志查询因timestamp字段未设formatES自动识别为strict_date_optional_time而某些客户端发来的2023-01-01被解析为2023-01-01T00:00:00.000Z另一些发2023/01/01则解析失败。统一设为format: strict_date_optional_time||epoch_millis覆盖所有常见格式。3.3 应用层代码里的魔鬼都在细节里第7条Kubernetes Pod就绪探针initialDelaySeconds必须≥P95冷启动耗时20%如开头所述我们用JMeter压测容器启动过程记录5次启动时间1.2s、1.3s、1.1s、1.4s、1.2s → P951.4s →initialDelaySeconds1700ms。同时在探针脚本里加入启动日志校验curl -f http://localhost:8080/actuator/health | jq -r .status | grep UP避免应用进程起来但Spring Boot Actuator未就绪。第8条Java CompletableFuture.allOf()必须配合exceptionally()捕获子任务异常allOf不会传播子任务异常导致get()时才抛出ExecutionException难以定位具体哪个任务失败。正确写法CompletableFutureVoid all CompletableFuture.allOf( task1.thenAccept(r - log.info(task1 ok)), task2.exceptionally(e - { log.error(task2 failed, e); return null; }), task3.exceptionally(e - { log.error(task3 failed, e); return null; }) );我们把这条写进IDEA Live Template输入cfall自动补全安全模板。第9条前端fetch请求必须设置signal.timeout且timeout值≤后端接口超时值的80%后端设了30s超时前端fetch却没设timeout导致网络卡顿时页面假死。我们封装了safeFetch函数const safeFetch (url: string, options: RequestInit {}) { const controller new AbortController(); const timeoutId setTimeout(() controller.abort(), 24000); // 30s * 0.8 return fetch(url, { ...options, signal: controller.signal }) .finally(() clearTimeout(timeoutId)); };3.4 监控告警层让告警成为决策依据而非噪音来源第10条Prometheus告警规则中rate()函数窗口必须≥样本采集间隔的4倍采集间隔15s若用rate(http_requests_total[30s])则可能因样本缺失导致rate为0产生误告。正确窗口[60s]或[90s]。我们用promtool check rules脚本在CI中校验所有规则。第11条告警分级必须与故障响应SLA强绑定且每级告警附带处置手册URLP0告警如DB主库宕机→ 5分钟内电话通知OnCall → 自动执行mysql-failover.sh→ 链接《主库切换SOP》P1告警如API错误率5%→ 企业微信通知 → 自动触发api-troubleshoot.py诊断脚本 → 链接《错误率突增排查清单》。告警信息里直接带手册链接省去搜索时间。第12条日志采样率必须按traceId哈希动态调整而非全局固定全量日志太贵固定采样又会漏掉关键链路。我们用Math.abs(traceId.hashCode()) % 100 sampleRate并将sampleRate设为变量错误日志sampleRate100全采INFO日志sampleRate1010%DEBUG日志sampleRate11%。采样率通过Apollo动态下发。3.5 发布运维层每一次上线都是对设计的终极考试第13条灰度发布比例必须按服务依赖深度反向设定核心服务如用户中心灰度1%而它的下游如积分服务灰度5%因为积分服务故障影响面小。我们用服务拓扑图自动生成灰度比例矩阵避免人工拍脑袋。第14条HTTP接口返回202 Accepted时必须在响应体中提供status_url字段且该URL必须支持GET轮询上游系统返回202却不给查询地址下游只能盲等。我们强制要求{ code: 202, msg: accepted, status_url: /v1/jobs/abc123/status }且status_url接口返回{ status: processing|success|failed, progress: 75 }。前端轮询5次后超时转人工介入。第15条数据库变更必须执行“三段式验证”语法校验→影子表同步→生产环境只读验证pt-online-schema-change执行前先用pt-table-checksum校验主从一致性变更中用pt-archiver将新表数据同步到影子表变更后切流前用SELECT COUNT(*) FROM table_name对比新旧表行数误差0.001%才放行。3.6 安全合规层安全不是加功能而是减攻击面第16条JWT token必须校验ississuer和audaudience字段且aud值必须与当前服务域名严格匹配曾有服务校验exp但忽略aud导致支付服务的token被营销服务盗用。现在所有鉴权中间件强制if (!token.getAudience().contains(https://pay.example.com)) throw InvalidTokenException();第17条敏感配置如DB密码必须存储于Vault且应用启动时通过Sidecar注入禁止任何形式的环境变量明文传递我们用Vault Agent Auto-AuthSidecar容器自动拉取secret并写入/vault/secrets/db.json主应用只读该文件。CI流水线禁止任何echo $DB_PASSWORD操作Git预提交钩子扫描明文密码。第18条前端XSS防护必须启用CSP头且script-src禁止unsafe-inline只允许hash或nonceContent-Security-Policy: script-src self sha256-abc123...。我们用Webpack插件自动生成hash每次构建更新CSP头杜绝内联脚本执行。3.7 架构治理层让复杂系统保持可演进性第19条前端静态资源CDN缓存策略中HTML必须no-cacheJS/CSS必须带内容哈希且缓存1年如前所述这是解决“HTML缓存导致JS加载失败”的终极方案。我们用Webpack的contenthash和HtmlWebpackPlugin自动注入哈希CDN配置Cache-Control: public, max-age31536000。第20条微服务间通信必须使用gRPC over TLS且证书必须由内部CA签发禁止自签名自签名证书导致gRPC客户端频繁报UNAVAILABLE: io exception。内部CA签发后证书有效期设为1年自动续期脚本每月检查并更新。第21条领域事件命名必须遵循“主体_动词_宾语_状态”格式且全部小写下划线order_created、payment_refunded、user_profile_updated。禁止OrderCreatedEvent或orderCreate。统一格式便于Flink SQL解析和Kafka Topic路由。3.8 团队协作层流程不是束缚而是减少沟通熵的工具第22条Code Review必须聚焦“可维护性”而非“代码风格”禁止评论“if后面没加大括号”改为“这个分支逻辑是否会被后续需求扩展如果是建议抽成独立方法”。我们用Review Bot自动检查风格人工只审设计。第23条周会站会必须每人只说3件事阻塞项、今日目标、需协作方禁止“我昨天做了XX”这种无效汇报。阻塞项必须带负责人和DDL如“支付回调验签失败需后端提供调试日志DDL今天18:00”。第24条技术债必须量化且纳入迭代计划“重构用户服务缓存逻辑”不算技术债“用户服务缓存命中率60%导致DB QPS超限预计重构后降低DB负载40%需3人日”才算。每季度技术债看板公示优先级按ROI排序。3.9 灾备容灾层假设一切都会坏然后设计怎么活下来第25条异地多活架构中城市级故障切换必须预设“数据一致性容忍窗口”上海机房故障切换到杭州但两地DB同步延迟1.2秒。我们定义订单创建后1.5秒内杭州机房禁止处理该用户的新订单避免超卖。这个窗口值来自同步延迟P990.3秒。第26条备份恢复演练必须每年执行且恢复时间目标RTO必须≤SLA要求的50%SLA要求RTO≤30分钟演练目标设为≤15分钟。演练时全程录像回放分析瓶颈是备份集下载慢还是MySQL恢复参数没调优还是DNS切换延迟第27条混沌工程实验必须从“最不可能故障”开始不先搞CPU打满而是先模拟“Kubernetes kubelet进程被kill”因为这是最隐蔽的故障——Pod还在Running状态但实际已失联。我们用chaos-mesh定期执行此实验验证监控告警和自愈能力。第28条所有线上配置变更必须留痕且变更记录必须关联Jira工单和Git Commit用Ansible Tower执行变更自动抓取ansible-playbook命令、执行人、时间、目标主机、变更前后的配置diff并写入Confluence。审计时5秒内可追溯到某次数据库参数修改是谁、何时、为何、改了什么。4. 实操落地如何把这28条变成团队肌肉记忆4.1 工具链固化让规范长在流水线里光有经验不够得让它自动运行。我们构建了三层工具链第一层Pre-Commit HookGit提交前自动执行eslint --fix前端mvn compilespotbugs:checkJavayamllintshellcheckAnsible检查application.yml中是否有明文密码正则password:.*[a-zA-Z0-9]任一失败提交被拒绝。第二层CI/CD PipelineJenkins流水线强制环节sonarqube扫描覆盖率70%失败docker build后trivy image scan检查CVE漏洞CVSS≥7.0失败kustomize build生成YAMLkubeval校验K8s语法helm linthelm template渲染conftest test验证策略合规性如“所有Deployment必须设resources”第三层Post-Deploy Guardrail应用上线后10分钟自动执行调用/actuator/health检查statusUP查询Prometheus验证http_server_requests_seconds_count{jobmyapp}[5m] 0检查ELK确认log_levelERROR的日志数3条全部通过发布成功任一失败自动回滚并告警。这套工具链不是一次性建设而是按28条经验逐条落地。比如第7条就绪探针我们在CI中加了kubectl wait --forconditionready pod -l appmyapp --timeout120s第14条202状态我们写了curl -s http://service/status_url | jq -r .status断言脚本。每条经验都有对应的自动化锚点让“人治”变成“机制治”。4.2 文档即代码让知识沉淀在可执行的仓库里我们不用Confluence写文档所有规范、经验、SOP都存在Git仓库/docs/standards/Markdown格式的编码规范但每条规范后跟example/目录放可运行的代码示例如java-value-object模块含UserId类和单元测试/docs/incidents/每起P0事故的复盘报告格式固定YYYYMMDD-incident-title.md含时间线、根因、改进措施、验证结果/infra/terraform/所有基础设施代码main.tf里直接写# ref: docs/incidents/20231015-db-snowball.md关联事故与修复新成员入职第一件事是git clone整个仓库make setup一键启动本地开发环境含Mock DB、Mock Redis、Mock Kafka并运行make test-docs验证所有文档示例都能跑通。知识不再锁在某个人脑子里而长在代码里随代码一起演化。4.3 经验传承用“故障演练”代替“培训PPT”我们每月组织一次“故障演练日”不讲理论只做三件事重现一个真实P0事故比如还原第3条连接池打满场景用sysctl -w net.ipv4.ip_local_port_range1024 2000缩小端口范围观察TIME_WAIT飙升现场debug所有人用ss -s、netstat、jstack实时分析导师只提问不解答“现在连接数为什么涨这么快”“哪个线程在阻塞”当场修改找到问题后立即改代码、改配置、改脚本提交PR走完整CI流程验证修复演练后胜出者最快定位根因并修复获得“故障猎人”徽章徽章挂在工位且计入晋升考核。比起听10小时PPT亲手把一个线上故障从爆炸到平息才是最深刻的学习。去年新入职的应届生在演练中用jstack发现线程池死锁后来他写的线程池监控工具成了团队标配。5. 常见问题与一线排查技巧实录5.1 “明明配置都对了为什么还是不生效”——配置生效链路全透视这是最高频问题。配置不生效往往不是配置错了而是没走到生效环节。我们画了一张“配置生效地图”覆盖所有常见场景配置位置生效时机验证方式常见失效点Spring Bootapplication.yml应用启动时加载curl /actuator/envgrep mypropKubernetes ConfigMapPod启动时挂载为文件kubectl exec -it pod -- cat /config/app.ymlMountPath路径错或subPath没指定文件名Nginxnginx.confnginx -s reload后nginx -t ps aux | grep nginxreload没执行或配置语法错误导致reload失败Prometheus Alert Ruleprometheus.yml重载后curl http://prometheus/api/v1/rulesrule_files路径错或rule文件没放在指定目录Vault SecretSidecar注入时kubectl exec -it pod -- cat /vault/secrets/db.jsonVault Agent没启动或policy权限不足实操技巧当怀疑配置失效按顺序执行查进程ps aux \| grep your_app确认启动参数是否带--spring.config.location进容器kubectl exec -it pod -- sh直接看文件内容查日志kubectl logs pod \| grep load config找加载日志查API对暴露/actuator的服务直接调用/actuator/configprops看最终生效值提示Kubernetes里ConfigMap更新后Pod内的文件不会自动更新必须重启Pod或用kubectl rollout restart deploy/myapp。我们为此写了configmap-watcher工具监听ConfigMap变更自动触发滚动更新。5.2 “告警狂轰滥炸到底哪个是真的”——告警降噪三板斧告警疲劳是运维最大敌人。我们的降噪策略第一斧静默非关键时段用Prometheus Alertmanager的inhibit_rules抑制“夜间DB慢查询告警”但若同时触发“DB连接数95%”则解除抑制——因为后者表明问题严重。第二斧聚合相似告警同一服务的5个Pod都报CPU 90%不发5条告警而是聚合为myapp CPU usage high on 5/8 pods并附Top3 Pod列表。第三斧自动诊断附加信息告警触发时自动执行诊断脚本# cpu-high-diagnose.sh echo Top 5 CPU processes:; top -bn1 | head -20 echo Load average:; uptime echo Memory usage:; free -h脚本输出直接附在告警消息里OnCall工程师一眼看到java process using 98% CPU立刻知道要jstack。5.3 “线上问题复现不了本地一切正常”——环境差异挖掘机本地OK线上炸90%是环境差异。我们用“环境差异检查清单”逐项排除JVM参数kubectl exec pod -- jinfo -flags $(pgrep java)vs 本地java -XX:PrintFlagsFinal -version \| grep UseG1GC时区kubectl exec pod -- datevsdate确认是否UTC vs CSTDNS解析kubectl exec pod -- nslookup service-namevs 本地nslookup检查CoreDNS配置内核参数kubectl exec pod -- sysctl net.ipv4.tcp_tw_reusevssysctl资源限制kubectl describe pod \| grep -A5 Limits确认CPU/Memory limit是否过小独家技巧用kubectl debug临时注入调试容器kubectl debug -it pod --imagenicolaka/netshoot --targetapp-container # 进入后可执行tcpdump、strace、curl等所有网络诊断命令比登录宿主机安全比重启Pod快。5.4 “这个Bug修了会不会引发新问题”——回归测试黄金三角修Bug不敢动怕牵一发而动全身。我们建立“回归测试黄金三角”三角顶点1核心链路自动化用例每个服务必须有smoke-test模块含5个最高频API的Postman集合CI中必跑。三角顶点2变更影响分析用jdeps --list-deps分析Java类依赖若修改UserService自动找出所有调用它的Controller标记为高风险回归点。三角顶点3线上流量录制回放用gojek/telkom录制生产流量脱敏后回放到测试环境验证修改后行为一致。注意录制流量必须过滤敏感字段如手机号、身份证号我们用正则phone:\*\*\*\*\*\*\*\*自动脱敏脱敏规则存在Git每次变更需评审。5.5 “文档写了一堆新人还是不会用”——文档可用性检测法文档好不好不看字数看新人能否独立完成。我们每月随机抽3个新人给他们一个任务任务为新服务接入公司统一日志系统要求不许问任何人只许查文档和代码检测点是否能在30分钟内找到logback-spring.xml模板是否能正确配置logstash地址是否能验证日志是否进入ELK若超时或失败文档作者必须重写。去年重写了7份文档现在新人平均12分钟完成接入。文档的价值是让人“不用思考就能做对”而不是“思考半天才能看懂”。我在实际带团队的过程中
返回列表