ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Java高级开发核心能力:JVM、并发与分布式一致性实践

2026/9/29 3:46:36 拓冰建站 浏览量
Java高级开发核心能力:JVM、并发与分布式一致性实践 说实话这年头“高级开发”这个头衔已经被市场喊烂了。有的公司3年经验就给高级有的公司8年还在中级混着有的高级天天写CRUD有的高级一个线程池参数就能把系统性能翻一倍。我在面试候选人和带团队的过程中越来越清楚地感觉到一件事高级开发不是一个年限标签而是一整套能力结构的结果。这篇文章不打算给你罗列一堆八股文背诵清单而是想认真聊聊我理解的Java高级开发到底需要具备哪些能力。如果你正在往高级岗位走或者已经是高级但总感觉自己差点意思这篇内容应该能帮你理清思路顺便也能当作一次能力自检。1. 先搞清楚高级开发到底“高”在哪1.1 三个段位的本质差异我见过太多工作三五年但能力模型还停留在“熟练工”层面的开发者。这个问题的核心症结在于很多人把“写代码的经验积累”误当成了“技术能力的提升”。初级到中级的跃迁比的是谁更熟练——语法熟不熟、框架用没用过、CRUD写得好不好看。这个阶段拼的是“量”代码写得越多接口调得越顺你就能从初级升到中级。但从中级到高级拼的完全不是熟练度而是你能否在复杂场景下做出正确的技术决策。同样是订单超时关单中级的做法是在定时任务里扫表高级的做法是评估数据量、延迟容忍度、消息中间件可靠性后设计一套延迟消息兜底扫描的双轨方案。我见过太多人有个误区觉得涨薪靠跳槽升级靠年限。但真相是残酷的年限只决定你见过多少问题不决定你能解决多少问题。那些工作七八年还停留在中级水平的人基本都有一个共同特征——他们一直在“用”技术却从来没想过这些技术“为什么”是这样设计的。1.2 高级开发的“能力分层模型”我带团队有一个习惯新人入职时我会给他画一个能力分层图帮他们找到自己的位置。这个分层模型分四层第一层是任务交付层。这层的人要的是“能干活”——给定需求能写出可运行的代码能修好bug。大多数初级和中级工程师都在这层。第二层是系统质量层。这层的人开始关注代码质量、性能、安全性、可维护性。他们不再满足于“能跑”而是追问“跑得稳不稳、挂得快不快、别人改起来难不难”。第三层是业务结果层。这层的人能够用技术手段直接撬动业务价值。别人问的是“怎么把这个接口写完”他们问的是“这个功能上线后能帮业务省多少成本、涨多少转化”。第四层是团队杠杆层。这层的人可以通过技术决策、架构设计、人才培养来放大整个团队的产出。他们要解决的不再是某一个问题而是一类问题不再是一个人写代码而是带着一群人写出好代码。高级开发者的门槛在你开始进入第二层和第三层之间。如果你的技术方案还在靠拍脑袋你的排查思路还停留在“重启大法”你的代码评审还在纠结变量命名那你离高级还有一段路。2. 硬技能JVM、并发与数据一致性2.1 JVM不只是面试题是线上救命的工具每次面试我都会问候选人对JVM的理解一半以上的人回答“类加载机制、垃圾回收、内存模型”讲得头头是道。但当我追问“你们线上有没有遇到过OOM怎么排查的”很多人就沉默了。这就是典型的八股文能力和工程能力之间的差距。JVM知识死记硬背是没用的它必须成为你排查线上问题的工具箱。我说一个真实场景。有一年我们一个线上服务频繁告警现象是接口超时率从1%飙到20%重启后恢复但运行两小时后又开始飙。我让人去查GC日志发现Full GC频繁触发每次停顿好几秒。继续深挖发现有一个定时任务每十分钟加载一次全量配置到内存这批数据大约占用堆内存的40%老年代频繁被打满。就是因为这个任务设计得不合理把大对象直接怼进了堆里。这个问题如果不懂JVM你是完全无法定位的。你会怀疑数据库慢查询、怀疑网络抖动、甚至怀疑云厂商出了问题但懂JVM的人会直接看GC日志看到大对象分配频繁触发Full GC再反推是哪里分配的大对象。我的建议是不要死记硬背那些参数。你要真正理解下面这几件事堆内存的分区结构新生代、老年代、元空间各自存什么对象从新生代晋升到老年代的触发条件是什么。常见GC算法的工作机制CMS和G1的核心差异、适用场景ZGC的出现解决了什么问题。线上JVM排查工具jstat看GC统计、jmap导堆转储、jstack看线程栈、Arthas做动态诊断。热词里有人搜“java怎么保证数据一致性”有人搜“aqs java”这些东西单独看都是知识点但在高级开发者的操作体系里它们是互相串联的JVM解决的是程序“跑得稳不稳”并发解决的是“吞吐高不高”数据一致性解决的是“算得准不准”。2.2 并发编程从synchronized到AQS再到线程池参数设计并发编程是Java面试中八股文最密集的领域synchronized、volatile、ReentrantLock、ConcurrentHashMap、ThreadPoolExecutor、AQS各个都能背出一大段。但我想说大部分人会背锁的升级过程却不知道什么时候该用哪种锁大部分人能默写线程池七大参数却设计不出一个合理的线程池配置。举一个很典型的例子有一次一个同事做某个对接业务账单的需求高峰期要处理几万条数据入库。他的方案是写一个for循环每条数据开一个线程去处理结果数据库连接池直接被打爆CPU跑满接口大面积超时。这就是典型的“会用多线程不懂并发控制”。高级开发者看并发问题脑子里应该有一个三维模型。第一维是正确性数据会不会被多个线程同时修改需不需要加锁用什么锁第二维是性能锁的粒度能不能更细能不能用CAS替代重量级锁能不能用读写锁分离场景第三维是资源线程池大小怎么定队列用有界还是无界拒绝策略选哪种线程池参数不是一个固定公式它取决于你的任务类型。CPU密集型任务线程数建议设为CPU核数1IO密集型任务可以设置得更高一些常见经验值是CPU核数2倍。但更准确的做法是结合压测结果动态调整而不是抄个公式就完事。再说说AQS。很多面试题会问“AQS的原理是什么”答案无非是CLH队列、state状态位、独占和共享模式。但真正重要的是理解AQS的设计哲学它把“同步状态的原子管理”和“线程的阻塞与唤醒”解耦了。理解了这一层你去看ReentrantLock、Semaphore、CountDownLatch的源码会豁然开朗因为它们本质上都是AQS这个通用框架的具体封装。2.3 数据一致性从单机事务到分布式最终一致热词里出现了“java怎么保证数据一致性”我猜测提问者大概率是被分布式事务折磨过。这个话题特别大我试着用最直白的方式拆解一下。单机环境下事务一致性靠数据库本地事务就能搞定。ACID四要素中原子性、一致性、隔离性、持久性各有各的实现机制这部分咱不展开。但到了分布式环境问题就复杂了你调用了A服务和B服务A成功了B失败了你怎么办解决分布式事务业界常见的方案我列一下2PC/XA模式刚性事务强一致性但性能差、协调者容易成为单点适合并发不高的场景。TCC方案Try-Confirm-Cancel三段式侵入性强但灵活性高适合对一致性要求高且并发量大的业务。本地消息表利用数据库本地事务和消息表先写业务表再写消息表通过定时任务扫描消息表投递消息。实现简单但消息可能延迟。事务消息以RocketMQ为代表将本地事务和消息发送绑定成一个原子操作先发送半消息本地事务成功后再提交确认消息。最大努力通知适用于跨机构、跨系统的场景不追求强一致只保证最终一致并配合对账补偿。看了这么多方案高级开发者的关键能力是权衡你的业务到底允许多大的不一致窗口你的团队有多少精力能维护复杂的分布式事务框架你的公司基础设施支持哪种中间件没有一个方案放之四海而皆准拉开差距的不是你掌握了几种方案而是你在具体场景下能不能选出性价比最高的那一种。除了分布式事务数据一致性还包含另一个维度各系统之间的数据对账。我在做支付系统的时候最常干的事就是对账。渠道返回的交易结果和本地订单状态不一致怎么办你得有一套自动对账人工复核差错处理机制。这些经验是看技术文档永远学不到的只能靠着在真实业务里踩坑踩出来。3. 框架与中间件看见代码背后的设计3.1 Spring生命周期值得你从头读一遍Java高级开发面试中Spring几乎是必考的尤其喜欢问Bean的生命周期和循环依赖。很多候选人能把三级缓存那套说得很流利但你再追问一句“为什么要三级缓存二级缓存解决不了吗”就卡壳了。这个问题的答案本质上是在说Spring需要区分“普通Bean”和“代理Bean”。当你在一个Bean上配置了AOP代理那么提前暴露给依赖方的对象必须是代理对象而不是原始对象。二级缓存存的是“早期暴露的原始对象”三级缓存存的是“生产代理对象的工厂”。之所以搞成三级是因为Spring在实例化Bean时还不知道这个Bean会不会被代理——而如果直接用二级缓存存原始对象后续生成代理就来不及替换了。我特别建议高级开发者认真地、从头到尾读一遍Spring的Bean生命周期源码。读完之后你对AOP、事务、依赖注入的理解会从“会用”升华到“懂原理”。更重要的是当线上出现某个诡异的Bean初始化异常、循环依赖警告、代理失效问题时你是有能力通过日志推断出具体卡在生命周期的哪个环节的。3.2 MQ与缓存高级开发必须具备的中间件心智如果说Spring是Java开发者的基本功那么MQ和缓存就是高级开发者的必杀技。以Kafka为例很多人知道它吞吐量高但不知道高吞吐背后的设计顺序写磁盘、页缓存、零拷贝、批量发送。这些设计不是学术空谈它们决定了你在实际使用时应该怎么做生产者要设置合理的batch.size和linger.ms换取更大的吞吐消费者要处理好分区分配策略和offset提交时机防止重复消费和消息丢失消费积压时优先考虑增加消费者实例还是调整拉取参数要结合分区数和消费耗时来判断。再说缓存。Redis几乎是Java应用标配但缓存设计的坑一点都不少。缓存穿透、缓存击穿、缓存雪崩每一个都是一道送命题。我见过不止一个团队因为没做缓存空值处理导致一个不存在的商品ID被恶意刷接口时请求全部打到数据库上数据库连接直接被打满整个服务雪崩。高级开发者设计缓存方案时应该有一套完整的思考框架哪些数据适合放缓存、缓存过期时间怎么定、更新策略选Cache Aside还是Write Through、缓存和数据库的一致性怎么保证、缓存故障时怎么降级。这套框架不是从某个技术博客上学来的而是来源于对业务场景的深入理解和对风险点的预判。3.3 数据访问全链路从ORM到分库分表Java也好、MySQL也好数据访问这一层是高级开发者绕不开的能力。先说ORM。MyBatis的Mapper代理机制、一级二级缓存、懒加载原理这些如果你只停留在用层面出了问题就毫无头绪。我遇到过一种情况一个同事在循环里执行单条SQL查询几千次调用导致数据库压力巨大。他当时的第一反应是“数据库太慢了”但实际问题是那根本不是数据库慢是他没用批量查询的API。再看分库分表。当单表数据量到了千万甚至亿级或者单库写入TPS打满你就不得不面对分库分表的改造。但这一步一旦迈出去就没法轻易回头跨库join失效、全局唯一ID要重设计、分布式事务复杂度上升、分页排序变成内存操作。我的经验是分库分表永远是最后的手段不是第一选择。优先考虑的是能不能归档冷数据能不能引入缓存扛住读压力能不能升级硬件临时顶住如果这些都不行再认真评估分库分表的成本——你的团队有没有能力承接后续的复杂度和维护成本改造周期内业务能不能接受停机或灰度这些判断力恰恰是高级开发者区别于普通开发者的地方。4. 设计能力代码之外的业务建模4.1 面向对象不是背概念是建模热词里有人搜“面向对象编程java”这让我有点意外——这居然是个持续有搜索量的关键词。但仔细想想也不意外因为很多Java开发写了好年代码对面向对象依然没有建立起真正的体感写的代码依然是一堆set/get和if/else堆出来的“贫血模型”。面向对象不是让你在代码里生硬地造类、造接口而是要求你用对象的视角去理解业务。订单、支付单、退款单、库存单它们的生命周期各是什么状态流转由谁触发行为应该内聚在哪个实体上举一个我印象特别深的例子。曾经有个需求是退货退款流程内含大量状态判断订单在什么状态下可以发起退款、退款到了什么状态可以取消、库存什么时候回滚、优惠券什么时候返还。一开始的方案是写一个巨大的service类每个方法里都有一大堆if-else判断状态。后来我愣是让团队重构把订单状态做成一个状态机模型状态流转的逻辑全部收敛到状态机里Service层只负责编排和调用。重构之后新增“仅退款”和“退货退款”两种流程时改动量小了不止一个量级而且每个状态的可达路径清晰可见测试也好写得多。4.2 设计模式放在真实代码里怎么落地设计模式不是让你背UML类图而是让你在合适的业务场景里用合适的结构解决问题。我面试时喜欢问“你最近在哪个项目里用过设计模式解决什么问题”。能把这个问题讲好的候选人十有八九是真·高级水平。因为设计模式的本质是**“应对变化”**——你的业务场景里有没有可能新增类型有没有可能替换实现有没有一组算法会在将来产生不同的变体举几个业务落地场景策略模式最典型的场景就是支付渠道。微信、支付宝、银联各一种支付实现controller层根据渠道类型动态选择处理器。模板方法模式适合“主流程固定、步骤内部变化”的场景。比如数据导入流程解析文件、校验数据、清洗转换、落库、发送通知不同文件格式只是个别步骤实现不同。责任链模式审批流、敏感词过滤、数据校验一层层传下去直到某个节点处理完毕。观察者模式订单创建后要发短信、发消息、更新库存、通知物流扣完订单创建主逻辑后把这些动作交给事件监听器异步处理。设计模式的落地难点不在于“会不会画类图”而在于识别的能力。同一个业务需求如果你能识别出它是策略模式还是模板方法的变体你的代码结构就会截然不同。4.3 系统设计拆分、边界和演进到了高级开发者的职业阶段“一亩三分地的代码”已经不够看了你要在更大的尺度上思考系统的架构。微服务怎么拆分、领域边界在哪里、数据归属谁、接口怎么设计、DDD该不该上、服务间怎么治理。微服务拆分是我在过往项目里踩坑最多的地方。最惨痛的一次教训是我们把一个低频的管理后台功能和核心交易流程放在了同一个微服务里。结果有一次管理后台批量导出报表直接把交易服务的数据库CPU打满正常下单也跟着超时。这就是拆分没考虑资源隔离导致的事故。有了这次教训我来总结拆分微服务的三个核心判断维度按业务域拆交易、商品、用户、营销各成一域每域的变更频率和团队归属相对独立。按流量特征拆高并发读写和低并发管理端坚决隔离资源竞争不复存在。按数据归属拆一个数据表只归一个服务管理其他服务要读写只能走API避免共享库带来的紧耦合。至于DDD我不建议一开始就全面引入因为它对整个团队的认知要求很高。更务实的路径是先画出核心业务域用限界上下文划分服务边界把充血模型用在最核心的领域逻辑上其它非核心模块保持事务脚本风格。架构设计的最高原则不是“最先进”而是“合适”和“可演进”。5. 故障排查与性能调优高级工程师的硬通货5.1 线上排查方法论现象→假设→验证高级开发者和初级开发者的分水岭一半在线上故障处理能力上。遇到问题初级开发者的第一反应是看代码、改代码、重启服务。高级开发者的脑回路则完全不同先收缩范围再建立假设最后有针对性地验证。举个具体例子。有一次线上告警“订单详情接口RT从50ms涨到500ms”如果直接去看代码你会发现代码没有任何改动完全无从下手。这时候应该怎么做先看监控把RT的涨点往前推看到底是从哪个时间点开始的。再看调用链确认RT是消耗在我们自己服务内部还是下游调用变慢。再查基础设施GC有没有异常、网络有没有抖动、CPU有没有飙升、依赖的数据库有没有慢查询。这个排查过程有一个关键词“分层”。从入口流量到业务逻辑到基础设施一层层剥开每一层都有明确的验证手段。善于用Arthas、链路追踪、监控大盘这些工具的高级开发者通常能在分钟级定位到问题根因不善于用工具的可能排查一整天还在原地打转。有一种情况尤其常见——线上偶发性的慢请求时好时坏重启后症状消失。这种问题最头疼因为它大概率是“低概率触发”的资源竞争问题可能是某个大对象偶发触发Full GC可能是某个线程池队列偶发阻塞可能是连接池在某个时刻被占满。这种问题只能靠保留现场堆转储、线程栈、GC日志来等它复现。5.2 性能压测与调优思路先会量化才能优化做性能调优不能靠“感觉”。你觉得自己写的代码快但快多少不知道。你觉得加个索引就行但加哪个列不知道。量化是调优的前提没有一个基准数据做底一切优化都是空谈。我一般建议团队做任何性能优化前先做一轮压测拿到基线数据。压测工具选JMeter或者开源压测平台都行关键是要保证场景真实、数据量贴合生产、持续时长足够至少跑20分钟以上才能把GC的影响暴露出来。拿到基线之后再依次排查先从代码层看有没有明显的低效逻辑——循环查库、N1查询、重复计算、大对象不释放。再往中间件层走——连接池大小是否合理、Redis的key过期策略是否合理、消息积压情况如何。最后到了基础设施层——JVM参数是否需要调、服务扩容是否要加、数据库缓冲池是否足够。不要上来就调JVM参数。80%的性能问题出在代码和SQL上只有20%才是真正的JVM或基础设施瓶颈。调参是锦上添花改代码是雪中送炭顺序别搞反了。5.3 稳定性保障限流、降级、熔断是保命手段高级开发者必须对线上稳定性有敬畏心。年轻人写代码容易追求“功能都有”老工程师写代码脑子里想的却是“这功能挂了会发生什么”。高并发场景下限流、降级、熔断是三大保命手段。限流是防止流量把系统击穿——常见的算法有固定窗口、滑动窗口、漏桶、令牌桶在Java生态里可以用Guava RateLimiter、Sentinel、或者网关层的限流组件。降级是当系统资源不足时主动放弃非核心功能——比如大促期间把积分商城、排行榜关闭先保住下单支付主链路。熔断是指当下游服务故障达到阈值上游直接短路不再调用避免故障扩散——Hystrix和Sentinel都实现了类似机制。这些手段不是用了就完事关键在于阈值设计的合理性和降级路径的演练频率。阈值设高了起不到保护作用设低了又会误伤正常流量。我见过最离谱的场景是限流阈值设得比正常高峰流量还低结果活动一上线全站都在报错这比不限流还可怕。所以稳定性设计一定要做预案、要演练。压测的时候不要只顾着看“最多能扛多少TPS”还要顺手验证一下限流生效后的表现、熔断触发后的表现、降级开关打开后的表现。要知道故障不可怕可怕的是故障发生了你却不知道系统在按什么规则运行。6. 软实力决定你能走多高6.1 业务理解与技术翻译能力很多技术人有一个致命的短板不屑于了解业务。他们觉得业务是产品经理的事技术人就该纯粹写代码。这种认知在初级岗位可能没什么但到了高级岗位大概率会成为职业天花板。我见过太多类似的场景产品提了个需求“会员等级要达到一定门槛才能配置优惠券”开发说“这个需求得改表、加字段、写配置页面工作量很大”。但如果你懂业务你会联想到这本质上是一个权限控制的问题——会员等级和权限点是关联关系只要把权限模型设计成可扩展的角色授权体系优惠券配置只是其中一个普通的权限点新增需求只是加一条配置而已。高级开发者应该有能力做“业务—技术”的翻译把产品诉求翻译成技术语言把技术约束翻译成产品听得懂的话。这样你在技术评审上才不会处于被动位置你才有能力用技术方案反过来优化业务方案。6.2 技术决策在约束条件下做选择工作中最难的其实不是“实现功能”而是在一堆约束条件下做取舍。时间、成本、人力、技术栈、团队能力每一样都是限制条件。高级开发者要有能力在约束条件下做出最合理的判断。举一个真实场景项目紧急上线数据库表设计需要支持json字段存储扩展信息这时候有两条路。一条是直接上MongoDB灵活、好用但团队没人系统用过另一条是继续用MySQL的json类型字段虽然是关系型数据库但能力足够支撑当前需求而且团队熟悉出问题时兜底能力强。这时候你选哪个正确的决定是MySQL。这不是技术洁癖而是风险意识。新技术引入是有隐性成本的学习成本、运维成本、故障排查成本、招聘成本。在没有明确收益的情况下贸然引入新技术就是在给团队挖坑。能做出这种判断的人才是真正对交付结果负责的人。6.3 带人、评审与沟通协作高级开发者的另一个身份是团队里的“技术影响力中心”。你不一定挂着管理头衔但你的一言一行都在影响团队的技术品味。代码评审是你发挥影响力的关键阵地。你在评审中关注什么团队就会重视什么。如果你只关注变量命名和代码格式团队就会把精力放在表面功夫上如果你追问事务边界、并发安全性、异常处理路径、扩展性设计团队才会真正思考更深层的设计问题。还有一点容易被忽视高级开发者的时间颗粒度决定了你的价值密度。初级开发者的时间被任务填满高级开发者必须学会把时间花在最高杠杆的事情上设计方案、评审架构、风险识别、技术规划。如果你发现自己每天都在救火、每天都在写CRUD那说明你所在的位置根本没有发挥出高级工程师应有的价值要么调整工作方式要么就得考虑换一个匹配你能力模型的团队了。7. 怎么补可执行的学习进阶路线7.1 先摆正心态八股文和工程能力是两码事搜“Java面试题”“Java八股文”的人很多这个现象很好理解因为面试要考嘛。但我特别想提醒一点背八股文能帮你过面试但救不了你的工程能力。我见过太多候选人面试时把AQS说得滚瓜烂熟到了实际项目里连一个线程池参数都定不明白。我不反对刷题背知识点面试本来就是某种程度的应试。但你要清醒地知道八股文是“点”工程能力是“网”。靠背八股文你掌握的是一堆孤立的知识点而高级开发者需要的是把这些知识点串成完整的体系。所以刷题要带着工程视角去刷这个知识点解决的是什么场景的问题如果我来实现会怎么设计还有没有更好的方案这样刷一道题胜过机械背诵十道题。7.2 一套可对照检查的能力自检清单我整理了一份自检清单你可以对着打个分看看自己离高级开发还差多少维度自检问题现在水平1-5JVM能力线上OOM能不能通过GC日志堆转储定位到具体代码并发能力能否正确设计线程池参数并预测其在高并发下的表现一致性能力面对跨系统数据不一致能否设计出可落地的对账和补偿方案框架原理能否讲清楚Spring Bean完整生命周期及循环依赖的三级缓存设计中间件能力能否在缓存穿透、击穿、雪崩场景下快速设计兜底方案设计能力能否用一个状态机模型重构复杂的业务流程代码架构能力能否独立完成一个微服务的业务域划分和接口边界设计排查能力面对线上偶发故障能否在30分钟内定位到根因软技能能否把复杂技术方案讲给产品和运营听并获得认可决策能力面对技术选型时能否在约束条件下给出风险可控的最优方案如果多数项目低于3分我建议你老老实实回到基础别急着跳槽谈薪。高级的title是靠能力撑住的不是靠面试技巧撑住的。7.3 动手实操源码、项目和复盘一个都别少学习路径这件事网上一搜一大堆我在这里只强调三个原则。第一源码是绕不开的“硬功夫”。Spring的核心是IoC和AOPJava并发的灵魂是AQSMyBatis的精华是Mapper代理这些框架的核心源码至少要精读两三遍。读源码不是通读而是带着问题和主线去读——比如读Spring源码就问你三件事Bean是怎么被创建出来的依赖是怎么注入进去的AOP是怎么织入的把这三条主线理清楚Spring源码的脉络就浮现了。第二项目是唯一能把知识变成能力的训练场。没有真实业务场景你很难真正理解数据一致性、分布式事务、性能调优这类问题。所以如果你现在手上没有好的项目我建议你自己造一个一个模拟电商的下单系统包含订单、库存、支付、积分几个模块用上RocketMQ做异步解耦、用Redis扛读流量、用ShardingSphere做分库分表、用Sentinel做流控。这个项目做完你会发现面试中被问到的那些“高级”问题你都亲自动手解决过了。第三复盘比做项目更重要。举个例子你线上遇到一次消息重复消费导致的数据重复处理完故障后花点时间深挖为什么会重复消费消费者的offset提交时机是什么幂等设计应该做在哪一层有没有更好的消息去重方案这个复盘过程就是你从“会修”到“懂根因”再到“能设计预防方案”的跃迁路径。一个认真复盘过的故障比你看一百篇技术博客都有用。说个我个人的习惯。我每隔半年会把过去半年里处理过的线上问题、做过的技术方案、踩过的坑整理成一篇笔记形成自己的“经验库”。这东西没有哪个网站能给你就是你职业生涯最宝贵的资产。等积累到一定厚度你回头看两年前的自己写的东西会有种明显的“意识迭代感”——这种成长体感比工资涨幅更让人踏实。