微服务架构在企业应用中广泛部署,技术选型中 Dubbo 和 Spring Cloud Gateway 经常被放在一起比较。实际上,它们解决不同层面的问题,本文将分析二者的核心差异,阐明各自适用场景和集成价值。
基本概念与定位
Dubbo(当前稳定版本 2.7.x/3.x)
Dubbo 是 Apache 开源的高性能 RPC 框架,专注于微服务间的远程过程调用与服务治理。

图表说明:Dubbo 采用经典的 RPC 架构模式,服务提供者将自身注册到注册中心,消费者从注册中心订阅服务,然后直接发起 RPC 调用。注册中心负责维护服务路由信息并通知消费者服务变化。
Spring Cloud Gateway(当前版本 3.x)
Spring Cloud Gateway 是基于 WebFlux 响应式编程模型构建的 API 网关组件,专注于外部请求的统一入口管理。支持 Spring Boot 3.x 和 Java 17+。

图表说明:Spring Cloud Gateway 作为系统流量的第一入口,接收所有外部 HTTP 请求,根据预定义的路由规则和过滤器链,将请求分发到不同的后端微服务。
核心功能差异
Dubbo 的核心功能
Dubbo 主要解决的是服务与服务之间的远程调用与服务治理问题:
java
// 服务提供方
@DubboService(version = "1.0.0")
public class UserServiceImpl implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Override
public User getUserById(Long id) {
log.info("获取用户信息,用户ID: {}", id);
// 实现逻辑
return new User(id, "张三", 28);
}
}
// 服务消费方
@Component
public class OrderService {
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
@DubboReference(version = "1.0.0", timeout = 3000, retries = 2)
private UserService userService;
public Order createOrder(Long userId, String productId) {
log.trace("开始处理订单创建,参数: userId={}, productId={}", userId, productId);
try {
// 直接调用远程服务,就像调用本地方法一样
User user = userService.getUserById(userId);
log.info("成功获取用户信息: {}", user);
// 处理订单逻辑
return new Order(UUID.randomUUID().toString(), user, productId);
} catch (RpcException e) {
log.error("调用用户服务失败", e);
throw new ServiceException("用户服务暂时不可用,请稍后重试");
}
}
}
Dubbo 的典型特性包括:
- 透明的 RPC 调用(像调用本地方法一样)
- 多种序列化协议支持(Hessian2、Protobuf、JSON 等)
- 丰富的负载均衡策略(随机、轮询、最少活跃调用数、一致性哈希等)
- 服务注册与发现
- 服务监控和管理
Spring Cloud Gateway 的核心功能
Spring Cloud Gateway 主要处理的是 API 流量管理与请求处理:
java
@Configuration
public class GatewayConfig {
private static final Logger log = LoggerFactory.getLogger(GatewayConfig.class);
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user_service_route", r -> r
.path("/api/users/**")
.filters(f -> f
.stripPrefix(1)
.addRequestHeader("X-Request-Source", "gateway")
.requestRateLimiter(c -> c
.setRateLimiter(redisRateLimiter())
.setKeyResolver(userKeyResolver())))
.uri("lb://user-service"))
.route("order_service_route", r -> r
.path("/api/orders/**")
.filters(f -> f
.stripPrefix(1)
.circuitBreaker(c -> c
.setName("orderServiceCircuitBreaker")
.setFallbackUri("forward:/fallback/orders")))
.uri("lb://order-service"))
.build();
}
@Bean
public RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(10, 20); // 令牌桶限流:每秒10个请求,突发20个请求
}
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getHeaders().getFirst("X-User-Id") != null ?
exchange.getRequest().getHeaders().getFirst("X-User-Id") : "anonymous");
}
}
Gateway 的典型特性包括:
- 基于 WebFlux 的响应式编程模型
- 动态路由配置
- 丰富的过滤器链(认证、限流、熔断、转换等)
- 请求/响应转换
- 与 Spring Cloud 生态无缝集成
Maven 依赖管理示例
Dubbo 依赖配置
xml
<!-- 父项目依赖管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>3.2.0</version>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 具体项目依赖 -->
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Spring Cloud Gateway 依赖配置
xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2022.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- JWT依赖 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
应用配置示例
Dubbo 服务提供者配置
yaml
# application.yml
spring:
application:
name: user-service
dubbo:
application:
name: ${spring.application.name}
qos-enable: true
qos-port: 22222
qos-accept-foreign-ip: false
protocol:
name: dubbo
port: -1
serialization: hessian2
registry:
address: nacos://localhost:8848
parameters:
namespace: public
provider:
timeout: 3000
retries: 0
delay: -1
filter: tracing
server:
port: 8081
logging:
level:
org.apache.dubbo: info
com.example.userservice: debug
Spring Cloud Gateway 配置
yaml
# application.yml
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: user_service_route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
- id: order_service_route
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: orderServiceCircuitBreaker
fallbackUri: forward:/fallback/orders
redis:
host: localhost
port: 6379
server:
port: 8080
logging:
level:
org.springframework.cloud.gateway: debug
reactor.netty: info
微服务项目架构示例
一个微服务项目中同时使用 Dubbo 和 Spring Cloud Gateway 的结构:
bash
microservice-demo/
├── api-gateway/ # Spring Cloud Gateway网关服务
├── common-api/ # 共享API接口定义
├── user-service/ # 用户服务
├── product-service/ # 商品服务
├── order-service/ # 订单服务
├── registry-center/ # 注册中心(Nacos/Zookeeper)
└── docker-compose.yml # 容器编排配置
案例分析:电商系统

