@umacloud/knowledge 1.0.15 → 1.0.17
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/governance-capabilities.md +1 -1
- package/00-governance/knowledge-map.md +4 -6
- 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/01-standards/app-runtime-model-configurable.md +76 -0
- package/ai/agent-evaluation-benchmark.md +4 -6
- package/ai/ai-agent-memory-context-management.md +4 -6
- package/ai/ai-cost-capacity-optimization-playbook.md +4 -6
- package/ai/ai-data-security-and-compliance-playbook.md +4 -6
- package/ai/ai-domain-index-and-checklist.md +4 -6
- package/ai/ai-governance-maturity-model.md +4 -6
- package/ai/ai-model-selection-and-routing-strategy.md +4 -6
- package/ai/ai-observability-and-oncall-runbook.md +4 -6
- package/ai/ai-rag-engineering-playbook.md +4 -6
- package/ai/ai-red-team-and-safety-evaluation.md +4 -6
- package/ai/ai-release-readiness-and-rollback-gate.md +4 -6
- package/ai/llm-agent-engineering-deep-dive.md +4 -6
- package/ai/prompt-and-tool-guardrails.md +4 -6
- 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 -5
- package/architecture/02-playbooks/system-design-playbook.md +1 -5
- package/architecture/adr-template-and-examples.md +4 -6
- package/architecture/api-gateway-deep-dive.md +1 -1
- package/architecture/configuration-management.md +95 -1158
- package/architecture/distributed-transactions.md +1 -1
- package/architecture/microservices-complete.md +1 -1
- package/architecture/resilience-and-disaster-patterns.md +87 -27
- package/architecture/service-governance.md +1 -1
- package/architecture/system-architecture-deep-dive.md +4 -6
- package/backend/01-standards/cjk-in-exports-and-documents.md +107 -0
- package/backend/01-standards/dependency-and-supply-chain-hygiene.md +90 -0
- package/backend/01-standards/django-complete.md +2 -2
- 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/nestjs-complete.md +23 -23
- 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 +4 -6
- package/cicd/release-readiness-gate.md +78 -27
- package/cloud-native/01-standards/container-security.md +1 -5
- package/cloud-native/01-standards/kubernetes-complete.md +1 -5
- package/cloud-native/02-playbooks/gitops-with-argocd.md +1 -5
- package/cloud-native/02-playbooks/k8s-troubleshooting-playbook.md +3 -7
- package/cloud-native/02-playbooks/multicloud-governance.md +1 -5
- package/cloud-native/02-playbooks/serverless-patterns.md +1 -5
- package/cloud-native/02-playbooks/service-mesh-playbook.md +1 -5
- package/cloud-native/03-checklists/container-security-checklist.md +1 -5
- package/cloud-native/03-checklists/k8s-production-readiness-checklist.md +1 -5
- package/cloud-native/04-antipatterns/container-antipatterns.md +1 -5
- package/cloud-native/04-antipatterns/k8s-antipatterns.md +1 -5
- package/cloud-native/05-cases/case-k8s-migration.md +1 -5
- package/cloud-native/05-cases/case-k8s-scaling.md +1 -5
- package/cloud-native/05-cases/case-k8s-security-incident.md +1 -5
- package/cloud-native/06-glossary/cloud-native-glossary.md +1 -5
- package/compliance/01-standards/audit-logging-and-evidence.md +111 -0
- package/compliance/01-standards/privacy-and-compliance-readiness.md +119 -0
- package/data/01-standards/elasticsearch-complete.md +2 -2
- package/data/01-standards/postgresql-complete.md +8 -8
- package/data/01-standards/redis-complete.md +11 -11
- package/data/data-governance-and-modeling-deep-dive.md +4 -6
- package/data-engineering/01-standards/kafka-complete.md +22 -22
- package/design/ui-full-lifecycle-cross-platform-playbook.md +1 -1
- package/design/ux-system-deep-dive.md +4 -6
- package/design-systems/00-craft-rules.md +1 -1
- package/design-systems/bold-geometric.md +1 -1
- package/design-systems/brutalist-bold.md +1 -1
- package/design-systems/editorial-clean.md +1 -1
- package/design-systems/glass-aurora.md +1 -1
- package/design-systems/modern-minimal.md +1 -1
- package/design-systems/premium-luxury.md +1 -1
- package/design-systems/soft-warm.md +1 -1
- package/design-systems/tech-utility.md +1 -1
- package/development/00-governance/document-template.md +3 -3
- package/development/01-standards/code-review-and-pr-hygiene.md +85 -0
- package/development/01-standards/golang-complete.md +2 -2
- package/development/01-standards/python-design-patterns.md +2 -2
- package/development/01-standards/typescript-advanced-types.md +2 -2
- package/development/03-checklists/production-readiness-checklist.md +6 -6
- package/development/09-maturity/quarterly-audit-template.md +3 -5
- package/development/11-ui-excellence/ui-aesthetic-system.md +3 -5
- package/development/13-implementation-assets/knowledge-gates-execution.md +3 -5
- package/development/api-contract-and-versioning-guide.md +4 -6
- package/development/api-governance-complete.md +4 -6
- package/development/backend-engineering-complete.md +4 -6
- package/development/code-review-quality-complete.md +11 -34
- package/development/concurrency-reliability-complete.md +4 -6
- package/development/database-engineering-complete.md +4 -6
- package/development/engineering-effectiveness-complete.md +4 -6
- package/development/engineering-standards-deep-dive.md +4 -6
- package/development/frontend-engineering-complete.md +4 -6
- package/development/performance-capacity-complete.md +4 -6
- package/development/refactor-migration-complete.md +4 -6
- package/development/refactoring-and-techdebt-playbook.md +4 -6
- package/development/security-in-development-complete.md +4 -6
- package/devops/01-standards/docker-complete.md +2 -2
- package/devops/01-standards/terraform-complete.md +3 -3
- 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/i18n-and-localization.md +1 -1
- package/frontend/01-standards/react-hooks-complete.md +33 -33
- package/frontend/01-standards/ui-states-and-resilient-data-fetching.md +97 -0
- package/frontend/01-standards/vue3-complete.md +2 -2
- package/high-quality-engineering-playbook.md +4 -6
- package/incident/02-playbooks/chaos-engineering-playbook.md +1 -5
- package/incident/postmortem-and-response-deep-dive.md +4 -6
- package/mobile/01-standards/flutter-complete.md +3 -8
- package/mobile/01-standards/react-native-complete.md +3 -8
- package/mobile/02-playbooks/mobile-performance.md +3 -9
- package/mobile/03-checklists/mobile-release-checklist.md +3 -5
- package/mobile/04-antipatterns/mobile-antipatterns.md +3 -5
- 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/01-standards/prometheus-monitoring-complete.md +2 -2
- package/operations/aiops-anomaly-detection.md +4 -8
- package/operations/capacity-planning.md +4 -8
- package/operations/chaos-engineering.md +4 -8
- package/operations/incident-command-system.md +4 -6
- package/operations/observability-complete.md +4 -8
- package/operations/slo-sli-playbook.md +4 -8
- package/operations/sre-operations-deep-dive.md +4 -6
- package/package.json +1 -1
- package/performance/01-standards/performance-budgets-and-load-testing.md +91 -0
- package/product/feature-prioritization-framework.md +97 -35
- package/product/kpi-and-metric-tree.md +69 -26
- package/product/product-discovery-and-prd-deep-dive.md +4 -6
- 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/01-standards/owasp-top10-complete.md +2 -2
- package/security/02-playbooks/incident-response-security-playbook.md +1 -5
- package/security/02-playbooks/penetration-testing-playbook.md +1 -5
- package/security/compliance-automation.md +1 -1
- package/security/container-security.md +1 -1
- package/security/devsecops-complete.md +1 -1
- package/security/sast-dast-sca.md +1 -1
- package/security/secrets-management.md +1 -1
- package/security/security-architecture-deep-dive.md +4 -6
- package/security/threat-modeling-stride-playbook.md +4 -6
- package/seed-templates/auth-system.md +1 -1
- package/seed-templates/blog-content.md +1 -1
- package/seed-templates/dashboard.md +1 -1
- package/seed-templates/docs-site.md +1 -1
- package/seed-templates/e-commerce.md +1 -1
- package/seed-templates/saas-landing.md +1 -1
- package/seed-templates/settings-page.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 -5
- package/testing/risk-based-test-matrix.md +75 -25
- package/testing/testing-strategy-deep-dive.md +4 -6
|
@@ -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` 落地,本文不重复。
|
|
@@ -5,8 +5,8 @@ domain: backend
|
|
|
5
5
|
category: 01-standards
|
|
6
6
|
difficulty: intermediate
|
|
7
7
|
tags: [backend, complete, nestjs, websocket, 依赖注入系统, 微服务, 快速开始, 数据库集成]
|
|
8
|
-
quality_score:
|
|
9
|
-
last_updated: 2026-06-
|
|
8
|
+
quality_score: 90
|
|
9
|
+
last_updated: 2026-06-29
|
|
10
10
|
---
|
|
11
11
|
# NestJS 完整指南
|
|
12
12
|
|
|
@@ -31,14 +31,14 @@ NestJS 是一个用于构建高效、可扩展 Node.js 服务端应用的渐进
|
|
|
31
31
|
|
|
32
32
|
### 何时选择 NestJS
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
[推荐] **大型团队协作**: 强约定 + 模块化架构减少代码风格分歧
|
|
35
|
+
[推荐] **微服务体系**: 内置 Transport 层,支持 Redis/Kafka/gRPC/NATS/MQTT
|
|
36
|
+
[推荐] **企业级后端**: 完善的认证/授权/缓存/队列/日志/健康检查生态
|
|
37
|
+
[推荐] **全栈 TypeScript**: 前后端共享类型定义,配合 Monorepo 高效开发
|
|
38
|
+
[推荐] **需要长期维护的系统**: 模块边界清晰,重构成本低
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
[避免] **简单 API / 原型验证**: 过度工程化,Express/Fastify 更轻便
|
|
41
|
+
[避免] **极致性能场景**: 框架层带来一定开销,考虑 Fastify 或 Go
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
@@ -1978,13 +1978,13 @@ export class AppModule {}
|
|
|
1978
1978
|
### 1. 循环依赖导致 undefined
|
|
1979
1979
|
|
|
1980
1980
|
```typescript
|
|
1981
|
-
//
|
|
1981
|
+
// [避免] 错误:A 和 B 互相注入,其中一个会是 undefined
|
|
1982
1982
|
@Injectable()
|
|
1983
1983
|
export class ServiceA {
|
|
1984
1984
|
constructor(private serviceB: ServiceB) {} // 可能是 undefined
|
|
1985
1985
|
}
|
|
1986
1986
|
|
|
1987
|
-
//
|
|
1987
|
+
// [推荐] 解决:使用 forwardRef 或提取公共逻辑
|
|
1988
1988
|
@Injectable()
|
|
1989
1989
|
export class ServiceA {
|
|
1990
1990
|
constructor(
|
|
@@ -1996,11 +1996,11 @@ export class ServiceA {
|
|
|
1996
1996
|
### 2. 请求作用域的性能问题
|
|
1997
1997
|
|
|
1998
1998
|
```typescript
|
|
1999
|
-
//
|
|
1999
|
+
// [避免] 不当:对所有服务使用请求作用域
|
|
2000
2000
|
@Injectable({ scope: Scope.REQUEST })
|
|
2001
2001
|
export class HeavyService {} // 每次请求都创建新实例
|
|
2002
2002
|
|
|
2003
|
-
//
|
|
2003
|
+
// [推荐] 正确:仅在确实需要请求上下文的服务上使用
|
|
2004
2004
|
@Injectable()
|
|
2005
2005
|
export class HeavyService {
|
|
2006
2006
|
doWork(requestContext: RequestContext) {
|
|
@@ -2012,14 +2012,14 @@ export class HeavyService {
|
|
|
2012
2012
|
### 3. 忘记导出 Provider
|
|
2013
2013
|
|
|
2014
2014
|
```typescript
|
|
2015
|
-
//
|
|
2015
|
+
// [避免] 错误:其他模块无法注入 UsersService
|
|
2016
2016
|
@Module({
|
|
2017
2017
|
providers: [UsersService],
|
|
2018
2018
|
// 缺少 exports
|
|
2019
2019
|
})
|
|
2020
2020
|
export class UsersModule {}
|
|
2021
2021
|
|
|
2022
|
-
//
|
|
2022
|
+
// [推荐] 正确
|
|
2023
2023
|
@Module({
|
|
2024
2024
|
providers: [UsersService],
|
|
2025
2025
|
exports: [UsersService],
|
|
@@ -2030,7 +2030,7 @@ export class UsersModule {}
|
|
|
2030
2030
|
### 4. 异步初始化陷阱
|
|
2031
2031
|
|
|
2032
2032
|
```typescript
|
|
2033
|
-
//
|
|
2033
|
+
// [避免] 错误:同步 forRoot 中使用异步操作
|
|
2034
2034
|
@Module({})
|
|
2035
2035
|
export class DatabaseModule {
|
|
2036
2036
|
static forRoot() {
|
|
@@ -2044,7 +2044,7 @@ export class DatabaseModule {
|
|
|
2044
2044
|
}
|
|
2045
2045
|
}
|
|
2046
2046
|
|
|
2047
|
-
//
|
|
2047
|
+
// [推荐] 正确:使用 useFactory + async
|
|
2048
2048
|
@Module({})
|
|
2049
2049
|
export class DatabaseModule {
|
|
2050
2050
|
static forRoot(): DynamicModule {
|
|
@@ -2065,13 +2065,13 @@ export class DatabaseModule {
|
|
|
2065
2065
|
### 5. 测试中未正确清理
|
|
2066
2066
|
|
|
2067
2067
|
```typescript
|
|
2068
|
-
//
|
|
2068
|
+
// [避免] 错误:测试间共享状态导致随机失败
|
|
2069
2069
|
describe('Service', () => {
|
|
2070
2070
|
let app: INestApplication;
|
|
2071
2071
|
beforeAll(async () => { app = /* ... */ });
|
|
2072
2072
|
// 测试完没有关闭
|
|
2073
2073
|
|
|
2074
|
-
//
|
|
2074
|
+
// [推荐] 正确:每次清理
|
|
2075
2075
|
afterAll(async () => {
|
|
2076
2076
|
await app.close();
|
|
2077
2077
|
});
|
|
@@ -2081,11 +2081,11 @@ describe('Service', () => {
|
|
|
2081
2081
|
### 6. ValidationPipe 未配置 whitelist
|
|
2082
2082
|
|
|
2083
2083
|
```typescript
|
|
2084
|
-
//
|
|
2084
|
+
// [避免] 危险:客户端可注入任意属性
|
|
2085
2085
|
app.useGlobalPipes(new ValidationPipe());
|
|
2086
2086
|
// POST { name: "Alice", isAdmin: true } -> isAdmin 会被传入 DTO
|
|
2087
2087
|
|
|
2088
|
-
//
|
|
2088
|
+
// [推荐] 安全:只保留 DTO 中定义的属性
|
|
2089
2089
|
app.useGlobalPipes(new ValidationPipe({
|
|
2090
2090
|
whitelist: true,
|
|
2091
2091
|
forbidNonWhitelisted: true,
|
|
@@ -2095,12 +2095,12 @@ app.useGlobalPipes(new ValidationPipe({
|
|
|
2095
2095
|
### 7. 生产环境 synchronize: true
|
|
2096
2096
|
|
|
2097
2097
|
```typescript
|
|
2098
|
-
//
|
|
2098
|
+
// [避免] 灾难性:自动同步会删除数据列
|
|
2099
2099
|
TypeOrmModule.forRoot({
|
|
2100
2100
|
synchronize: true, // 绝对不能在生产环境开启
|
|
2101
2101
|
});
|
|
2102
2102
|
|
|
2103
|
-
//
|
|
2103
|
+
// [推荐] 正确:使用迁移管理数据库变更
|
|
2104
2104
|
TypeOrmModule.forRoot({
|
|
2105
2105
|
synchronize: false,
|
|
2106
2106
|
migrations: ['dist/migrations/*.js'],
|