@umacloud/knowledge 1.0.14 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/00-governance/knowledge-map.md +1 -1
- package/agentic-delivery/01-standards/context-engineering-for-delivery.md +94 -0
- package/agentic-delivery/01-standards/eval-driven-delivery.md +90 -0
- package/agentic-delivery/01-standards/generated-code-failure-modes.md +91 -0
- package/agentic-delivery/01-standards/production-readiness-scorecard.md +79 -0
- package/agentic-delivery/01-standards/self-improving-memory-and-regression-sets.md +80 -0
- package/agentic-delivery/01-standards/spec-as-contract.md +88 -0
- package/agentic-delivery/01-standards/test-discipline-for-generated-code.md +94 -0
- package/agentic-delivery/01-standards/test-integrity-and-anti-gaming.md +92 -0
- package/agentic-delivery/01-standards/verifier-critic-pattern.md +89 -0
- package/ai/agent-evaluation-benchmark.md +1 -1
- package/ai/ai-agent-memory-context-management.md +1 -1
- package/ai/ai-cost-capacity-optimization-playbook.md +1 -1
- package/ai/ai-data-security-and-compliance-playbook.md +1 -1
- package/ai/ai-domain-index-and-checklist.md +1 -1
- package/ai/ai-governance-maturity-model.md +1 -1
- package/ai/ai-model-selection-and-routing-strategy.md +1 -1
- package/ai/ai-observability-and-oncall-runbook.md +1 -1
- package/ai/ai-rag-engineering-playbook.md +1 -1
- package/ai/ai-red-team-and-safety-evaluation.md +1 -1
- package/ai/ai-release-readiness-and-rollback-gate.md +1 -1
- package/ai/llm-agent-engineering-deep-dive.md +1 -1
- package/ai/prompt-and-tool-guardrails.md +1 -1
- package/api/01-standards/api-versioning-and-deprecation-policy.md +100 -0
- package/architecture/01-standards/configuration-and-environment-management.md +104 -0
- package/architecture/01-standards/domain-driven-design-complete.md +105 -0
- package/architecture/02-playbooks/migration-playbook.md +1 -1
- package/architecture/02-playbooks/system-design-playbook.md +1 -1
- package/architecture/adr-template-and-examples.md +1 -1
- package/architecture/configuration-management.md +95 -1158
- package/architecture/resilience-and-disaster-patterns.md +87 -27
- package/architecture/system-architecture-deep-dive.md +1 -1
- package/backend/01-standards/dependency-and-supply-chain-hygiene.md +90 -0
- package/backend/01-standards/error-handling-taxonomy.md +88 -0
- package/backend/01-standards/idempotency-and-safe-retries.md +101 -0
- package/backend/01-standards/message-queue-patterns.md +96 -374
- package/backend/01-standards/queue-and-consumer-reliability.md +98 -0
- package/backend/01-standards/resilience-and-fault-tolerance.md +101 -0
- package/backend/01-standards/transactions-and-concurrency-control.md +92 -0
- package/cicd/cicd-blueprint-deep-dive.md +1 -1
- package/cicd/release-readiness-gate.md +78 -27
- package/cloud-native/01-standards/container-security.md +1 -1
- package/cloud-native/01-standards/kubernetes-complete.md +1 -1
- package/cloud-native/02-playbooks/gitops-with-argocd.md +1 -1
- package/cloud-native/02-playbooks/k8s-troubleshooting-playbook.md +1 -1
- package/cloud-native/02-playbooks/multicloud-governance.md +1 -1
- package/cloud-native/02-playbooks/serverless-patterns.md +1 -1
- package/cloud-native/02-playbooks/service-mesh-playbook.md +1 -1
- package/cloud-native/03-checklists/container-security-checklist.md +1 -1
- package/cloud-native/03-checklists/k8s-production-readiness-checklist.md +1 -1
- package/cloud-native/04-antipatterns/container-antipatterns.md +1 -1
- package/cloud-native/04-antipatterns/k8s-antipatterns.md +1 -1
- package/cloud-native/05-cases/case-k8s-migration.md +1 -1
- package/cloud-native/05-cases/case-k8s-scaling.md +1 -1
- package/cloud-native/05-cases/case-k8s-security-incident.md +1 -1
- package/cloud-native/06-glossary/cloud-native-glossary.md +1 -1
- package/compliance/01-standards/audit-logging-and-evidence.md +111 -0
- package/compliance/01-standards/privacy-and-compliance-readiness.md +119 -0
- package/data/data-governance-and-modeling-deep-dive.md +1 -1
- package/design/ux-system-deep-dive.md +1 -1
- package/development/00-governance/document-template.md +1 -1
- package/development/01-standards/code-review-and-pr-hygiene.md +85 -0
- package/development/03-checklists/production-readiness-checklist.md +6 -6
- package/development/09-maturity/quarterly-audit-template.md +1 -1
- package/development/11-ui-excellence/ui-aesthetic-system.md +1 -1
- package/development/13-implementation-assets/knowledge-gates-execution.md +1 -1
- package/development/api-contract-and-versioning-guide.md +1 -1
- package/development/api-governance-complete.md +1 -1
- package/development/backend-engineering-complete.md +1 -1
- package/development/code-review-quality-complete.md +11 -34
- package/development/concurrency-reliability-complete.md +1 -1
- package/development/database-engineering-complete.md +1 -1
- package/development/engineering-effectiveness-complete.md +1 -1
- package/development/engineering-standards-deep-dive.md +1 -1
- package/development/frontend-engineering-complete.md +1 -1
- package/development/performance-capacity-complete.md +1 -1
- package/development/refactor-migration-complete.md +1 -1
- package/development/refactoring-and-techdebt-playbook.md +1 -1
- package/development/security-in-development-complete.md +1 -1
- package/experts/architect/contract-first-api-design.md +140 -0
- package/experts/product-manager/prd-template-and-structure.md +144 -0
- package/experts/product-manager/requirements-engineering-ears.md +133 -0
- package/experts/qa-lead/test-plan-template.md +127 -0
- package/frontend/01-standards/accessibility-acceptance-gate.md +91 -0
- package/frontend/01-standards/accessibility-complete.md +3 -3
- package/frontend/01-standards/ui-states-and-resilient-data-fetching.md +97 -0
- package/high-quality-engineering-playbook.md +1 -1
- package/incident/02-playbooks/chaos-engineering-playbook.md +1 -1
- package/incident/postmortem-and-response-deep-dive.md +1 -1
- package/mobile/01-standards/flutter-complete.md +5 -5
- package/mobile/01-standards/react-native-complete.md +5 -5
- package/mobile/02-playbooks/mobile-performance.md +6 -6
- package/mobile/03-checklists/mobile-release-checklist.md +2 -2
- package/mobile/04-antipatterns/mobile-antipatterns.md +2 -2
- package/observability/01-standards/observability-and-slo-operations.md +88 -0
- package/observability/01-standards/observability-standards.md +2 -0
- package/operations/01-standards/cost-and-finops-engineering.md +84 -0
- package/operations/01-standards/production-readiness-review.md +103 -0
- package/operations/aiops-anomaly-detection.md +1 -1
- package/operations/capacity-planning.md +1 -1
- package/operations/chaos-engineering.md +1 -1
- package/operations/incident-command-system.md +1 -1
- package/operations/observability-complete.md +1 -1
- package/operations/slo-sli-playbook.md +1 -1
- package/operations/sre-operations-deep-dive.md +1 -1
- package/package.json +1 -1
- package/performance/01-standards/performance-budgets-and-load-testing.md +91 -0
- package/product/feature-prioritization-framework.md +1 -1
- package/product/kpi-and-metric-tree.md +1 -1
- package/product/product-discovery-and-prd-deep-dive.md +1 -1
- package/release-engineering/01-standards/feature-flag-lifecycle.md +92 -0
- package/release-engineering/01-standards/progressive-delivery-and-release.md +92 -0
- package/release-engineering/02-playbooks/release-rollback-and-recovery-playbook.md +99 -0
- package/release-engineering/03-checklists/release-rollback-readiness-checklist.md +61 -0
- package/release-engineering/04-antipatterns/release-antipatterns.md +63 -0
- package/security/01-standards/authorization-and-access-control.md +94 -0
- package/security/02-playbooks/incident-response-security-playbook.md +1 -1
- package/security/02-playbooks/penetration-testing-playbook.md +1 -1
- package/security/security-architecture-deep-dive.md +1 -1
- package/security/threat-modeling-stride-playbook.md +1 -1
- package/testing/01-standards/ci-test-gates-and-coverage.md +93 -0
- package/testing/01-standards/contract-testing-and-api-contracts.md +102 -0
- package/testing/01-standards/test-data-and-ephemeral-environments.md +105 -0
- package/testing/02-playbooks/e2e-testing-playbook.md +1 -1
- package/testing/risk-based-test-matrix.md +1 -1
- package/testing/testing-strategy-deep-dive.md +1 -1
|
@@ -1,379 +1,101 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: message-queue-patterns
|
|
3
|
-
title:
|
|
3
|
+
title: 消息队列选型与消息模式规范(按场景选队列 + 用对消息模式,商业级必读)
|
|
4
4
|
domain: backend
|
|
5
5
|
category: 01-standards
|
|
6
|
-
difficulty:
|
|
7
|
-
tags: [
|
|
8
|
-
quality_score:
|
|
9
|
-
last_updated: 2026-06-
|
|
6
|
+
difficulty: advanced
|
|
7
|
+
tags: [message-queue, kafka, rabbitmq, redis-streams, broker-selection, pub-sub, work-queue, event-streaming, event-sourcing, cqrs, fanout, routing, partitioning, schema-evolution, 消息队列, 选型, 消息模式, 事件流, 商业级]
|
|
8
|
+
quality_score: 95
|
|
9
|
+
last_updated: 2026-06-29
|
|
10
10
|
---
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
|
22
|
-
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
except ProcessingError as e:
|
|
103
|
-
logger.error(f"Failed to process: {e}")
|
|
104
|
-
send_to_dlq(msg) # 发送到死信队列
|
|
105
|
-
consumer.commit(msg)
|
|
106
|
-
finally:
|
|
107
|
-
consumer.close()
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Kafka 最佳实践
|
|
111
|
-
|
|
112
|
-
- **分区数**: 通常等于消费者数量的倍数
|
|
113
|
-
- **Key 设计**: 使用业务 ID 保证同一实体的消息有序
|
|
114
|
-
- **保留策略**: 根据业务需求设置(7 天/30 天/永久)
|
|
115
|
-
- **压缩**: 使用 lz4 或 snappy 减少网络和存储开销
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## RabbitMQ
|
|
120
|
-
|
|
121
|
-
### Exchange 类型
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
Direct: routing_key 精确匹配
|
|
125
|
-
Fanout: 广播到所有绑定队列
|
|
126
|
-
Topic: routing_key 模式匹配 (*.error, order.#)
|
|
127
|
-
Headers: 基于 header 属性匹配
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### 生产者
|
|
131
|
-
|
|
132
|
-
```python
|
|
133
|
-
import pika
|
|
134
|
-
import json
|
|
135
|
-
|
|
136
|
-
connection = pika.BlockingConnection(pika.ConnectionParameters(
|
|
137
|
-
host="rabbitmq",
|
|
138
|
-
credentials=pika.PlainCredentials("guest", "guest"),
|
|
139
|
-
heartbeat=600,
|
|
140
|
-
))
|
|
141
|
-
channel = connection.channel()
|
|
142
|
-
|
|
143
|
-
# 声明持久化队列和交换机
|
|
144
|
-
channel.exchange_declare(exchange="orders", exchange_type="topic", durable=True)
|
|
145
|
-
channel.queue_declare(queue="order-processing", durable=True)
|
|
146
|
-
channel.queue_bind(queue="order-processing", exchange="orders", routing_key="order.created")
|
|
147
|
-
|
|
148
|
-
def publish_order_event(order_id: str, event_type: str, data: dict):
|
|
149
|
-
channel.basic_publish(
|
|
150
|
-
exchange="orders",
|
|
151
|
-
routing_key=f"order.{event_type}",
|
|
152
|
-
body=json.dumps({"order_id": order_id, **data}),
|
|
153
|
-
properties=pika.BasicProperties(
|
|
154
|
-
delivery_mode=2, # 持久化消息
|
|
155
|
-
content_type="application/json",
|
|
156
|
-
message_id=str(uuid.uuid4()),
|
|
157
|
-
timestamp=int(time.time()),
|
|
158
|
-
),
|
|
159
|
-
)
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### 消费者
|
|
163
|
-
|
|
164
|
-
```python
|
|
165
|
-
def callback(ch, method, properties, body):
|
|
166
|
-
try:
|
|
167
|
-
event = json.loads(body)
|
|
168
|
-
process_order(event)
|
|
169
|
-
ch.basic_ack(delivery_tag=method.delivery_tag)
|
|
170
|
-
except Exception as e:
|
|
171
|
-
logger.error(f"Processing failed: {e}")
|
|
172
|
-
# 拒绝并重新入队(或发送到 DLQ)
|
|
173
|
-
ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
|
|
174
|
-
|
|
175
|
-
channel.basic_qos(prefetch_count=10) # 流控
|
|
176
|
-
channel.basic_consume(queue="order-processing", on_message_callback=callback)
|
|
177
|
-
channel.start_consuming()
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### 死信队列 (DLQ)
|
|
181
|
-
|
|
182
|
-
```python
|
|
183
|
-
# 声明 DLQ
|
|
184
|
-
channel.queue_declare(queue="order-processing-dlq", durable=True)
|
|
185
|
-
|
|
186
|
-
# 主队列绑定 DLQ
|
|
187
|
-
channel.queue_declare(
|
|
188
|
-
queue="order-processing",
|
|
189
|
-
durable=True,
|
|
190
|
-
arguments={
|
|
191
|
-
"x-dead-letter-exchange": "",
|
|
192
|
-
"x-dead-letter-routing-key": "order-processing-dlq",
|
|
193
|
-
"x-message-ttl": 86400000, # 消息 TTL: 24h
|
|
194
|
-
"x-max-length": 100000, # 队列最大长度
|
|
195
|
-
},
|
|
196
|
-
)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## Redis Streams
|
|
202
|
-
|
|
203
|
-
### 基本操作
|
|
204
|
-
|
|
205
|
-
```python
|
|
206
|
-
import redis
|
|
207
|
-
|
|
208
|
-
r = redis.Redis(host="localhost", port=6379, decode_responses=True)
|
|
209
|
-
|
|
210
|
-
# 生产者:添加消息到 Stream
|
|
211
|
-
message_id = r.xadd("order-events", {
|
|
212
|
-
"order_id": "ORD-001",
|
|
213
|
-
"event": "created",
|
|
214
|
-
"amount": "99.99",
|
|
215
|
-
"timestamp": str(int(time.time())),
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
# 创建消费者组
|
|
219
|
-
r.xgroup_create("order-events", "order-service", id="0", mkstream=True)
|
|
220
|
-
|
|
221
|
-
# 消费者:读取消息
|
|
222
|
-
while True:
|
|
223
|
-
messages = r.xreadgroup(
|
|
224
|
-
groupname="order-service",
|
|
225
|
-
consumername="worker-1",
|
|
226
|
-
streams={"order-events": ">"},
|
|
227
|
-
count=10,
|
|
228
|
-
block=5000,
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
for stream, entries in messages:
|
|
232
|
-
for msg_id, fields in entries:
|
|
233
|
-
try:
|
|
234
|
-
process_event(fields)
|
|
235
|
-
r.xack("order-events", "order-service", msg_id)
|
|
236
|
-
except Exception as e:
|
|
237
|
-
logger.error(f"Failed: {e}")
|
|
238
|
-
# 消息留在 PEL 中,稍后重试
|
|
239
|
-
|
|
240
|
-
# 处理 pending 消息(故障恢复)
|
|
241
|
-
pending = r.xpending_range("order-events", "order-service", "-", "+", count=100)
|
|
242
|
-
for entry in pending:
|
|
243
|
-
if entry["time_since_delivered"] > 300000: # 超过 5 分钟未确认
|
|
244
|
-
messages = r.xclaim(
|
|
245
|
-
"order-events", "order-service", "worker-1",
|
|
246
|
-
min_idle_time=300000,
|
|
247
|
-
message_ids=[entry["message_id"]],
|
|
248
|
-
)
|
|
249
|
-
for msg_id, fields in messages:
|
|
250
|
-
reprocess_event(fields)
|
|
251
|
-
r.xack("order-events", "order-service", msg_id)
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
---
|
|
255
|
-
|
|
256
|
-
## 事件驱动架构模式
|
|
257
|
-
|
|
258
|
-
### 事件溯源 (Event Sourcing)
|
|
259
|
-
|
|
260
|
-
```python
|
|
261
|
-
# 事件存储
|
|
262
|
-
class EventStore:
|
|
263
|
-
def __init__(self, producer: KafkaProducer):
|
|
264
|
-
self.producer = producer
|
|
265
|
-
|
|
266
|
-
def append(self, aggregate_id: str, event: DomainEvent):
|
|
267
|
-
self.producer.send(
|
|
268
|
-
topic=f"events-{event.aggregate_type}",
|
|
269
|
-
key=aggregate_id,
|
|
270
|
-
value={
|
|
271
|
-
"event_id": str(uuid.uuid4()),
|
|
272
|
-
"aggregate_id": aggregate_id,
|
|
273
|
-
"event_type": event.__class__.__name__,
|
|
274
|
-
"data": event.to_dict(),
|
|
275
|
-
"version": event.version,
|
|
276
|
-
"timestamp": datetime.utcnow().isoformat(),
|
|
277
|
-
},
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
# 事件重放
|
|
281
|
-
class OrderAggregate:
|
|
282
|
-
def __init__(self):
|
|
283
|
-
self.status = None
|
|
284
|
-
self.items = []
|
|
285
|
-
self.total = 0
|
|
286
|
-
|
|
287
|
-
def apply(self, event: DomainEvent):
|
|
288
|
-
if isinstance(event, OrderCreated):
|
|
289
|
-
self.status = "created"
|
|
290
|
-
self.items = event.items
|
|
291
|
-
elif isinstance(event, OrderPaid):
|
|
292
|
-
self.status = "paid"
|
|
293
|
-
self.total = event.amount
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### 幂等消费者
|
|
297
|
-
|
|
298
|
-
```python
|
|
299
|
-
class IdempotentConsumer:
|
|
300
|
-
def __init__(self, redis_client: redis.Redis):
|
|
301
|
-
self.redis = redis_client
|
|
302
|
-
self.ttl = 86400 * 7 # 7 天去重窗口
|
|
303
|
-
|
|
304
|
-
def process(self, message_id: str, handler: Callable):
|
|
305
|
-
key = f"processed:{message_id}"
|
|
306
|
-
if self.redis.exists(key):
|
|
307
|
-
logger.info(f"Duplicate message {message_id}, skipping")
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
handler()
|
|
311
|
-
|
|
312
|
-
self.redis.set(key, "1", ex=self.ttl)
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### 重试策略
|
|
316
|
-
|
|
317
|
-
```python
|
|
318
|
-
import time
|
|
319
|
-
from functools import wraps
|
|
320
|
-
|
|
321
|
-
def retry_with_backoff(max_retries=3, base_delay=1.0, max_delay=60.0):
|
|
322
|
-
def decorator(func):
|
|
323
|
-
@wraps(func)
|
|
324
|
-
def wrapper(*args, **kwargs):
|
|
325
|
-
for attempt in range(max_retries + 1):
|
|
326
|
-
try:
|
|
327
|
-
return func(*args, **kwargs)
|
|
328
|
-
except RetryableError as e:
|
|
329
|
-
if attempt == max_retries:
|
|
330
|
-
raise
|
|
331
|
-
delay = min(base_delay * (2 ** attempt), max_delay)
|
|
332
|
-
jitter = delay * 0.1 * random.random()
|
|
333
|
-
time.sleep(delay + jitter)
|
|
334
|
-
logger.warning(f"Retry {attempt + 1}/{max_retries}: {e}")
|
|
335
|
-
return wrapper
|
|
336
|
-
return decorator
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
---
|
|
340
|
-
|
|
341
|
-
## 监控指标
|
|
342
|
-
|
|
343
|
-
| 指标 | 说明 | 告警阈值 |
|
|
344
|
-
|------|------|----------|
|
|
345
|
-
| Consumer Lag | 消费者落后的消息数 | > 10000 |
|
|
346
|
-
| Message Rate | 每秒消息产生/消费量 | 异常波动 |
|
|
347
|
-
| Error Rate | 处理失败率 | > 1% |
|
|
348
|
-
| DLQ Size | 死信队列堆积数 | > 100 |
|
|
349
|
-
| Processing Latency | 消息处理延迟 P99 | > 5s |
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
353
|
-
## 常见反模式
|
|
354
|
-
|
|
355
|
-
| 反模式 | 问题 | 正确做法 |
|
|
356
|
-
|--------|------|----------|
|
|
357
|
-
| 消息体过大 | 网络/存储开销 | 消息只传 ID + 元数据,数据走存储 |
|
|
358
|
-
| 不做幂等 | 重复处理 | 消息 ID 去重 + 幂等写入 |
|
|
359
|
-
| 自动提交 offset | 消息丢失 | 处理成功后手动提交 |
|
|
360
|
-
| 忽略 DLQ | 失败消息丢失 | 配置死信队列并监控 |
|
|
361
|
-
| 无重试策略 | 临时故障导致消息丢失 | 指数退避重试 |
|
|
362
|
-
| 强依赖消息顺序 | 扩展困难 | 仅在必要时保证分区内有序 |
|
|
363
|
-
|
|
364
|
-
---
|
|
365
|
-
|
|
366
|
-
## Agent Checklist
|
|
367
|
-
|
|
368
|
-
- [ ] 根据吞吐量和延迟需求选择合适的消息队列
|
|
369
|
-
- [ ] 生产者启用幂等写入和重试
|
|
370
|
-
- [ ] 消费者手动提交 offset/ack
|
|
371
|
-
- [ ] 实现幂等消费者(消息 ID 去重)
|
|
372
|
-
- [ ] 配置死信队列 (DLQ) 并监控大小
|
|
373
|
-
- [ ] 实现指数退避重试策略
|
|
374
|
-
- [ ] 消息体控制在 1MB 以内
|
|
375
|
-
- [ ] Kafka 分区 Key 设计保证业务有序性
|
|
376
|
-
- [ ] 消费者 Group 内消费者数 <= 分区数
|
|
377
|
-
- [ ] 监控 Consumer Lag / Error Rate / DLQ Size
|
|
378
|
-
- [ ] 消息 Schema 有版本管理(Avro/Protobuf + Schema Registry)
|
|
379
|
-
- [ ] 生产环境 Kafka 至少 3 副本,acks=all
|
|
11
|
+
# 消息队列选型与消息模式规范(商业级必读)
|
|
12
|
+
|
|
13
|
+
> 引入消息队列前先答两个问题:**选哪种队列**、**用哪种消息模式**。选错队列,要么吞吐扛不住、要么为简单任务上了重平台;用错模式,要么把事件流当任务队列、要么把广播写成点对点,越用越拧巴。
|
|
14
|
+
> 本规范只解决"选型 + 模式":按场景把队列类型选对、把生产/消费模式用对。**消费侧怎么写才可靠**(投递语义、幂等有效一次、可见性超时、顺序、毒消息与死信、背压)是另一件事,见 `backend/01-standards/queue-and-consumer-reliability`,本文不重复;**任务该不该异步、怎么编排**见 `backend/01-standards/background-jobs-and-async`。
|
|
15
|
+
|
|
16
|
+
## 1. 三类队列定位(先分清你要什么)
|
|
17
|
+
|
|
18
|
+
| 维度 | 事件流平台(如 Kafka 类) | 消息代理(如 RabbitMQ 类) | 轻量流(如 Redis Streams 类) |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| 定位 | 持久化、可重放的事件日志 | 灵活路由的任务/消息分发 | 进程内/小规模轻量事件流 |
|
|
21
|
+
| 量级 | 极高吞吐、海量留存 | 中等吞吐、复杂路由 | 中等吞吐、低运维成本 |
|
|
22
|
+
| 消费模型 | 消费组 + 位点(offset),可回放 | 队列/交换机路由,消费即出队 | 消费组 + PEL(待确认列表) |
|
|
23
|
+
| 留存与重放 | 按保留期留存,可重放历史 | 通常消费即删除,不便重放 | 可留存一段,能重放近期 |
|
|
24
|
+
| 有序粒度 | 分区内有序 | 队列内有序 | 流内有序 |
|
|
25
|
+
| 典型场景 | 事件溯源、日志聚合、数据管道、多消费方 | 任务队列、RPC、按规则路由分发 | 轻量异步、已有该存储栈、低门槛 |
|
|
26
|
+
|
|
27
|
+
**选型判据**:需要**重放历史 / 多个独立消费方 / 超高吞吐** → 事件流平台;需要**复杂路由 / 每条消息一次性派给一个工作者** → 消息代理;**规模不大、已有该内存存储、想省一套中间件** → 轻量流。别为一个定时任务上重型事件平台,也别用轻量流硬扛海量留存与回放。
|
|
28
|
+
|
|
29
|
+
## 2. 选型决策清单(按需求倒推)
|
|
30
|
+
|
|
31
|
+
| 需求信号 | 倾向选择 |
|
|
32
|
+
|---|---|
|
|
33
|
+
| 同一份事件要被多个团队/服务各自独立消费 | 事件流平台(消费组互不影响 + 可回放) |
|
|
34
|
+
| 要按 routing key / header 把消息精确分发到不同队列 | 消息代理(交换机路由能力强) |
|
|
35
|
+
| 吞吐在十万~百万级、需长期留存与重算 | 事件流平台 |
|
|
36
|
+
| 经典工作队列:N 个 worker 抢任务,处理完即删 | 消息代理 |
|
|
37
|
+
| 团队已重度使用某内存存储、不想新增运维面 | 轻量流(够用即可) |
|
|
38
|
+
| 强延迟敏感 + 简单点对点 | 消息代理 / 轻量流 |
|
|
39
|
+
|
|
40
|
+
选型还要算**运维成本**:事件流平台能力最强但运维最重(分区、副本、保留、再平衡都要管);轻量流最省心但能力边界明显。能力够用的前提下,**选运维最轻的那个**。
|
|
41
|
+
|
|
42
|
+
## 3. 核心生产/消费模式
|
|
43
|
+
|
|
44
|
+
| 模式 | 用途 | 关键点 |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| 工作队列 work queue | N 个消费者瓜分任务 | 每条消息只被一个消费者成功处理;按预取控制并发 |
|
|
47
|
+
| 发布订阅 pub/sub(fanout) | 一条消息广播给所有订阅方 | 每个订阅方一份;新增订阅方不影响既有 |
|
|
48
|
+
| 路由/主题 routing/topic | 按 key/pattern 精确或模式投递 | 路由键设计决定可扩展性,别用一个万能队列 |
|
|
49
|
+
| 分区有序 partitioned | 同实体有序、跨实体并行 | 用实体键路由到同一分区,仅保证分区内有序(顺序细节见 reliability 文档) |
|
|
50
|
+
| 请求/响应 over MQ | 异步 RPC | 用 correlation-id + 回复队列;超时要兜底,别永久等 |
|
|
51
|
+
|
|
52
|
+
## 4. 关键设计点(选型之后立刻要定)
|
|
53
|
+
|
|
54
|
+
- **分区/路由键设计**:键决定**并行度与有序性**。用业务实体 ID 作分区键,让同一实体落同一分区(有序)、不同实体散开(并行)。键选错会造成热分区或丧失可扩展性。
|
|
55
|
+
- **消费者数 ≤ 分区数**:事件流平台里,消费组内并行度受分区数上限制约;分区数要按目标吞吐与未来扩容预留。
|
|
56
|
+
- **消息载荷小而稳**:消息传 **ID/引用 + 必要元数据**,大对象走对象存储,别把大 blob 塞进消息体撑爆网络与留存。
|
|
57
|
+
- **Schema 演进有契约**:消息体用带版本的结构化 Schema(如 Avro/Protobuf/JSON + 版本字段 + Schema Registry 思路),**只做向后兼容的演进**(加可选字段,不改语义、不删必填),消费者要容忍未知新增字段。
|
|
58
|
+
- **保留与回放策略**:事件流平台明确保留期(按业务与重算需求);用到回放时,消费者必须**幂等**才能安全重放(见 reliability 文档)。
|
|
59
|
+
- **多消费方解耦**:同一事件被多方消费时,用独立消费组/订阅,彼此进度互不影响,杜绝"一个慢消费方拖垮其他人"。
|
|
60
|
+
|
|
61
|
+
## 5. 事件驱动架构模式(选型支撑的上层玩法)
|
|
62
|
+
|
|
63
|
+
- **事件溯源 Event Sourcing**:以**事件序列**为真相源,状态由事件重放得出。要求底座支持持久化与有序回放(事件流平台是天然载体);聚合重建依赖事件幂等可重放。
|
|
64
|
+
- **CQRS**:写侧产生事件,读侧消费事件构建查询视图,读写分离各自扩展。注意读模型是**最终一致**的,UI/契约要承认这点。
|
|
65
|
+
- **Saga / 事件编排**:跨服务长流程用事件串联,每步有补偿动作,避免分布式强事务(分布式事务取舍见 `architecture/distributed-transactions`)。
|
|
66
|
+
- **Outbox 投递**:业务写库与"待发事件"同事务落库,再由投递器异步发出,杜绝"库改了消息没发/消息发了库回滚"(端到端可靠属 reliability 文档范畴)。
|
|
67
|
+
|
|
68
|
+
## 6. 监控与容量(选型落地的运维基线)
|
|
69
|
+
|
|
70
|
+
| 指标 | 看什么 | 含义 |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| 消费滞后 lag | 消费组落后生产的量 | 持续增长 = 消费跟不上,要扩容/优化/限流 |
|
|
73
|
+
| 生产/消费速率 | 每秒入队/出队 | 异常骤变是上游异常或消费停摆的早信号 |
|
|
74
|
+
| 死信堆积 | DLQ 大小 | 堆积说明有系统性失败(处置见 reliability 文档) |
|
|
75
|
+
| 处理延迟 | 入队到处理完的 P99 | 端到端时延,影响业务体验 |
|
|
76
|
+
| 分区均衡 | 各分区流量/lag 分布 | 不均 = 路由键设计问题(热分区) |
|
|
77
|
+
|
|
78
|
+
容量上:分区数、消费者并发、留存大小要**按目标峰值预留余量**,别按当前流量卡满;扩容路径(加分区/加消费者)要提前想清楚,事件流平台的分区数通常**只能增不能减**。
|
|
79
|
+
|
|
80
|
+
## 7. 反模式(出现即不合格)
|
|
81
|
+
|
|
82
|
+
1. **场景与队列错配**:为简单定时任务上重型事件平台,或用轻量流硬扛海量留存与回放。
|
|
83
|
+
2. **一个万能队列**:所有消息塞进一个队列/主题,不做路由与隔离,无法独立扩展与监控。
|
|
84
|
+
3. **路由键/分区键拍脑袋**:键设计不当导致热分区、丧失有序性或无法并行。
|
|
85
|
+
4. **大对象进消息体**:把大 blob 塞进消息,撑爆网络、留存与重放成本。
|
|
86
|
+
5. **Schema 无版本、破坏性演进**:改语义/删必填字段,消费者直接崩。
|
|
87
|
+
6. **多消费方共用一个消费组**:本该独立消费的多方互相抢消息、互相拖累。
|
|
88
|
+
7. **消费者数 > 分区数还指望线性扩展**:多出来的消费者空转,吞吐上不去。
|
|
89
|
+
8. **不监控 lag 与分区均衡**:消费早跟不上或热分区,积压到爆才发现。
|
|
90
|
+
9. **把可靠性细节当选型问题糊弄**:投递语义/幂等/死信不按 reliability 规范做(见交叉引用)。
|
|
91
|
+
|
|
92
|
+
## 8. 最低交付 checklist
|
|
93
|
+
|
|
94
|
+
- [ ] 按"重放/多消费方/超高吞吐 vs 复杂路由 vs 轻量省心"把队列类型选对,并算了运维成本。
|
|
95
|
+
- [ ] 分区/路由键用业务实体 ID 设计,同实体有序、跨实体并行;消费者数 ≤ 分区数。
|
|
96
|
+
- [ ] 消息载荷小(传 ID/引用),大对象走对象存储。
|
|
97
|
+
- [ ] 消息 Schema 带版本、只做向后兼容演进,消费者容忍未知新增字段。
|
|
98
|
+
- [ ] 事件流平台明确保留期与回放策略;多消费方用独立消费组解耦。
|
|
99
|
+
- [ ] 监控 lag / 速率 / DLQ / 处理延迟 / 分区均衡,容量按峰值预留并想清扩容路径。
|
|
100
|
+
- [ ] 事件溯源/CQRS/Saga/Outbox 等上层模式按需选用,承认读模型最终一致。
|
|
101
|
+
- [ ] 消费侧可靠性(投递语义/幂等有效一次/可见性超时/顺序/毒消息/背压)按 `backend/01-standards/queue-and-consumer-reliability` 落地,本文不重复。
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: queue-and-consumer-reliability
|
|
3
|
+
title: 队列与消费者可靠性规范(投递语义/幂等有效一次/顺序/可见性超时/毒消息,商业级必读)
|
|
4
|
+
domain: backend
|
|
5
|
+
category: 01-standards
|
|
6
|
+
difficulty: advanced
|
|
7
|
+
tags: [queue, consumer, reliability, idempotent-consumer, effectively-once, at-least-once, dead-letter-queue, poison-message, visibility-timeout, redelivery, ordering, backpressure, consumer-lag, outbox, inbox, 队列, 消费者, 幂等, 有效一次, 死信, 毒消息, 可见性超时, 顺序, 商业级]
|
|
8
|
+
quality_score: 95
|
|
9
|
+
last_updated: 2026-06-29
|
|
10
|
+
---
|
|
11
|
+
# 队列与消费者可靠性规范(商业级必读)
|
|
12
|
+
|
|
13
|
+
> 异步队列把"耗时/可削峰"的工作从请求路径里挪走,但也引入一组分布式难题:消息会**重复投递**、会**乱序**、会**卡住**、会**毒死消费者**。把这些当"偶发"忽略,结果就是重复扣款、订单错乱、队列雪崩、一条坏消息阻塞整条队列。
|
|
14
|
+
> 这份规范讲的不是选哪个队列产品(选型与各产品用法见 `backend/01-standards/message-queue-patterns`),也不只是"任务该不该异步"(任务编排见 `backend/01-standards/background-jobs-and-async`),而是**消费侧怎么写才可靠**:投递语义、幂等与有效一次、顺序、可见性超时与重投、毒消息与死信、背压与堆积。
|
|
15
|
+
|
|
16
|
+
## 1. 先认清投递语义(一切的前提)
|
|
17
|
+
|
|
18
|
+
| 语义 | 含义 | 现实可得性 |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| 至多一次 at-most-once | 不重复,但可能丢 | 简单,但丢消息通常不可接受 |
|
|
21
|
+
| 至少一次 at-least-once | 不丢,但可能重复 | **主流默认**——必须假设会重复 |
|
|
22
|
+
| 恰好一次 exactly-once | 不丢不重 | 端到端几乎不存在;分布式下是营销词 |
|
|
23
|
+
|
|
24
|
+
**结论:按"至少一次 + 可能乱序 + 可能重投"来设计。** 真正能做到的不是传输层的"恰好一次",而是**业务上的"有效一次"(effectively-once)**——传输可以重复投递,但靠**消费幂等**保证副作用只发生一次。任何依赖"队列保证不重复"的设计都是错的。
|
|
25
|
+
|
|
26
|
+
## 2. 幂等消费与有效一次(核心中的核心)
|
|
27
|
+
|
|
28
|
+
同一条消息可能被投递 2 次、5 次(重投、重平衡、消费者崩溃后重启都会导致)。涉钱/发货/发邮件/外部副作用的消费**必须幂等**:
|
|
29
|
+
|
|
30
|
+
- **去重键**:用稳定的业务键或消息 ID 作为去重依据(生产者要保证同一逻辑事件用同一 ID)。
|
|
31
|
+
- **去重落地**:处理前检查"这个 ID 处理过吗",处理后记录;去重表/标记要和业务副作用在**同一事务**里提交,否则"业务做了但没记上去重"仍会重复。
|
|
32
|
+
- **首选天然幂等写**:`UPSERT`、`SET 状态=已支付`、条件更新(`WHERE 状态=待支付`)这类操作天然幂等,优于"先查再插"的竞态写法。
|
|
33
|
+
- **去重窗口**:去重记录保留足够覆盖最大可能重投间隔(含 DLQ 重放),并有清理策略防无限增长。
|
|
34
|
+
- **副作用收口**:把外部副作用(扣款/发消息)做成可幂等或带幂等键调用(见 `backend/01-standards/idempotency-and-safe-retries`)。
|
|
35
|
+
|
|
36
|
+
## 3. 可见性超时与重投机制
|
|
37
|
+
|
|
38
|
+
至少一次队列普遍用"取出即隐藏一段时间(可见性超时 / ack 截止),处理完确认(ack),否则到期重新可见被别人取"的机制。用错会**自伤**:
|
|
39
|
+
|
|
40
|
+
- **处理完才确认**:先处理成功、再 ack/提交位点;**绝不**取出就自动确认(自动提交 = 崩溃即丢消息)。
|
|
41
|
+
- **可见性超时 > 处理耗时**:超时必须覆盖正常处理时间 + 余量。设太短 → 还没处理完消息就被重新投递给另一个消费者,造成**并发重复处理**;设太长 → 真崩溃了消息长时间不重投,延迟恢复。
|
|
42
|
+
- **长任务续租**:处理时间不确定的任务要在处理中**续租/心跳延长**可见性,而不是一开始设一个超大超时。
|
|
43
|
+
- **确认要可靠**:ack/提交本身失败要能感知;位点提交粒度与"处理成功"对齐,避免提交了未处理或处理了未提交。
|
|
44
|
+
|
|
45
|
+
## 4. 顺序:只在必要处保证,别全局强序
|
|
46
|
+
|
|
47
|
+
全局严格有序和高吞吐/可扩展天然冲突。
|
|
48
|
+
|
|
49
|
+
- **按需分区有序**:只对**同一实体**(同一订单/同一账户)要求有序——用实体键路由到同一分区/队列,保证**分区内**有序即可,不同实体并行处理。
|
|
50
|
+
- **别假设跨分区有序**:多分区/多消费者天然乱序;业务逻辑不能依赖"先发的先到"。
|
|
51
|
+
- **乱序容忍设计**:用版本号/时间戳/状态机让消费对乱序与重复**收敛到正确终态**(如旧版本更新被丢弃、状态只能单向前进),比强行保序更健壮。
|
|
52
|
+
- **有序与重试的张力**:严格有序队列里,一条卡住的消息会阻塞其后全部——更需要快速隔离毒消息(见 §5)。
|
|
53
|
+
|
|
54
|
+
## 5. 毒消息与死信队列(DLQ)
|
|
55
|
+
|
|
56
|
+
"毒消息"(poison message)= 无论重试多少次都必然失败的消息(数据损坏、不可解析、触发确定性 bug)。不隔离它,它会反复重试**阻塞队列、刷爆日志、耗尽资源**。
|
|
57
|
+
|
|
58
|
+
- **限次重试 + 退避抖动**:瞬时失败重试有限次,指数退避 + 抖动(避免重试风暴);区分**可重试**(网络/限流/5xx)与**不可重试**(解析失败/校验不过/业务拒绝)——不可重试的别浪费重试,直接进 DLQ。
|
|
59
|
+
- **超限进 DLQ**:超过重试上限的消息移入死信队列,**带上下文**(原消息 + 失败原因 + 重试次数 + 时间),不静默丢弃。
|
|
60
|
+
- **DLQ 必须被监控与处置**:DLQ 不是垃圾桶——堆积要告警,要有人看、能诊断、能修复后**重放**。DLQ 无人管 = 消息悄悄全丢。
|
|
61
|
+
- **隔离优先于阻塞**:宁可让一条坏消息进 DLQ,也不要让它卡住整条队列拖垮正常消息。
|
|
62
|
+
|
|
63
|
+
## 6. 背压、堆积与消费者健康
|
|
64
|
+
|
|
65
|
+
- **监控消费滞后(lag)**:盯消费者落后量(待处理积压)。lag 持续增长 = 消费跟不上生产,要么扩消费者、要么限生产、要么优化处理。
|
|
66
|
+
- **有界并发与预取**:消费者设合理预取/并发上限,别一次抓太多撑爆内存或长时间占住不 ack。
|
|
67
|
+
- **背压而非无限缓冲**:下游处理不过来时传递背压(放慢拉取/拒绝),不要把消息全拉进内存无界堆积到 OOM。
|
|
68
|
+
- **慢消费者隔离**:不同类型任务用不同队列/消费者池,一类慢任务别拖垮另一类(呼应 `backend/01-standards/resilience-and-fault-tolerance` 的舱壁)。
|
|
69
|
+
- **优雅停机**:消费者收到停止信号要处理完在途消息(或安全释放回队列)再退出,不硬切。
|
|
70
|
+
|
|
71
|
+
## 7. 生产侧可靠性:别在源头就丢/错
|
|
72
|
+
|
|
73
|
+
- **入队与事务一致(outbox)**:"写库 + 发消息"要么都成要么都不成。用 **outbox 模式**——业务与"待发消息"同事务写库,再由投递器异步发出——避免"事务回滚了消息却发了"或"事务提交了消息没发"。
|
|
74
|
+
- **消费幂等也要 inbox 思路**:接收侧记录已处理消息 ID(inbox),配合 outbox 构成端到端有效一次。
|
|
75
|
+
- **载荷小而稳**:消息传 ID/引用而非大对象;Schema 带版本,演进保持兼容,消费者能容忍新增字段。
|
|
76
|
+
|
|
77
|
+
## 8. 反模式(出现即不合格)
|
|
78
|
+
|
|
79
|
+
1. **假设恰好一次**:依赖队列"不会重复",消费不幂等 → 重复扣款/重复发货。
|
|
80
|
+
2. **取出即自动确认**:auto-ack/自动提交位点,消费者一崩消息就丢。
|
|
81
|
+
3. **可见性超时短于处理**:消息处理中就被重投,并发重复处理。
|
|
82
|
+
4. **毒消息无限重试**:一条坏消息反复失败阻塞队列、刷爆日志、烧资源。
|
|
83
|
+
5. **有 DLQ 没人看**:死信堆积无告警无重放,消息悄悄全丢。
|
|
84
|
+
6. **全局强序**:为顺序牺牲扩展性,一条卡住阻塞全部。
|
|
85
|
+
7. **无界拉取/缓冲**:消费者一次抓太多或无限缓冲,OOM。
|
|
86
|
+
8. **不监控 lag**:消费早已跟不上,积压到爆才发现。
|
|
87
|
+
9. **入队与事务不一致**:无 outbox,消息与数据状态错位。
|
|
88
|
+
|
|
89
|
+
## 9. 最低交付 checklist
|
|
90
|
+
|
|
91
|
+
- [ ] 按"至少一次 + 可能乱序"设计;靠消费幂等实现业务"有效一次"。
|
|
92
|
+
- [ ] 用稳定去重键,去重记录与业务副作用同事务提交;优先天然幂等写。
|
|
93
|
+
- [ ] 处理成功后才 ack/提交位点;可见性超时 > 处理耗时,长任务续租。
|
|
94
|
+
- [ ] 仅对同一实体按分区保证有序,业务对乱序/重复能收敛到正确终态。
|
|
95
|
+
- [ ] 限次重试 + 退避抖动,区分可重试/不可重试;超限进带上下文的 DLQ。
|
|
96
|
+
- [ ] DLQ 有监控告警、可诊断、可重放;坏消息隔离而非阻塞整队。
|
|
97
|
+
- [ ] 监控消费 lag;有界并发/预取 + 背压;慢消费者隔离;消费者优雅停机。
|
|
98
|
+
- [ ] 生产侧用 outbox 保证入队与事务一致;载荷小、Schema 带版本兼容演进。
|