主题
微服务架构实战
1. 微服务架构概述
1.1 微服务架构的概念
微服务架构是一种将应用程序设计为一系列松耦合服务的方法。每个服务都实现特定的业务功能,并且可以独立部署、扩展和管理。微服务架构的核心思想是"将复杂的应用拆分为简单的服务"。
1.2 微服务架构的优势
- 灵活性:每个服务可以独立开发、部署和扩展
- 可维护性:服务边界清晰,代码库更小,更易于理解和维护
- 技术多样性:不同服务可以使用不同的技术栈
- 弹性:单个服务故障不会影响整个系统
- 可扩展性:可以根据服务的需求独立扩展
- 持续交付:支持更快的开发和部署周期
1.3 微服务架构的挑战
- 服务发现:如何找到网络中的服务实例
- 配置管理:如何管理分布式环境中的配置
- 负载均衡:如何在多个服务实例之间分配流量
- 熔断限流:如何处理服务故障和流量峰值
- 分布式事务:如何确保跨服务操作的一致性
- 分布式追踪:如何追踪跨服务的请求
- 监控告警:如何监控分布式系统的健康状态
- 安全管理:如何确保服务间通信的安全
1.4 微服务架构参考模型
mermaid
flowchart TD
subgraph 接入层
A[API网关]
B[负载均衡器]
C[认证授权服务]
end
subgraph 服务层
D[订单服务]
E[用户服务]
F[产品服务]
G[支付服务]
H[库存服务]
end
subgraph 数据层
I[订单数据库]
J[用户数据库]
K[产品数据库]
L[支付数据库]
M[库存数据库]
end
subgraph 基础服务层
N[服务发现]
O[配置中心]
P[消息队列]
Q[分布式追踪]
R[监控告警]
S[日志管理]
end
A --> B
B --> C
C --> D
C --> E
C --> F
D --> E
D --> F
D --> G
D --> H
E --> J
F --> K
G --> L
H --> M
D --> I
D --> N
E --> N
F --> N
G --> N
H --> N
D --> O
E --> O
F --> O
G --> O
H --> O
D --> P
E --> P
F --> P
G --> P
H --> P
D --> Q
E --> Q
F --> Q
G --> Q
H --> Q
D --> R
E --> R
F --> R
G --> R
H --> R
D --> S
E --> S
F --> S
G --> S
H --> S2. 微服务设计原则
2.1 服务拆分原则
- 单一职责原则:每个服务只负责一个特定的业务功能
- 边界清晰原则:服务边界应该基于业务领域,而不是技术实现
- 独立部署原则:每个服务可以独立部署,不影响其他服务
- 数据自治原则:每个服务拥有自己的数据存储
- 接口稳定原则:服务接口应该保持稳定,避免频繁变更
2.2 服务拆分策略
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 按业务领域拆分 | 根据业务功能模块拆分 | 大型企业应用,业务逻辑复杂 |
| 按用户旅程拆分 | 根据用户操作流程拆分 | 面向用户的应用,注重用户体验 |
| 按技术栈拆分 | 根据技术特性拆分 | 多技术栈应用,需要技术隔离 |
| 按数据边界拆分 | 根据数据模型拆分 | 数据密集型应用,需要数据隔离 |
2.3 服务接口设计
RESTful API
- 使用标准HTTP方法(GET, POST, PUT, DELETE)
- 使用URL表示资源
- 使用HTTP状态码表示操作结果
- 使用JSON作为数据格式
gRPC
- 使用Protocol Buffers作为接口定义语言
- 基于HTTP/2,支持双向流
- 高性能,低延迟
- 支持多种语言
GraphQL
- 客户端定义需要的数据结构
- 单个请求获取多个资源
- 强类型 schema
- 支持实时更新
2.4 服务版本管理
URL路径版本
/api/v1/users /api/v2/users查询参数版本
/api/users?version=1 /api/users?version=2头部版本
GET /api/users X-API-Version: 1语义化版本
- 主版本(breaking changes)
- 次版本(backward compatible)
- 补丁版本(bug fixes)
3. 服务发现
3.1 服务发现概述
服务发现在微服务架构中扮演着至关重要的角色,它解决了以下问题:
- 如何找到网络中的服务实例
- 如何处理服务实例的动态变化
- 如何在多个服务实例之间进行负载均衡
3.2 服务发现模式
客户端发现
- 客户端负责查询服务注册表
- 客户端负责负载均衡
- 优点:简单,无额外网络跳数
- 缺点:客户端需要集成服务发现逻辑
服务端发现
- 客户端通过负载均衡器访问服务
- 负载均衡器负责查询服务注册表
- 优点:客户端无需集成服务发现逻辑
- 缺点:增加了网络跳数
3.3 服务发现实现
3.3.1 Eureka
java
// 服务端配置
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: true
// 客户端配置
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true3.3.2 Consul
bash
# 安装Consul
brew install consul # macOS
choco install consul # Windows
# 启动Consul代理
consul agent -dev
# 注册服务
curl --request PUT --data @service.json http://localhost:8500/v1/agent/service/register
# 服务配置示例 (service.json)
{
"ID": "user-service-1",
"Name": "user-service",
"Tags": ["v1"],
"Address": "127.0.0.1",
"Port": 8080,
"Check": {
"HTTP": "http://127.0.0.1:8080/health",
"Interval": "10s"
}
}
# 发现服务
curl http://localhost:8500/v1/catalog/service/user-service3.3.3 Nacos
java
// 服务端配置
server.port=8848
spring.application.name=nacos-server
// 客户端配置
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
service: ${spring.application.name}
// 服务注册与发现示例
@RestController
public class UserController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/services")
public List<String> getServices() {
return discoveryClient.getServices();
}
}4. 配置中心
4.1 配置中心概述
配置中心是微服务架构中的核心组件,它解决了以下问题:
- 集中管理分布式环境中的配置
- 支持配置的动态更新
- 支持不同环境的配置隔离
- 支持配置的版本管理
- 支持配置的加密和访问控制
4.2 配置中心实现
4.2.1 Spring Cloud Config
java
// 服务端配置
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/your-username/config-repo
search-paths: '{application}'
username: your-username
password: your-password
// 客户端配置
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888
profile: dev
label: master
// 配置刷新
@RestController
@RefreshScope
public class ConfigController {
@Value("${app.message}")
private String message;
@GetMapping("/message")
public String getMessage() {
return message;
}
}4.2.2 Apollo
java
// 客户端配置
app:
id: user-service
apollo:
meta: http://localhost:8080
bootstrap:
enabled: true
namespaces: application,mysql,redis
// 使用配置
@RestController
public class UserController {
@Value("${app.message}")
private String message;
@GetMapping("/message")
public String getMessage() {
return message;
}
}4.2.3 Nacos Config
java
// 客户端配置
spring:
application:
name: user-service
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP
file-extension: yaml
// 使用配置
@RestController
@RefreshScope
public class ConfigController {
@Value("${app.message}")
private String message;
@GetMapping("/message")
public String getMessage() {
return message;
}
}5. 熔断限流
5.1 熔断限流概述
熔断限流是微服务架构中的重要保护机制,它解决了以下问题:
- 防止服务雪崩:当一个服务故障时,避免其他服务因调用它而也发生故障
- 保护系统:在流量高峰期,保护系统不被过载
- 提高可用性:在服务故障时,快速失败并返回降级响应
5.2 熔断器模式
熔断器的三个状态:
- 关闭状态:服务正常运行,统计失败次数
- 开启状态:服务故障,直接返回降级响应
- 半开状态:尝试恢复服务,允许少量请求通过
5.2.1 Hystrix
java
// 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
// 启用Hystrix
@SpringBootApplication
@EnableCircuitBreaker
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// 使用Hystrix
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "getUserFallback")
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return restTemplate.getForObject("http://user-service/user/{id}", User.class, id);
}
public User getUserFallback(Long id) {
return new User(id, "默认用户", "默认邮箱");
}
}5.2.2 Sentinel
java
// 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
// 配置Sentinel
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true
// 使用Sentinel
@RestController
public class UserController {
@SentinelResource(value = "getUser", fallback = "getUserFallback")
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
if (id == 1) {
throw new RuntimeException("服务异常");
}
return new User(id, "用户" + id, "user" + id + "@example.com");
}
public User getUserFallback(Long id) {
return new User(id, "默认用户", "默认邮箱");
}
}5.3 限流实现
5.3.1 基于令牌桶的限流
java
// 令牌桶限流实现
public class RateLimiter {
private final int capacity; // 桶容量
private final double rate; // 令牌生成速率(个/秒)
private double tokens; // 当前令牌数
private long lastRefillTime; // 上次填充时间
public RateLimiter(int capacity, double rate) {
this.capacity = capacity;
this.rate = rate;
this.tokens = capacity;
this.lastRefillTime = System.nanoTime();
}
public synchronized boolean tryAcquire() {
refill();
if (tokens >= 1) {
tokens--;
return true;
}
return false;
}
private void refill() {
long now = System.nanoTime();
double elapsed = (now - lastRefillTime) / 1e9; // 秒
double newTokens = elapsed * rate;
if (newTokens > 0) {
tokens = Math.min(tokens + newTokens, capacity);
lastRefillTime = now;
}
}
}
// 使用示例
RateLimiter limiter = new RateLimiter(10, 2); // 桶容量10,速率2个/秒
@GetMapping("/limited")
public String limited() {
if (limiter.tryAcquire()) {
return "请求成功";
} else {
return "请求过于频繁,请稍后再试";
}
}5.3.2 Sentinel限流
java
// 配置限流规则
@Configuration
public class SentinelConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("getUser");
rule.setCount(10); // QPS限制为10
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
FlowRuleManager.loadRules(rules);
}
}5. API网关
5.1 API网关概述
API网关是微服务架构中的重要组件,它解决了以下问题:
- 统一入口:为所有服务提供统一的访问入口
- 路由转发:根据请求路径将请求转发到对应的服务
- 负载均衡:在多个服务实例之间分配流量
- 认证授权:统一处理认证和授权
- 限流熔断:保护后端服务
- 日志监控:记录所有请求的日志
- 协议转换:支持不同协议之间的转换
5.2 API网关实现
5.2.1 Spring Cloud Gateway
java
// 配置
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/user/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/fallback
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
filters:
- StripPrefix=1
// 启用Gateway
@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
// 熔断 fallback
@RestController
public class FallbackController {
@GetMapping("/fallback")
public Map<String, Object> fallback() {
Map<String, Object> result = new HashMap<>();
result.put("code", 503);
result.put("message", "服务暂时不可用");
return result;
}
}5.2.2 Zuul
java
// 配置
spring:
application:
name: api-gateway
server:
port: 8080
zuul:
routes:
user-service:
path: /user/**
serviceId: user-service
order-service:
path: /order/**
serviceId: order-service
// 启用Zuul
@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
// 自定义过滤器
@Component
public class AuthFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.setResponseBody("{\"code\": 401, \"message\": \"未授权\"}");
}
return null;
}
}5.2.3 Kong
bash
# 安装Kong
docker run -d --name kong-database \n -p 5432:5432 \n -e POSTGRES_DB=kong \n -e POSTGRES_USER=kong \n -e POSTGRES_PASSWORD=kong \n postgres:9.6
docker run --rm \n --link kong-database:kong-database \n -e KONG_DATABASE=postgres \n -e KONG_PG_HOST=kong-database \n -e KONG_PG_USER=kong \n -e KONG_PG_PASSWORD=kong \n -e KONG_CASSANDRA_CONTACT_POINTS=kong-database \n kong:latest kong migrations bootstrap
docker run -d --name kong \n --link kong-database:kong-database \n -e KONG_DATABASE=postgres \n -e KONG_PG_HOST=kong-database \n -e KONG_PG_USER=kong \n -e KONG_PG_PASSWORD=kong \n -e KONG_CASSANDRA_CONTACT_POINTS=kong-database \n -e KONG_PROXY_ACCESS_LOG=/dev/stdout \n -e KONG_ADMIN_ACCESS_LOG=/dev/stdout \n -e KONG_PROXY_ERROR_LOG=/dev/stderr \n -e KONG_ADMIN_ERROR_LOG=/dev/stderr \n -e KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl \n -p 8000:8000 \n -p 8443:8443 \n -p 8001:8001 \n -p 8444:8444 \n kong:latest
# 添加服务
curl -i -X POST http://localhost:8001/services/ \n --data name=user-service \n --data url=http://user-service:8080
# 添加路由
curl -i -X POST http://localhost:8001/services/user-service/routes \n --data paths[]=/user \n --data methods[]=GET \n --data methods[]=POST \n --data strip_path=true
# 添加插件(限流)
curl -i -X POST http://localhost:8001/services/user-service/plugins \n --data name=rate-limiting \n --data config.minute=10 \n --data config.policy=local6. 分布式事务
6.1 分布式事务概述
分布式事务是微服务架构中的挑战之一,它解决了以下问题:
- 确保跨服务操作的一致性
- 处理部分服务失败的情况
- 平衡一致性和可用性
6.2 分布式事务模式
两阶段提交(2PC)
- 准备阶段:协调者询问所有参与者是否可以执行操作
- 提交阶段:如果所有参与者都准备就绪,协调者命令所有参与者提交操作
- 优点:强一致性
- 缺点:性能差,协调者单点故障
补偿事务(TCC)
- Try:尝试执行操作,预留资源
- Confirm:确认执行操作
- Cancel:取消执行操作,释放资源
- 优点:性能较好
- 缺点:实现复杂
本地消息表
- 事务发起方将操作和消息写入本地数据库
- 消息处理器将消息发送到消息队列
- 事务参与方消费消息并执行操作
- 优点:可靠性高
- 缺点:实现复杂,有延迟
Saga模式
- 将长事务拆分为多个短事务
- 每个短事务都有对应的补偿操作
- 按顺序执行短事务,失败时执行补偿操作
- 优点:性能好,可用性高
- 缺点:最终一致性,实现复杂
6.3 分布式事务实现
6.3.1 Seata
java
// 添加依赖
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
// 配置
spring:
cloud:
seata:
tx-service-group: my_test_tx_group
// 使用Seata
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
@PostMapping("/create")
public Order createOrder(@RequestBody OrderDTO orderDTO) {
return orderService.createOrder(orderDTO);
}
}
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order createOrder(OrderDTO orderDTO) {
// 创建订单
Order order = new Order();
order.setUserId(orderDTO.getUserId());
order.setProductId(orderDTO.getProductId());
order.setCount(orderDTO.getCount());
order.setAmount(orderDTO.getAmount());
order.setStatus(0);
orderMapper.insert(order);
// 扣减库存
restTemplate.postForObject(
"http://inventory-service/deduct",
new InventoryDTO(orderDTO.getProductId(), orderDTO.getCount()),
Boolean.class
);
// 扣减账户余额
restTemplate.postForObject(
"http://account-service/deduct",
new AccountDTO(orderDTO.getUserId(), orderDTO.getAmount()),
Boolean.class
);
return order;
}
}7. 分布式追踪
7.1 分布式追踪概述
分布式追踪是微服务架构中的重要组件,它解决了以下问题:
- 追踪跨服务的请求链路
- 识别性能瓶颈
- 分析服务依赖关系
- 定位故障原因
7.2 分布式追踪实现
7.2.1 Zipkin
java
// 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
// 配置
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0
// 启动Zipkin
java -jar zipkin-server-2.23.16-exec.jar
// 查看追踪信息
// 访问 http://localhost:94117.2.2 Jaeger
java
// 添加依赖
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-jaeger-web-starter</artifactId>
<version>3.3.1</version>
</dependency>
// 配置
opentracing:
jaeger:
service-name: user-service
udp-sender:
host: localhost
port: 6831
// 启动Jaeger
docker run -d --name jaeger \n -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \n -p 5775:5775/udp \n -p 6831:6831/udp \n -p 6832:6832/udp \n -p 5778:5778 \n -p 16686:16686 \n -p 14250:14250 \n -p 14268:14268 \n -p 14269:14269 \n -p 9411:9411 \n jaegertracing/all-in-one:1.22
// 查看追踪信息
// 访问 http://localhost:166867.2.3 SkyWalking
java
// 添加依赖
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.7.0</version>
</dependency>
// 配置
# 在JVM参数中添加
-javaagent:/path/to/skywalking-agent.jar
-Dskywalking.agent.service_name=user-service
-Dskywalking.collector.backend_service=localhost:11800
// 启动SkyWalking
docker run -d --name skywalking-oap \n -p 11800:11800 \n -p 12800:12800 \n --restart always \n apache/skywalking-oap-server:8.7.0-es6
docker run -d --name skywalking-ui \n -p 8080:8080 \n --link skywalking-oap:oap \n -e SW_OAP_ADDRESS=http://oap:12800 \n --restart always \n apache/skywalking-ui:8.7.0
// 查看追踪信息
// 访问 http://localhost:80807. 微服务监控
7.1 微服务监控概述
微服务监控是微服务架构中的重要组件,它解决了以下问题:
- 监控分布式系统的健康状态
- 识别性能瓶颈
- 预测系统故障
- 提供可视化的监控仪表盘
7.2 微服务监控实现
7.2.1 Prometheus + Grafana
yaml
# Prometheus配置 (prometheus.yml)
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'spring-actuator'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['user-service:8080', 'order-service:8080', 'product-service:8080']
# 启动Prometheus
docker run -d --name prometheus \n -p 9090:9090 \n -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml \n prom/prometheus
# 启动Grafana
docker run -d --name grafana \n -p 3000:3000 \n grafana/grafana
# 配置Grafana数据源
# 访问 http://localhost:3000,添加Prometheus数据源
# 导入仪表盘
# 在Grafana中导入Spring Boot 2.0仪表盘 (ID: 12856)7.2.2 ELK Stack
bash
# 启动Elasticsearch
docker run -d --name elasticsearch \n -p 9200:9200 \n -p 9300:9300 \n -e "discovery.type=single-node" \n -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \n docker.elastic.co/elasticsearch/elasticsearch:7.14.0
# 启动Kibana
docker run -d --name kibana \n -p 5601:5601 \n --link elasticsearch:elasticsearch \n -e "ELASTICSEARCH_HOSTS=http://elasticsearch:9200" \n docker.elastic.co/kibana/kibana:7.14.0
# 启动Logstash
docker run -d --name logstash \n -p 5044:5044 \n --link elasticsearch:elasticsearch \n -v /path/to/logstash.conf:/usr/share/logstash/pipeline/logstash.conf \n docker.elastic.co/logstash/logstash:7.14.0
# Logstash配置 (logstash.conf)
input {
tcp {
port => 5044
codec => json_lines
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "logs-%{+YYYY.MM.dd}"
}
}
# 配置应用日志
# 在application.yml中添加
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
level:
root: info
com.example: debug
# 添加Logstash依赖
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>6.6</version>
</dependency>
# 配置logback.xml
<configuration>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<root level="info">
<appender-ref ref="LOGSTASH"/>
<appender-ref ref="CONSOLE"/>
</root>
</configuration>8. 微服务安全
8.1 微服务安全概述
微服务安全是微服务架构中的重要组成部分,它解决了以下问题:
- 确保服务间通信的安全
- 保护敏感数据
- 实现细粒度的访问控制
- 防止恶意攻击
8.2 微服务安全实践
服务间通信安全
- 使用TLS/SSL加密传输
- 使用JWT或OAuth 2.0进行认证
- 使用API密钥进行服务间认证
API网关安全
- 统一认证授权
- 限流和防DDoS攻击
- 请求验证和过滤
数据安全
- 敏感数据加密存储
- 数据访问控制
- 数据脱敏
容器安全
- 镜像安全扫描
- 最小权限原则
- 网络隔离
审计和监控
- 记录安全事件
- 监控异常访问
- 定期安全审计
8.3 微服务安全实现
8.3.1 OAuth 2.0 + JWT
java
// 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
// 配置
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://auth-server:8080/oauth2/token
client:
registration:
keycloak:
client-id: user-service
client-secret: your-client-secret
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
keycloak:
issuer-uri: http://auth-server:8080
// 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}8.3.2 服务网格安全
yaml
# Istio mTLS配置
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
# Istio授权策略
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: user-service
namespace: default
spec:
selector:
matchLabels:
app: user-service
rules:
- from:
- source:
principals:
- cluster.local/ns/default/sa/order-service
to:
- operation:
methods:
- GET
paths:
- /user/*9. 微服务架构实战项目
9.1 项目概述
本项目旨在构建一个基于微服务架构的电商系统,包含用户、订单、产品、支付和库存等核心服务。
9.2 技术栈
| 分类 | 技术 | 版本 | 用途 |
|---|---|---|---|
| 语言 | Java | 11+ | 后端服务开发 |
| 框架 | Spring Boot | 2.5+ | 应用框架 |
| 微服务框架 | Spring Cloud | 2020.0+ | 微服务生态 |
| 服务发现 | Eureka | - | 服务注册与发现 |
| 配置中心 | Spring Cloud Config | - | 配置管理 |
| API网关 | Spring Cloud Gateway | - | 统一入口 |
| 熔断限流 | Sentinel | - | 服务保护 |
| 分布式追踪 | SkyWalking | 8.7+ | 链路追踪 |
| 监控告警 | Prometheus + Grafana | - | 系统监控 |
| 消息队列 | Kafka | 2.8+ | 异步通信 |
| 数据库 | MySQL | 8.0+ | 数据存储 |
| 缓存 | Redis | 6.0+ | 缓存 |
| 容器化 | Docker | 20.0+ | 应用容器化 |
| 编排 | Kubernetes | 1.21+ | 容器编排 |
9.3 项目结构
ecommerce-microservices/
├── api-gateway/ # API网关服务
├── auth-service/ # 认证授权服务
├── user-service/ # 用户服务
├── product-service/ # 产品服务
├── order-service/ # 订单服务
├── payment-service/ # 支付服务
├── inventory-service/ # 库存服务
├── config-server/ # 配置中心
├── discovery-server/ # 服务发现
├── monitoring/ # 监控相关配置
├── docker-compose.yml # Docker Compose配置
├── k8s/ # Kubernetes配置
└── README.md # 项目说明9.4 核心服务实现
9.4.1 用户服务
java
// 用户服务API
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public User register(@RequestBody UserRegisterDTO dto) {
return userService.register(dto);
}
@PostMapping("/login")
public LoginResponse login(@RequestBody UserLoginDTO dto) {
return userService.login(dto);
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody UserUpdateDTO dto) {
return userService.updateUser(id, dto);
}
}
// 用户服务实现
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtUtil jwtUtil;
public User register(UserRegisterDTO dto) {
// 检查用户是否已存在
if (userMapper.findByUsername(dto.getUsername()) != null) {
throw new RuntimeException("用户名已存在");
}
// 创建用户
User user = new User();
user.setUsername(dto.getUsername());
user.setPassword(passwordEncoder.encode(dto.getPassword()));
user.setEmail(dto.getEmail());
user.setPhone(dto.getPhone());
user.setCreatedAt(new Date());
userMapper.insert(user);
return user;
}
public LoginResponse login(UserLoginDTO dto) {
// 查找用户
User user = userMapper.findByUsername(dto.getUsername());
if (user == null || !passwordEncoder.matches(dto.getPassword(), user.getPassword())) {
throw new RuntimeException("用户名或密码错误");
}
// 生成JWT令牌
String token = jwtUtil.generateToken(user.getId(), user.getUsername());
return new LoginResponse(token, user);
}
public User getUserById(Long id) {
return userMapper.findById(id);
}
public User updateUser(Long id, UserUpdateDTO dto) {
User user = userMapper.findById(id);
if (user == null) {
throw new RuntimeException("用户不存在");
}
// 更新用户信息
if (dto.getEmail() != null) {
user.setEmail(dto.getEmail());
}
if (dto.getPhone() != null) {
user.setPhone(dto.getPhone());
}
if (dto.getPassword() != null) {
user.setPassword(passwordEncoder.encode(dto.getPassword()));
}
userMapper.update(user);
return user;
}
}9.4.2 订单服务
java
// 订单服务API
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public Order createOrder(@RequestBody OrderCreateDTO dto) {
return orderService.createOrder(dto);
}
@GetMapping("/{id}")
public Order getOrder(@PathVariable Long id) {
return orderService.getOrderById(id);
}
@GetMapping("/user/{userId}")
public List<Order> getOrdersByUserId(@PathVariable Long userId) {
return orderService.getOrdersByUserId(userId);
}
@PutMapping("/{id}/status")
public Order updateOrderStatus(@PathVariable Long id, @RequestParam Integer status) {
return orderService.updateOrderStatus(id, status);
}
}
// 订单服务实现
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public Order createOrder(OrderCreateDTO dto) {
// 检查产品是否存在
Product product = restTemplate.getForObject(
"http://product-service/product/{id}",
Product.class,
dto.getProductId()
);
if (product == null) {
throw new RuntimeException("产品不存在");
}
// 检查库存
Boolean hasStock = restTemplate.postForObject(
"http://inventory-service/check",
new InventoryCheckDTO(dto.getProductId(), dto.getCount()),
Boolean.class
);
if (!hasStock) {
throw new RuntimeException("库存不足");
}
// 创建订单
Order order = new Order();
order.setUserId(dto.getUserId());
order.setProductId(dto.getProductId());
order.setProductName(product.getName());
order.setCount(dto.getCount());
order.setPrice(product.getPrice());
order.setTotalAmount(product.getPrice() * dto.getCount());
order.setStatus(0); // 待支付
order.setCreatedAt(new Date());
orderMapper.insert(order);
// 扣减库存
restTemplate.postForObject(
"http://inventory-service/deduct",
new InventoryDeductDTO(dto.getProductId(), dto.getCount()),
Boolean.class
);
// 发送订单创建消息
kafkaTemplate.send("order-create", order);
return order;
}
public Order getOrderById(Long id) {
return orderMapper.findById(id);
}
public List<Order> getOrdersByUserId(Long userId) {
return orderMapper.findByUserId(userId);
}
public Order updateOrderStatus(Long id, Integer status) {
Order order = orderMapper.findById(id);
if (order == null) {
throw new RuntimeException("订单不存在");
}
order.setStatus(status);
order.setUpdatedAt(new Date());
orderMapper.update(order);
// 发送订单状态更新消息
kafkaTemplate.send("order-status-update", order);
return order;
}
}9.4.3 产品服务
java
// 产品服务API
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@PostMapping
public Product createProduct(@RequestBody ProductCreateDTO dto) {
return productService.createProduct(dto);
}
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return productService.getProductById(id);
}
@GetMapping
public List<Product> getProducts(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) Integer page,
@RequestParam(required = false) Integer size) {
return productService.getProducts(keyword, page, size);
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody ProductUpdateDTO dto) {
return productService.updateProduct(id, dto);
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
}
// 产品服务实现
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
public Product createProduct(ProductCreateDTO dto) {
Product product = new Product();
product.setName(dto.getName());
product.setDescription(dto.getDescription());
product.setPrice(dto.getPrice());
product.setStock(dto.getStock());
product.setCategoryId(dto.getCategoryId());
product.setCreatedAt(new Date());
productMapper.insert(product);
return product;
}
public Product getProductById(Long id) {
return productMapper.findById(id);
}
public List<Product> getProducts(String keyword, Integer page, Integer size) {
if (page == null) page = 1;
if (size == null) size = 10;
int offset = (page - 1) * size;
return productMapper.findByKeyword(keyword, offset, size);
}
public Product updateProduct(Long id, ProductUpdateDTO dto) {
Product product = productMapper.findById(id);
if (product == null) {
throw new RuntimeException("产品不存在");
}
if (dto.getName() != null) {
product.setName(dto.getName());
}
if (dto.getDescription() != null) {
product.setDescription(dto.getDescription());
}
if (dto.getPrice() != null) {
product.setPrice(dto.getPrice());
}
if (dto.getStock() != null) {
product.setStock(dto.getStock());
}
if (dto.getCategoryId() != null) {
product.setCategoryId(dto.getCategoryId());
}
product.setUpdatedAt(new Date());
productMapper.update(product);
return product;
}
public void deleteProduct(Long id) {
productMapper.delete(id);
}
}9.5 项目部署
9.5.1 Docker Compose部署
yaml
# docker-compose.yml
version: '3.8'
services:
# 基础服务
discovery-server:
build: ./discovery-server
ports:
- "8761:8761"
environment:
- SPRING_PROFILES_ACTIVE=docker
config-server:
build: ./config-server
ports:
- "8888:8888"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
depends_on:
- discovery-server
# 核心服务
user-service:
build: ./user-service
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
- SPRING_CLOUD_CONFIG_URI=http://config-server:8888
depends_on:
- discovery-server
- config-server
product-service:
build: ./product-service
ports:
- "8082:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
- SPRING_CLOUD_CONFIG_URI=http://config-server:8888
depends_on:
- discovery-server
- config-server
order-service:
build: ./order-service
ports:
- "8083:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
- SPRING_CLOUD_CONFIG_URI=http://config-server:8888
depends_on:
- discovery-server
- config-server
inventory-service:
build: ./inventory-service
ports:
- "8084:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
- SPRING_CLOUD_CONFIG_URI=http://config-server:8888
depends_on:
- discovery-server
- config-server
payment-service:
build: ./payment-service
ports:
- "8085:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
- SPRING_CLOUD_CONFIG_URI=http://config-server:8888
depends_on:
- discovery-server
- config-server
# API网关
api-gateway:
build: ./api-gateway
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://discovery-server:8761/eureka/
- SPRING_CLOUD_CONFIG_URI=http://config-server:8888
depends_on:
- discovery-server
- config-server
# 消息队列
kafka:
image: wurstmeister/kafka:2.13-2.8.1
ports:
- "9092:9092"
environment:
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092
- KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092
depends_on:
- zookeeper
zookeeper:
image: wurstmeister/zookeeper:3.4.6
ports:
- "2181:2181"
# 监控
prometheus:
image: prom/prometheus:v2.26.0
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:8.0.6
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
depends_on:
- prometheus
# 数据库
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=ecommerce
volumes:
- mysql-data:/var/lib/mysql
# 缓存
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
mysql-data:9.5.2 Kubernetes部署
yaml
# k8s/namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name: ecommerce
# k8s/discovery-server.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: discovery-server
namespace: ecommerce
spec:
replicas: 1
selector:
matchLabels:
app: discovery-server
template:
metadata:
labels:
app: discovery-server
spec:
containers:
- name: discovery-server
image: your-registry/discovery-server:latest
ports:
- containerPort: 8761
env:
- name: SPRING_PROFILES_ACTIVE
value: kubernetes
---
apiVersion: v1
kind: Service
metadata:
name: discovery-server
namespace: ecommerce
spec:
selector:
app: discovery-server
ports:
- port: 8761
targetPort: 8761
# k8s/api-gateway.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: ecommerce
spec:
replicas: 2
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: api-gateway
image: your-registry/api-gateway:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: kubernetes
- name: EUREKA_CLIENT_SERVICEURL_DEFAULTZONE
value: http://discovery-server:8761/eureka/
---
apiVersion: v1
kind: Service
metadata:
name: api-gateway
namespace: ecommerce
spec:
selector:
app: api-gateway
ports:
- port: 80
targetPort: 8080
type: LoadBalancer9.6 项目监控
应用监控
- 配置Prometheus监控应用指标
- 使用Grafana创建监控仪表盘
- 设置告警规则
日志监控
- 配置ELK Stack收集日志
- 设置日志告警
- 定期清理日志
分布式追踪
- 配置SkyWalking进行链路追踪
- 分析服务调用链
- 识别性能瓶颈
健康检查
- 实现API健康检查端点
- 配置Kubernetes健康检查
- 定期执行端到端测试
10. 最佳实践与总结
10.1 微服务架构最佳实践
服务设计
- 遵循单一职责原则
- 定义清晰的服务边界
- 设计稳定的API接口
- 使用领域驱动设计(DDD)指导服务拆分
技术选型
- 根据服务特性选择合适的技术栈
- 统一核心框架和工具
- 考虑技术的成熟度和社区支持
开发流程
- 采用敏捷开发方法
- 实现持续集成和持续部署
- 自动化测试
- 代码审查
部署运维
- 使用容器化技术
- 采用基础设施即代码
- 实现自动化部署
- 建立完善的监控体系
团队协作
- 采用DevOps文化
- 建立跨功能团队
- 促进知识共享
- 建立清晰的沟通机制
10.2 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 服务调用超时 | 网络延迟或服务响应慢 | 实现熔断和超时机制,优化服务性能 |
| 服务实例发现失败 | 服务注册延迟或网络问题 | 增加服务健康检查,实现重试机制 |
| 配置更新不及时 | 配置中心同步延迟 | 实现配置的动态刷新,增加配置版本控制 |
| 分布式事务不一致 | 部分服务失败 | 采用Saga模式或TCC模式,实现补偿机制 |
| 系统性能下降 | 服务调用链过长或资源不足 | 优化服务调用链,实现缓存,增加资源 |
| 安全漏洞 | 认证授权不严格或依赖漏洞 | 加强认证授权,定期安全扫描,及时更新依赖 |
10.3 技术展望
服务网格
- 服务网格技术的普及
- 简化服务间通信和安全管理
无服务器架构
- Function as a Service (FaaS)的应用
- 进一步简化运维
AI驱动的微服务
- 使用AI优化服务调度
- 智能故障预测和自愈
边缘计算
- 微服务在边缘设备的部署
- 边缘与云的协同
多云部署
- 跨云平台的微服务部署
- 云厂商中立的微服务架构
10.4 学习建议
实践为主
- 搭建微服务架构的实验环境
- 开发和部署实际的微服务应用
深入学习
- 学习微服务架构的核心概念和原理
- 了解各种微服务框架和工具
持续关注
- 关注微服务技术的最新发展
- 参与社区活动和讨论
项目实战
- 参与或构建微服务架构项目
- 积累实际项目经验
认证考试
- 考取相关的微服务和云原生认证
- 提升专业技能和竞争力
微服务架构是现代软件架构的重要趋势,掌握微服务架构的设计和实现技术将为你的职业发展打开新的大门。通过本课程的学习,你已经具备了构建和管理微服务架构的核心能力,希望你能够在实际工作中不断实践和创新,成为一名优秀的微服务架构师。