场景示例
1. 模板方法模式规范订单处理流程
java
// 抽象订单处理模板
public abstract class AbstractOrderProcessor {
private static final Logger log = LoggerFactory.getLogger(AbstractOrderProcessor.class);
// 模板方法
public final OrderDTO process(Long userId, String productId, int quantity) {
log.trace("开始订单处理流程: userId={}, productId={}, quantity={}",
userId, productId, quantity);
// 1. 验证参数
validateParameters(userId, productId, quantity);
// 2. 预处理
preProcess(userId, productId, quantity);
// 3. 创建订单(具体子类实现)
Order order = createOrder(userId, productId, quantity);
// 4. 后处理
postProcess(order);
log.info("订单处理完成: orderId={}", order.getId());
return new OrderDTO(order.getId(), "订单创建成功");
}
// 抽象方法由子类实现
protected abstract Order createOrder(Long userId, String productId, int quantity);
// 钩子方法,子类可选择性覆盖
protected void validateParameters(Long userId, String productId, int quantity) {
if (userId == null || userId <= 0) {
throw new IllegalArgumentException("无效的用户ID");
}
if (productId == null || productId.isEmpty()) {
throw new IllegalArgumentException("无效的商品ID");
}
if (quantity <= 0) {
throw new IllegalArgumentException("商品数量必须大于0");
}
}
protected void preProcess(Long userId, String productId, int quantity) {
// 默认空实现
}
protected void postProcess(Order order) {
// 默认空实现
}
}
// 具体订单处理器实现
@Service
public class StandardOrderProcessor extends AbstractOrderProcessor {
private static final Logger log = LoggerFactory.getLogger(StandardOrderProcessor.class);
@DubboReference(version = "1.0.0", timeout = 3000)
private UserService userService;
@DubboReference(version = "1.0.0", timeout = 3000, check = false)
private ProductService productService;
@Autowired
private OrderRepository orderRepository;
@Autowired
private DistributedLock distributedLock;
@Autowired
private EventPublisher eventPublisher;
@Override
protected void preProcess(Long userId, String productId, int quantity) {
// 验证用户是否存在
User user = userService.getUserById(userId);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 检查商品库存
Product product = productService.getProduct(productId);
if (product == null) {
throw new BusinessException("商品不存在");
}
if (product.getStock() < quantity) {
throw new BusinessException("商品库存不足");
}
}
@Override
@Transactional
protected Order createOrder(Long userId, String productId, int quantity) {
String lockKey = "product:stock:" + productId;
try {
// 获取分布式锁
boolean locked = distributedLock.tryLock(lockKey, 10, TimeUnit.SECONDS);
if (!locked) {
throw new ConcurrentOperationException("获取商品锁失败,请稍后重试");
}
// 再次检查库存并预留
String reservationId = productService.tryReserveStock(productId, quantity);
if (reservationId == null) {
throw new BusinessException("库存预留失败");
}
// 确认库存预留
boolean confirmed = productService.confirmReservation(reservationId);
if (!confirmed) {
throw new BusinessException("确认库存预留失败");
}
// 创建订单
Order order = new Order();
order.setUserId(userId);
order.setProductId(productId);
order.setQuantity(quantity);
order.setAmount(calculateAmount(productId, quantity));
order.setStatus(OrderStatus.CREATED);
order.setCreateTime(LocalDateTime.now());
return orderRepository.save(order);
} finally {
distributedLock.unlock(lockKey);
}
}
@Override
protected void postProcess(Order order) {
// 发布订单创建事件
eventPublisher.publishOrderCreatedEvent(order);
}
private BigDecimal calculateAmount(String productId, int quantity) {
Product product = productService.getProduct(productId);
return product.getPrice().multiply(new BigDecimal(quantity));
}
}
// 订单控制器 - 只负责HTTP请求处理
@RestController
@RequestMapping("/orders")
public class OrderController {
private static final Logger log = LoggerFactory.getLogger(OrderController.class);
@Autowired
private AbstractOrderProcessor orderProcessor;
@PostMapping
public ResponseEntity<OrderDTO> createOrder(@RequestBody OrderRequest request,
@RequestHeader("X-User-Id") String userId) {
log.info("收到创建订单请求,用户ID: {}, 商品ID: {}", userId, request.getProductId());
try {
OrderDTO result = orderProcessor.process(
Long.valueOf(userId), request.getProductId(), request.getQuantity());
return ResponseEntity.ok(result);
} catch (BusinessException e) {
log.warn("业务异常: {}", e.getMessage());
return ResponseEntity.badRequest()
.body(new OrderDTO(null, e.getMessage()));
} catch (ServiceException e) {
log.error("服务异常: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(new OrderDTO(null, "服务暂时不可用,请稍后重试"));
} catch (Exception e) {
log.error("创建订单异常", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new OrderDTO(null, "系统错误,请联系客服"));
}
}
}
2. 幂等性处理机制实现
java
// 幂等性注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
String value(); // 幂等键表达式
String expireTime() default "1h"; // 幂等标记过期时间
}
// 幂等性AOP切面
@Aspect
@Component
public class IdempotentAspect {
private static final Logger log = LoggerFactory.getLogger(IdempotentAspect.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private SpelExpressionParser parser;
@Around("@annotation(idempotent)")
public Object around(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {
// 解析幂等键
String idempotentKey = resolveIdempotentKey(joinPoint, idempotent.value());
String lockKey = "idempotent:" + idempotentKey;
// 尝试获取幂等锁
Boolean isFirstRequest = redisTemplate.opsForValue().setIfAbsent(
lockKey, "PROCESSING", parseTimeToLive(idempotent.expireTime()), TimeUnit.SECONDS);
if (Boolean.FALSE.equals(isFirstRequest)) {
// 已经存在处理中的请求,检查是否有结果
Object result = redisTemplate.opsForValue().get(lockKey);
if ("PROCESSING".equals(result)) {
log.info("检测到重复请求,幂等键: {}", idempotentKey);
throw new DuplicateRequestException("请求正在处理中,请勿重复提交");
} else if (result != null) {
log.info("返回幂等请求缓存结果,幂等键: {}", idempotentKey);
return result;
}
}
try {
// 执行实际方法
Object result = joinPoint.proceed();
// 存储执行结果
redisTemplate.opsForValue().set(
lockKey, result, parseTimeToLive(idempotent.expireTime()), TimeUnit.SECONDS);
return result;
} catch (Throwable e) {
// 出现异常,清除幂等锁
redisTemplate.delete(lockKey);
throw e;
}
}
private String resolveIdempotentKey(ProceedingJoinPoint joinPoint, String expression) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);
Object[] args = joinPoint.getArgs();
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], args[i]);
}
return parser.parseExpression(expression).getValue(context, String.class);
}
private long parseTimeToLive(String expireTime) {
Pattern pattern = Pattern.compile("(\\d+)([smhd])");
Matcher matcher = pattern.matcher(expireTime);
if (matcher.matches()) {
long value = Long.parseLong(matcher.group(1));
String unit = matcher.group(2);
switch (unit) {
case "s": return value;
case "m": return value * 60;
case "h": return value * 60 * 60;
case "d": return value * 60 * 60 * 24;
default: return 3600; // 默认1小时
}
}
return 3600; // 默认1小时
}
@Bean
public SpelExpressionParser spelExpressionParser() {
return new SpelExpressionParser();
}
}
// 在ProductService接口中使用幂等注解
public interface ProductService {
// 普通查询接口
Product getProduct(String productId);
// TCC事务接口 - 添加幂等性保证
String tryReserveStock(String productId, int quantity);
@Idempotent(value = "#reservationId", expireTime = "10m")
boolean confirmReservation(String reservationId);
@Idempotent(value = "#reservationId", expireTime = "10m")
boolean cancelReservation(String reservationId);
}
3. 分布式锁实现
java
// 分布式锁接口
public interface DistributedLock {
boolean tryLock(String key, long timeout, TimeUnit unit);
void unlock(String key);
}
// 基于Redis的分布式锁实现
@Component
public class RedisDistributedLock implements DistributedLock {
private static final Logger log = LoggerFactory.getLogger(RedisDistributedLock.class);
private final RedisTemplate<String, String> redisTemplate;
private final ThreadLocal<String> lockValues = new ThreadLocal<>();
public RedisDistributedLock(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public boolean tryLock(String key, long timeout, TimeUnit unit) {
String lockKey = "lock:" + key;
String lockValue = UUID.randomUUID().toString();
Boolean success = redisTemplate.opsForValue().setIfAbsent(
lockKey, lockValue, timeout, unit);
if (Boolean.TRUE.equals(success)) {
lockValues.set(lockValue);
log.debug("获取分布式锁成功: {}", lockKey);
return true;
}
log.debug("获取分布式锁失败: {}", lockKey);
return false;
}
@Override
public void unlock(String key) {
String lockKey = "lock:" + key;
String expectedValue = lockValues.get();
if (expectedValue != null) {
// 使用Lua脚本保证原子性检查和删除
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then "
+ "return redis.call('del', KEYS[1]) else return 0 end";
Long result = redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(lockKey),
expectedValue);
if (Long.valueOf(1).equals(result)) {
log.debug("释放分布式锁成功: {}", lockKey);
} else {
log.warn("释放分布式锁失败,锁可能已过期: {}", lockKey);
}
lockValues.remove();
}
}
}
4. 多级缓存策略实现
java
// 缓存配置
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(cacheConfiguration)
.withCacheConfiguration("products",
cacheConfiguration.entryTtl(Duration.ofMinutes(30)))
.withCacheConfiguration("users",
cacheConfiguration.entryTtl(Duration.ofMinutes(60)))
.build();
}
@Bean
public CaffeineCacheManager caffeineCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.recordStats());
return cacheManager;
}
@Bean
public CompositeCache compositeCache(
CaffeineCacheManager caffeineCacheManager,
CacheManager redisCacheManager) {
return new CompositeCache(caffeineCacheManager, redisCacheManager);
}
}
// 组合缓存实现(一级本地缓存 + 二级分布式缓存)
@Component
public class CompositeCache {
private static final Logger log = LoggerFactory.getLogger(CompositeCache.class);
private final CaffeineCacheManager localCacheManager;
private final CacheManager distributedCacheManager;
public CompositeCache(CaffeineCacheManager localCacheManager, CacheManager distributedCacheManager) {
this.localCacheManager = localCacheManager;
this.distributedCacheManager = distributedCacheManager;
}
public <T> T get(String cacheName, Object key, Class<T> type, Supplier<T> valueLoader) {
String cacheKey = key.toString();
// 1. 查询本地缓存
Cache localCache = localCacheManager.getCache(cacheName);
T value = localCache != null ? localCache.get(cacheKey, type) : null;
if (value != null) {
log.debug("本地缓存命中: {}/{}", cacheName, cacheKey);
return value;
}
// 2. 查询分布式缓存
Cache distributedCache = distributedCacheManager.getCache(cacheName);
value = distributedCache != null ? distributedCache.get(cacheKey, type) : null;
if (value != null) {
log.debug("分布式缓存命中: {}/{}", cacheName, cacheKey);
// 回填本地缓存
if (localCache != null) {
localCache.put(cacheKey, value);
}
return value;
}
// 3. 查询数据源
log.debug("缓存未命中,加载数据源: {}/{}", cacheName, cacheKey);
value = valueLoader.get();
// 4. 同时更新本地缓存和分布式缓存
if (value != null) {
if (distributedCache != null) {
distributedCache.put(cacheKey, value);
}
if (localCache != null) {
localCache.put(cacheKey, value);
}
}
return value;
}
public void invalidate(String cacheName, Object key) {
String cacheKey = key.toString();
// 同时失效本地缓存和分布式缓存
Cache localCache = localCacheManager.getCache(cacheName);
if (localCache != null) {
localCache.evict(cacheKey);
}
Cache distributedCache = distributedCacheManager.getCache(cacheName);
if (distributedCache != null) {
distributedCache.evict(cacheKey);
}
log.debug("缓存已失效: {}/{}", cacheName, cacheKey);
}
}
// 在ProductService实现中使用多级缓存
@Service
public class ProductServiceImpl implements ProductService {
private static final Logger log = LoggerFactory.getLogger(ProductServiceImpl.class);
@Autowired
private ProductRepository productRepository;
@Autowired
private StockReservationRepository reservationRepository;
@Autowired
private CompositeCache compositeCache;
@Override
public Product getProduct(String productId) {
return compositeCache.get("products", productId, Product.class, () -> {
log.info("从数据库加载商品: {}", productId);
return productRepository.findById(productId)
.orElse(null);
});
}
// 数据库JPA查询方法 - 使用悲观锁
public interface ProductRepository extends JpaRepository<Product, String> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE p.id = :id")
Optional<Product> findByIdWithLock(@Param("id") String id);
}
}
5. 线程池配置与调优
java
@Configuration
public class ThreadPoolConfig {
private static final Logger log = LoggerFactory.getLogger(ThreadPoolConfig.class);
@Bean
public ThreadPoolTaskExecutor serviceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("service-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 添加线程池监控
executor.setTaskDecorator(runnable -> {
long startTime = System.currentTimeMillis();
return () -> {
try {
runnable.run();
} finally {
long executionTime = System.currentTimeMillis() - startTime;
log.debug("任务执行时间: {}ms", executionTime);
}
};
});
return executor;
}
@Bean
public ThreadPoolTaskExecutor asyncOperationExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(300);
executor.setThreadNamePrefix("async-");
// 使用丢弃最老的任务策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
return executor;
}
// 异步处理事件发布
@Bean
public AsyncEventPublisher asyncEventPublisher(ThreadPoolTaskExecutor asyncOperationExecutor) {
return new AsyncEventPublisher(asyncOperationExecutor);
}
}
// 异步事件发布器
@Component
public class AsyncEventPublisher implements EventPublisher {
private static final Logger log = LoggerFactory.getLogger(AsyncEventPublisher.class);
private final ThreadPoolTaskExecutor executor;
private final RabbitTemplate rabbitTemplate;
@Autowired
public AsyncEventPublisher(ThreadPoolTaskExecutor asyncOperationExecutor, RabbitTemplate rabbitTemplate) {
this.executor = asyncOperationExecutor;
this.rabbitTemplate = rabbitTemplate;
}
@Override
public void publishOrderCreatedEvent(Order order) {
executor.execute(() -> {
try {
OrderCreatedEvent event = new OrderCreatedEvent();
event.setOrderId(order.getId());
event.setUserId(order.getUserId());
event.setProductId(order.getProductId());
event.setQuantity(order.getQuantity());
event.setAmount(order.getAmount());
event.setCreateTime(LocalDateTime.now());
rabbitTemplate.convertAndSend("order-exchange", "order.created", event);
log.info("异步发布订单创建事件,订单ID: {}", order.getId());
} catch (Exception e) {
log.error("发布订单创建事件失败", e);
// 可以添加重试逻辑或写入本地事件表
}
});
}
}
6. 熔断详细配置和服务降级
java
@Configuration
public class ResilienceConfig {
private static final Logger log = LoggerFactory.getLogger(ResilienceConfig.class);
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(10)
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(10))
.permittedNumberOfCallsInHalfOpenState(5)
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(3))
.build())
.build());
}
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> specificCustomizer() {
return factory -> factory.configure(builder -> builder
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(20)
.failureRateThreshold(40)
.waitDurationInOpenState(Duration.ofSeconds(20))
.permittedNumberOfCallsInHalfOpenState(10)
.recordExceptions(IOException.class, TimeoutException.class)
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(5))
.build()), "userService", "productService");
}
// 服务降级处理器
@Bean
public FallbackController fallbackController() {
return new FallbackController();
}
}
// 降级处理控制器
@RestController
@RequestMapping("/fallback")
public class FallbackController {
private static final Logger log = LoggerFactory.getLogger(FallbackController.class);
@GetMapping("/users")
public ResponseEntity<Map<String, Object>> userServiceFallback() {
log.warn("用户服务降级启动");
Map<String, Object> response = new HashMap<>();
response.put("code", 503);
response.put("message", "用户服务暂时不可用,请稍后重试");
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response);
}
@GetMapping("/orders")
public ResponseEntity<Map<String, Object>> orderServiceFallback() {
log.warn("订单服务降级启动");
Map<String, Object> response = new HashMap<>();
response.put("code", 503);
response.put("message", "订单服务暂时不可用,请稍后重试");
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response);
}
@GetMapping("/products")
public ResponseEntity<Map<String, Object>> productServiceFallback() {
log.warn("商品服务降级启动");
Map<String, Object> response = new HashMap<>();
response.put("code", 503);
response.put("message", "商品服务暂时不可用,请稍后重试");
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response);
}
}
// Dubbo服务降级示例
@Configuration
public class DubboFallbackConfig {
@Bean
public UserServiceMock userServiceMock() {
return new UserServiceMock();
}
}
// 服务降级Mock实现
public class UserServiceMock implements UserService {
private static final Logger log = LoggerFactory.getLogger(UserServiceMock.class);
@Override
public User getUserById(Long id) {
log.warn("用户服务降级,返回Mock数据, userId: {}", id);
// 返回基础用户信息,避免上游服务完全失败
return new User(id, "默认用户", 0);
}
}
7. 监控指标与健康检查
java
@Configuration
public class MetricsConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config()
.commonTags("application", "order-service");
}
@Bean
public DubboMetricsCollector dubboMetricsCollector(MeterRegistry registry) {
return new DubboMetricsCollector(registry);
}
}
// Dubbo指标收集器
@Component
public class DubboMetricsCollector {
private static final Logger log = LoggerFactory.getLogger(DubboMetricsCollector.class);
private final MeterRegistry registry;
public DubboMetricsCollector(MeterRegistry registry) {
this.registry = registry;
// 注册自定义仪表盘
Gauge.builder("dubbo.services.count", this, DubboMetricsCollector::getServiceCount)
.description("Dubbo服务数量")
.register(registry);
}
private int getServiceCount() {
// 获取服务数量逻辑
return ApplicationModel.defaultModel().getServiceRepository().allProviderModels().size();
}
// 记录方法调用计数和耗时
public <T> T recordMethodMetrics(String serviceName, String methodName, Supplier<T> supplier) {
Timer.Sample sample = Timer.start(registry);
try {
T result = supplier.get();
sample.stop(Timer.builder("dubbo.method.timer")
.tag("service", serviceName)
.tag("method", methodName)
.register(registry));
registry.counter("dubbo.method.counter",
"service", serviceName,
"method", methodName,
"status", "success").increment();
return result;
} catch (Exception e) {
registry.counter("dubbo.method.counter",
"service", serviceName,
"method", methodName,
"status", "error").increment();
throw e;
}
}
}
// 健康检查接口
@RestController
@RequestMapping("/actuator/health")
public class CustomHealthCheckController {
private static final Logger log = LoggerFactory.getLogger(CustomHealthCheckController.class);
@Autowired
private HealthContributor userServiceHealthContributor;
@Autowired
private HealthContributor productServiceHealthContributor;
@Autowired
private HealthContributor databaseHealthContributor;
@GetMapping("/liveness")
public ResponseEntity<Map<String, Object>> liveness() {
// 检查应用是否活着
Map<String, Object> health = new HashMap<>();
health.put("status", "UP");
health.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(health);
}
@GetMapping("/readiness")
public ResponseEntity<Map<String, Object>> readiness() {
// 检查应用是否可以接收流量
Map<String, Object> health = new HashMap<>();
Map<String, Object> components = new HashMap<>();
Health userServiceHealth = ((HealthIndicator) userServiceHealthContributor).health();
Health productServiceHealth = ((HealthIndicator) productServiceHealthContributor).health();
Health databaseHealth = ((HealthIndicator) databaseHealthContributor).health();
components.put("userService", userServiceHealth.getStatus().getCode());
components.put("productService", productServiceHealth.getStatus().getCode());
components.put("database", databaseHealth.getStatus().getCode());
boolean isReady = userServiceHealth.getStatus() == Status.UP
&& productServiceHealth.getStatus() == Status.UP
&& databaseHealth.getStatus() == Status.UP;
health.put("status", isReady ? "UP" : "DOWN");
health.put("components", components);
health.put("timestamp", System.currentTimeMillis());
return ResponseEntity.status(isReady ? HttpStatus.OK : HttpStatus.SERVICE_UNAVAILABLE)
.body(health);
}
}
// Dubbo服务健康检查贡献者
@Component
public class DubboServiceHealthContributor implements HealthContributor, HealthIndicator {
private static final Logger log = LoggerFactory.getLogger(DubboServiceHealthContributor.class);
@DubboReference(version = "1.0.0", check = false)
private HealthCheckService healthCheckService;
@Override
public Health health() {
try {
boolean isHealthy = healthCheckService.isHealthy();
if (isHealthy) {
return Health.up().build();
} else {
return Health.down().withDetail("reason", "服务报告不健康状态").build();
}
} catch (Exception e) {
log.warn("Dubbo服务健康检查失败", e);
return Health.down(e).build();
}
}
@Override
public NamedContributor<Health> contribute() {
return NamedContributor.of("dubboService", this);
}
}
8. 数据一致性验证机制
java
// 定时对账任务
@Component
@EnableScheduling
public class DataConsistencyChecker {
private static final Logger log = LoggerFactory.getLogger(DataConsistencyChecker.class);
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductService productService;
@Autowired
private EventPublisher eventPublisher;
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
public void checkOrderAndInventoryConsistency() {
log.info("开始执行订单与库存一致性检查");
// 查询昨天的所有订单
LocalDateTime yesterday = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0);
LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
List<Order> orders = orderRepository.findByCreateTimeBetween(yesterday, today);
log.info("查询到{}条订单记录需要检查", orders.size());
Map<String, Integer> productQuantityMap = new HashMap<>();
// 统计订单中的商品数量
for (Order order : orders) {
productQuantityMap.compute(order.getProductId(), (k, v) -> {
return (v == null ? 0 : v) + order.getQuantity();
});
}
// 检查库存记录中的出库数量是否一致
for (Map.Entry<String, Integer> entry : productQuantityMap.entrySet()) {
String productId = entry.getKey();
Integer orderQuantity = entry.getValue();
try {
Integer stockDeductionQuantity = productService.getProductDeductionQuantity(
productId, yesterday, today);
if (!orderQuantity.equals(stockDeductionQuantity)) {
log.error("数据不一致:商品[{}],订单数量[{}],库存扣减数量[{}]",
productId, orderQuantity, stockDeductionQuantity);
// 发布数据不一致事件,触发人工审核或自动修复
eventPublisher.publishDataInconsistencyEvent(
productId, orderQuantity, stockDeductionQuantity);
} else {
log.info("数据一致:商品[{}],数量[{}]", productId, orderQuantity);
}
} catch (Exception e) {
log.error("检查商品[{}]数据一致性时发生错误", productId, e);
}
}
log.info("订单与库存一致性检查完成");
}
// 数据修复任务
@Transactional
public void repairInconsistentData(String productId, Integer orderQuantity, Integer stockDeductionQuantity) {
log.info("开始修复数据不一致:商品[{}]", productId);
try {
// 计算差值
int diff = orderQuantity - stockDeductionQuantity;
if (diff > 0) {
// 订单数量大于库存扣减数量,需要补扣库存
productService.manualDeductStock(productId, diff);
log.info("已补扣库存:商品[{}],数量[{}]", productId, diff);
} else if (diff < 0) {
// 库存扣减数量大于订单数量,需要恢复库存
productService.manualIncreaseStock(productId, -diff);
log.info("已恢复库存:商品[{}],数量[{}]", productId, -diff);
}
// 记录修复日志
recordRepairLog(productId, orderQuantity, stockDeductionQuantity, diff);
} catch (Exception e) {
log.error("修复数据不一致时发生错误:商品[{}]", productId, e);
throw new ServiceException("数据修复失败:" + e.getMessage());
}
}
private void recordRepairLog(String productId, Integer orderQuantity,
Integer stockDeductionQuantity, int diff) {
// 记录修复操作日志
}
}
Spring Cloud Gateway 与 Zuul 对比
特性 | Spring Cloud Gateway | Netflix Zuul 1.x |
---|---|---|
编程模型 | 响应式、非阻塞 | 阻塞式 |
性能 | 更高 | 相对较低 |
开发活跃度 | 非常活跃 | 较低(Zuul 1.x 已进入维护模式) |
Spring 集成 | 原生集成 | 需额外配置 |
WebSocket 支持 | 原生支持 | 不支持 |
动态路由 | 支持 | 有限支持 |
云原生环境部署
Kubernetes 环境中部署 Dubbo 和 Spring Cloud Gateway 的架构:

