文章目录
一、核心机制:网络检查与数据执行的分离
Weaviate的两阶段提交有一个关键设计选择:第一阶段只检查网络连通性,第二阶段才执行真正的数据操作。 这种分离带来了独特的行为模式和错误处理逻辑。
想象一个分布式团队协作:第一阶段大家确认"我能收到消息",第二阶段才开始"实际干活"。这种设计优先解决分布式系统中最常见的网络分区问题。
1、两阶段流程的技术实现
2、准备阶段的"虚假成功"机制
func (s *Shard) preparePutObject(ctx context.Context, requestID string, object *storobj.Object) replica.SimpleResponse {
// 只做基本参数验证
uuid, err := parseBytesUUID(object.ID())
if err != nil {
return replica.SimpleResponse{Errors: []replica.Error{{
Code: replica.StatusPreconditionFailed, Msg: err.Error(),
}}}
}
// 关键:只存储任务,不执行实际操作
task := func(ctx context.Context) interface{} {
// 真正的数据操作延迟到提交阶段
if err := s.putOne(ctx, uuid, object); err != nil {
return replica.SimpleResponse{Errors: []replica.Error{
{Code: replica.StatusConflict, Msg: err.Error()},
}}
}
return replica.SimpleResponse{}
}
s.replicationMap.set(requestID, task)
return replica.SimpleResponse{} // 返回"准备成功",但未实际执行
}
核心特点: 准备阶段关注的是"我能接收到消息吗?"而不是"我能成功执行这个操作吗?"这种设计让网络问题能够被快速识别,但数据完整性问题被延迟到执行阶段。
二、一致性级别的差异化行为
1、标准多节点场景
在3副本环境下,假设1个副本数据损坏但网络正常,2个副本网络不通:
一致性级别 | 需要响应数 | 实际响应数 | 结果 |
---|---|---|---|
ALL | 3个 | 1个 | “cannot reach enough replicas” |
QUORUM | 2个 | 1个 | “cannot reach enough replicas” |
ONE | 1个 | 1个 | “invalid checksum” |
2、单节点部署的特殊行为
关键发现: 在单节点部署中,即使理论上所有一致性级别都只需要1个节点,ALL级别仍然表现不同:
场景:单节点部署,数据损坏但网络正常
- ALL级别:返回 "cannot reach enough replicas"
- QUORUM级别:返回 "invalid checksum"
- ONE级别:返回 "invalid checksum"
这揭示了ALL级别的特殊实现逻辑。
3、 ALL级别的严格健康检查
// 可能的ALL级别实现逻辑(推测)
func checkReplicaAvailability(consistencyLevel ConsistencyLevel, replica Replica) bool {
if consistencyLevel == ALL {
// ALL级别要求副本不仅网络可达,还要数据健康
return replica.isNetworkReachable() && replica.isDataHealthy()
} else {
// 其他级别只检查网络连通性
return replica.isNetworkReachable()
}
}
设计哲学差异:
一致性级别 | 对"可用副本"的定义 |
---|---|
ALL | 副本必须网络可达 且 数据完整 |
QUORUM/ONE | 副本只需网络可达,数据问题在执行时处理 |
4、错误信息的实际指导价值
这种差异化的错误处理为运维提供了不同的诊断方向:
"cannot reach enough replicas"的含义:
- 网络分区问题(多数情况)
- 节点健康问题(ALL级别特有)
- 数据完整性问题(ALL级别特有)
"invalid checksum"的含义:
- 纯粹的数据损坏问题
- 需要进行数据修复或重建