尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

微服务设计里常见的反模式

微服务设计里常见的反模式 微服务设计里常见的反模式Spring Cloud 中的网关、事务和配置中心分别解决不同问题。反模式通常不是“用了某个组件”而是把组件放到不适合的调用路径或把局部机制当成完整业务保证。判断时要结合线程模型、一致性要求与配置更新频率。网关黑洞在 Spring Cloud Gateway 响应式链条中混入同步 I/OSpring Cloud Gateway 基于 Spring WebFlux 和 Reactor Netty。EventLoop 线程应保持可推进长时间同步阻塞会影响分配到同一线程的其他连接。因此不要在GlobalFilter中直接调用同步 Redis Client 或 JDBC。一次慢调用会占住当前 EventLoop影响范围取决于线程与连接分配不能凭一段代码直接推导吞吐损失。使用非阻塞客户端或明确隔离同步调用Reactive Redis Template / Lettuce 可以让这段 I/O 接入响应式链路。暂时无法改造的同步服务可调度到有上限的专用执行器但线程切换不会增加下游容量仍要设置超时、并发和拒绝策略。下面示例演示异步取出主体标识。网关应先移除客户端伪造的身份头下游也要验证请求确实来自受信网关或采用可验证令牌仅添加X-Authenticated-Subject不能建立完整信任链。不要把完整用户 JSON 放进请求头。Component public class ReactiveAuthFilter implements GlobalFilter, Ordered { Autowired private ReactiveStringRedisTemplate reactiveRedisTemplate; Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token exchange.getRequest().getHeaders().getFirst(X-Auth-Token); if (StringUtils.isEmpty(token)) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } // 正确使用非阻塞响应式 Flux/Mono 链式调用 return reactiveRedisTemplate.opsForValue().get(token: token) .switchIfEmpty(Mono.error(new UnauthorizedException(Token Expired))) .flatMap(subjectId - { // 仅传递必要的主体标识并覆盖客户端同名头。 ServerHttpRequest mutatedRequest exchange.getRequest().mutate() .headers(headers - { headers.remove(X-Authenticated-Subject); headers.set(X-Authenticated-Subject, subjectId); }) .build(); return chain.filter(exchange.mutate().request(mutatedRequest).build()); }); } Override public int getOrder() { return -100; } }分布式事务泛滥跨微服务强行使用 RPC Seata AT 模式包揽一切跨服务事务会延长资源持有时间并把多个依赖的失败绑在一起。是否使用 Seata AT、TCC、Saga 或事务消息取决于业务不变量、补偿可能性和团队运维能力。支付、库存等场景不能笼统“降级为最终一致性”必须先定义哪些状态允许暂时不同、用户会看到什么、如何对账。[Order Service] ──(Lock Order Row)── [Inventory Service] ──(Lock SKU Row)── [Point Service (Slow)] │ │ ▼ ▼ 数据库连接卡死 锁等待超时报错 (Lock Wait Timeout)按业务语义选择事务与消息事务消息适合本地事务与事件发布需要一致的场景消费方仍要处理重复、顺序和补偿。Saga 需要为每一步定义补偿并不适用于所有不可逆动作。下面 RocketMQ 片段只展示发送入口完整实现还需要本地事务监听、事务状态回查、幂等消费与对账。Service public class OrderApplicationService { Autowired private RocketMQTemplate rocketMQTemplate; public void createOrder(OrderDTO orderDTO) { // 1. 本地数据库事务仅处理订单生成 String transactionId UUID.randomUUID().toString(); // 2. 发送 RocketMQ 半事务消息 (Half Message) rocketMQTemplate.sendMessageInTransaction( order-transaction-group, order-created-topic, MessageBuilder.withPayload(orderDTO).setHeader(TX_ID, transactionId).build(), orderDTO ); } }配置中心滥用把 Nacos/Apollo 当作本地 High-Frequency Cache配置中心用于分发版本化配置不适合作为每次请求都查询的业务缓存。监听回调也不应执行无上限工作解析失败、更新并发和旧快照保留都需要明确处理。读取经过验证的本地快照应用在本地读取当前配置快照更新时先解析与校验成功后再原子替换。RefreshScope会在刷新时重建代理目标但不自动保证配置对象不可变或只刷新一次。下方代码只是属性注入示例正式配置还应有范围校验、更新日志和失败时继续使用旧快照的策略。Component RefreshScope // 刷新行为取决于配置事件与 Spring Cloud 实现 public class DynamicFeatureConfig { Value(${feature.max.retry.count:3}) private int maxRetryCount; // 暴露只读 getter避免任何写操作与复杂重构逻辑 public int getMaxRetryCount() { return maxRetryCount; } }微服务健康度审查 Checklist先检查 Gateway 过滤器是否存在同步 Redis、JDBC 或文件调用并用 BlockHound、线程转储或受控延迟验证。OpenFeign 超时依据上游预算和总体截止时间设置不使用无限等待也不复制通用秒数。再审查跨服务事务持有哪些锁、如何补偿以及依赖变慢时连接如何释放。配置中心则验证错误配置、重复更新和回滚确认请求只读本地已校验快照。每个反模式都有适用条件和替代成本评审结论应附上当前版本、负载与失败测试而不是仅凭注解或依赖名称判断。
返回列表