后端架构设计:从单体应用到微服务演进

引言

三年前,我参与了一个电商平台的架构升级项目。当时系统已经无法支撑快速增长的业务需求:部署一次要停机2小时,一个小bug需要重启整个系统,双十一流量高峰时整个服务都会崩溃。

经过半年的努力,我们将单体应用拆分为微服务架构,实现了零停机部署、灰度发布、弹性伸缩。系统可用性从95%提升到99.9%,部署频率从每月一次提升到每天多次。

这段经历让我深刻认识到:架构设计不是炫技,而是根据业务需求选择最合适的方案。

本文将带你系统地了解后端架构设计,从单体到微服务的演进之路。

第一章:单体应用架构

1.1 什么是单体应用?

单体应用是将所有功能模块打包在一个应用中部署运行的架构模式。

┌─────────────────────────────┐
│      单体应用              │
│  ┌──────────────────────┐  │
│  │   用户模块           │  │
│  ├──────────────────────┤  │
│  │   商品模块           │  │
│  ├──────────────────────┤  │
│  │   订单模块           │  │
│  ├──────────────────────┤  │
│  │   支付模块           │  │
│  └──────────────────────┘  │
│           ↓                 │
│      [共享数据库]          │
└─────────────────────────────┘

1.2 单体应用的三层架构

// 经典的三层架构示例
// 1. Controller层(控制层)
@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public Response<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return Response.success(user);
    }
    
    @PostMapping
    public Response<User> createUser(@RequestBody User user) {
        User created = userService.createUser(user);
        return Response.success(created);
    }
}

// 2. Service层(业务逻辑层)
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private EmailService emailService;
    
    @Transactional
    public User createUser(User user) {
        // 业务逻辑
        validateUser(user);
        User saved = userRepository.save(user);
        emailService.sendWelcomeEmail(user.getEmail());
        return saved;
    }
    
    public User getUserById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
    }
    
    private void validateUser(User user) {
        if (user.getEmail() == null || !user.getEmail().contains("@")) {
            throw new InvalidEmailException();
        }
    }
}

// 3. Repository层(数据访问层)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
    List<User> findByAgeGreaterThan(int age);
}

1.3 单体应用的优缺点

优点:

  • ✅ 开发简单:所有代码在一起,易于理解
  • ✅ 部署简单:只需部署一个应用
  • ✅ 测试简单:启动一个进程就能测试
  • ✅ 容易调试:可以直接打断点调试

缺点:

  • ❌ 扩展困难:必须整体扩展,无法针对性优化
  • ❌ 部署风险:一处改动需要重新部署整个应用
  • ❌ 技术栈受限:整个应用必须使用相同技术
  • ❌ 代码耦合:随着功能增加,代码越来越难维护

1.4 何时使用单体架构?

✅ 适合场景:

  • 初创项目,需求不明确
  • 团队规模小(<10人)
  • 业务相对简单
  • 追求快速上线

❌ 不适合场景:

  • 业务复杂,模块众多
  • 团队规模大,需要并行开发
  • 需要频繁部署更新
  • 不同模块有不同的性能需求

第二章:分层架构优化

2.1 DDD领域驱动设计

// 传统的贫血模型
public class Order {
    private Long id;
    private String status;
    private BigDecimal amount;
    // 只有getter/setter
}

public class OrderService {
    public void completeOrder(Order order) {
        // 业务逻辑全在Service层
        order.setStatus("COMPLETED");
        order.setCompletedTime(new Date());
        orderRepository.save(order);
    }
}

// DDD的充血模型
public class Order {
    private Long id;
    private OrderStatus status;
    private Money amount;
    private List<OrderItem> items;
    
    // 业务逻辑在领域对象内
    public void complete() {
        if (this.status != OrderStatus.PAID) {
            throw new IllegalStateException("只有已支付订单才能完成");
        }
        this.status = OrderStatus.COMPLETED;
        this.completedTime = LocalDateTime.now();
        // 发布领域事件
        DomainEventPublisher.publish(new OrderCompletedEvent(this));
    }
    
    public void cancel(String reason) {
        if (this.status == OrderStatus.COMPLETED) {
            throw new IllegalStateException("已完成订单不能取消");
        }
        this.status = OrderStatus.CANCELLED;
        this.cancelReason = reason;
        DomainEventPublisher.publish(new OrderCancelledEvent(this));
    }
    
