高并发系统设计模式总结

Python并发编程专题 · 构建可扩展高吞吐系统的架构指南

专题:Python并发编程系统学习

关键词:Python, 并发编程, 高并发, 设计模式, Reactor, Actor模型, 熔断器, 限流算法

一、Reactor与Proactor模式

Reactor和Proactor是两种最核心的I/O多路复用架构模式,几乎所有高性能网络框架(Netty、Nginx、Node.js、Python asyncio)都基于它们构建。理解这两种模式的区别,是掌握高并发网络编程的基础。

1.1 Reactor模式:事件驱动的同步非阻塞I/O

Reactor模式的核心思想是"事件多路复用 + 事件处理器注册"。由一个Reactor对象负责监听所有I/O事件(可读、可写、连接建立等),当事件发生时将事件分发给对应的事件处理器(Handler)去处理。整个过程是同步的——应用程序发起I/O操作后不会阻塞等待,而是立即返回,当数据准备好后再通过回调通知。

Python中的asyncio本质上是Reactor模式的实现。事件循环(Event Loop)扮演Reactor的角色,负责轮询所有Future/Awaitable对象的状态;协程(Coroutine)则充当事件处理器。当await一个协程时,控制权交还给事件循环,事件循环继续处理其他任务,直到被等待的操作完成再切换回来。

Reactor模式有以下三种变体:

# 简易的Reactor模式实现(Python示例) import selectors import socket class Reactor: """简单的Reactor事件循环""" def __init__(self): self._selector = selectors.DefaultSelector() self._handlers = {} # fd -> handler def register(self, sock, events, handler): """注册socket和对应的事件处理器""" self._selector.register(sock, events, handler) def unregister(self, sock): """注销socket""" self._selector.unregister(sock) def run(self): """启动事件循环""" while True: events = self._selector.select(timeout=None) for key, mask in events: handler = key.data handler(key.fileobj, mask) # 使用示例:Echo服务器 def accept_handler(sock, mask): """接受新连接""" conn, addr = sock.accept() conn.setblocking(False) reactor.register(conn, selectors.EVENT_READ, echo_handler) def echo_handler(conn, mask): """处理客户端数据""" data = conn.recv(1024) if data: conn.sendall(data) else: reactor.unregister(conn) conn.close() reactor = Reactor() server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', 8888)) server.listen(100) server.setblocking(False) reactor.register(server, selectors.EVENT_READ, accept_handler) reactor.run()

1.2 Proactor模式:异步非阻塞I/O

Proactor模式与Reactor最大的区别在于:Reactor在事件就绪时通知应用程序去读/写(应用程序自己完成读/写操作),而Proactor在操作完成时通知应用程序操作结果(操作系统完成读/写操作)。前者是"告诉我什么时候可以读",后者是"帮我把数据读到缓冲区然后告诉我"。

Proactor模式依赖操作系统的真正异步I/O接口(如Windows的IOCP、Linux的io_uring)。在Python中,可以通过asyncio配合ProactorEventLoop(Windows平台默认)使用。Linux平台传统上缺乏真正的异步I/O(AIO有诸多限制),直到io_uring的出现才真正实现Proactor模式。

核心对比:Reactor是"事件就绪通知",Proactor是"操作完成通知"。在Linux上推荐使用Reactor模式(epoll),因为io_uring的上层封装尚不成熟;在Windows上Proactor(IOCP)是最高效的选择。Python asyncio在Windows上默认使用ProactorEventLoop,在Linux上默认使用SelectorEventLoop(基于epoll的Reactor)。

二、Actor模型

Actor模型起源于1973年,由Carl Hewitt提出,是处理高并发分布式系统的经典计算模型。其核心理念是"一切皆Actor"——每个Actor是一个独立的计算单元,拥有自己的私有状态,通过异步消息传递与其他Actor通信,不共享任何可变状态。

2.1 Actor模型的三大特征

2.2 Actor模型在Python中的实现

Python社区有多个Actor模型的实现库,最成熟的是pykka和thespian。此外也可以基于multiprocessing或asyncio自行实现轻量级Actor框架。需要注意的是,由于GIL的存在,基于线程的Actor实现无法真正利用多核,通常建议基于多进程实现。

