缓存是救命稻草但用错了就是毒药。很多团队以为只要加上Redis就能解决一切性能问题结果缓存击穿、缓存雪崩、缓存与数据库数据不一致这些坑一个接一个。实际上合理的缓存策略能让API响应时间从秒级降到毫秒级但关键在于分层设计。第一层是本地缓存比如Caffeine或Guava Cache它们直接在应用进程内存储热数据访问速度最快但容量受限且多实例间需要同步。第二层是分布式缓存如Redis或Memcached用于存储跨实例共享的高频数据。一个典型的优化场景是商品详情页将商品基本信息、库存、评价等按不同维度缓存并设置合理的过期时间。热点数据必须做本地缓存兜底因为一旦某个商品突然爆火大量的请求会瞬间涌入Redis如果没有本地缓存层作为屏障Redis连接池会迅速耗尽数据库直接被压垮。数据库查询往往是API性能的最大瓶颈而索引优化是最基础却最容易被忽视的手段。很多开发者在建表时随手加几个索引然后在慢查询日志里痛苦的找原因。索引的选择性直接决定了查询效率比如一个性别字段只有“男”和“女”两种值区分度极低加索引反而可能比全表扫描更慢。正确的做法是先分析业务查询模式为WHERE、JOIN、ORDER BY涉及的字段建立复合索引并注意索引字段的顺序。例如查询某个分类下最近上架的商品应该先放分类ID再放上架时间这样数据库能快速定位到目标数据块。避免使用SELECT 也是提升性能的捷径因为每次查询只返回需要的字段可以减少磁盘I/O和网络传输量。一次性能优化实战中将某个统计报表API的查询从全字段扫描改为只取5个关键字段配合覆盖索引响应时间从800ms降到了40ms。异步处理不是银弹但用对场景能实现数量级的性能提升。很多API之所以响应慢是因为在请求处理过程中做了大量不必要同步等待。比如用户下单成功后立即发送邮件通知和短信通知这些操作完全可以异步执行。将非关键路径上的耗时操作异步化能立刻释放线程资源让API的吞吐量翻倍。具体实现上可以使用消息队列如RabbitMQ或Kafka将通知、日志记录、数据清洗等任务放入队列由消费端在后台慢慢处理。对于写入操作还可以采用批量提交技术将多次小写入合并成一次大写入减少数据库事务开销。有一个真实案例某API每秒接收上万条埋点数据逐个插入数据库导致CPU使用率飙升到90%改为每100条批量插入后CPU使用率降到20%API响应时间从200ms降到5ms。连接池的配置参数经常被忽视但它直接影响API的并发处理能力。默认的数据库连接池设置往往过于保守比如HikariCP默认的maximumPoolSize是10这在高并发场景下瞬间就会成为瓶颈。连接池的核心目标不是要造大池子而是让每个连接都被高效复用。配置过大反而会带来副作用比如数据库服务器需要维护更多的空闲连接消耗内存和CPU。正确的做法是根据API的TP99响应时间和并发线程数来计算合理的大小。一个经验公式是连接数 线程数 × (1 阻塞因子)。如果API的平均响应时间是50ms其中30ms是在等待数据库查询结果那么阻塞因子就是0.6假设有20个工作线程连接数配置为32左右比较合理。动态调整连接池大小才是高级玩法利用监控数据自动扩缩容可以在业务高峰时自动增加连接数低谷时减少资源消耗。数据压缩是一把双刃剑用得好能显著减少网络传输时间用不好反而增加CPU负担。对于文本类数据如JSON、XML响应体启用Gzip压缩通常能减少60%-80%的传输数据量。在带宽紧张的场景下压缩带来的收益远超CPU的额外开销。但需要注意的是对于已经压缩过的数据如图片、视频或者非常小的响应体小于1KB再压缩就是画蛇添足。开启压缩时要合理设置压缩级别默认级别通常已经足够过高的压缩级别会在服务端消耗大量CPU而节省的带宽却微乎其微。除了传输层面的压缩还可以考虑数据结构的精简比如去掉多余的字段、使用更紧凑的编码格式如Protocol Buffers替代JSON这样从源头上减少数据量。一个金融API在优化时将响应体中所有数值字段从字符串改为整数类型字段名从完整单词缩写为单个字母再配合Gzip压缩数据传输量减少了85%API整体响应速度提升了3倍。API的端点设计本身对性能有深远影响。很多人只关注代码层面的优化却忽略了接口粒度的合理性。粗粒度接口虽然减少了请求次数但传输了大量不需要的数据细粒度接口虽然按需返回但频繁的HTTP连接开销也不容忽视。最优解是采用GraphQL或者自定义的字段选择器让客户端精确控制返回内容。例如设计一个用户信息API允许客户端通过参数指定返回字段如/api/v1/user/1001?fieldsid,name,avatar这样可以避免每次返回所有字段。另外分页是API设计的必备手段但传统的OFFSET分页在数据量大时性能急剧下降因为数据库需要扫描前面所有的行。更高效的方案是基于游标的分页例如使用上一页最后一条记录的ID作为查询条件这样每次查询都可以直接走索引无论翻到第几页响应时间都保持稳定。某社交平台的消息列表API采用游标分页后即使数据量达到千万级别每页查询时间依然能控制在10ms以内。代码层面的微优化往往能产生意想不到的累积效应。比如频繁的字符串拼接在Java中会创建大量临时对象导致GC压力增大。使用StringBuilder代替操作符在循环中能减少90%的对象创建。另一个常见问题是不必要的装箱拆箱操作在计算密集型API中大量使用Integer和Long对象而不是基本类型int和long会让性能下降30%以上。避免在热点路径中使用正则表达式因为它们通常需要编译和复杂的状态机匹配一个简单的字符串indexOf方法性能是正则的10倍。此外要注意异常处理的性能开销不要用异常来控制业务逻辑流程因为异常对象的创建和栈填充成本很高。正确做法是预先判断条件避免进入异常分支。在一次API优化项目中仅仅是修复了循环中的字符串拼接和异常滥用问题API的TPS就从1200提升到了1800。监控和压测是性能优化的眼睛和耳朵没有它们所有优化都是盲人摸象。在优化之前必须先建立完善的性能基线包括平均响应时间、TP99、TP999、吞吐量、错误率等指标。使用APM工具如SkyWalking或Pinpoint可以精确追踪每个API调用在各个环节的耗时分布快速定位瓶颈点。例如通过监控发现某个API的数据库执行时间只占20%而网络I/O等待占60%那就应该优先优化数据传输而不是数据库查询。压测不是一次性工作而是贯穿整个优化过程的持续活动。每次代码变更后都应该进行对比压测验证优化效果。压测时要注意模拟真实用户行为包括用户思考时间、请求分布、并发模型等。很多团队在压测时只关注平均响应时间却忽略了长尾请求导致上线后TP999严重恶化。正确的做法是设置性能红线比如TP99必须小于200ms任何导致红线突破的变更都应被回滚。