    public Money calculateTotal() {
        return items.stream()
            .map(OrderItem::getSubtotal)
            .reduce(Money.ZERO, Money::add);
    }
}

// 应用服务层变得更薄
@Service
public class OrderApplicationService {
    @Autowired
    private OrderRepository orderRepository;
    
    @Transactional
    public void completeOrder(Long orderId) {
        Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
        
        // 调用领域对象的方法
        order.complete();
        
        orderRepository.save(order);
    }
}

2.2 分层架构最佳实践

┌─────────────────────────────────┐
│     表现层(Presentation)      │  ← HTTP请求、响应
├─────────────────────────────────┤
│     应用层(Application)       │  ← 用例、流程编排
├─────────────────────────────────┤
│     领域层(Domain)            │  ← 核心业务逻辑
├─────────────────────────────────┤
│     基础设施层(Infrastructure)│  ← 数据库、缓存、MQ
└─────────────────────────────────┘
# Python FastAPI示例
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

# 1. Domain层:领域模型
class User:
    def __init__(self, id, email, password):
        self.id = id
        self.email = email
        self._password = password
    
    def verify_password(self, password):
        return check_password(password, self._password)
    
    def change_password(self, old_password, new_password):
        if not self.verify_password(old_password):
            raise ValueError("原密码错误")
        self._password = hash_password(new_password)

# 2. Infrastructure层:数据持久化
class UserRepository:
    def __init__(self, db: Session):
        self.db = db
    
    def get_by_id(self, user_id: int) -> User:
        user_model = self.db.query(UserModel).filter_by(id=user_id).first()
        if not user_model:
            raise UserNotFound(user_id)
        return self._to_domain(user_model)
    
    def save(self, user: User):
        user_model = self._to_model(user)
        self.db.add(user_model)
        self.db.commit()
    
    def _to_domain(self, model):
        return User(model.id, model.email, model.password)
    
    def _to_model(self, domain):
        return UserModel(
            id=domain.id,
            email=domain.email,
            password=domain._password
        )

# 3. Application层:用例
class ChangePasswordUseCase:
    def __init__(self, user_repo: UserRepository):
        self.user_repo = user_repo
    
    def execute(self, user_id: int, old_password: str, new_password: str):
        # 获取用户
        user = self.user_repo.get_by_id(user_id)
        
        # 执行业务逻辑
        user.change_password(old_password, new_password)
        
        # 保存
        self.user_repo.save(user)
        
        return {"message": "密码修改成功"}

# 4. Presentation层:API接口
app = FastAPI()

@app.post("/users/{user_id}/change-password")
def change_password(
    user_id: int,
    request: ChangePasswordRequest,
    db: Session = Depends(get_db)
):
    repo = UserRepository(db)
    use_case = ChangePasswordUseCase(repo)
    result = use_case.execute(user_id, request.old_password, request.new_password)
    return result

第三章:服务化架构(SOA)

3.1 SOA基础概念

┌─────────────┐     ┌─────────────┐
│  用户服务   │────▶│  订单服务   │
└─────────────┘     └─────────────┘
       │                    │
       │                    ▼
       │            ┌─────────────┐
       └───────────▶│  支付服务   │
                    └─────────────┘
         通过ESB(企业服务总线)通信

3.2 RESTful API设计

// Node.js + Express 示例
const express = require('express');
const app = express();

// 用户服务API
app.get('/api/v1/users', async (req, res) => {
  // 获取用户列表
  const { page = 1, limit = 10, sort = 'created_at' } = req.query;
  const users = await userService.getUsers({ page, limit, sort });
  
  res.json({
    data: users,
    pagination: {
      page: parseInt(page),
      limit: parseInt(limit),
      total: await userService.count()
    }
  });
});

app.get('/api/v1/users/:id', async (req, res) => {
  // 获取单个用户
  const user = await userService.getUserById(req.params.id);
  if (!user) {
    return res.status(404).json({ error: 'User not found' });
  }
  res.json({ data: user });
});

app.post('/api/v1/users', async (req, res) => {
  // 创建用户
  const { email, name, password } = req.body;
  
  // 验证
  if (!email || !password) {
    return res.status(400).json({ error: 'Email and password are required' });
  }
  
  const user = await userService.createUser({ email, name, password });
  res.status(201).json({ data: user });
});

app.put('/api/v1/users/:id', async (req, res) => {
  // 更新用户
  const user = await userService.updateUser(req.params.id, req.body);
  res.json({ data: user });
});