# 基于multiprocessing的简易Actor实现 import multiprocessing as mp from queue import Empty import time class Actor(mp.Process): """Actor基类""" def __init__(self): super().__init__() self._mailbox = mp.Queue() def send(self, message): """向Actor发送消息(异步非阻塞)""" self._mailbox.put(message) def run(self): """不断从邮箱取消息并处理,子类需覆写on_message""" while True: try: message = self._mailbox.get(timeout=1) self.on_message(message) except Empty: continue except KeyboardInterrupt: break def on_message(self, message): """处理消息——子类实现""" raise NotImplementedError class CounterActor(Actor): """计数器Actor示例""" def __init__(self): super().__init__() self._count = 0 def on_message(self, message): if message == 'increment': self._count += 1 print(f'计数: {self._count}') elif message == 'get_count': print(f'当前计数: {self._count}') elif message == 'stop': self.terminate() if __name__ == '__main__': actor = CounterActor() actor.start() actor.send('increment') actor.send('increment') actor.send('increment') actor.send('get_count') time.sleep(1) actor.send('stop') actor.join()

2.3 Actor模型的适用场景

Actor模型最适合有大量独立实体、实体之间通过消息通信的场景。典型的应用包括:分布式聊天系统(每个用户连接对应一个Actor)、游戏服务器(每个玩家/房间对应一个Actor)、物联网设备管理(每个设备对应一个Actor)以及金融交易系统(每个订单流对应一个Actor)。Akka(JVM)和Erlang/OTP是Actor模型最成功的工业级实现。

三、事件驱动架构

事件驱动架构(Event-Driven Architecture, EDA)是一种软件架构范式,系统的各个组件通过产生和消费事件进行通信,而不是通过直接调用。这种架构在松耦合、可扩展性和异步处理方面具有天然优势,是构建高并发系统的关键模式之一。

3.1 核心组件

3.2 事件驱动力在Python中的实现

# Python事件总线实现示例 import asyncio from collections import defaultdict from typing import Callable, Any class EventBus: """简单的事件总线实现""" def __init__(self): self._subscribers = defaultdict(list) def subscribe(self, event_type: str, callback: Callable): """订阅事件""" self._subscribers[event_type].append(callback) def unsubscribe(self, event_type: str, callback: Callable): """取消订阅""" if callback in self._subscribers[event_type]: self._subscribers[event_type].remove(callback) async def publish(self, event_type: str, data: Any = None): """异步发布事件""" if event_type not in self._subscribers: return # 并发执行所有订阅者的回调 tasks = [ asyncio.create_task(cb(event_type, data)) for cb in self._subscribers[event_type] ] await asyncio.gather(*tasks, return_exceptions=True) # 使用示例 async def order_created_handler(event_type, data): """订单创建事件处理器""" print(f"处理订单创建: order_id={data['order_id']}") await asyncio.sleep(0.1) print(f"订单创建完成: {data['order_id']}") async def send_notification_handler(event_type, data): """通知发送处理器""" print(f"发送通知: user_id={data['user_id']}") async def main(): bus = EventBus() bus.subscribe('order.created', order_created_handler) bus.subscribe('order.created', send_notification_handler) await bus.publish('order.created', { 'order_id': 'ORD-20260506-001', 'user_id': 'USER-001', 'amount': 299.00 }) asyncio.run(main())

3.3 事件溯源(Event Sourcing)

事件溯源是一种更极端的事件驱动设计:不存储系统的当前状态,只存储所有发生过的事件。当前状态通过重放(Replay)所有事件计算得出。这种设计的优势包括:完整的审计日志、支持时点回溯(Time Travel)调试、天然支持CQRS分离。缺点是事件存储量会持续增长,需要对事件进行快照(Snapshot)来优化重放性能。

架构决策:事件驱动架构虽然带来了松耦合和高扩展性,但也引入了最终一致性的问题。系统设计者需要在强一致性和高可用性之间做出权衡(即CAP定理的约束)。对于金融交易类对一致性要求极高的场景,配合事件溯源使用时要格外小心。

四、线程池与工作窃取

线程池是并发编程中最基础的资源管理手段。通过复用已创建的线程,减少线程创建和销毁的开销,同时通过限制线程数量防止系统资源耗尽。在高并发场景下,线程池的配置和调优直接影响系统的吞吐量和响应时间。

4.1 固定线程池 vs 弹性线程池

