去年双十一那几天我们一个跑营销触达的服务直接慢成狗老板在群里发飙让我赶紧查。我盯着日志看了半天发现根本不是什么高深问题全是连接没复用、请求没合并、同步阻塞这些低级毛病。折腾了两天把性能拉回来之后我专门整理了一份优化清单今天拿出来分享一下。我用的是个微APIEyun这套体系下面这些点其实换哪家API都通用关键是思路。一、为什么调用效率这么重要很多人觉得API调一下几百毫秒无所谓但量一上来就崩。假设你一秒要发500条消息单次请求300ms串行跑得150秒才能跑完用户早跑了。效率问题往往是积累出来的单独看每个点都不大叠一起就是灾难。我下面讲的5个点都是实战中真真切切踩过的。二、连接池复用别每次都新建连接最早我写代码就是 requests.get 一把梭每次请求都走一遍TCP握手TLS握手本地测试根本感觉不到上量之后才发现光握手就吃掉一两百毫秒。正确做法是用 requests.Session 复用连接底层会保持keep-alive连续请求同一个host能省掉重复握手开销。如果用aiohttp它的ClientSession也是同理。实测在同一批1000次调用里不用Session要40多秒用Session能压到15秒以内提升非常明显。注意事项Session要全局复用别每次new但要注意线程安全多线程场景下要么加锁要么用连接池。三、批量合并能合并的别拆开发有些API天然支持批量比如Eyun 的群发接口可以一次传多个接收人但很多人图省事还是循环单条发这是纯浪费。我遇到过一个同事给1000个客户发通知循环调了1000次单发接口服务直接卡死。改成批量接口一次发完耗时从几十秒降到两三秒。除了发送查询类接口也要看有没有批量能力比如获取多个群成员信息能一次查完就别for循环。注意事项批量接口一般有数量上限比如一次最多50个超过要分批另外批量失败要处理部分成功的场景别一条失败全批回滚。四、异步化别同步干等同步调用是性能杀手特别是调用第三方API你不知道对面什么时候返回干等就是浪费线程。对于IO密集的场景我用asyncio改成协程并发拉起多个请求同时等待整体吞吐能翻几倍。如果业务复杂不想动异步改造那就上消息队列把API调用丢到队列里worker消费主流程不阻塞。下面是我常用的连接池异步调用组合效果挺稳import asyncio import aiohttp async def batch_send(messages, semaphore): 批量并发发送semaphore控制并发上限 async with aiohttp.ClientSession() as session: async def send_one(msg): async with semaphore: async with session.post( https://api.example.com/send, jsonmsg ) as resp: return await resp.json() return await asyncio.gather(*[send_one(m) for m in messages]) # 并发上限设50避免压垮对端 sem asyncio.Semaphore(50) result asyncio.run(batch_send(msg_list, sem))注意事项并发别开太猛否则触发限流反而更慢asyncio和同步代码混用要小心别在异步函数里调阻塞调用。五、缓存优化能不调就不调有些数据基本不变比如联系人信息、群成员列表、用户标签每次都调API拉一遍纯属浪费。我的做法是本地缓存Redis或内存联系人信息缓存几小时群成员列表缓存十几分钟命中率一般能到80%以上。失效策略用TTL主动失效数据变更时通过回调刷新缓存。有个坑要提醒下缓存别缓存太久特别是头像URL这种会过期的缓存太久用的时候全是404。实测加了缓存之后QPS能顶到原来的3-4倍因为大量请求直接走缓存了。注意事项缓存要做穿透保护查不到的也别每次都打API可以用空值缓存短时间。六、智能限流别让对端把你封了调得太猛触发风控是另一种低效我之前就因为没做限流IP被临时封了半小时整个服务瘫掉。限流我推荐令牌桶算法控制每秒最大请求数同时允许一定突发。Eyun 这类API一般有自己的QPS限制你的限流值要设得比它低一点留个余量。import time class TokenBucket: def __init__(self, rate, capacity): self.rate rate # 每秒补充令牌数 self.capacity capacity # 桶容量 self.tokens capacity self.last_time time.time() def acquire(self): now time.time() self.tokens min( self.capacity, self.tokens (now - self.last_time) * self.rate ) self.last_time now if self.tokens 1: self.tokens - 1 return True return False注意事项限流要做在调用入口统一拦截分布式场景要用Redis实现共享限流单机限流在多实例下不准。七、优化前后性能对比优化项优化前优化后提升幅度连接复用40s/1000次15s/1000次~62%批量合并1000次请求20次请求95%请求量异步化串行150s并发15s~90%缓存优化QPS 200QPS 8004倍智能限流频繁封禁稳定运行可用性提升八、几点心得先测量再优化别凭感觉改代码先把耗时打点埋好找出真正的瓶颈再动手。优化要循序渐进一次改一个点跑数据对比不然出问题都不知道是哪个改动引入的。别过度优化业务量没那么大的时候简单方案够用就行引入复杂的异步框架维护成本很高。监控是底线调用量、成功率、延迟分布这些指标要实时可见出问题第一时间能发现。关注对端的限制API文档里的QPS限制、批量上限都是硬约束按这个设计自己的调用策略。写这么多其实就是想说效率优化没有银弹都是一个个细节扣出来的。把这几个点检查一遍大部分性能问题都能解决大半。更详细的接口参数和限流规则可以参考 Eyun开发文档文档里有具体的QPS限制和最佳实践说明做优化之前先看一遍能少走不少弯路。