为什么这个错误发生 #
retry_on_primary_exception 表示在主分片上执行的操作失败,需要在主分片上重试。这个异常通常在主分片状态发生变化时发生。
这个错误可能由以下原因引起:
- 主分片已迁移:操作执行时主分片已迁移到其他节点
- 主分片不再是主:原主分片降级为副本,新的主分片已选出
- 主分片恢复中:主分片正在恢复过程中,暂时无法处理写操作
- 并发版本冲突:存在并发操作导致主分片变更
- 分片重新分配:分片被重新分配到其他节点
- 节点故障转移:原主分片所在的节点故障,主分片已转移到其他节点
如何修复这个错误 #
1. 检查分片状态 #
# 查看分片分配状态
GET /_cat/shards?v&h=index,shard,prirep,state,node
# 查看特定分片
GET /_cluster/allocation/explain
{
"index": "<index>",
"shard": 0,
"primary": true
}
2. 重试操作 #
客户端通常会自动重试,也可以手动重试:
# 对于索引操作
POST /<index>/_doc/<id>?retry_on_conflict=3
{
"field": "value"
}
# 对于更新操作
POST /<index>/_update/<id>?retry_on_conflict=3
{
"doc": {
"field": "value"
}
}
3. 使用路由 #
使用路由确保操作发送到正确的分片:
# 使用路由参数
POST /<index>/_doc/<id>?routing=<user_id>
{
"field": "value"
}
4. 检查集群健康状态 #
# 等待集群稳定
GET /_cluster/health?wait_for_status=yellow&timeout=50s
# 查看未分配的分片
GET /_cat/shards?v | grep UNASSIGNED
5. 等待分片迁移完成 #
# 查看正在恢复的分片
GET /_cat/recovery?v
# 等待迁移完成
GET /_cluster/health?wait_for_no_relocating_shards=true&timeout=50s
6. 使用乐观并发控制 #
# 使用序列号进行条件更新
POST /<index>/_update/<id>
{
"doc": {
"field": "value"
},
"if_seq_no": 5,
"if_primary_term": 1
}
7. 检查节点日志 #
# 查看主分片相关日志
grep -i "primary" /path/to/easysearch/logs/easysearch.log | tail -50
# 查看分片迁移日志
grep -i "relocation" /path/to/easysearch/logs/easysearch.log | tail -50
8. 调整副本设置 #
如果主分片频繁变更,可能是副本配置问题:
# 检查副本数量
GET /<index>/_settings?flat_settings=true
# 临时减少副本以稳定集群
PUT /<index>/_settings
{
"index": {
"number_of_replicas": 0
}
}
# 等待稳定后再恢复副本
PUT /<index>/_settings
{
"index": {
"number_of_replicas": 1
}
}
9. 检查分片分配规则 #
# 查看分配规则
GET /_cluster/settings?filter_path=**.routing.allocation
# 确保没有阻止分配的规则
10. 使用客户端重试机制 #
# Python 客户端配置重试
from elasticsearch import Elasticsearch, ElasticsearchException
from elasticsearch.helpers import bulk
import time
es = Elasticsearch(
["http://localhost:9200"],
max_retries=3,
retry_on_timeout=True,
retry_on_status=[503, 504] # Service Unavailable, Gateway Timeout
)
# 或使用指数退避
from elastic_transport import Retry
retry = Retry(
limit=5,
backoff_factor=1,
status_forcelist=[503, 504]
)
预防措施 #
- 配置合理的副本数以提高可用性
- 避免在分片迁移时执行大量写操作
- 实现客户端自动重试机制
- 监控分片健康状态和迁移进度
- 使用负载均衡器分发请求
- 配置合理的超时时间
- 避免在集群不稳定时执行关键操作
- 使用乐观并发控制处理并发写操作





