-
Notifications
You must be signed in to change notification settings - Fork 2.4k
healthcheck: update healthy tablets correctly when a stream returns an error or times out #7654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -404,17 +404,17 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { | |
| } | ||
| } | ||
|
|
||
| func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, shr *query.StreamHealthResponse, currentTarget *query.Target, trivialNonMasterUpdate bool, isMasterUpdate bool, isMasterChange bool) { | ||
| func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, currentTarget *query.Target, trivialUpdate bool, isPrimaryUp bool) { | ||
| // hc.healthByAlias is authoritative, it should be updated | ||
| hc.mu.Lock() | ||
| defer hc.mu.Unlock() | ||
|
|
||
| tabletAlias := tabletAliasString(topoproto.TabletAliasString(shr.TabletAlias)) | ||
|
|
||
| hcErrorCounters.Add([]string{shr.Target.Keyspace, shr.Target.Shard, topoproto.TabletTypeLString(shr.Target.TabletType)}, 0) | ||
| targetKey := hc.keyFromTarget(shr.Target) | ||
| targetChanged := currentTarget.TabletType != shr.Target.TabletType || currentTarget.Keyspace != shr.Target.Keyspace || currentTarget.Shard != shr.Target.Shard | ||
| tabletAlias := tabletAliasString(topoproto.TabletAliasString(th.Tablet.Alias)) | ||
| targetKey := hc.keyFromTarget(th.Target) | ||
| targetChanged := currentTarget.TabletType != th.Target.TabletType || currentTarget.Keyspace != th.Target.Keyspace || currentTarget.Shard != th.Target.Shard | ||
| if targetChanged { | ||
| // Error counter has to be set here in case we get a new tablet type for the first time in a stream response | ||
| hcErrorCounters.Add([]string{th.Target.Keyspace, th.Target.Shard, topoproto.TabletTypeLString(th.Target.TabletType)}, 0) | ||
| // keyspace and shard are not expected to change, but just in case ... | ||
| // move this tabletHealthCheck to the correct map | ||
| oldTargetKey := hc.keyFromTarget(currentTarget) | ||
|
|
@@ -427,44 +427,48 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, shr *query.StreamHealt | |
| // add it to the map by target | ||
| hc.healthData[targetKey][tabletAlias] = th | ||
|
|
||
| if isMasterUpdate { | ||
| if len(hc.healthy[targetKey]) == 0 { | ||
| hc.healthy[targetKey] = append(hc.healthy[targetKey], th) | ||
| } else { | ||
| // We already have one up server, see if we | ||
| // need to replace it. | ||
| if shr.TabletExternallyReparentedTimestamp < hc.healthy[targetKey][0].MasterTermStartTime { | ||
| log.Warningf("not marking healthy master %s as Up for %s because its MasterTermStartTime is smaller than the highest known timestamp from previous MASTERs %s: %d < %d ", | ||
| topoproto.TabletAliasString(shr.TabletAlias), | ||
| topoproto.KeyspaceShardString(shr.Target.Keyspace, shr.Target.Shard), | ||
| topoproto.TabletAliasString(hc.healthy[targetKey][0].Tablet.Alias), | ||
| shr.TabletExternallyReparentedTimestamp, | ||
| hc.healthy[targetKey][0].MasterTermStartTime) | ||
| if th.Target.TabletType == topodata.TabletType_MASTER { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would presume that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is a good point. I suppose this is more of a consistency check - to make sure that we still behave correctly if a caller passes in |
||
| if isPrimaryUp { | ||
| if len(hc.healthy[targetKey]) == 0 { | ||
| hc.healthy[targetKey] = append(hc.healthy[targetKey], th) | ||
| } else { | ||
| // Just replace it. | ||
| hc.healthy[targetKey][0] = th | ||
| // We already have one up server, see if we | ||
| // need to replace it. | ||
| if th.MasterTermStartTime < hc.healthy[targetKey][0].MasterTermStartTime { | ||
| log.Warningf("not marking healthy master %s as Up for %s because its MasterTermStartTime is smaller than the highest known timestamp from previous MASTERs %s: %d < %d ", | ||
| topoproto.TabletAliasString(th.Tablet.Alias), | ||
| topoproto.KeyspaceShardString(th.Target.Keyspace, th.Target.Shard), | ||
| topoproto.TabletAliasString(hc.healthy[targetKey][0].Tablet.Alias), | ||
| th.MasterTermStartTime, | ||
| hc.healthy[targetKey][0].MasterTermStartTime) | ||
| } else { | ||
| // Just replace it. | ||
| hc.healthy[targetKey][0] = th | ||
| } | ||
| } | ||
| } else { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this section was the reason you added the MASTER check, it may read better if you explicitly checked for it here. Something like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The MASTER check was already there but in the form of a boolean (isMasterUpdate).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The concern was the deep nesting which made it non-obvious. A cascading if (or switch) may read better. Try it. If it doesn't improve it, we can keep this as is.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I think the switch made it better. |
||
| // No healthy master tablet | ||
| hc.healthy[targetKey] = []*TabletHealth{} | ||
| } | ||
| } | ||
| if !trivialNonMasterUpdate { | ||
| if !trivialUpdate { | ||
| // We re-sort the healthy tablet list whenever we get a health update for tablets we can route to. | ||
| // Tablets from other cells for non-master targets should not trigger a re-sort; | ||
| // they should also be excluded from healthy list. | ||
| if shr.Target.TabletType != topodata.TabletType_MASTER && hc.isIncluded(shr.Target.TabletType, shr.TabletAlias) { | ||
| if th.Target.TabletType != topodata.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { | ||
| hc.recomputeHealthy(targetKey) | ||
| } | ||
| if targetChanged && currentTarget.TabletType != topodata.TabletType_MASTER && hc.isIncluded(shr.Target.TabletType, shr.TabletAlias) { // also recompute old target's healthy list | ||
| if targetChanged && currentTarget.TabletType != topodata.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { // also recompute old target's healthy list | ||
| oldTargetKey := hc.keyFromTarget(currentTarget) | ||
| hc.recomputeHealthy(oldTargetKey) | ||
| } | ||
| } | ||
| if isMasterChange { | ||
| log.Errorf("Adding 1 to MasterPromoted counter for tablet: %v, shr.Tablet: %v, shr.TabletType: %v", currentTarget, topoproto.TabletAliasString(shr.TabletAlias), shr.Target.TabletType) | ||
| hcMasterPromotedCounters.Add([]string{shr.Target.Keyspace, shr.Target.Shard}, 1) | ||
| if currentTarget.TabletType != topodata.TabletType_MASTER && th.Target.TabletType == topodata.TabletType_MASTER { | ||
| log.Errorf("Adding 1 to MasterPromoted counter for target: %v, tablet: %v, tabletType: %v", currentTarget, topoproto.TabletAliasString(th.Tablet.Alias), th.Target.TabletType) | ||
| hcMasterPromotedCounters.Add([]string{th.Target.Keyspace, th.Target.Shard}, 1) | ||
| } | ||
| // broadcast to subscribers | ||
| hc.broadcast(th) | ||
|
|
||
| } | ||
|
|
||
| func (hc *HealthCheckImpl) recomputeHealthy(key keyspaceShardTabletType) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename this to
isPrimaryUpdate? Otherwise, I was reading it as "is primary up".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is supposed to be "is primary up". The old parameters (isMasterChange and isMasterUpdate) were actually unnecessary because all the information they pass in is available within the scope of this func. However, we do need to know whether the primary should be marked unhealthy (if there is an error/timeout on the healthcheck connection), so I introduced this parameter.