第6章:微服务架构¶
6.1 微服务概述¶
什么是微服务¶
微服务架构是一种将单一应用程序开发为一套小型服务的方法,每个服务运行在自己的进程中,并使用轻量级机制(通常是HTTP API)进行通信。
微服务的特点¶
- 单一职责:每个服务只做一件事
- 独立部署:服务可以独立部署和扩展
- 技术栈灵活:不同服务可以使用不同技术
- 去中心化:没有中心化的管理
微服务的优势¶
- 开发效率高:小团队独立开发
- 部署灵活:独立部署,快速迭代
- 技术选型灵活:根据需求选择技术
- 容错性强:单个服务故障不影响整体
微服务的挑战¶
- 运维复杂:需要管理大量服务
- 分布式事务:跨服务事务处理复杂
- 服务治理:服务发现、负载均衡等
- 调试困难:分布式系统调试困难
6.2 微服务拆分¶
6.2.1 拆分原则¶
单一职责原则¶
每个服务应该只负责一个业务领域。
示例: - 用户服务:用户管理 - 订单服务:订单管理 - 商品服务:商品管理
业务边界原则¶
根据业务边界拆分,保持业务完整性。
示例: - 电商系统可以拆分为: - 用户服务 - 商品服务 - 订单服务 - 支付服务 - 库存服务
数据独立性原则¶
每个服务拥有独立的数据存储。
示例:
Python
# 用户服务使用MySQL
class UserService:
def __init__(self):
self.db = MySQLConnection('user_db')
def get_user(self, user_id):
return self.db.query("SELECT * FROM users WHERE id = %s", user_id)
# 订单服务使用MongoDB
class OrderService:
def __init__(self):
self.db = MongoClient('order_db')
def get_order(self, order_id):
return self.db.orders.find_one({'id': order_id})
6.2.2 拆分策略¶
垂直拆分¶
按业务功能拆分。
示例:
水平拆分¶
按数据量拆分。
示例:
Text Only
订单服务
├── 订单服务1(订单ID < 1000000)
├── 订单服务2(1000000 <= 订单ID < 2000000)
└── 订单服务3(订单ID >= 2000000)
按读写拆分¶
将读操作和写操作拆分。
示例:
6.2.3 拆分步骤¶
- 识别业务边界
- 定义服务接口
- 拆分数据存储
- 实现服务通信
- 迁移数据
- 灰度发布
Python
# 示例:从单体应用拆分微服务
# 原单体应用
class MonolithicApp:
def create_order(self, user_id, product_id):
# 获取用户
user = self.get_user(user_id)
# 获取商品
product = self.get_product(product_id)
# 创建订单
order = self.create_order_record(user, product)
return order
# 拆分后的微服务
class OrderService:
def __init__(self):
self.user_client = UserClient()
self.product_client = ProductClient()
self.db = OrderDatabase()
def create_order(self, user_id, product_id):
# 调用用户服务
user = self.user_client.get_user(user_id)
# 调用商品服务
product = self.product_client.get_product(product_id)
# 创建订单
order = self.db.create_order(user, product)
return order
6.3 服务发现¶
6.3.1 服务注册中心¶
服务注册中心用于管理服务实例的注册和发现。
主流方案: - Eureka - Consul - ZooKeeper - Nacos
6.3.2 Eureka¶
Java
// 服务端配置
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
// 客户端配置
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// 服务调用
@RestController
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/order/{id}")
public Order getOrder(@PathVariable String id) {
// 发现服务
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
ServiceInstance instance = instances.get(0);
// 调用服务
String url = instance.getUri() + "/user/" + id;
User user = restTemplate.getForObject(url, User.class);
return order;
}
}
6.3.3 Consul¶
Python
import consul
# 服务注册
consul_client = consul.Consul(host='localhost', port=8500)
consul_client.agent.service.register(
name='user-service',
service_id='user-service-1',
address='localhost',
port=8001,
tags=['user', 'api']
)
# 服务发现
services = consul_client.agent.services()
user_services = [s for s in services.values() if s['Service'] == 'user-service']
# 调用服务
if user_services:
service = user_services[0]
url = f"http://{service['Address']}:{service['Port']}/user/1"
response = requests.get(url)
6.3.4 Nacos¶
Python
from nacos import NacosClient
# 服务注册
client = NacosClient('localhost', 8848)
client.add_naming_instance(
service_name='user-service',
ip='127.0.0.1',
port=8001,
cluster_name='DEFAULT',
weight=1.0
)
# 服务发现
instances = client.list_naming_instance(
service_name='user-service',
cluster_name='DEFAULT'
)
# 调用服务
if instances:
instance = instances['hosts'][0]
url = f"http://{instance['ip']}:{instance['port']}/user/1"
response = requests.get(url)
6.4 配置中心¶
6.4.1 配置中心的作用¶
- 集中管理:统一管理所有服务的配置
- 动态更新:配置变更无需重启服务
- 版本控制:配置版本管理
- 环境隔离:不同环境使用不同配置
6.4.2 Spring Cloud Config¶
Java
// 配置服务器
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
配置文件(application.yml):
Java
// 客户端配置
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// 使用配置
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String version;
6.4.3 Apollo¶
Python
from apollo_client import Config
# 创建配置客户端
config = Config(
app_id='user-service',
namespace='application',
config_server_url='http://localhost:8080'
)
# 获取配置
app_name = config.get_value('app.name', 'default')
app_version = config.get_value('app.version', '1.0.0')
# 监听配置变更
def config_change_handler(change):
print(f"Config changed: {change}")
config.add_change_listener(config_change_handler)
6.5 服务通信¶
6.5.1 REST API¶
Python
from fastapi import FastAPI, HTTPException
import httpx
app = FastAPI()
# 用户服务
@app.get("/users/{user_id}")
async def get_user(user_id: int): # async def定义异步函数;用await调用
user = db.query("SELECT * FROM users WHERE id = %s", user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
# 订单服务调用用户服务
@app.post("/orders")
async def create_order(user_id: int, product_id: int):
# 调用用户服务
async with httpx.AsyncClient() as client:
response = await client.get(f"http://user-service/users/{user_id}") # await等待异步操作完成
if response.status_code == 404:
raise HTTPException(status_code=404, detail="User not found")
user = response.json()
# 创建订单
order = create_order_record(user, product_id)
return order
6.5.2 gRPC¶
Protocol Buffer
// user_service.proto
syntax = "proto3";
service UserService {
rpc GetUser(GetUserRequest) returns (GetUserResponse);
}
message GetUserRequest {
int32 user_id = 1;
}
message GetUserResponse {
int32 id = 1;
string name = 2;
string email = 3;
}
Python
# 服务端实现
import grpc
from concurrent import futures
class UserServiceImpl(user_service_pb2_grpc.UserServiceServicer):
def GetUser(self, request, context):
user = db.query("SELECT * FROM users WHERE id = %s", request.user_id)
if not user:
context.set_code(grpc.StatusCode.NOT_FOUND)
context.set_details('User not found')
return user_service_pb2.GetUserResponse()
return user_service_pb2.GetUserResponse(
id=user['id'],
name=user['name'],
email=user['email']
)
# 客户端调用
# ⚠️ 安全警告:grpc.insecure_channel() 不使用 TLS 加密,数据以明文传输。
# 生产环境请使用 grpc.secure_channel() 并配置 TLS 证书:
# credentials = grpc.ssl_channel_credentials(root_certificates=...)
# channel = grpc.secure_channel('host:port', credentials)
def get_user(user_id):
with grpc.insecure_channel('localhost:50051') as channel:
stub = user_service_pb2_grpc.UserServiceStub(channel)
response = stub.GetUser(user_service_pb2.GetUserRequest(user_id=user_id))
return response
6.5.3 消息队列¶
Python
# 使用消息队列进行异步通信
import json
from kafka import KafkaProducer, KafkaConsumer
# 生产者:订单服务
producer = KafkaProducer(
bootstrap_servers=['localhost:9092'],
value_serializer=lambda v: json.dumps(v).encode('utf-8') # lambda匿名函数:简洁的单行函数
)
def create_order(user_id, product_id):
# 创建订单
order = db.create_order(user_id, product_id)
# 发送消息到库存服务
producer.send('order-created', {
'order_id': order['id'],
'product_id': product_id,
'quantity': 1
})
return order
# 消费者:库存服务
consumer = KafkaConsumer(
'order-created',
bootstrap_servers=['localhost:9092'],
value_deserializer=lambda m: json.loads(m.decode('utf-8')) # json.loads将JSON字符串转为Python对象
)
for message in consumer:
# 扣减库存
deduct_inventory(message.value['product_id'], message.value['quantity'])
6.6 实战练习¶
练习1:设计一个微服务架构¶
为一个电商平台设计微服务架构: 1. 确定服务拆分方案 2. 设计服务接口 3. 选择服务发现方案 4. 设计配置中心
练习2:实现服务注册与发现¶
使用Consul实现服务注册与发现: 1. 实现服务注册 2. 实现服务发现 3. 实现服务调用
练习3:实现配置中心¶
使用Apollo实现配置中心: 1. 配置服务端 2. 配置客户端 3. 实现配置动态更新
6.7 面试准备¶
常见面试题¶
- 什么是微服务?它解决了什么问题?
- 如何进行微服务拆分?
- 什么是服务发现?有哪些实现方案?
- 微服务之间如何通信?
- 微服务的优缺点?
项目经验准备¶
准备一个微服务项目: - 服务拆分方案 - 技术选型 - 遇到的挑战 - 解决方案
6.8 总结¶
本章介绍了微服务架构,包括微服务拆分、服务发现、配置中心和服务通信。微服务架构是现代系统架构的主流选择。
关键要点¶
- 微服务按业务边界拆分,每个服务独立部署
- 服务发现用于管理服务实例
- 配置中心集中管理服务配置
- 服务通信可以使用REST API、gRPC、消息队列
- 微服务提高了开发效率,但增加了运维复杂度
下一步¶
下一章将深入学习服务治理,包括负载均衡、熔断降级、限流等内容。