@gordon.gan/specflow 1.3.3-beta → 1.4.1
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/README.md +6 -2
- package/dist/integrations/shared/capability-evidence.js +37 -1
- package/dist/integrations/shared/command-catalog.js +1 -0
- package/dist/integrations/shared/parity-manifest.js +6 -0
- package/package.json +1 -1
- package/prompts/approval/database-guidance.md +79 -0
- package/prompts/approval/generate.md +1191 -0
- package/skills/database/LICENSE +405 -0
- package/skills/database/ORIGIN.md +6 -0
- package/skills/database/README.md +30 -0
- package/skills/database/elasticsearch/LICENSE.txt +202 -0
- package/skills/database/elasticsearch/SKILL.md +199 -0
- package/skills/database/elasticsearch/examples/01-fulltext-search.md +215 -0
- package/skills/database/elasticsearch/examples/02-aggregation-report.md +206 -0
- package/skills/database/elasticsearch/examples/03-reindex-zero-downtime.md +200 -0
- package/skills/database/elasticsearch/examples/04-cluster-monitoring.md +204 -0
- package/skills/database/elasticsearch/references/01-query-dsl-fulltext.md +162 -0
- package/skills/database/elasticsearch/references/02-query-dsl-term.md +210 -0
- package/skills/database/elasticsearch/references/03-aggregations-metric.md +161 -0
- package/skills/database/elasticsearch/references/04-aggregations-bucket.md +236 -0
- package/skills/database/elasticsearch/references/05-mapping-types.md +134 -0
- package/skills/database/elasticsearch/references/06-analyzers.md +187 -0
- package/skills/database/elasticsearch/references/07-cluster-ops.md +225 -0
- package/skills/database/elasticsearch/references/08-elk-integration.md +170 -0
- package/skills/database/mysql/SKILL.md +195 -0
- package/skills/database/mysql/examples/01-connection-pool.md +75 -0
- package/skills/database/mysql/examples/02-slow-query-optimization.md +98 -0
- package/skills/database/mysql/examples/03-master-slave-setup.md +144 -0
- package/skills/database/mysql/examples/04-backup-strategy.md +212 -0
- package/skills/database/mysql/references/01-functions-string.md +103 -0
- package/skills/database/mysql/references/02-functions-date.md +152 -0
- package/skills/database/mysql/references/03-functions-aggregate-window.md +167 -0
- package/skills/database/mysql/references/04-functions-json.md +129 -0
- package/skills/database/mysql/references/05-sql-ddl-types.md +235 -0
- package/skills/database/mysql/references/06-index-optimization.md +232 -0
- package/skills/database/mysql/references/07-replication-ha.md +213 -0
- package/skills/database/mysql/references/08-backup-restore.md +207 -0
- package/skills/database/mysql/references/09-advanced-features.md +345 -0
- package/skills/database/oracle/LICENSE.txt +202 -0
- package/skills/database/oracle/SKILL.md +238 -0
- package/skills/database/oracle/examples/01-plsql-procedure.md +90 -0
- package/skills/database/oracle/examples/02-awr-analysis.md +99 -0
- package/skills/database/oracle/examples/03-rman-backup.md +108 -0
- package/skills/database/oracle/examples/04-dataguard-setup.md +146 -0
- package/skills/database/oracle/references/01-functions-string.md +91 -0
- package/skills/database/oracle/references/02-functions-date.md +71 -0
- package/skills/database/oracle/references/03-analytic-functions.md +103 -0
- package/skills/database/oracle/references/04-plsql-guide.md +303 -0
- package/skills/database/oracle/references/05-performance-tuning.md +164 -0
- package/skills/database/oracle/references/06-backup-recovery.md +115 -0
- package/skills/database/oracle/references/07-dataguard-rac.md +76 -0
- package/skills/database/oracle/references/08-security.md +170 -0
- package/skills/database/oracle/references/09-sql-syntax.md +152 -0
- package/skills/database/oracle/references/10-features.md +174 -0
- package/skills/database/postgresql/LICENSE.txt +202 -0
- package/skills/database/postgresql/SKILL.md +182 -0
- package/skills/database/postgresql/examples/.gitkeep +0 -0
- package/skills/database/postgresql/examples/01-jsonb-query.md +72 -0
- package/skills/database/postgresql/examples/02-cte-recursive.md +110 -0
- package/skills/database/postgresql/examples/03-performance-tuning.md +114 -0
- package/skills/database/postgresql/examples/04-streaming-replication.md +113 -0
- package/skills/database/postgresql/references/.gitkeep +0 -0
- package/skills/database/postgresql/references/01-functions-string.md +174 -0
- package/skills/database/postgresql/references/02-functions-datetime.md +54 -0
- package/skills/database/postgresql/references/03-functions-aggregate-window.md +142 -0
- package/skills/database/postgresql/references/04-functions-jsonb.md +117 -0
- package/skills/database/postgresql/references/05-fulltext-search.md +109 -0
- package/skills/database/postgresql/references/06-index-types.md +95 -0
- package/skills/database/postgresql/references/07-partition-fdw.md +133 -0
- package/skills/database/postgresql/references/08-replication-backup.md +215 -0
- package/skills/database/redis/LICENSE.txt +202 -0
- package/skills/database/redis/SKILL.md +922 -0
- package/skills/database/redis/examples/01-cache-usage.md +104 -0
- package/skills/database/redis/examples/02-session-storage.md +72 -0
- package/skills/database/redis/examples/03-leaderboard.md +63 -0
- package/skills/database/redis/examples/04-redis-cluster-setup.md +70 -0
- package/skills/database/redis/examples/05-stream-queue.md +65 -0
- package/skills/database/redis/references/command-quick-ref.md +180 -0
- package/skills/database/redis/references/commands-admin-key.md +413 -0
- package/skills/database/redis/references/commands-set-sorted-advanced.md +539 -0
- package/skills/database/redis/references/commands-string-hash-list.md +458 -0
- package/skills/database/redis/references/memory-optimization.md +150 -0
- package/skills/database/redis/references/redis-conf-production.md +139 -0
- package/skills/specflow-approval/SKILL.md +427 -0
- package/templates/approval.md +464 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# 示例: 聚合报表 — 电商销售分析
|
|
2
|
+
|
|
3
|
+
## 场景
|
|
4
|
+
|
|
5
|
+
基于订单数据构建销售分析仪表盘:销售额趋势、TOP 品类、品牌分布、价格区段。
|
|
6
|
+
|
|
7
|
+
## 步骤
|
|
8
|
+
|
|
9
|
+
### 1. 创建索引
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
PUT /orders
|
|
13
|
+
{
|
|
14
|
+
"settings": {
|
|
15
|
+
"number_of_shards": 3,
|
|
16
|
+
"number_of_replicas": 1
|
|
17
|
+
},
|
|
18
|
+
"mappings": {
|
|
19
|
+
"properties": {
|
|
20
|
+
"order_id": { "type": "keyword" },
|
|
21
|
+
"user_id": { "type": "keyword" },
|
|
22
|
+
"product_id": { "type": "keyword" },
|
|
23
|
+
"product_name": { "type": "text", "fields": { "keyword": { "type": "keyword" } } },
|
|
24
|
+
"category": { "type": "keyword" },
|
|
25
|
+
"brand": { "type": "keyword" },
|
|
26
|
+
"amount": { "type": "float" },
|
|
27
|
+
"quantity": { "type": "integer" },
|
|
28
|
+
"status": { "type": "keyword" },
|
|
29
|
+
"region": { "type": "keyword" },
|
|
30
|
+
"order_date": { "type": "date" },
|
|
31
|
+
"payment_date": { "type": "date" }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. 按品类统计销售额 (terms + sum)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# 每个品类的总销售额, 降序排列
|
|
41
|
+
GET /orders/_search
|
|
42
|
+
{
|
|
43
|
+
"size": 0,
|
|
44
|
+
"aggs": {
|
|
45
|
+
"by_category": {
|
|
46
|
+
"terms": {
|
|
47
|
+
"field": "category",
|
|
48
|
+
"size": 20,
|
|
49
|
+
"order": { "total_sales": "desc" }
|
|
50
|
+
},
|
|
51
|
+
"aggs": {
|
|
52
|
+
"total_sales": { "sum": { "field": "amount" } },
|
|
53
|
+
"avg_order": { "avg": { "field": "amount" } },
|
|
54
|
+
"order_count": { "value_count": { "field": "order_id" } }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. 每日销售趋势 (date_histogram + sum)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 按天统计销售额
|
|
65
|
+
GET /orders/_search
|
|
66
|
+
{
|
|
67
|
+
"size": 0,
|
|
68
|
+
"query": {
|
|
69
|
+
"range": {
|
|
70
|
+
"order_date": { "gte": "now-30d", "lte": "now" }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"aggs": {
|
|
74
|
+
"daily_sales": {
|
|
75
|
+
"date_histogram": {
|
|
76
|
+
"field": "order_date",
|
|
77
|
+
"calendar_interval": "day",
|
|
78
|
+
"format": "yyyy-MM-dd",
|
|
79
|
+
"min_doc_count": 0,
|
|
80
|
+
"extended_bounds": {
|
|
81
|
+
"min": "2024-01-01",
|
|
82
|
+
"max": "2024-12-31"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"aggs": {
|
|
86
|
+
"revenue": { "sum": { "field": "amount" } },
|
|
87
|
+
"orders": { "value_count": { "field": "order_id" } }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 4. 价格区段分布 (range + stats)
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 价格区段 + 每个区段的统计
|
|
98
|
+
GET /orders/_search
|
|
99
|
+
{
|
|
100
|
+
"size": 0,
|
|
101
|
+
"aggs": {
|
|
102
|
+
"price_ranges": {
|
|
103
|
+
"range": {
|
|
104
|
+
"field": "amount",
|
|
105
|
+
"ranges": [
|
|
106
|
+
{ "key": "低价 (<100)", "to": 100 },
|
|
107
|
+
{ "key": "中低价 (100-500)", "from": 100, "to": 500 },
|
|
108
|
+
{ "key": "中价 (500-2000)", "from": 500, "to": 2000 },
|
|
109
|
+
{ "key": "高价 (2000-10000)", "from": 2000, "to": 10000 },
|
|
110
|
+
{ "key": "超高 (>10000)", "from": 10000 }
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
"aggs": {
|
|
114
|
+
"amount_stats": { "stats": { "field": "amount" } },
|
|
115
|
+
"brand_distribution": {
|
|
116
|
+
"terms": { "field": "brand", "size": 5 }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 5. 地区分布 + TOP 品牌 (嵌套聚合)
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# 各地区销售额, 每个地区 TOP 品牌
|
|
128
|
+
GET /orders/_search
|
|
129
|
+
{
|
|
130
|
+
"size": 0,
|
|
131
|
+
"aggs": {
|
|
132
|
+
"by_region": {
|
|
133
|
+
"terms": {
|
|
134
|
+
"field": "region",
|
|
135
|
+
"size": 10,
|
|
136
|
+
"order": { "revenue": "desc" }
|
|
137
|
+
},
|
|
138
|
+
"aggs": {
|
|
139
|
+
"revenue": { "sum": { "field": "amount" } },
|
|
140
|
+
"order_count": { "value_count": { "field": "order_id" } },
|
|
141
|
+
"top_brands": {
|
|
142
|
+
"terms": {
|
|
143
|
+
"field": "brand",
|
|
144
|
+
"size": 5,
|
|
145
|
+
"order": { "brand_revenue": "desc" }
|
|
146
|
+
},
|
|
147
|
+
"aggs": {
|
|
148
|
+
"brand_revenue": { "sum": { "field": "amount" } }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 6. 综合仪表盘查询 (一次查询完成多项分析)
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# 一次查询返回多种聚合结果
|
|
161
|
+
GET /orders/_search
|
|
162
|
+
{
|
|
163
|
+
"size": 0,
|
|
164
|
+
"query": {
|
|
165
|
+
"bool": {
|
|
166
|
+
"filter": [
|
|
167
|
+
{ "term": { "status": "completed" } },
|
|
168
|
+
{ "range": { "order_date": { "gte": "now-30d/d", "lte": "now" } } }
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"aggs": {
|
|
173
|
+
"overview": { // 总体指标
|
|
174
|
+
"stats": { "field": "amount" }
|
|
175
|
+
},
|
|
176
|
+
"total_revenue": {
|
|
177
|
+
"sum": { "field": "amount" }
|
|
178
|
+
},
|
|
179
|
+
"unique_customers": {
|
|
180
|
+
"cardinality": { "field": "user_id" }
|
|
181
|
+
},
|
|
182
|
+
"sales_trend": { // 日销售趋势
|
|
183
|
+
"date_histogram": {
|
|
184
|
+
"field": "order_date",
|
|
185
|
+
"calendar_interval": "day"
|
|
186
|
+
},
|
|
187
|
+
"aggs": {
|
|
188
|
+
"daily_revenue": { "sum": { "field": "amount" } }
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"top_categories": { // TOP 品类
|
|
192
|
+
"terms": { "field": "category", "size": 10 },
|
|
193
|
+
"aggs": {
|
|
194
|
+
"cat_revenue": { "sum": { "field": "amount" } }
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"price_distribution": { // 价格分布
|
|
198
|
+
"percentiles": {
|
|
199
|
+
"field": "amount",
|
|
200
|
+
"percents": [25, 50, 75, 90, 99]
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
# 一次请求返回: 总览统计 + 总销售额 + 去重用户数 + 日趋势 + TOP 品类 + 价格百分位
|
|
206
|
+
```
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# 示例: 零停机重建索引 (Zero-Downtime Reindex)
|
|
2
|
+
|
|
3
|
+
## 场景
|
|
4
|
+
|
|
5
|
+
需要修改已有索引的 mapping(如添加字段、修改分词器),但生产环境不能停机。
|
|
6
|
+
|
|
7
|
+
## 核心思路
|
|
8
|
+
|
|
9
|
+
Alias(别名) + Reindex(数据迁移) + 原子切换。
|
|
10
|
+
|
|
11
|
+
## 步骤
|
|
12
|
+
|
|
13
|
+
### 1. 假设已有索引和别名
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 初始状态: 已有 products_v1 索引, 通过 products 别名访问
|
|
17
|
+
GET /products/_search
|
|
18
|
+
{
|
|
19
|
+
"query": { "match_all": {} }
|
|
20
|
+
}
|
|
21
|
+
# 别名可以透明访问
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. 创建新索引 (v2) 使用新的 mapping
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
PUT /products_v2
|
|
28
|
+
{
|
|
29
|
+
"settings": {
|
|
30
|
+
"number_of_shards": 5,
|
|
31
|
+
"number_of_replicas": 1,
|
|
32
|
+
"refresh_interval": "-1"
|
|
33
|
+
},
|
|
34
|
+
"mappings": {
|
|
35
|
+
"properties": {
|
|
36
|
+
"title": {
|
|
37
|
+
"type": "text",
|
|
38
|
+
"analyzer": "ik_max_word",
|
|
39
|
+
"fields": {
|
|
40
|
+
"keyword": { "type": "keyword", "ignore_above": 256 },
|
|
41
|
+
"pinyin": { "type": "text", "analyzer": "pinyin" }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"description": {
|
|
45
|
+
"type": "text",
|
|
46
|
+
"analyzer": "ik_max_word"
|
|
47
|
+
},
|
|
48
|
+
"price": { "type": "double" },
|
|
49
|
+
"new_field": { "type": "keyword" },
|
|
50
|
+
"search_all": {
|
|
51
|
+
"type": "text",
|
|
52
|
+
"analyzer": "ik_max_word"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. 执行 Reindex 数据迁移
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# 使用 slices=auto 并行加速
|
|
63
|
+
POST /_reindex?slices=auto&wait_for_completion=false
|
|
64
|
+
{
|
|
65
|
+
"source": {
|
|
66
|
+
"index": "products_v1"
|
|
67
|
+
},
|
|
68
|
+
"dest": {
|
|
69
|
+
"index": "products_v2"
|
|
70
|
+
},
|
|
71
|
+
"script": {
|
|
72
|
+
"source": """
|
|
73
|
+
// 如果新索引有 copy_to 字段, 在脚本中处理
|
|
74
|
+
if (ctx._source.title != null && ctx._source.description != null) {
|
|
75
|
+
ctx._source.search_all = ctx._source.title + ' ' + ctx._source.description;
|
|
76
|
+
}
|
|
77
|
+
// 添加新字段默认值
|
|
78
|
+
ctx._source.new_field = 'migrated';
|
|
79
|
+
"""
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
# 返回 task id, 可用 _tasks API 查看进度
|
|
83
|
+
GET /_tasks/<task_id>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 4. 原子切换别名 (零停机)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# 关键步骤: 一次操作移除旧别名 + 添加新别名
|
|
90
|
+
# 这期间已有查询不会中断
|
|
91
|
+
POST /_aliases
|
|
92
|
+
{
|
|
93
|
+
"actions": [
|
|
94
|
+
{ "remove": { "index": "products_v1", "alias": "products" } },
|
|
95
|
+
{ "add": { "index": "products_v2", "alias": "products" } }
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
# 原子操作, 切换完成后所有通过 products 别名的查询自动指向 v2
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 5. 验证并删除旧索引
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# 验证新索引数据完整
|
|
105
|
+
GET /products/_search
|
|
106
|
+
{
|
|
107
|
+
"query": { "match_all": {} },
|
|
108
|
+
"size": 0
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# 确认无误后删除旧索引
|
|
112
|
+
DELETE /products_v1
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Reindex 进阶技巧
|
|
116
|
+
|
|
117
|
+
### 跨集群 Reindex
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
POST /_reindex
|
|
121
|
+
{
|
|
122
|
+
"source": {
|
|
123
|
+
"remote": {
|
|
124
|
+
"host": "http://old-cluster:9200",
|
|
125
|
+
"username": "elastic",
|
|
126
|
+
"password": "pass"
|
|
127
|
+
},
|
|
128
|
+
"index": "products"
|
|
129
|
+
},
|
|
130
|
+
"dest": {
|
|
131
|
+
"index": "products_v2"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 只迁移部分数据
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
POST /_reindex
|
|
140
|
+
{
|
|
141
|
+
"source": {
|
|
142
|
+
"index": "products_v1",
|
|
143
|
+
"query": {
|
|
144
|
+
"term": { "status": "active" }
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"dest": {
|
|
148
|
+
"index": "products_active"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 冲突处理
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# 跳过已存在的文档 (op_type=create)
|
|
157
|
+
POST /_reindex
|
|
158
|
+
{
|
|
159
|
+
"source": { "index": "products_v1" },
|
|
160
|
+
"dest": {
|
|
161
|
+
"index": "products_v2",
|
|
162
|
+
"op_type": "create"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# 或者使用 version_type=external 保留旧版本
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Reindex 大小和速度
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# 限制批次大小 (默认 1000)
|
|
173
|
+
POST /_reindex
|
|
174
|
+
{
|
|
175
|
+
"source": {
|
|
176
|
+
"index": "products_v1",
|
|
177
|
+
"size": 5000
|
|
178
|
+
},
|
|
179
|
+
"dest": {
|
|
180
|
+
"index": "products_v2"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# 限制速率 (每秒文档数)
|
|
185
|
+
PUT /_cluster/settings
|
|
186
|
+
{
|
|
187
|
+
"transient": {
|
|
188
|
+
"indices.recovery.max_bytes_per_sec": "200mb"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 注意事项
|
|
194
|
+
|
|
195
|
+
1. **大索引 Reindex**:建议 `slices=auto` 并行执行,可根据数据节点数自动调整并行度
|
|
196
|
+
2. **源索引不影响**:Reindex 期间源索引可继续读写服务
|
|
197
|
+
3. **Refresh 优化**:新索引设 `refresh_interval: -1`,迁移完再恢复
|
|
198
|
+
4. **副本优化**:新索引设 `number_of_replicas: 0`,迁移完再调回
|
|
199
|
+
5. **验证数据完整性**:迁移后对比文档数 (`_cat/count`)
|
|
200
|
+
6. **善后清理**:确认新索引正常后删除旧索引释放空间
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# 示例: 集群监控实战
|
|
2
|
+
|
|
3
|
+
## 场景
|
|
4
|
+
|
|
5
|
+
日常运维需要监控 Elasticsearch 集群的健康状态、性能指标和资源使用情况。
|
|
6
|
+
|
|
7
|
+
## 1. 集群健康检查
|
|
8
|
+
|
|
9
|
+
### 快速健康状态
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# 绿色 = 全部正常, 黄色 = 副本未分配, 红色 = 主分片丢失
|
|
13
|
+
GET /_cluster/health?pretty
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"cluster_name": "production",
|
|
19
|
+
"status": "yellow",
|
|
20
|
+
"timed_out": false,
|
|
21
|
+
"number_of_nodes": 5,
|
|
22
|
+
"number_of_data_nodes": 3,
|
|
23
|
+
"active_primary_shards": 125,
|
|
24
|
+
"active_shards": 240,
|
|
25
|
+
"relocating_shards": 0,
|
|
26
|
+
"initializing_shards": 0,
|
|
27
|
+
"unassigned_shards": 10,
|
|
28
|
+
"delayed_unassigned_shards": 0,
|
|
29
|
+
"active_shards_percent_as_number": 96.0
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**解读**:unassigned_shards=10, active_shards_percent=96% → 有副本未分配。检查节点是否宕机。
|
|
34
|
+
|
|
35
|
+
### 详细健康诊断
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 查看所有未分配分片的原因
|
|
39
|
+
GET /_cluster/allocation/explain?pretty
|
|
40
|
+
|
|
41
|
+
# 重点关注字段:
|
|
42
|
+
# - current_node: 当前所在节点
|
|
43
|
+
# - can_remain_on_current_node: 能否保留
|
|
44
|
+
# - can_rebalance_cluster: 能否再平衡
|
|
45
|
+
# - node_decision: 节点决策
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 2. 节点监控
|
|
49
|
+
|
|
50
|
+
### 节点概览
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# 节点角色和资源使用
|
|
54
|
+
GET /_cat/nodes?v&h=name,node.role,heap.percent,ram.percent,cpu,load_1m,disk.used_percent,master
|
|
55
|
+
|
|
56
|
+
# 示例输出:
|
|
57
|
+
# name node.role heap.percent ram.percent cpu load_1m disk.used_percent master
|
|
58
|
+
# master-1 m 42 35 8 2.3 42 *
|
|
59
|
+
# data-1 d 67 72 35 12.5 56 -
|
|
60
|
+
# data-2 d 55 60 28 9.8 52 -
|
|
61
|
+
# coord-1 - 48 45 15 4.1 38 -
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**告警阈值**:
|
|
65
|
+
- heap.percent > 85 → GC 压力大
|
|
66
|
+
- cpu > 80 → 需要扩容
|
|
67
|
+
- disk.used_percent > 85 → 需要清理或 ILM
|
|
68
|
+
|
|
69
|
+
### 热点线程排查 (CPU 突增)
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 当集群 CPU 突然飙高时
|
|
73
|
+
GET /_nodes/hot_threads
|
|
74
|
+
|
|
75
|
+
# 返回每个节点的热点线程堆栈
|
|
76
|
+
# 重点关注:
|
|
77
|
+
# - bulk 线程 → 写入压力大
|
|
78
|
+
# - search 线程 → 查询压力大
|
|
79
|
+
# - merge 线程 → 段合并 (大批量写入后)
|
|
80
|
+
# - GC 线程 → 内存问题
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 节点统计
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# 获取节点级别详细统计
|
|
87
|
+
GET /_nodes/stats/indices,os,process,jvm,fs,transport,http
|
|
88
|
+
|
|
89
|
+
# 关注指标:
|
|
90
|
+
# - indices.indexing: 写入速率
|
|
91
|
+
# - indices.search: 查询速率
|
|
92
|
+
# - jvm.mem.heap_used_percent: 堆内存使用
|
|
93
|
+
# - jvm.gc.collectors.young.collection_time_in_millis: GC 时间
|
|
94
|
+
# - os.cpu.percent: CPU
|
|
95
|
+
# - fs.total.available_in_bytes: 磁盘空间
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 3. 索引监控
|
|
99
|
+
|
|
100
|
+
### 索引概览
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# 查看所有索引的大小和文档数
|
|
104
|
+
GET /_cat/indices?v&h=index,docs.count,store.size,pri.store.size
|
|
105
|
+
|
|
106
|
+
# 查看索引分片分布
|
|
107
|
+
GET /_cat/shards?v
|
|
108
|
+
|
|
109
|
+
# 按大小排序
|
|
110
|
+
GET /_cat/indices?v&s=store.size:desc
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 段 (Segment) 监控
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# 检查段的统计
|
|
117
|
+
GET /my_index/_segments
|
|
118
|
+
|
|
119
|
+
# 查看各索引段数
|
|
120
|
+
GET /_cat/segments?v&h=index,shard,segment,size,committed,search
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**段过多 (>100)** 表示需要 force_merge:`POST /my_index/_forcemerge?max_num_segments=1`
|
|
124
|
+
|
|
125
|
+
## 4. 性能监控脚本
|
|
126
|
+
|
|
127
|
+
### Shell 健康检查脚本
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
#!/bin/bash
|
|
131
|
+
# es_health_check.sh
|
|
132
|
+
ES_HOST="http://localhost:9200"
|
|
133
|
+
|
|
134
|
+
# 集群健康
|
|
135
|
+
echo "=== 集群健康 ==="
|
|
136
|
+
curl -s "$ES_HOST/_cluster/health?pretty" | python3 -c "
|
|
137
|
+
import json, sys
|
|
138
|
+
h = json.load(sys.stdin)
|
|
139
|
+
print(f'状态: {h[\"status\"]}')
|
|
140
|
+
print(f'节点: {h[\"number_of_nodes\"]} (数据节点: {h[\"number_of_data_nodes\"]})')
|
|
141
|
+
print(f'活跃分片: {h[\"active_shards\"]}/{h[\"active_primary_shards\"]}p')
|
|
142
|
+
print(f'未分配: {h[\"unassigned_shards\"]}')
|
|
143
|
+
print(f'活跃率: {h[\"active_shards_percent_as_number\"]:.1f}%')
|
|
144
|
+
"
|
|
145
|
+
|
|
146
|
+
# 节点资源
|
|
147
|
+
echo -e "\n=== 节点资源 ==="
|
|
148
|
+
curl -s "$ES_HOST/_cat/nodes?v&h=name,node.role,heap.percent,cpu,load_1m,disk.used_percent"
|
|
149
|
+
|
|
150
|
+
# 索引 TOP 10 大索引
|
|
151
|
+
echo -e "\n=== TOP 10 大索引 ==="
|
|
152
|
+
curl -s "$ES_HOST/_cat/indices?v&h=index,docs.count,store.size&s=store.size:desc&limit=10"
|
|
153
|
+
|
|
154
|
+
# JVM 堆内存 Top 节点
|
|
155
|
+
echo -e "\n=== JVM 内存 (Top 5) ==="
|
|
156
|
+
curl -s "$ES_HOST/_nodes/stats/jvm" | python3 -c "
|
|
157
|
+
import json, sys
|
|
158
|
+
nodes = json.load(sys.stdin)['nodes']
|
|
159
|
+
for node_id, info in sorted(nodes.items(), key=lambda x: x[1]['jvm']['mem']['heap_used_percent'], reverse=True)[:5]:
|
|
160
|
+
name = info['name']
|
|
161
|
+
mem = info['jvm']['mem']
|
|
162
|
+
gc = info['jvm']['gc']['collectors']
|
|
163
|
+
print(f'{name}: heap={mem[\"heap_used_percent\"]}% old_gc={gc[\"old\"][\"collection_count\"]}次({gc[\"old\"][\"collection_time_in_millis\"]//1000}s)')
|
|
164
|
+
"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 5. 告警规则建议
|
|
168
|
+
|
|
169
|
+
| 指标 | 警告阈值 | 严重阈值 | 检查间隔 |
|
|
170
|
+
|------|---------|---------|---------|
|
|
171
|
+
| cluster health status | yellow > 5min | red | 1min |
|
|
172
|
+
| heap usage | > 80% | > 90% | 1min |
|
|
173
|
+
| CPU | > 70% | > 85% | 5min |
|
|
174
|
+
| disk usage | > 80% | > 90% | 1min |
|
|
175
|
+
| unassigned shards | > 0 | > 5 | 1min |
|
|
176
|
+
| search latency P99 | > 1s | > 5s | 5min |
|
|
177
|
+
| indexing latency P99 | > 500ms | > 2s | 5min |
|
|
178
|
+
| GC old gen count | > 5/min | > 10/min | 1min |
|
|
179
|
+
|
|
180
|
+
## 6. Kibana 监控配置
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
# 启用 Kibana 监控 UI (Stack Monitoring)
|
|
184
|
+
# Management → Stack Monitoring
|
|
185
|
+
# 可查看:
|
|
186
|
+
# - 集群概览 (节点/索引/分片)
|
|
187
|
+
# - 节点 CPU/内存/磁盘/IO
|
|
188
|
+
# - 索引搜索/写入速率
|
|
189
|
+
# - GC 统计
|
|
190
|
+
# - 慢查询 Top N
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 性能排查清单
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
1. 是否 Yellow/Red → 检查未分配分片 (allocation/explain)
|
|
197
|
+
2. CPU 高 → hot_threads 排查
|
|
198
|
+
3. 查询慢 → Profile API + 慢查询日志
|
|
199
|
+
4. 写入慢 → 检查 refresh_interval + Bulk 优化
|
|
200
|
+
5. 磁盘满 → ILM 清理 + force_merge
|
|
201
|
+
6. GC 频繁 → 减少分片/字段, 增加堆内存
|
|
202
|
+
7. Segments 多 → force_merge (只读索引)
|
|
203
|
+
8. 深度分页 → 改用 search_after
|
|
204
|
+
```
|