# Python ThreadPoolExecutor 源码级分析 import concurrent.futures import time import threading def analyze_pool_behavior(): """分析ThreadPoolExecutor的线程管理行为""" def worker_task(task_id): thread_name = threading.current_thread().name print(f" [线程:{thread_name}] 执行任务 {task_id}") time.sleep(2) return task_id print("=== 固定线程池(max_workers=3)行为分析 ===") with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: futures = [] for i in range(6): print(f" 提交任务 {i},当前活跃线程数应 ≤ 3") fut = executor.submit(worker_task, i) futures.append(fut) for f in concurrent.futures.as_completed(futures): print(f" 任务 {f.result()} 完成") print("\n=== 线程池内部结构 === ") print("- _max_workers: 最大线程数") print("- _threads: 当前存活的工作线程集合") print("- _work_queue: 存放待执行任务的SimpleQueue") print("- _idle_semaphore: 控制空闲线程数量的信号量") print(" submit() 首先尝试用_idle_semaphore获取空闲线程") print(" 若无空闲线程且存活线程数

4.2 工作窃取算法(Work Stealing)

工作窃取算法是Java ForkJoinPool的核心设计,也被Python的官方文档推荐作为高并发任务调度的参考实现。基本思想是:每个工作线程维护一个双端队列(Deque),线程从队列的头部获取任务执行;当自己的队列为空时,从其他线程队列的尾部"窃取"任务执行。这种设计能最大程度地平衡各线程的负载,减少空闲等待。

工作窃取算法的优势在于:减少了线程间的竞争(每个线程只操作自己的队列头部),同时实现了全局负载均衡(空闲线程主动窃取忙线程的任务)。对于递归分解类任务(如归并排序、文件树遍历)效果特别显著。

五、缓存策略

缓存是应对高并发的第一道防线。合理的缓存策略可以将数据库的QPS从万级别提升到百万级别。但缓存并非银弹——缓存的更新策略、失效策略以及异常场景的处理,都直接影响系统的正确性和可用性。

5.1 缓存更新模式对比

模式 操作流程 优点 缺点
Cache Aside 读:先查缓存→命中则返回;未命中查DB→回填缓存→返回
写:更新DB→删除缓存
实现简单,适用读多写少场景 存在短暂的缓存与DB不一致窗口
Read Through 读请求全部由缓存层代理;缓存未命中时缓存层自动加载DB数据 对应用层透明,客户端无感知 缓存层需要支持自动加载
Write Through 写请求先写缓存,缓存同步写DB,两者都成功后返回 数据强一致性(写缓存和写DB在同一个事务中) 写延迟增加,写吞吐量受限于DB
Write Behind 写请求只写缓存,异步批量写回DB 写吞吐量极高,适合大量写入场景 缓存故障可能丢失数据

5.2 缓存失效策略

LRU(Least Recently Used)是最常用的缓存淘汰算法,其核心假设是"最近被访问的数据将来也会被访问"。Redis的近似LRU实现通过采样+淘汰的方式减少了内存开销。LFU(Least Frequently Used)适用于访问频率差异大的场景,但实现复杂度更高。TTL(Time To Live)是最简单的失效策略——给每个缓存项设置过期时间,到期自动失效,适合有明确时效性的数据。

5.3 缓存异常的应对策略

  • 缓存雪崩:大量缓存同时过期,导致所有请求直接打到数据库。应对方案包括:给过期时间加随机偏移量避免集中过期;使用多级缓存(本地缓存+分布式缓存);在数据库层面做限流保护。
  • 缓存击穿:热点Key在过期瞬间被大量并发请求穿透。应对方案:使用互斥锁(Mutex Key)——当缓存失效时,只允许一个线程去加载数据,其他线程等待或返回默认值。
  • 缓存穿透:查询一个根本不存在的数据(如恶意攻击),每次都会穿透缓存打到数据库。应对方案:缓存空值(Null Object Pattern)并设置较短的TTL;使用布隆过滤器(Bloom Filter)在缓存层之前拦截不存在的Key。