app.delete('/api/v1/users/:id', async (req, res) => {
  // 删除用户
  await userService.deleteUser(req.params.id);
  res.status(204).send();
});

// RESTful最佳实践
// 1. 使用HTTP动词表示操作
// 2. 使用名词表示资源
// 3. 使用合适的HTTP状态码
// 4. 提供版本控制
// 5. 支持分页、排序、过滤
// 6. 返回统一的数据格式

3.3 服务间通信

// Go语言gRPC示例
// 1. 定义proto文件
// user.proto
syntax = "proto3";

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc CreateUser(CreateUserRequest) returns (User);
  rpc UpdateUser(UpdateUserRequest) returns (User);
}

message GetUserRequest {
  int64 id = 1;
}

message User {
  int64 id = 1;
  string email = 2;
  string name = 3;
  int64 created_at = 4;
}

// 2. 服务端实现
type userServiceServer struct {
    pb.UnimplementedUserServiceServer
    userRepo *UserRepository
}

func (s *userServiceServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
    user, err := s.userRepo.GetByID(req.Id)
    if err != nil {
        return nil, status.Errorf(codes.NotFound, "user not found: %v", err)
    }
    
    return &pb.User{
        Id:        user.ID,
        Email:     user.Email,
        Name:      user.Name,
        CreatedAt: user.CreatedAt.Unix(),
    }, nil
}

// 3. 客户端调用
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := pb.NewUserServiceClient(conn)

user, err := client.GetUser(context.Background(), &pb.GetUserRequest{
    Id: 123,
})
if err != nil {
    log.Fatal(err)
}

fmt.Printf("User: %v\n", user)

第四章:微服务架构

4.1 微服务架构全景

                   ┌──────────────┐
                   │  API Gateway │
                   └──────┬───────┘
                          │
        ┌─────────────────┼─────────────────┐
        │                 │                 │
   ┌────▼────┐      ┌────▼────┐      ┌────▼────┐
   │用户服务 │      │商品服务 │      │订单服务 │
   └────┬────┘      └────┬────┘      └────┬────┘
        │                │                 │
   ┌────▼────┐      ┌────▼────┐      ┌────▼────┐
   │用户DB   │      │商品DB   │      │订单DB   │
   └─────────┘      └─────────┘      └─────────┘
   
        所有服务注册到服务注册中心
              ┌──────────────┐
              │服务注册中心  │
              └──────────────┘

4.2 Spring Cloud微服务示例

// 1. 服务注册中心(Eureka Server)
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// application.yml
server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

// 2. 用户微服务
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    @Autowired
    private OrderServiceClient orderServiceClient;
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    @GetMapping("/{id}/orders")
    public List<Order> getUserOrders(@PathVariable Long id) {
        // 通过Feign调用订单服务
        return orderServiceClient.getOrdersByUserId(id);
    }
}

// 3. Feign客户端(调用其他服务)
@FeignClient(name = "order-service")
public interface OrderServiceClient {
    @GetMapping("/orders/user/{userId}")
    List<Order> getOrdersByUserId(@PathVariable("userId") Long userId);
}

// 4. 配置中心
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

// 5. API网关(Gateway)
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-Gateway", "true")
                    .circuitBreaker(c -> c
                        .setName("userServiceCircuitBreaker")
                        .setFallbackUri("/fallback/users")
                    )
                )
                .uri("lb://user-service")
            )
            .route("order-service", r -> r
                .path("/api/orders/**")
                .filters(f -> f.stripPrefix(1))
                .uri("lb://order-service")
            )
            .build();
    }
}

4.3 服务治理

4.3.1 服务熔断(Circuit Breaker)
// 使用Resilience4j实现熔断
@Service
public class OrderService {
    @Autowired
    private UserServiceClient userServiceClient;
    
    @CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
    @Retry(name = "userService")
    @RateLimiter(name = "userService")
    public User getUser(Long userId) {
        return userServiceClient.getUser(userId);
    }
    
    // 降级方法
    private User getUserFallback(Long userId, Exception ex) {
        log.error("Failed to get user {}, using fallback", userId, ex);
        return new User(userId, "Unknown User", "fallback@example.com");
    }
}

// application.yml配置
resilience4j:
  circuitbreaker:
    instances:
      userService:
        sliding-window-size: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s
        permitted-number-of-calls-in-half-open-state: 3
  retry:
    instances:
      userService:
        max-attempts: 3
        wait-duration: 500ms
  ratelimiter:
    instances:
      userService:
        limit-for-period: 100
        limit-refresh-period: 1s
