第二部分:全栈开发技能(3篇)—— 后端架构设计:从单体应用到微服务演进
·
后端架构设计:从单体应用到微服务演进
引言
三年前,我参与了一个电商平台的架构升级项目。当时系统已经无法支撑快速增长的业务需求:部署一次要停机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. 完整微服务
- 所有模块都是独立服务
- 完善的基础设施
总结
选择架构的黄金法则:
- 从简单开始:不要过早优化
- 根据需求选择:没有最好的架构,只有最合适的
- 渐进式演进:架构是演进出来的,不是设计出来的
- 关注业务价值:技术服务于业务
记住:架构设计的目标是降低系统的复杂度,而不是增加复杂度。
文章字数:约10500字
阅读时间:约40分钟
难度等级:★★★★☆(适合有一定后端开发经验的学习者)
更多推荐

所有评论(0)