# 缓存穿透防护:布隆过滤器 + 互斥锁更新缓存 import hashlib import time from typing import Optional class BloomFilter: """简易布隆过滤器(用于缓存穿透防护)""" def __init__(self, size: int = 1000000, hash_count: int = 3): self.size = size self.hash_count = hash_count self.bit_array = 0 # 使用整数位运算模拟位数组 def _hashes(self, item: str): """生成多个哈希值的位位置""" result = [] for i in range(self.hash_count): h = hashlib.md5(f"{item}:{i}".encode()).hexdigest() result.append(int(h, 16) % self.size) return result def add(self, item: str): """将元素加入布隆过滤器""" for pos in self._hashes(item): self.bit_array |= (1 << pos) def contains(self, item: str) -> bool: """检查元素是否可能存在(可能存在误判)""" for pos in self._hashes(item): if not (self.bit_array & (1 << pos)): return False return True class CacheManager: """带防护的缓存管理器""" def __init__(self): self._cache = {} self._bloom = BloomFilter() self._loading = set() # 正在加载中的Key集合 def get_or_load(self, key: str, loader, ttl: float = 60.0) -> Optional[any]: """从缓存获取,未命中则加载(带互斥锁防缓存击穿)""" # 第一步:布隆过滤器拦截明显不存在的Key if not self._bloom.contains(key): return None # 第二步:尝试从缓存获取 if key in self._cache: value, expire_at = self._cache[key] if time.time() < expire_at: return value else: del self._cache[key] # 第三步:互斥锁——只允许一个线程加载 if key in self._loading: # 其他线程等待或返回None return None self._loading.add(key) try: value = loader() if value is not None: self._bloom.add(key) self._cache[key] = (value, time.time() + ttl) else: # 缓存空值(短TTL防穿透) self._cache[key] = (None, time.time() + 10.0) return value finally: self._loading.discard(key)

六、限流算法

限流是系统自我保护的最后一道防线。当请求量超过系统处理能力时,限流机制通过有选择地拒绝部分请求,确保系统不会崩溃,保证大部分请求仍能获得正常响应。常见的限流维度包括:QPS(每秒查询数)、并发连接数、带宽使用率等。

6.1 四种核心限流算法对比

算法 原理 特点 适用场景
固定窗口 以固定时间窗口(如1秒)为单位计数;达到阈值后拒绝后续请求;窗口结束时重置计数 实现最简单,内存占用极低(只需一个计数器+时间戳) 流量曲线相对平滑的简单限流
滑动窗口 将固定窗口细分为多个小格子;只统计当前时间前一个完整窗口内的请求总量 解决固定窗口的"临界突变"问题;精度由格子数量决定 对流量平稳性要求较高的场景
漏桶(Leaky Bucket) 将请求比作水,漏桶以恒定速率漏水;请求先进入桶中暂存,超过桶容量的请求被丢弃 强制输出速率恒定,能平滑突发流量;即使输入有波动,输出也保持稳定 需要保护下游系统不被突发流量冲击的场景
令牌桶(Token Bucket) 以固定速率向桶中添加令牌;每个请求需要获取一个令牌才能执行;桶满时令牌不再增加 允许一定程度的突发(桶内令牌可以累积);能限制平均速率的同时容忍突发流量 大多数通用限流场景,API网关限流的首选
# 四种限流算法的Python实现 import time from collections import deque class FixedWindowRateLimiter: """固定窗口限流器""" def __init__(self, limit: int, window: float = 1.0): self.limit = limit self.window = window self._count = 0 self._window_start = time.time() def allow(self) -> bool: now = time.time() if now - self._window_start >= self.window: self._count = 0 self._window_start = now if self._count < self.limit: self._count += 1 return True return False class SlidingWindowRateLimiter: """滑动窗口限流器""" def __init__(self, limit: int, window: float = 1.0, slots: int = 10): self.limit = limit self.window = window self.slot_size = window / slots self._slots = deque() # 存储每个时间戳的计数 def allow(self) -> bool: now = time.time() cutoff = now - self.window # 移除过期的时间槽 while self._slots and self._slots[0][0] < cutoff: self._slots.popleft() total = sum(count for _, count in self._slots) if total < self.limit: # 找到或创建当前时间槽 if self._slots and self._slots[-1][0] >= now - self.slot_size: self._slots[-1] = (self._slots[-1][0], self._slots[-1][1] + 1) else: self._slots.append((now, 1)) return True return False class TokenBucket: """令牌桶限流器""" def __init__(self, rate: float, capacity: int): self.rate = rate # 令牌生成速率(个/秒) self.capacity = capacity # 桶容量 self._tokens = capacity self._last_refill = time.time() def _refill(self): now = time.time() elapsed = now - self._last_refill new_tokens = elapsed * self.rate self._tokens = min(self.capacity, self._tokens + new_tokens) self._last_refill = now def allow(self, tokens: int = 1) -> bool: self._refill() if self._tokens >= tokens: self._tokens -= tokens return True return False class LeakyBucket: """漏桶限流器""" def __init__(self, rate: float, capacity: int): self.rate = rate # 漏水速率(请求/秒) self.capacity = capacity self._water = 0.0 # 当前桶中的水量 self._last_leak = time.time() def allow(self) -> bool: now = time.time() # 先漏水 elapsed = now - self._last_leak leaked = elapsed * self.rate self._water = max(0.0, self._water - leaked) self._last_leak = now # 尝试注水 if self._water < self.capacity: self._water += 1.0 return True return False # 对比测试 def benchmark(): import random limiters = [ ("固定窗口", FixedWindowRateLimiter(100, 1.0)), ("滑动窗口", SlidingWindowRateLimiter(100, 1.0, 10)), ("令牌桶", TokenBucket(100, 120)), ("漏桶", LeakyBucket(100, 120)), ] for name, limiter in limiters: allowed = sum(1 for _ in range(200) if limiter.allow()) print(f"{name}: 200请求通过{allowed}个") benchmark()