4.3.2 服务限流
# Python使用Redis实现令牌桶限流
import time
import redis

class TokenBucketRateLimiter:
    def __init__(self, redis_client, capacity=100, refill_rate=10):
        """
        capacity: 桶容量
        refill_rate: 每秒填充速率
        """
        self.redis = redis_client
        self.capacity = capacity
        self.refill_rate = refill_rate
    
    def allow_request(self, key):
        """检查是否允许请求"""
        bucket_key = f"rate_limit:{key}"
        now = time.time()
        
        # 使用Lua脚本保证原子性
        lua_script = """
        local capacity = tonumber(ARGV[1])
        local refill_rate = tonumber(ARGV[2])
        local now = tonumber(ARGV[3])
        local requested = tonumber(ARGV[4])
        
        local bucket = redis.call('HMGET', KEYS[1], 'tokens', 'last_refill')
        local tokens = tonumber(bucket[1]) or capacity
        local last_refill = tonumber(bucket[2]) or now
        
        -- 计算应该补充的令牌
        local time_passed = now - last_refill
        local tokens_to_add = time_passed * refill_rate
        tokens = math.min(capacity, tokens + tokens_to_add)
        
        -- 检查是否有足够的令牌
        if tokens >= requested then
            tokens = tokens - requested
            redis.call('HMSET', KEYS[1], 'tokens', tokens, 'last_refill', now)
            redis.call('EXPIRE', KEYS[1], 3600)
            return 1
        else
            return 0
        end
        """
        
        result = self.redis.eval(
            lua_script, 1, bucket_key,
            self.capacity, self.refill_rate, now, 1
        )
        
        return result == 1

# 使用
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse

app = FastAPI()
redis_client = redis.Redis(host='localhost', port=6379)
rate_limiter = TokenBucketRateLimiter(redis_client, capacity=100, refill_rate=10)

@app.get("/api/data")
async def get_data(user_id: str):
    if not rate_limiter.allow_request(f"user:{user_id}"):
        raise HTTPException(status_code=429, detail="Too Many Requests")
    
    return {"data": "some data"}

4.4 分布式事务

4.4.1 Saga模式
// 编排式Saga(Orchestration)
@Service
public class OrderSagaOrchestrator {
    @Autowired
    private OrderService orderService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private DeliveryService deliveryService;
    
    public void createOrder(CreateOrderRequest request) {
        String sagaId = UUID.randomUUID().toString();
        
        try {
            // 1. 创建订单
            Long orderId = orderService.createOrder(request);
            
            // 2. 扣减库存
            try {
                inventoryService.reserveStock(request.getItems());
            } catch (Exception e) {
                orderService.cancelOrder(orderId);
                throw e;
            }
            
            // 3. 支付
            try {
                paymentService.processPayment(orderId, request.getAmount());
            } catch (Exception e) {
                inventoryService.releaseStock(request.getItems());
                orderService.cancelOrder(orderId);
                throw e;
            }
            
            // 4. 安排配送
            try {
                deliveryService.scheduleDelivery(orderId);
            } catch (Exception e) {
                paymentService.refund(orderId);
                inventoryService.releaseStock(request.getItems());
                orderService.cancelOrder(orderId);
                throw e;
            }
            
        } catch (Exception e) {
            log.error("Saga failed: {}", sagaId, e);
            throw new SagaException("Order creation failed", e);
        }
    }
}

// 事件驱动式Saga(Choreography)
@Service
public class OrderService {
    @Autowired
    private EventPublisher eventPublisher;
    
    @Transactional
    public void createOrder(CreateOrderRequest request) {
        Order order = new Order(request);
        orderRepository.save(order);
        
        // 发布订单创建事件
        eventPublisher.publish(new OrderCreatedEvent(
            order.getId(),
            order.getItems(),
            order.getAmount()
        ));
    }
    
    @EventListener
    public void handlePaymentCompleted(PaymentCompletedEvent event) {
        Order order = orderRepository.findById(event.getOrderId());
        order.markAsPaid();
        orderRepository.save(order);
        
        // 发布订单已支付事件
        eventPublisher.publish(new OrderPaidEvent(order.getId()));
    }
    
    @EventListener
    public void handlePaymentFailed(PaymentFailedEvent event) {
        Order order = orderRepository.findById(event.getOrderId());
        order.cancel();
        orderRepository.save(order);
        
        // 发布订单取消事件(触发补偿)
        eventPublisher.publish(new OrderCancelledEvent(order.getId()));
    }
}

