跳转至

第6章:微服务架构

微服务架构

6.1 微服务概述

什么是微服务

微服务架构是一种将单一应用程序开发为一套小型服务的方法,每个服务运行在自己的进程中,并使用轻量级机制(通常是HTTP API)进行通信。

微服务的特点

  1. 单一职责:每个服务只做一件事
  2. 独立部署:服务可以独立部署和扩展
  3. 技术栈灵活:不同服务可以使用不同技术
  4. 去中心化:没有中心化的管理

微服务的优势

  1. 开发效率高:小团队独立开发
  2. 部署灵活:独立部署,快速迭代
  3. 技术选型灵活:根据需求选择技术
  4. 容错性强:单个服务故障不影响整体

微服务的挑战

  1. 运维复杂:需要管理大量服务
  2. 分布式事务:跨服务事务处理复杂
  3. 服务治理:服务发现、负载均衡等
  4. 调试困难:分布式系统调试困难

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
电商系统
├── 用户服务
├── 商品服务
├── 订单服务
├── 支付服务
└── 库存服务

水平拆分

按数据量拆分。

示例

Text Only
订单服务
├── 订单服务1(订单ID < 1000000)
├── 订单服务2(1000000 <= 订单ID < 2000000)
└── 订单服务3(订单ID >= 2000000)

按读写拆分

将读操作和写操作拆分。

示例

Text Only
商品服务
├── 商品写服务(创建、更新商品)
└── 商品读服务(查询商品)

6.2.3 拆分步骤

  1. 识别业务边界
  2. 定义服务接口
  3. 拆分数据存储
  4. 实现服务通信
  5. 迁移数据
  6. 灰度发布
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 配置中心的作用

  1. 集中管理:统一管理所有服务的配置
  2. 动态更新:配置变更无需重启服务
  3. 版本控制:配置版本管理
  4. 环境隔离:不同环境使用不同配置

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)

YAML
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-repo/config-repo

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 面试准备

常见面试题

  1. 什么是微服务?它解决了什么问题?
  2. 如何进行微服务拆分?
  3. 什么是服务发现?有哪些实现方案?
  4. 微服务之间如何通信?
  5. 微服务的优缺点?

项目经验准备

准备一个微服务项目: - 服务拆分方案 - 技术选型 - 遇到的挑战 - 解决方案

6.8 总结

本章介绍了微服务架构,包括微服务拆分、服务发现、配置中心和服务通信。微服务架构是现代系统架构的主流选择。

关键要点

  1. 微服务按业务边界拆分,每个服务独立部署
  2. 服务发现用于管理服务实例
  3. 配置中心集中管理服务配置
  4. 服务通信可以使用REST API、gRPC、消息队列
  5. 微服务提高了开发效率,但增加了运维复杂度

下一步

下一章将深入学习服务治理,包括负载均衡、熔断降级、限流等内容。