6.2 限流的架构实践

在分层架构中,限流应该部署在离用户最近的位置:反向代理层(如Nginx的limit_req模块)、网关层(如Kong的Rate Limiting插件)、应用层(如Python中间件)。多层限流的阈值通常是倒金字塔结构——越接近用户层的阈值越低,越靠近业务层越高,形成层层递减的保护机制。

七、熔断器模式

熔断器模式(Circuit Breaker Pattern)是分布式系统中防止级联故障的关键手段。当一个下游服务持续出现故障时,熔断器会快速切断对该服务的调用,避免调用方长时间等待和资源耗尽。熔断器由三种状态构成一个有限状态机,围绕失败阈值、超时重置和半开试探三个核心参数运转。

7.1 三种状态及状态转换

  • CLOSED(关闭):初始状态,请求正常通过。熔断器持续统计失败率,当失败率超过阈值(如5秒内失败率>50%)时,状态转为OPEN。
  • OPEN(打开):所有请求被直接拒绝(快速失败),不发起实际调用。经过设定的超时时间(如30秒)后,状态转为HALF_OPEN。
  • HALF_OPEN(半开):允许少量探测请求通过。如果探测请求成功,说明下游服务已恢复,状态转为CLOSED;如果探测请求仍然失败,状态转回OPEN,重置超时计时器。
# Python熔断器实现 import time import functools from enum import Enum from typing import Callable, Optional class CircuitState(Enum): CLOSED = "closed" OPEN = "open" HALF_OPEN = "half_open" class CircuitBreaker: """熔断器实现""" def __init__( self, failure_threshold: int = 5, # 连续失败次数阈值 recovery_timeout: float = 30.0, # 熔断后切换到半开状态的时间 half_open_max_requests: int = 3, # 半开状态下允许的最大探测请求数 ): self.failure_threshold = failure_threshold self.recovery_timeout = recovery_timeout self.half_open_max_requests = half_open_max_requests self._state = CircuitState.CLOSED self._failure_count = 0 self._last_failure_time = 0.0 self._half_open_requests = 0 @property def state(self) -> CircuitState: if self._state == CircuitState.OPEN: if time.time() - self._last_failure_time >= self.recovery_timeout: self._state = CircuitState.HALF_OPEN self._half_open_requests = 0 return self._state def call(self, func: Callable, fallback: Optional[Callable] = None, *args, **kwargs): """调用被熔断器保护的函数""" current_state = self.state if current_state == CircuitState.OPEN: return self._fail_fast(fallback) if current_state == CircuitState.HALF_OPEN: if self._half_open_requests >= self.half_open_max_requests: return self._fail_fast(fallback) self._half_open_requests += 1 try: result = func(*args, **kwargs) self._on_success() return result except Exception as e: self._on_failure() if fallback: return fallback(*args, **kwargs) raise def _on_success(self): """成功调用——重置熔断器""" self._state = CircuitState.CLOSED self._failure_count = 0 self._half_open_requests = 0 def _on_failure(self): """失败调用——累计失败次数""" self._failure_count += 1 self._last_failure_time = time.time() if self._failure_count >= self.failure_threshold: self._state = CircuitState.OPEN def _fail_fast(self, fallback=None): """快速失败""" if fallback: return fallback() raise CircuitBreakerOpenError("熔断器已打开,请求被拒绝") class CircuitBreakerOpenError(Exception): """熔断器打开异常""" pass # 使用示例 def remote_api_call(): """模拟一个可能失败的外部API调用""" if time.time() % 3 < 1: # 约1/3的概率失败 raise ConnectionError("服务不可达") return {"status": "ok", "data": "response"} def fallback_response(): """降级返回的默认响应""" return {"status": "fallback", "data": "服务暂不可用,返回缓存数据"} breaker = CircuitBreaker(failure_threshold=3, recovery_timeout=5.0) for i in range(20): try: result = breaker.call(remote_api_call, fallback=fallback_response) print(f"请求 {i+1}: state={breaker.state.value}, result={result}") except Exception as e: print(f"请求 {i+1}: state={breaker.state.value}, error={e}") time.sleep(0.5)