@Service
public class InventoryService {
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        try {
            reserveStock(event.getItems());
            eventPublisher.publish(new StockReservedEvent(event.getOrderId()));
        } catch (Exception e) {
            eventPublisher.publish(new StockReservationFailedEvent(event.getOrderId()));
        }
    }
    
    @EventListener
    public void handleOrderCancelled(OrderCancelledEvent event) {
        // 补偿:释放库存
        releaseStock(event.getOrderId());
    }
}
4.4.2 TCC模式
// Try-Confirm-Cancel模式
public interface TccTransaction {
    // 第一阶段:尝试执行,预留资源
    boolean try();
    
    // 第二阶段:确认执行
    boolean confirm();
    
    // 第二阶段:取消执行,释放资源
    boolean cancel();
}

@Service
public class PaymentTccService implements TccTransaction {
    @Override
    @Transactional
    public boolean try(PaymentRequest request) {
        // 冻结账户金额
        Account account = accountRepository.findById(request.getAccountId());
        if (account.getBalance() < request.getAmount()) {
            return false;
        }
        
        // 创建冻结记录
        FrozenBalance frozen = new FrozenBalance(
            request.getTransactionId(),
            account.getId(),
            request.getAmount()
        );
        frozenBalanceRepository.save(frozen);
        
        return true;
    }
    
    @Override
    @Transactional
    public boolean confirm(String transactionId) {
        // 扣减冻结的金额
        FrozenBalance frozen = frozenBalanceRepository.findByTransactionId(transactionId);
        Account account = accountRepository.findById(frozen.getAccountId());
        
        account.deduct(frozen.getAmount());
        accountRepository.save(account);
        
        frozenBalanceRepository.delete(frozen);
        return true;
    }
    
    @Override
    @Transactional
    public boolean cancel(String transactionId) {
        // 解冻金额
        FrozenBalance frozen = frozenBalanceRepository.findByTransactionId(transactionId);
        frozenBalanceRepository.delete(frozen);
        return true;
    }
}

第五章:高可用架构设计

5.1 负载均衡

# Nginx负载均衡配置
upstream backend {
    # 轮询(默认)
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
    
    # 加权轮询
    server backend1.example.com weight=5;
    server backend2.example.com weight=3;
    server backend3.example.com weight=2;
    
    # IP哈希
    ip_hash;
    
    # 最少连接
    least_conn;
    
    # 健康检查
    server backend1.example.com max_fails=3 fail_timeout=30s;
    
    # 备份服务器
    server backend4.example.com backup;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # 超时设置
        proxy_connect_timeout 5s;
        proxy_send_timeout 10s;
        proxy_read_timeout 10s;
        
        # 重试
        proxy_next_upstream error timeout http_500 http_502 http_503;
        proxy_next_upstream_tries 3;
    }
}

5.2 缓存策略

// 多级缓存架构
@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;
    
    @Autowired
    private RedisTemplate<String, Product> redisTemplate;
    
    // 本地缓存(Caffeine)
    private LoadingCache<Long, Product> localCache = Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(5, TimeUnit.MINUTES)
        .build(key -> getFromRedisOrDb(key));
    
    public Product getProduct(Long id) {
        // 1. 先查本地缓存
        return localCache.get(id);
    }
    
    private Product getFromRedisOrDb(Long id) {
        // 2. 再查Redis
        String key = "product:" + id;
        Product product = redisTemplate.opsForValue().get(key);
        
        if (product != null) {
            return product;
        }
        
        // 3. 最后查数据库
        product = productRepository.findById(id)
            .orElseThrow(() -> new ProductNotFoundException(id));
        
        // 写入Redis(设置随机过期时间防止缓存雪崩)
        long expireTime = 3600 + new Random().nextInt(600);
        redisTemplate.opsForValue().set(key, product, expireTime, TimeUnit.SECONDS);
        
        return product;
    }
    
    // 缓存更新
    @CacheEvict(value = "products", key = "#id")
    public void updateProduct(Long id, Product product) {
        productRepository.save(product);
        
        // 清除本地缓存
        localCache.invalidate(id);
        
        // 清除Redis缓存
        redisTemplate.delete("product:" + id);
        
        // 发送缓存失效消息到其他节点
        messagingService.sendCacheInvalidation("product", id);
    }
}