Helm chart 示例(部分):
yaml
# gateway-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
replicas: 2
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/actuator/prometheus"
prometheus.io/port: "8080"
spec:
containers:
- name: api-gateway
image: example/api-gateway:1.0.0
ports:
- containerPort: 8080
resources:
limits:
memory: "512Mi"
cpu: "500m"
env:
- name: SPRING_PROFILES_ACTIVE
value: "k8s"
- name: SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR
value: "nacos-service:8848"
- name: SPRING_REDIS_HOST
value: "redis-service"
- name: ZIPKIN_ENDPOINT
value: "http://zipkin-service:9411/api/v2/spans"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
volumeMounts:
- name: config-volume
mountPath: /app/config
volumes:
- name: config-volume
configMap:
name: gateway-config
服务治理策略对比
Dubbo 和 Spring Cloud Gateway 的服务治理策略比较:
服务治理策略 | Dubbo 实现 | Spring Cloud Gateway 实现 |
---|---|---|
熔断降级 | 使用 Sentinel 或 Hystrix 集成 | 内置 Resilience4j 或 Circuitbreaker 实现 |
限流 | 基于接口级别的限流 | 基于路由和请求属性的灵活限流 |
负载均衡 | 内置多种算法(随机、轮询等) | 需结合 Ribbon 或 LoadBalancer 实现 |
灰度发布 | 基于标签路由实现 | 基于权重或请求参数路由实现 |
分布式追踪 | 通过过滤器扩展实现 | 原生支持 Sleuth/Micrometer |
监控指标 | 通过 MetricsFilter 收集 | 通过 Actuator/Micrometer 收集 |
常见问题与排查
Dubbo 常见问题
-
服务无法发现
- 检查注册中心连接
- 验证接口版本号一致性
- 查看 provider 是否成功注册
- 排查工具:
dubbo-admin
或dubbo qos
命令
-
调用超时
- 检查 timeout 配置
- 排查 provider 性能瓶颈
- 检查网络延迟
- 排查工具:Arthas 或 JProfiler 分析性能
Gateway 常见问题
-
路由不生效
- 检查路由定义顺序
- 验证 predicate 条件
- 查看日志中的路由匹配情况
- 排查工具:开启 DEBUG 日志
-
性能问题
- 检查过滤器链复杂度
- 优化响应式编程模型
- 考虑启用响应缓存
- 排查工具:JMeter 性能测试
分布式追踪问题排查
css
[请求] -> [Gateway] -> [用户服务] -> [订单服务]
| | | |
| v v v
+---------> [Zipkin/Jaeger] <----------+
- 链路断开:检查 trace ID 和 span ID 是否正确传递
- 缺少 span:确认每个服务都正确配置了 trace 过滤器
- 延迟数据:检查追踪数据异步发送配置
总结
特性 | Dubbo | Spring Cloud Gateway |
---|---|---|
定位 | RPC 框架 | API 网关 |
通信模式 | 二进制 RPC(基于 TCP/HTTP2) | HTTP/REST |
适用场景 | 服务间高效通信 | 外部请求统一入口 |
编程模型 | 同步调用 | 响应式异步 |
性能特点 | 高吞吐、低延迟 | 灵活路由、动态配置 |
生态系统 | Apache Dubbo 生态 | Spring Cloud 生态 |
序列化方式 | 多协议(Hessian2/Protobuf/JSON 等) | JSON/XML 等 HTTP 格式 |
服务治理 | 内置丰富治理功能 | 需与其他组件配合 |
云原生适配 | 逐步完善中 | 原生支持较好 |
分布式事务 | 需结合 TCC/SAGA 模式 | 需结合事务协调服务 |
事件驱动支持 | 需外部集成消息队列 | 结合 Spring Cloud Stream |
安全能力 | 需定制扩展实现 | 原生过滤器链支持 |
最佳部署位置 | 微服务内部通信 | 系统边界和微服务前端 |