7.2 熔断器 vs 限流 vs 服务降级

这三者常常一起使用但目的不同:限流是对调用方自身的保护——限制自身发出的请求量;熔断是对下游依赖的保护——当下游故障时主动切断调用;降级是业务层面的决策——在系统压力大时主动关闭非核心功能以保证核心功能的可用性。在微服务架构实践中,合理的做法是在网关层做限流,在Feign/gRPC客户端层做熔断,在业务层做降级。

八、总结:选择正确的并发架构

高并发系统设计没有"一招鲜"的解决方案。每种模式都有其适用边界和权衡取舍。下面给出系统化的架构决策指南,帮助根据具体场景选择最合适的并发模型。

8.1 决策矩阵

业务场景 推荐架构 核心技术 典型系统
I/O密集型网络服务 Reactor事件驱动 + 异步编程 epoll/kqueue/Python asyncio Web服务器、API网关、消息推送
CPU密集型计算任务 多进程 + 工作窃取线程池 concurrent.futures.ProcessPoolExecutor 视频转码、大规模数据清洗
高吞吐数据管道 事件驱动 + Actor模型 Kafka + 消息队列 + Akka/Pykka 日志收集、物联网数据处理
大规模有状态会话服务 Actor模型 Erlang/OTP、Akka 即时通信、游戏服务器
高可用微服务调用链 熔断器 + 限流 + 超时重试 Hystrix/Sentinel/resilience4j 电商订单系统、支付网关
高QPS读多写少服务 多级缓存 + 读写分离 Redis + CDN + CQRS 内容资讯站、商品详情页

8.2 架构选型原则

  1. 无状态优先原则:尽可能将系统设计为无状态服务,这样可以通过水平扩展轻松提升并发能力。只有必须维护状态的场景才考虑Actor或有状态服务。
  2. 异步优先原则:在IO操作上优先使用异步非阻塞模型(asyncio),避免线程阻塞。线程是昂贵的资源,每个线程约占用8MB的栈空间(主线程外),1000个线程就是8GB内存。
  3. 分层保护原则:每个服务层都做好自我保护——入口限流、依赖熔断、异常降级,防止一个服务的故障传播到整个调用链。
  4. 可观测性原则:高并发系统必须有完善的监控和追踪(Metrics + Tracing + Logging),否则系统出现问题将难以定位。推荐使用Prometheus + OpenTelemetry + ELK的组合。
  5. 防御性编程原则:始终假设下游可能失败,为所有外部调用设置超时、重试(带退避)和兜底策略。不要相信任何外部系统的SLA承诺。

核心思想:高并发系统设计的本质不是"让系统跑得更快",而是"让系统在压力下依然稳定"。架构的终极目标不是追求单机性能的极致,而是构建一个有弹性(Resilient)、可伸缩(Scalable)、可维护(Maintainable)的分布式系统。没有完美的架构,只有最合适的权衡。

"A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work." — John Gall, Systemantics

(翻译:一个能工作的复杂系统,总是从一个能工作的简单系统演化而来。从一个复杂系统从头设计,从来不会成功,也无法通过修补让它成功。)

本学习笔记为本人学习资料,不得转载