// 缓存穿透防护(布隆过滤器)
@Component
public class BloomFilterCache {
    private BloomFilter<Long> bloomFilter = BloomFilter.create(
        Funnels.longFunnel(),
        100000,  // 预期元素数量
        0.01     // 误判率
    );
    
    @PostConstruct
    public void init() {
        // 初始化时加载所有产品ID
        List<Long> productIds = productRepository.findAllIds();
        productIds.forEach(bloomFilter::put);
    }
    
    public boolean mightExist(Long productId) {
        return bloomFilter.mightContain(productId);
    }
}

// 缓存击穿防护(分布式锁)
public Product getProductWithLock(Long id) {
    String key = "product:" + id;
    String lockKey = "lock:product:" + id;
    
    // 先查缓存
    Product product = redisTemplate.opsForValue().get(key);
    if (product != null) {
        return product;
    }
    
    // 获取分布式锁
    Boolean lockAcquired = redisTemplate.opsForValue()
        .setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS);
    
    if (Boolean.TRUE.equals(lockAcquired)) {
        try {
            // 双重检查
            product = redisTemplate.opsForValue().get(key);
            if (product != null) {
                return product;
            }
            
            // 查询数据库
            product = productRepository.findById(id)
                .orElseThrow(() -> new ProductNotFoundException(id));
            
            // 写入缓存
            redisTemplate.opsForValue().set(key, product, 3600, TimeUnit.SECONDS);
            
            return product;
        } finally {
            // 释放锁
            redisTemplate.delete(lockKey);
        }
    } else {
        // 等待一段时间后重试
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return getProductWithLock(id);
    }
}

5.3 数据库读写分离

# Python Django示例
# settings.py
DATABASES = {
    'default': {},  # 主库(写)
    'replica1': {},  # 从库1(读)
    'replica2': {},  # 从库2(读)
}

DATABASE_ROUTERS = ['myapp.db_router.DatabaseRouter']

# db_router.py
import random

class DatabaseRouter:
    def db_for_read(self, model, **hints):
        """读操作路由到从库"""
        return random.choice(['replica1', 'replica2'])
    
    def db_for_write(self, model, **hints):
        """写操作路由到主库"""
        return 'default'
    
    def allow_relation(self, obj1, obj2, **hints):
        """允许任何关系"""
        return True
    
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """只在主库执行迁移"""
        return db == 'default'

# 使用
from django.db import transaction

# 读操作(自动使用从库)
users = User.objects.all()

# 写操作(自动使用主库)
user = User.objects.create(email='test@example.com')

# 强制使用主库读取(刚写入的数据)
with transaction.atomic(using='default'):
    user = User.objects.using('default').get(id=123)

第六章:架构选择指南

6.1 技术选型决策树

开始
  │
  ├─ 团队<10人? ──Yes─> 单体应用
  │      │
  │      No
  │      │
  ├─ 业务复杂度高? ──No─> 分层单体
  │      │
  │      Yes
  │      │
  ├─ 需要独立部署? ──No─> 模块化单体
  │      │
  │      Yes
  │      │
  └─> 微服务架构

6.2 各架构对比

维度单体应用SOA微服务
复杂度⭐⭐⭐⭐⭐⭐⭐⭐⭐
开发速度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
部署难度⭐⭐⭐⭐⭐⭐⭐⭐
可扩展性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
技术灵活性⭐⭐⭐⭐⭐⭐⭐⭐
运维成本⭐⭐⭐⭐⭐⭐⭐⭐⭐
团队要求⭐⭐⭐⭐⭐⭐⭐⭐⭐

6.3 迁移策略

单体应用演进路径:

1. 单体应用(All in One)
   ↓
2. 模块化单体(Modular Monolith)
   - 清晰的模块边界
   - 独立的包结构
   ↓
3. 垂直拆分(Strangler Pattern)
   - 先拆分独立的功能模块
   - 新功能用微服务开发
   ↓
4. 完整微服务
   - 所有模块都是独立服务
   - 完善的基础设施

总结

选择架构的黄金法则:

  1. 从简单开始:不要过早优化
  2. 根据需求选择:没有最好的架构,只有最合适的
  3. 渐进式演进:架构是演进出来的,不是设计出来的
  4. 关注业务价值:技术服务于业务

记住:架构设计的目标是降低系统的复杂度,而不是增加复杂度。


文章字数:约10500字
阅读时间:约40分钟
难度等级:★★★★☆(适合有一定后端开发经验的学习者)

更多推荐