read-health check endpoint returns success if cluster can serve read requests (#11310)

This commit is contained in:
Krishna Srinivas
2021-02-09 01:00:44 -08:00
committed by GitHub
parent 3d74efa6b1
commit 876b79b8d8
8 changed files with 98 additions and 7 deletions

View File

@@ -1461,6 +1461,40 @@ type HealthResult struct {
WriteQuorum int
}
// ReadHealth returns if the cluster can serve read requests
func (z *erasureServerPools) ReadHealth(ctx context.Context) bool {
erasureSetUpCount := make([][]int, len(z.serverPools))
for i := range z.serverPools {
erasureSetUpCount[i] = make([]int, len(z.serverPools[i].sets))
}
diskIDs := globalNotificationSys.GetLocalDiskIDs(ctx)
diskIDs = append(diskIDs, getLocalDiskIDs(z))
for _, localDiskIDs := range diskIDs {
for _, id := range localDiskIDs {
poolIdx, setIdx, err := z.getPoolAndSet(id)
if err != nil {
logger.LogIf(ctx, err)
continue
}
erasureSetUpCount[poolIdx][setIdx]++
}
}
b := z.BackendInfo()
readQuorum := b.StandardSCData[0]
for poolIdx := range erasureSetUpCount {
for setIdx := range erasureSetUpCount[poolIdx] {
if erasureSetUpCount[poolIdx][setIdx] < readQuorum {
return false
}
}
}
return true
}
// Health - returns current status of the object layer health,
// provides if write access exists across sets, additionally
// can be used to query scenarios if health may be lost

View File

@@ -1623,3 +1623,9 @@ func (fs *FSObjects) Health(ctx context.Context, opts HealthOptions) HealthResul
Healthy: newObjectLayerFn() != nil,
}
}
// ReadHealth returns "read" health of the object layer
func (fs *FSObjects) ReadHealth(ctx context.Context) bool {
_, err := os.Stat(fs.fsPath)
return err == nil
}

View File

@@ -254,3 +254,8 @@ func (a GatewayUnsupported) IsCompressionSupported() bool {
func (a GatewayUnsupported) Health(_ context.Context, _ HealthOptions) HealthResult {
return HealthResult{}
}
// ReadHealth - No Op.
func (a GatewayUnsupported) ReadHealth(_ context.Context) bool {
return true
}

View File

@@ -216,7 +216,8 @@ func guessIsHealthCheckReq(req *http.Request) bool {
return aType == authTypeAnonymous && (req.Method == http.MethodGet || req.Method == http.MethodHead) &&
(req.URL.Path == healthCheckPathPrefix+healthCheckLivenessPath ||
req.URL.Path == healthCheckPathPrefix+healthCheckReadinessPath ||
req.URL.Path == healthCheckPathPrefix+healthCheckClusterPath)
req.URL.Path == healthCheckPathPrefix+healthCheckClusterPath ||
req.URL.Path == healthCheckPathPrefix+healthCheckClusterReadPath)
}
// guessIsMetricsReq - returns true if incoming request looks

View File

@@ -64,6 +64,29 @@ func ClusterCheckHandler(w http.ResponseWriter, r *http.Request) {
writeResponse(w, http.StatusOK, nil, mimeNone)
}
// ClusterReadCheckHandler returns if the server is ready for requests.
func ClusterReadCheckHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "ClusterReadCheckHandler")
if shouldProxy() {
w.Header().Set(xhttp.MinIOServerStatus, unavailable)
writeResponse(w, http.StatusServiceUnavailable, nil, mimeNone)
return
}
objLayer := newObjectLayerFn()
ctx, cancel := context.WithTimeout(ctx, globalAPIConfig.getClusterDeadline())
defer cancel()
result := objLayer.ReadHealth(ctx)
if !result {
writeResponse(w, http.StatusServiceUnavailable, nil, mimeNone)
return
}
writeResponse(w, http.StatusOK, nil, mimeNone)
}
// ReadinessCheckHandler Checks if the process is up. Always returns success.
func ReadinessCheckHandler(w http.ResponseWriter, r *http.Request) {
if shouldProxy() {

View File

@@ -23,11 +23,12 @@ import (
)
const (
healthCheckPath = "/health"
healthCheckLivenessPath = "/live"
healthCheckReadinessPath = "/ready"
healthCheckClusterPath = "/cluster"
healthCheckPathPrefix = minioReservedBucketPath + healthCheckPath
healthCheckPath = "/health"
healthCheckLivenessPath = "/live"
healthCheckReadinessPath = "/ready"
healthCheckClusterPath = "/cluster"
healthCheckClusterReadPath = "/cluster/read"
healthCheckPathPrefix = minioReservedBucketPath + healthCheckPath
)
// registerHealthCheckRouter - add handler functions for liveness and readiness routes.
@@ -38,6 +39,7 @@ func registerHealthCheckRouter(router *mux.Router) {
// Cluster check handler to verify cluster is active
healthRouter.Methods(http.MethodGet).Path(healthCheckClusterPath).HandlerFunc(httpTraceAll(ClusterCheckHandler))
healthRouter.Methods(http.MethodGet).Path(healthCheckClusterReadPath).HandlerFunc(httpTraceAll(ClusterReadCheckHandler))
// Liveness handler
healthRouter.Methods(http.MethodGet).Path(healthCheckLivenessPath).HandlerFunc(httpTraceAll(LivenessCheckHandler))

View File

@@ -155,6 +155,7 @@ type ObjectLayer interface {
// Returns health of the backend
Health(ctx context.Context, opts HealthOptions) HealthResult
ReadHealth(ctx context.Context) bool
// ObjectTagging operations
PutObjectTags(context.Context, string, string, string, ObjectOptions) (ObjectInfo, error)