拆得越细,通信成本越高
微服务把一个大应用拆成多个小模块,各自独立部署、独立运行。听起来很美,但拆得越细,服务之间调用就越频繁。比如用户下单这个操作,可能要经过订单服务、库存服务、支付服务、通知服务,每个服务都得远程调用一次。本来在单体架构里是内存调用的事,现在全变成了网络请求,延迟自然就上去了。
你点个外卖,从提交订单到支付成功,后台可能已经跑了五六次跨服务通信。如果每次通信耗时 50ms,加起来就是 300ms 起步。用户虽然感觉不到明显卡顿,但在高并发场景下,这点延迟会被放大,甚至拖垮整个系统。
减少远程调用次数
最直接的办法是减少不必要的远程调用。比如前端需要展示用户信息和最近三笔订单,传统做法是先调用户服务,再循环调订单服务三次。其实可以设计一个聚合接口,由网关层统一拉取数据,一次返回,避免“N+1 查询”问题。
类似地,有些校验逻辑原本放在下游服务,上游每次都得先查一遍。其实可以把这些高频读的数据缓存到本地,比如用 Redis 存一份用户状态,更新时通过消息队列异步同步。虽然会有一点延迟,但换来的是响应速度的大幅提升。
优化服务间通信方式
默认用 HTTP/JSON 的 REST 调用虽然通用,但开销不小。头部信息多,序列化反序列化也费时间。换成 gRPC + Protobuf 后,同样的接口性能能提升一倍以上。Protobuf 二进制编码体积小,序列化快,gRPC 还支持 HTTP/2 多路复用,避免了 TCP 握手的开销。
service OrderService {
rpc GetOrder (OrderRequest) returns (OrderResponse);
}
message OrderRequest {
string order_id = 1;
}
message OrderResponse {
string status = 1;
double amount = 2;
}这种定义方式比 JSON 接口更紧凑,传输效率更高,特别适合内部服务之间的高频调用。
合理使用异步处理
不是所有操作都需要实时响应。比如用户注册后发欢迎邮件、记录操作日志、触发风控检查,这些都可以扔进消息队列异步执行。主流程只负责核心逻辑,完成就立刻返回,不被下游拖慢。
像 Kafka、RabbitMQ 这类工具,能把原本串行的调用变成并行处理。用户提交订单后,系统只要保证消息发出去就行,后续服务各忙各的,既降低了耦合,又减少了等待时间。
部署拓扑也要讲究
服务部署的位置直接影响网络延迟。两个服务如果跨地域部署,哪怕代码再优化,物理距离决定的光速延迟没法突破。尽量把高频互调的服务放在同一个可用区,甚至同一台宿主机内,通过 Docker 网络直连,延迟能压到毫秒以内。
比如订单服务和库存服务总是成对出现,干脆就把它们部署在同一个集群里。配合服务网格(如 Istio)做智能路由,还能自动避开高延迟节点,进一步提升稳定性。
监控真实延迟数据
别靠猜,要用数据说话。接入链路追踪系统,比如 Jaeger 或 SkyWalking,能清楚看到每一次请求经过了哪些服务,每一段花了多少时间。有时候你以为是数据库慢,其实是某个服务在序列化时卡住了。
有个团队发现下单超时,查了一圈数据库、网络都没问题,最后发现是某个服务返回的 JSON 数据太大,序列化耗时超过 200ms。改成分页返回后,整体延迟下降了 60%。没有监控,这种问题很难定位。