微服务架构设计与实践指南
深入探讨微服务架构的设计原则、实现模式和最佳实践,从单体应用到微服务的完整转型指南
2025年9月18日
DocsLib Team
微服务架构设计分布式系统Spring Cloud服务治理
微服务架构设计与实践指南
微服务架构是一种将单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,并使用轻量级机制(通常是HTTP API)进行通信。本文将深入探讨微服务架构的设计原则、实现模式和最佳实践。
1. 微服务架构概述
1.1 什么是微服务
微服务架构是一种架构风格,它将应用程序构建为一组松散耦合的服务。每个服务:
- 独立部署:可以独立开发、测试和部署
- 业务导向:围绕业务能力组织
- 去中心化:去中心化的数据管理和治理
- 故障隔离:一个服务的故障不会影响整个系统
- 技术多样性:可以使用不同的编程语言和数据库
1.2 微服务 vs 单体架构
单体架构 (Monolithic):
┌─────────────────────────────────┐
│ 单体应用 │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │用户 │ │订单 │ │支付 │ │
│ │管理 │ │管理 │ │管理 │ │
│ └─────┘ └─────┘ └─────┘ │
│ 共享数据库 │
└─────────────────────────────────┘
微服务架构 (Microservices):
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 用户服务 │ │ 订单服务 │ │ 支付服务 │
│ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │
│ │ API │ │ │ │ API │ │ │ │ API │ │
│ └─────┘ │ │ └─────┘ │ │ └─────┘ │
│ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │
│ │ DB │ │ │ │ DB │ │ │ │ DB │ │
│ └─────┘ │ │ └─────┘ │ │ └─────┘ │
└─────────┘ └─────────┘ └─────────┘
1.3 微服务的优势与挑战
优势
- 技术多样性:每个服务可以选择最适合的技术栈
- 独立部署:加快开发和部署速度
- 故障隔离:提高系统整体可用性
- 团队自治:小团队可以独立负责特定服务
- 可扩展性:可以针对特定服务进行扩展
挑战
- 分布式系统复杂性:网络延迟、故障处理
- 数据一致性:分布式事务管理
- 服务间通信:API设计和版本管理
- 运维复杂性:监控、日志、部署管理
- 测试复杂性:集成测试和端到端测试
2. 微服务设计原则
2.1 单一职责原则
每个微服务应该有明确的业务边界和职责。
// 用户服务 - 只负责用户相关操作
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
/**
* 获取用户信息
*/
@GetMapping("/{userId}")
public ResponseEntity<User> getUser(@PathVariable Long userId) {
User user = userService.findById(userId);
return ResponseEntity.ok(user);
}
/**
* 创建用户
*/
@PostMapping
public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {
User user = userService.createUser(request);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
/**
* 更新用户信息
*/
@PutMapping("/{userId}")
public ResponseEntity<User> updateUser(
@PathVariable Long userId,
@RequestBody UpdateUserRequest request) {
User user = userService.updateUser(userId, request);
return ResponseEntity.ok(user);
}
}
// 订单服务 - 只负责订单相关操作
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 创建订单
*/
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
Order order = orderService.createOrder(request);
return ResponseEntity.status(HttpStatus.CREATED).body(order);
}
/**
* 获取用户订单列表
*/
@GetMapping("/user/{userId}")
public ResponseEntity<List<Order>> getUserOrders(@PathVariable Long userId) {
List<Order> orders = orderService.findByUserId(userId);
return ResponseEntity.ok(orders);
}
}
2.2 数据库分离
每个微服务应该拥有自己的数据库,避免共享数据库。
# docker-compose.yml
version: '3.8'
services:
# 用户服务数据库
user-db:
image: mysql:8.0
environment:
MYSQL_DATABASE: user_service
MYSQL_ROOT_PASSWORD: password
ports:
- "3306:3306"
volumes:
- user_data:/var/lib/mysql
# 订单服务数据库
order-db:
image: mysql:8.0
environment:
MYSQL_DATABASE: order_service
MYSQL_ROOT_PASSWORD: password
ports:
- "3307:3306"
volumes:
- order_data:/var/lib/mysql
# 支付服务数据库
payment-db:
image: postgresql:13
environment:
POSTGRES_DB: payment_service
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- payment_data:/var/lib/postgresql/data
volumes:
user_data:
order_data:
payment_data:
2.3 API优先设计
在开发服务之前,先设计API接口。
# user-service-api.yaml
openapi: 3.0.0
info:
title: User Service API
version: 1.0.0
description: 用户服务API文档
paths:
/api/users:
post:
summary: 创建用户
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: 用户创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: 请求参数错误
/api/users/{userId}:
get:
summary: 获取用户信息
parameters:
- name: userId
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: 成功获取用户信息
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: 用户不存在
components:
schemas:
User:
type: object
properties:
id:
type: integer
format: int64
username:
type: string
email:
type: string
firstName:
type: string
lastName:
type: string
createdAt:
type: string
format: date-time
CreateUserRequest:
type: object
required:
- username
- email
- password
properties:
username:
type: string
minLength: 3
maxLength: 50
email:
type: string
format: email
password:
type: string
minLength: 8
firstName:
type: string
lastName:
type: string
3. 服务间通信
3.1 同步通信 - REST API
// 订单服务调用用户服务
@Service
public class OrderService {
@Autowired
private UserServiceClient userServiceClient;
@Autowired
private OrderRepository orderRepository;
/**
* 创建订单
*/
public Order createOrder(CreateOrderRequest request) {
// 验证用户是否存在
User user = userServiceClient.getUser(request.getUserId());
if (user == null) {
throw new UserNotFoundException("User not found: " + request.getUserId());
}
// 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setStatus(OrderStatus.PENDING);
order.setCreatedAt(LocalDateTime.now());
return orderRepository.save(order);
}
}
// 用户服务客户端
@Component
public class UserServiceClient {
@Autowired
private RestTemplate restTemplate;
@Value("${services.user.url}")
private String userServiceUrl;
/**
* 获取用户信息
*/
public User getUser(Long userId) {
try {
String url = userServiceUrl + "/api/users/" + userId;
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
return response.getBody();
} catch (HttpClientErrorException.NotFound e) {
return null;
} catch (Exception e) {
throw new ServiceCommunicationException("Failed to get user: " + userId, e);
}
}
}
// 配置RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 设置超时时间
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000);
factory.setReadTimeout(10000);
restTemplate.setRequestFactory(factory);
// 添加错误处理
restTemplate.setErrorHandler(new CustomResponseErrorHandler());
return restTemplate;
}
}
3.2 异步通信 - 消息队列
// 使用RabbitMQ进行异步通信
@Configuration
@EnableRabbit
public class RabbitConfig {
public static final String ORDER_EXCHANGE = "order.exchange";
public static final String ORDER_CREATED_QUEUE = "order.created.queue";
public static final String ORDER_CREATED_ROUTING_KEY = "order.created";
@Bean
public TopicExchange orderExchange() {
return new TopicExchange(ORDER_EXCHANGE);
}
@Bean
public Queue orderCreatedQueue() {
return QueueBuilder.durable(ORDER_CREATED_QUEUE).build();
}
@Bean
public Binding orderCreatedBinding() {
return BindingBuilder
.bind(orderCreatedQueue())
.to(orderExchange())
.with(ORDER_CREATED_ROUTING_KEY);
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(new Jackson2JsonMessageConverter());
return template;
}
}
// 订单服务 - 发布事件
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 创建订单并发布事件
*/
public Order createOrder(CreateOrderRequest request) {
// 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setStatus(OrderStatus.PENDING);
order.setCreatedAt(LocalDateTime.now());
Order savedOrder = orderRepository.save(order);
// 发布订单创建事件
OrderCreatedEvent event = new OrderCreatedEvent(
savedOrder.getId(),
savedOrder.getUserId(),
savedOrder.getProductId(),
savedOrder.getQuantity(),
savedOrder.getCreatedAt()
);
rabbitTemplate.convertAndSend(
RabbitConfig.ORDER_EXCHANGE,
RabbitConfig.ORDER_CREATED_ROUTING_KEY,
event
);
return savedOrder;
}
}
// 库存服务 - 监听事件
@Component
public class InventoryEventListener {
@Autowired
private InventoryService inventoryService;
/**
* 处理订单创建事件
*/
@RabbitListener(queues = RabbitConfig.ORDER_CREATED_QUEUE)
public void handleOrderCreated(OrderCreatedEvent event) {
try {
// 减少库存
inventoryService.decreaseStock(event.getProductId(), event.getQuantity());
log.info("Successfully decreased stock for product: {} by quantity: {}",
event.getProductId(), event.getQuantity());
} catch (InsufficientStockException e) {
log.error("Insufficient stock for product: {}", event.getProductId());
// 发布库存不足事件,触发订单取消
publishInsufficientStockEvent(event);
} catch (Exception e) {
log.error("Failed to process order created event", e);
// 重试机制或死信队列处理
}
}
}
// 事件对象
public class OrderCreatedEvent {
private Long orderId;
private Long userId;
private Long productId;
private Integer quantity;
private LocalDateTime createdAt;
// 构造函数、getter、setter
}
3.3 服务发现
// 使用Spring Cloud Eureka进行服务发现
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
// eureka-server配置
# application.yml
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
// 微服务注册到Eureka
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// 微服务配置
# application.yml
spring:
application:
name: user-service
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
// 使用Feign进行服务调用
@FeignClient(name = "user-service")
public interface UserServiceClient {
@GetMapping("/api/users/{userId}")
User getUser(@PathVariable("userId") Long userId);
@PostMapping("/api/users")
User createUser(@RequestBody CreateUserRequest request);
}
// 启用Feign
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
4. 数据管理
4.1 分布式事务
Saga模式
// 订单处理Saga
@Component
public class OrderProcessingSaga {
@Autowired
private OrderService orderService;
@Autowired
private PaymentService paymentService;
@Autowired
private InventoryService inventoryService;
@Autowired
private NotificationService notificationService;
/**
* 处理订单创建的Saga流程
*/
public void processOrder(CreateOrderRequest request) {
SagaTransaction saga = new SagaTransaction();
try {
// 步骤1:创建订单
Order order = orderService.createOrder(request);
saga.addCompensation(() -> orderService.cancelOrder(order.getId()));
// 步骤2:减少库存
inventoryService.reserveStock(request.getProductId(), request.getQuantity());
saga.addCompensation(() -> inventoryService.releaseStock(request.getProductId(), request.getQuantity()));
// 步骤3:处理支付
Payment payment = paymentService.processPayment(order.getId(), request.getPaymentInfo());
saga.addCompensation(() -> paymentService.refund(payment.getId()));
// 步骤4:确认订单
orderService.confirmOrder(order.getId());
// 步骤5:发送通知
notificationService.sendOrderConfirmation(order.getUserId(), order.getId());
log.info("Order processed successfully: {}", order.getId());
} catch (Exception e) {
log.error("Order processing failed, executing compensation", e);
saga.compensate();
throw new OrderProcessingException("Failed to process order", e);
}
}
}
// Saga事务管理器
public class SagaTransaction {
private final List<Runnable> compensations = new ArrayList<>();
public void addCompensation(Runnable compensation) {
compensations.add(0, compensation); // 逆序添加
}
public void compensate() {
for (Runnable compensation : compensations) {
try {
compensation.run();
} catch (Exception e) {
log.error("Compensation failed", e);
}
}
}
}
事件溯源模式
// 事件存储
@Entity
@Table(name = "event_store")
public class EventStore {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "aggregate_id")
private String aggregateId;
@Column(name = "event_type")
private String eventType;
@Column(name = "event_data", columnDefinition = "TEXT")
private String eventData;
@Column(name = "version")
private Long version;
@Column(name = "created_at")
private LocalDateTime createdAt;
// getter、setter
}
// 事件
public abstract class DomainEvent {
private final String aggregateId;
private final LocalDateTime occurredAt;
protected DomainEvent(String aggregateId) {
this.aggregateId = aggregateId;
this.occurredAt = LocalDateTime.now();
}
// getter
}
public class OrderCreatedEvent extends DomainEvent {
private final Long userId;
private final Long productId;
private final Integer quantity;
private final BigDecimal amount;
public OrderCreatedEvent(String orderId, Long userId, Long productId, Integer quantity, BigDecimal amount) {
super(orderId);
this.userId = userId;
this.productId = productId;
this.quantity = quantity;
this.amount = amount;
}
// getter
}
// 聚合根
public class OrderAggregate {
private String id;
private Long userId;
private OrderStatus status;
private List<OrderItem> items;
private BigDecimal totalAmount;
private Long version;
private final List<DomainEvent> uncommittedEvents = new ArrayList<>();
/**
* 创建订单
*/
public static OrderAggregate createOrder(String orderId, Long userId, List<OrderItem> items) {
OrderAggregate order = new OrderAggregate();
order.id = orderId;
order.userId = userId;
order.items = items;
order.status = OrderStatus.PENDING;
order.totalAmount = items.stream()
.map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
order.version = 0L;
// 添加事件
order.addEvent(new OrderCreatedEvent(
orderId, userId,
items.get(0).getProductId(),
items.get(0).getQuantity(),
order.totalAmount
));
return order;
}
/**
* 确认订单
*/
public void confirmOrder() {
if (this.status != OrderStatus.PENDING) {
throw new IllegalStateException("Order can only be confirmed when pending");
}
this.status = OrderStatus.CONFIRMED;
this.addEvent(new OrderConfirmedEvent(this.id));
}
private void addEvent(DomainEvent event) {
this.uncommittedEvents.add(event);
this.version++;
}
public List<DomainEvent> getUncommittedEvents() {
return new ArrayList<>(uncommittedEvents);
}
public void markEventsAsCommitted() {
uncommittedEvents.clear();
}
}
// 事件存储仓库
@Repository
public class EventStoreRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private ObjectMapper objectMapper;
/**
* 保存事件
*/
public void saveEvents(String aggregateId, List<DomainEvent> events, Long expectedVersion) {
for (DomainEvent event : events) {
try {
String eventData = objectMapper.writeValueAsString(event);
jdbcTemplate.update(
"INSERT INTO event_store (aggregate_id, event_type, event_data, version, created_at) VALUES (?, ?, ?, ?, ?)",
aggregateId,
event.getClass().getSimpleName(),
eventData,
expectedVersion + 1,
event.getOccurredAt()
);
expectedVersion++;
} catch (Exception e) {
throw new EventStoreException("Failed to save event", e);
}
}
}
/**
* 加载事件
*/
public List<DomainEvent> loadEvents(String aggregateId) {
List<EventStore> eventStores = jdbcTemplate.query(
"SELECT * FROM event_store WHERE aggregate_id = ? ORDER BY version",
new Object[]{aggregateId},
(rs, rowNum) -> {
EventStore eventStore = new EventStore();
eventStore.setId(rs.getLong("id"));
eventStore.setAggregateId(rs.getString("aggregate_id"));
eventStore.setEventType(rs.getString("event_type"));
eventStore.setEventData(rs.getString("event_data"));
eventStore.setVersion(rs.getLong("version"));
eventStore.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
return eventStore;
}
);
return eventStores.stream()
.map(this::deserializeEvent)
.collect(Collectors.toList());
}
private DomainEvent deserializeEvent(EventStore eventStore) {
try {
Class<?> eventClass = Class.forName("com.example.events." + eventStore.getEventType());
return (DomainEvent) objectMapper.readValue(eventStore.getEventData(), eventClass);
} catch (Exception e) {
throw new EventStoreException("Failed to deserialize event", e);
}
}
}
4.2 CQRS模式
// 命令模型
@Entity
@Table(name = "orders")
public class OrderWriteModel {
@Id
private String id;
@Column(name = "user_id")
private Long userId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Column(name = "total_amount")
private BigDecimal totalAmount;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// getter、setter
}
// 查询模型
@Document(collection = "order_views")
public class OrderReadModel {
@Id
private String id;
private Long userId;
private String userEmail;
private String userName;
private OrderStatus status;
private BigDecimal totalAmount;
private List<OrderItemView> items;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// getter、setter
}
public class OrderItemView {
private Long productId;
private String productName;
private String productImage;
private BigDecimal price;
private Integer quantity;
private BigDecimal subtotal;
// getter、setter
}
// 命令处理器
@Component
public class OrderCommandHandler {
@Autowired
private OrderWriteRepository orderWriteRepository;
@Autowired
private EventPublisher eventPublisher;
/**
* 处理创建订单命令
*/
public void handle(CreateOrderCommand command) {
// 验证命令
validateCreateOrderCommand(command);
// 创建订单
OrderWriteModel order = new OrderWriteModel();
order.setId(UUID.randomUUID().toString());
order.setUserId(command.getUserId());
order.setStatus(OrderStatus.PENDING);
order.setTotalAmount(command.getTotalAmount());
order.setCreatedAt(LocalDateTime.now());
order.setUpdatedAt(LocalDateTime.now());
orderWriteRepository.save(order);
// 发布事件
eventPublisher.publish(new OrderCreatedEvent(
order.getId(),
order.getUserId(),
command.getItems(),
order.getTotalAmount()
));
}
/**
* 处理确认订单命令
*/
public void handle(ConfirmOrderCommand command) {
OrderWriteModel order = orderWriteRepository.findById(command.getOrderId())
.orElseThrow(() -> new OrderNotFoundException(command.getOrderId()));
if (order.getStatus() != OrderStatus.PENDING) {
throw new IllegalStateException("Order can only be confirmed when pending");
}
order.setStatus(OrderStatus.CONFIRMED);
order.setUpdatedAt(LocalDateTime.now());
orderWriteRepository.save(order);
// 发布事件
eventPublisher.publish(new OrderConfirmedEvent(order.getId()));
}
}
// 查询处理器
@Component
public class OrderQueryHandler {
@Autowired
private OrderReadRepository orderReadRepository;
/**
* 获取用户订单列表
*/
public List<OrderReadModel> getUserOrders(Long userId, Pageable pageable) {
return orderReadRepository.findByUserIdOrderByCreatedAtDesc(userId, pageable);
}
/**
* 获取订单详情
*/
public OrderReadModel getOrderDetail(String orderId) {
return orderReadRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
}
/**
* 搜索订单
*/
public List<OrderReadModel> searchOrders(OrderSearchCriteria criteria) {
Query query = new Query();
if (criteria.getUserId() != null) {
query.addCriteria(Criteria.where("userId").is(criteria.getUserId()));
}
if (criteria.getStatus() != null) {
query.addCriteria(Criteria.where("status").is(criteria.getStatus()));
}
if (criteria.getStartDate() != null && criteria.getEndDate() != null) {
query.addCriteria(Criteria.where("createdAt")
.gte(criteria.getStartDate())
.lte(criteria.getEndDate()));
}
query.with(Sort.by(Sort.Direction.DESC, "createdAt"));
return mongoTemplate.find(query, OrderReadModel.class);
}
}
// 事件处理器 - 更新查询模型
@Component
public class OrderViewUpdater {
@Autowired
private OrderReadRepository orderReadRepository;
@Autowired
private UserServiceClient userServiceClient;
@Autowired
private ProductServiceClient productServiceClient;
/**
* 处理订单创建事件
*/
@EventHandler
public void on(OrderCreatedEvent event) {
// 获取用户信息
User user = userServiceClient.getUser(event.getUserId());
// 获取商品信息
List<OrderItemView> itemViews = event.getItems().stream()
.map(item -> {
Product product = productServiceClient.getProduct(item.getProductId());
OrderItemView itemView = new OrderItemView();
itemView.setProductId(item.getProductId());
itemView.setProductName(product.getName());
itemView.setProductImage(product.getImageUrl());
itemView.setPrice(item.getPrice());
itemView.setQuantity(item.getQuantity());
itemView.setSubtotal(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())));
return itemView;
})
.collect(Collectors.toList());
// 创建查询模型
OrderReadModel orderView = new OrderReadModel();
orderView.setId(event.getOrderId());
orderView.setUserId(event.getUserId());
orderView.setUserEmail(user.getEmail());
orderView.setUserName(user.getFirstName() + " " + user.getLastName());
orderView.setStatus(OrderStatus.PENDING);
orderView.setTotalAmount(event.getTotalAmount());
orderView.setItems(itemViews);
orderView.setCreatedAt(event.getOccurredAt());
orderView.setUpdatedAt(event.getOccurredAt());
orderReadRepository.save(orderView);
}
/**
* 处理订单确认事件
*/
@EventHandler
public void on(OrderConfirmedEvent event) {
OrderReadModel orderView = orderReadRepository.findById(event.getOrderId())
.orElseThrow(() -> new OrderNotFoundException(event.getOrderId()));
orderView.setStatus(OrderStatus.CONFIRMED);
orderView.setUpdatedAt(event.getOccurredAt());
orderReadRepository.save(orderView);
}
}
5. 服务治理
5.1 API网关
// 使用Spring Cloud Gateway
@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
// 网关配置
# application.yml
spring:
cloud:
gateway:
routes:
# 用户服务路由
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
- name: CircuitBreaker
args:
name: user-service-cb
fallbackUri: forward:/fallback/user
# 订单服务路由
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 5
redis-rate-limiter.burstCapacity: 10
- AddRequestHeader=X-Request-Source, api-gateway
# 支付服务路由
- id: payment-service
uri: lb://payment-service
predicates:
- Path=/api/payments/**
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,GATEWAY_TIMEOUT
methods: GET,POST
# 全局过滤器
default-filters:
- name: GlobalLogging
- name: AddResponseHeader
args:
name: X-Response-Time
value: "#{T(System).currentTimeMillis()}"
// 自定义过滤器
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 跳过认证的路径
if (isPublicPath(request.getPath().value())) {
return chain.filter(exchange);
}
// 获取Authorization头
String authHeader = request.getHeaders().getFirst("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
return unauthorized(exchange);
}
String token = authHeader.substring(7);
try {
// 验证JWT token
if (!jwtTokenUtil.validateToken(token)) {
return unauthorized(exchange);
}
// 提取用户信息并添加到请求头
String userId = jwtTokenUtil.getUserIdFromToken(token);
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
} catch (Exception e) {
return unauthorized(exchange);
}
}
private boolean isPublicPath(String path) {
return path.startsWith("/api/auth/") ||
path.startsWith("/api/public/") ||
path.equals("/health");
}
private Mono<Void> unauthorized(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
@Override
public int getOrder() {
return -100; // 高优先级
}
}
// 限流Key解析器
@Component("userKeyResolver")
public class UserKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
// 基于用户ID限流
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
if (userId != null) {
return Mono.just(userId);
}
// 基于IP限流
String clientIp = getClientIp(exchange.getRequest());
return Mono.just(clientIp);
}
private String getClientIp(ServerHttpRequest request) {
String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
return xForwardedFor.split(",")[0].trim();
}
String xRealIp = request.getHeaders().getFirst("X-Real-IP");
if (xRealIp != null && !xRealIp.isEmpty()) {
return xRealIp;
}
return request.getRemoteAddress() != null ?
request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
}
}
5.2 熔断器
// 使用Resilience4j
@Configuration
public class CircuitBreakerConfig {
@Bean
public CircuitBreaker userServiceCircuitBreaker() {
return CircuitBreaker.ofDefaults("user-service");
}
@Bean
public CircuitBreakerConfig userServiceCircuitBreakerConfig() {
return CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 失败率阈值50%
.waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断器打开后等待30秒
.slidingWindowSize(10) // 滑动窗口大小
.minimumNumberOfCalls(5) // 最小调用次数
.permittedNumberOfCallsInHalfOpenState(3) // 半开状态允许的调用次数
.build();
}
}
// 在服务调用中使用熔断器
@Service
public class OrderService {
@Autowired
private UserServiceClient userServiceClient;
private final CircuitBreaker circuitBreaker;
public OrderService(CircuitBreaker userServiceCircuitBreaker) {
this.circuitBreaker = userServiceCircuitBreaker;
}
/**
* 创建订单(带熔断保护)
*/
public Order createOrder(CreateOrderRequest request) {
// 使用熔断器保护用户服务调用
Supplier<User> userSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, () -> userServiceClient.getUser(request.getUserId()));
try {
User user = userSupplier.get();
// 创建订单逻辑
Order order = new Order();
order.setUserId(user.getId());
order.setUserEmail(user.getEmail());
// ... 其他订单创建逻辑
return orderRepository.save(order);
} catch (CallNotPermittedException e) {
// 熔断器打开,使用降级逻辑
log.warn("User service circuit breaker is open, using fallback");
return createOrderWithFallback(request);
}
}
/**
* 降级方法
*/
private Order createOrderWithFallback(CreateOrderRequest request) {
// 使用缓存的用户信息或默认值
Order order = new Order();
order.setUserId(request.getUserId());
order.setUserEmail("unknown@example.com"); // 默认值
order.setStatus(OrderStatus.PENDING_VERIFICATION); // 特殊状态,需要后续验证
return orderRepository.save(order);
}
}
// 使用注解方式
@Component
public class PaymentService {
@Autowired
private BankServiceClient bankServiceClient;
/**
* 处理支付(使用注解配置熔断器)
*/
@CircuitBreaker(name = "bank-service", fallbackMethod = "processPaymentFallback")
@Retry(name = "bank-service")
@TimeLimiter(name = "bank-service")
public CompletableFuture<Payment> processPayment(PaymentRequest request) {
return CompletableFuture.supplyAsync(() -> {
// 调用银行服务
BankResponse response = bankServiceClient.processPayment(request);
// 创建支付记录
Payment payment = new Payment();
payment.setOrderId(request.getOrderId());
payment.setAmount(request.getAmount());
payment.setStatus(PaymentStatus.COMPLETED);
payment.setTransactionId(response.getTransactionId());
return paymentRepository.save(payment);
});
}
/**
* 支付降级方法
*/
public CompletableFuture<Payment> processPaymentFallback(PaymentRequest request, Exception ex) {
log.error("Payment processing failed, using fallback", ex);
return CompletableFuture.supplyAsync(() -> {
// 创建待处理的支付记录
Payment payment = new Payment();
payment.setOrderId(request.getOrderId());
payment.setAmount(request.getAmount());
payment.setStatus(PaymentStatus.PENDING); // 待处理状态
payment.setFailureReason(ex.getMessage());
return paymentRepository.save(payment);
});
}
}
// Resilience4j配置
# application.yml
resilience4j:
circuitbreaker:
instances:
user-service:
failure-rate-threshold: 50
wait-duration-in-open-state: 30s
sliding-window-size: 10
minimum-number-of-calls: 5
permitted-number-of-calls-in-half-open-state: 3
bank-service:
failure-rate-threshold: 60
wait-duration-in-open-state: 60s
sliding-window-size: 20
retry:
instances:
bank-service:
max-attempts: 3
wait-duration: 1s
retry-exceptions:
- java.net.SocketTimeoutException
- java.io.IOException
timelimiter:
instances:
bank-service:
timeout-duration: 10s
6. 监控和可观测性
6.1 分布式链路追踪
// 使用Spring Cloud Sleuth + Zipkin
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
// 配置采样率
@Bean
public ProbabilityBasedSampler alwaysSampler() {
return new ProbabilityBasedSampler(1.0f); // 100%采样
}
}
// 配置链路追踪
# application.yml
spring:
sleuth:
zipkin:
base-url: http://zipkin-server:9411
sampler:
probability: 1.0 # 采样率
application:
name: order-service
// 自定义Span
@Service
public class OrderService {
private final Tracer tracer;
public OrderService(Tracer tracer) {
this.tracer = tracer;
}
/**
* 创建订单(带自定义追踪)
*/
public Order createOrder(CreateOrderRequest request) {
Span span = tracer.nextSpan()
.name("create-order")
.tag("user.id", String.valueOf(request.getUserId()))
.tag("order.amount", request.getTotalAmount().toString())
.start();
try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
// 验证用户
Span userValidationSpan = tracer.nextSpan()
.name("validate-user")
.start();
try (Tracer.SpanInScope userWs = tracer.withSpanInScope(userValidationSpan)) {
User user = userServiceClient.getUser(request.getUserId());
userValidationSpan.tag("user.email", user.getEmail());
} finally {
userValidationSpan.end();
}
// 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
order.setTotalAmount(request.getTotalAmount());
order.setStatus(OrderStatus.PENDING);
order.setCreatedAt(LocalDateTime.now());
Order savedOrder = orderRepository.save(order);
span.tag("order.id", savedOrder.getId());
span.event("order.created");
return savedOrder;
} catch (Exception e) {
span.tag("error", e.getMessage());
throw e;
} finally {
span.end();
}
}
}
// 异步处理的链路追踪
@Component
public class OrderEventHandler {
private final Tracer tracer;
public OrderEventHandler(Tracer tracer) {
this.tracer = tracer;
}
@RabbitListener(queues = "order.created.queue")
public void handleOrderCreated(OrderCreatedEvent event,
@Header Map<String, Object> headers) {
// 从消息头中恢复追踪上下文
SpanBuilder spanBuilder = tracer.nextSpan().name("handle-order-created");
// 如果有父Span信息,设置父子关系
if (headers.containsKey("X-Trace-Id")) {
String traceId = (String) headers.get("X-Trace-Id");
String spanId = (String) headers.get("X-Span-Id");
// 设置追踪上下文
}
Span span = spanBuilder.start();
try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
span.tag("order.id", event.getOrderId());
span.tag("user.id", String.valueOf(event.getUserId()));
// 处理订单创建事件
processOrderCreatedEvent(event);
span.event("order.processed");
} catch (Exception e) {
span.tag("error", e.getMessage());
throw e;
} finally {
span.end();
}
}
}
6.2 指标监控
// 使用Micrometer + Prometheus
@Configuration
public class MetricsConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"application", "order-service",
"version", "1.0.0"
);
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
// 自定义指标
@Service
public class OrderService {
private final Counter orderCreatedCounter;
private final Timer orderProcessingTimer;
private final Gauge activeOrdersGauge;
private final DistributionSummary orderAmountSummary;
public OrderService(MeterRegistry meterRegistry) {
this.orderCreatedCounter = Counter.builder("orders.created")
.description("Number of orders created")
.register(meterRegistry);
this.orderProcessingTimer = Timer.builder("orders.processing.time")
.description("Order processing time")
.register(meterRegistry);
this.activeOrdersGauge = Gauge.builder("orders.active")
.description("Number of active orders")
.register(meterRegistry, this, OrderService::getActiveOrderCount);
this.orderAmountSummary = DistributionSummary.builder("orders.amount")
.description("Order amount distribution")
.baseUnit("dollars")
.register(meterRegistry);
}
/**
* 创建订单(带指标监控)
*/
@Timed(name = "orders.create", description = "Time taken to create an order")
public Order createOrder(CreateOrderRequest request) {
return Timer.Sample.start(orderProcessingTimer)
.stop(() -> {
try {
Order order = doCreateOrder(request);
// 记录指标
orderCreatedCounter.increment(
Tags.of(
"status", "success",
"user.type", getUserType(request.getUserId())
)
);
orderAmountSummary.record(order.getTotalAmount().doubleValue());
return order;
} catch (Exception e) {
orderCreatedCounter.increment(
Tags.of(
"status", "error",
"error.type", e.getClass().getSimpleName()
)
);
throw e;
}
});
}
private double getActiveOrderCount() {
return orderRepository.countByStatus(OrderStatus.PENDING);
}
}
// 健康检查
@Component
public class OrderServiceHealthIndicator implements HealthIndicator {
@Autowired
private OrderRepository orderRepository;
@Autowired
private UserServiceClient userServiceClient;
@Override
public Health health() {
try {
// 检查数据库连接
long orderCount = orderRepository.count();
// 检查依赖服务
boolean userServiceHealthy = checkUserServiceHealth();
if (userServiceHealthy) {
return Health.up()
.withDetail("database", "UP")
.withDetail("orderCount", orderCount)
.withDetail("userService", "UP")
.build();
} else {
return Health.down()
.withDetail("database", "UP")
.withDetail("orderCount", orderCount)
.withDetail("userService", "DOWN")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("database", "DOWN")
.withDetail("error", e.getMessage())
.build();
}
}
private boolean checkUserServiceHealth() {
try {
// 简单的健康检查调用
userServiceClient.healthCheck();
return true;
} catch (Exception e) {
return false;
}
}
}
// Prometheus配置
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
enabled: true
prometheus:
enabled: true
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
http.server.requests: true
orders.processing.time: true
6.3 日志聚合
// 结构化日志配置
@Configuration
public class LoggingConfig {
@Bean
public Logger structuredLogger() {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
// JSON编码器
JsonEncoder jsonEncoder = new JsonEncoder();
jsonEncoder.setContext(context);
jsonEncoder.start();
// 控制台输出
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
consoleAppender.setContext(context);
consoleAppender.setEncoder(jsonEncoder);
consoleAppender.start();
// 根日志器
ch.qos.logback.classic.Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.addAppender(consoleAppender);
rootLogger.setLevel(Level.INFO);
return rootLogger;
}
}
// 日志配置文件
<!-- logback-spring.xml -->
<configuration>
<springProfile name="!local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp/>
<logLevel/>
<loggerName/>
<message/>
<mdc/>
<arguments/>
<stackTrace/>
<pattern>
<pattern>
{
"service": "order-service",
"traceId": "%X{traceId:-}",
"spanId": "%X{spanId:-}"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>
</springProfile>
<springProfile name="local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [%X{traceId:-},%X{spanId:-}] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</springProfile>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
// 自定义日志组件
@Component
public class AuditLogger {
private final Logger logger = LoggerFactory.getLogger("AUDIT");
private final ObjectMapper objectMapper;
public AuditLogger(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
/**
* 记录订单操作审计日志
*/
public void logOrderOperation(String operation, String orderId, Long userId, Object details) {
try {
AuditLog auditLog = AuditLog.builder()
.operation(operation)
.resourceType("ORDER")
.resourceId(orderId)
.userId(userId)
.timestamp(LocalDateTime.now())
.details(objectMapper.writeValueAsString(details))
.build();
logger.info("AUDIT: {}", objectMapper.writeValueAsString(auditLog));
} catch (Exception e) {
logger.error("Failed to log audit event", e);
}
}
}
@Data
@Builder
public class AuditLog {
private String operation;
private String resourceType;
private String resourceId;
private Long userId;
private LocalDateTime timestamp;
private String details;
}
7. 安全性
7.1 服务间认证
// JWT Token工具类
@Component
public class JwtTokenUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
/**
* 生成服务间调用token
*/
public String generateServiceToken(String serviceId) {
Map<String, Object> claims = new HashMap<>();
claims.put("service_id", serviceId);
claims.put("type", "service");
return Jwts.builder()
.setClaims(claims)
.setSubject(serviceId)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 验证服务token
*/
public boolean validateServiceToken(String token, String expectedServiceId) {
try {
Claims claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
String serviceId = claims.get("service_id", String.class);
String type = claims.get("type", String.class);
return "service".equals(type) &&
expectedServiceId.equals(serviceId) &&
!isTokenExpired(claims);
} catch (Exception e) {
return false;
}
}
private boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
// 服务间调用拦截器
@Component
public class ServiceAuthInterceptor implements HandlerInterceptor {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 检查是否是服务间调用
String serviceToken = request.getHeader("X-Service-Token");
if (serviceToken == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
// 验证服务token
String expectedServiceId = getExpectedServiceId(request);
if (!jwtTokenUtil.validateServiceToken(serviceToken, expectedServiceId)) {
response.setStatus(HttpStatus.FORBIDDEN.value());
return false;
}
return true;
}
private String getExpectedServiceId(HttpServletRequest request) {
// 根据请求路径或其他信息确定期望的服务ID
String path = request.getRequestURI();
if (path.startsWith("/api/internal/")) {
return "order-service"; // 示例
}
return null;
}
}
// Feign客户端添加服务认证
@Component
public class ServiceAuthRequestInterceptor implements RequestInterceptor {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Value("${spring.application.name}")
private String serviceId;
@Override
public void apply(RequestTemplate template) {
// 为服务间调用添加认证token
String serviceToken = jwtTokenUtil.generateServiceToken(serviceId);
template.header("X-Service-Token", serviceToken);
}
}
7.2 数据加密
// 敏感数据加密
@Component
public class DataEncryptionService {
private final AESUtil aesUtil;
public DataEncryptionService(@Value("${encryption.key}") String encryptionKey) {
this.aesUtil = new AESUtil(encryptionKey);
}
/**
* 加密敏感字段
*/
public String encryptSensitiveData(String data) {
if (data == null || data.isEmpty()) {
return data;
}
try {
return aesUtil.encrypt(data);
} catch (Exception e) {
throw new EncryptionException("Failed to encrypt data", e);
}
}
/**
* 解密敏感字段
*/
public String decryptSensitiveData(String encryptedData) {
if (encryptedData == null || encryptedData.isEmpty()) {
return encryptedData;
}
try {
return aesUtil.decrypt(encryptedData);
} catch (Exception e) {
throw new DecryptionException("Failed to decrypt data", e);
}
}
}
// JPA实体加密
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username")
private String username;
@Convert(converter = EncryptedStringConverter.class)
@Column(name = "email")
private String email;
@Convert(converter = EncryptedStringConverter.class)
@Column(name = "phone")
private String phone;
// getter、setter
}
// 加密转换器
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
@Autowired
private DataEncryptionService encryptionService;
@Override
public String convertToDatabaseColumn(String attribute) {
return encryptionService.encryptSensitiveData(attribute);
}
@Override
public String convertToEntityAttribute(String dbData) {
return encryptionService.decryptSensitiveData(dbData);
}
}
8. 部署和运维
8.1 容器化部署
# 多阶段构建Dockerfile
FROM openjdk:11-jdk-slim AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
# 构建应用
RUN ./mvnw clean package -DskipTests
# 运行时镜像
FROM openjdk:11-jre-slim
# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 安装必要的工具
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# 复制应用文件
COPY --from=builder /app/target/*.jar app.jar
# 设置文件权限
RUN chown -R appuser:appuser /app
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 暴露端口
EXPOSE 8080
# 启动应用
ENTRYPOINT ["java", "-jar", "-Djava.security.egd=file:/dev/./urandom", "app.jar"]
# docker-compose.yml
version: '3.8'
services:
# 服务发现
eureka-server:
image: microservices/eureka-server:latest
ports:
- "8761:8761"
environment:
- SPRING_PROFILES_ACTIVE=docker
networks:
- microservices-network
# API网关
api-gateway:
image: microservices/api-gateway:latest
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka-server:8761/eureka
depends_on:
- eureka-server
networks:
- microservices-network
# 用户服务
user-service:
image: microservices/user-service:latest
environment:
- SPRING_PROFILES_ACTIVE=docker
- SPRING_DATASOURCE_URL=jdbc:mysql://user-db:3306/user_service
- EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka-server:8761/eureka
depends_on:
- user-db
- eureka-server
networks:
- microservices-network
deploy:
replicas: 2
resources:
limits:
memory: 512M
reservations:
memory: 256M
# 用户服务数据库
user-db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=user_service
- MYSQL_USER=user_service
- MYSQL_PASSWORD=password
volumes:
- user_data:/var/lib/mysql
networks:
- microservices-network
# 订单服务
order-service:
image: microservices/order-service:latest
environment:
- SPRING_PROFILES_ACTIVE=docker
- SPRING_DATASOURCE_URL=jdbc:mysql://order-db:3306/order_service
- EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka-server:8761/eureka
- SPRING_RABBITMQ_HOST=rabbitmq
depends_on:
- order-db
- eureka-server
- rabbitmq
networks:
- microservices-network
deploy:
replicas: 3
resources:
limits:
memory: 512M
reservations:
memory: 256M
# 订单服务数据库
order-db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=order_service
- MYSQL_USER=order_service
- MYSQL_PASSWORD=password
volumes:
- order_data:/var/lib/mysql
networks:
- microservices-network
# 消息队列
rabbitmq:
image: rabbitmq:3-management
ports:
- "15672:15672"
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=password
volumes:
- rabbitmq_data:/var/lib/rabbitmq
networks:
- microservices-network
# Redis缓存
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- microservices-network
# 监控
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
networks:
- microservices-network
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
networks:
- microservices-network
# 链路追踪
zipkin:
image: openzipkin/zipkin
ports:
- "9411:9411"
networks:
- microservices-network
volumes:
user_data:
order_data:
rabbitmq_data:
redis_data:
prometheus_data:
grafana_data:
networks:
microservices-network:
driver: bridge
8.2 Kubernetes部署
# user-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: microservices/user-service:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "kubernetes"
- name: SPRING_DATASOURCE_URL
value: "jdbc:mysql://user-db-service:3306/user_service"
- name: SPRING_DATASOURCE_USERNAME
valueFrom:
secretKeyRef:
name: user-db-secret
key: username
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: user-db-secret
key: password
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: v1
kind: Secret
metadata:
name: user-db-secret
type: Opaque
data:
username: dXNlcl9zZXJ2aWNl # base64 encoded
password: cGFzc3dvcmQ= # base64 encoded
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: microservices-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
spec:
rules:
- host: api.microservices.local
http:
paths:
- path: /api/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
- path: /api/orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
- path: /api/payments
pathType: Prefix
backend:
service:
name: payment-service
port:
number: 80
9. 最佳实践总结
9.1 设计原则
- 单一职责:每个微服务只负责一个业务领域
- 数据独立:每个服务拥有独立的数据存储
- API优先:先设计API接口,再实现服务
- 故障隔离:服务间故障不应相互影响
- 自动化:部署、测试、监控全面自动化
9.2 开发建议
- 渐进式迁移:从单体应用逐步拆分为微服务
- 领域驱动设计:基于业务领域划分服务边界
- 契约测试:确保服务间接口的兼容性
- 版本管理:API版本化和向后兼容
- 文档维护:保持API文档和架构文档的更新
9.3 运维要点
- 监控全覆盖:应用监控、基础设施监控、业务监控
- 日志集中化:统一日志收集和分析
- 自动化部署:CI/CD流水线和蓝绿部署
- 容量规划:基于监控数据进行容量规划
- 灾难恢复:制定完善的灾难恢复计划
9.4 团队组织
- 跨功能团队:每个团队负责完整的服务生命周期
- DevOps文化:开发和运维紧密协作
- 知识共享:定期技术分享和最佳实践交流
- 持续学习:跟上技术发展趋势
结语
微服务架构是一种强大的架构模式,能够帮助组织构建可扩展、可维护的分布式系统。但同时也带来了复杂性挑战,需要在技术、流程和组织层面做好充分准备。
成功实施微服务架构的关键在于:
- 明确的业务边界划分
- 完善的基础设施支撑
- 强大的监控和运维能力
- 成熟的团队协作模式
希望本文能够为你的微服务架构实践提供有价值的参考和指导。