|
@@ -22,6 +22,7 @@ import (
|
|
|
"net/http"
|
|
"net/http"
|
|
|
"path"
|
|
"path"
|
|
|
"strings"
|
|
"strings"
|
|
|
|
|
+ "time"
|
|
|
|
|
|
|
|
pioutil "github.com/coreos/etcd/pkg/ioutil"
|
|
pioutil "github.com/coreos/etcd/pkg/ioutil"
|
|
|
"github.com/coreos/etcd/pkg/types"
|
|
"github.com/coreos/etcd/pkg/types"
|
|
@@ -149,6 +150,8 @@ func newSnapshotHandler(tr Transporter, r Raft, snapshotter *snap.Snapshotter, c
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const unknownSnapshotSender = "UNKNOWN_SNAPSHOT_SENDER"
|
|
|
|
|
+
|
|
|
// ServeHTTP serves HTTP request to receive and process snapshot message.
|
|
// ServeHTTP serves HTTP request to receive and process snapshot message.
|
|
|
//
|
|
//
|
|
|
// If request sender dies without closing underlying TCP connection,
|
|
// If request sender dies without closing underlying TCP connection,
|
|
@@ -159,9 +162,12 @@ func newSnapshotHandler(tr Transporter, r Raft, snapshotter *snap.Snapshotter, c
|
|
|
// received and processed.
|
|
// received and processed.
|
|
|
// 2. this case should happen rarely, so no further optimization is done.
|
|
// 2. this case should happen rarely, so no further optimization is done.
|
|
|
func (h *snapshotHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
func (h *snapshotHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
+ start := time.Now()
|
|
|
|
|
+
|
|
|
if r.Method != "POST" {
|
|
if r.Method != "POST" {
|
|
|
w.Header().Set("Allow", "POST")
|
|
w.Header().Set("Allow", "POST")
|
|
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
|
|
|
+ snapshotReceiveFailures.WithLabelValues(unknownSnapshotSender).Inc()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -169,6 +175,7 @@ func (h *snapshotHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
if err := checkClusterCompatibilityFromHeader(r.Header, h.cid); err != nil {
|
|
if err := checkClusterCompatibilityFromHeader(r.Header, h.cid); err != nil {
|
|
|
http.Error(w, err.Error(), http.StatusPreconditionFailed)
|
|
http.Error(w, err.Error(), http.StatusPreconditionFailed)
|
|
|
|
|
+ snapshotReceiveFailures.WithLabelValues(unknownSnapshotSender).Inc()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -177,19 +184,22 @@ func (h *snapshotHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
dec := &messageDecoder{r: r.Body}
|
|
dec := &messageDecoder{r: r.Body}
|
|
|
// let snapshots be very large since they can exceed 512MB for large installations
|
|
// let snapshots be very large since they can exceed 512MB for large installations
|
|
|
m, err := dec.decodeLimit(uint64(1 << 63))
|
|
m, err := dec.decodeLimit(uint64(1 << 63))
|
|
|
|
|
+ from := types.ID(m.From).String()
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
msg := fmt.Sprintf("failed to decode raft message (%v)", err)
|
|
msg := fmt.Sprintf("failed to decode raft message (%v)", err)
|
|
|
plog.Errorf(msg)
|
|
plog.Errorf(msg)
|
|
|
http.Error(w, msg, http.StatusBadRequest)
|
|
http.Error(w, msg, http.StatusBadRequest)
|
|
|
recvFailures.WithLabelValues(r.RemoteAddr).Inc()
|
|
recvFailures.WithLabelValues(r.RemoteAddr).Inc()
|
|
|
|
|
+ snapshotReceiveFailures.WithLabelValues(from).Inc()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- receivedBytes.WithLabelValues(types.ID(m.From).String()).Add(float64(m.Size()))
|
|
|
|
|
|
|
+ receivedBytes.WithLabelValues(from).Add(float64(m.Size()))
|
|
|
|
|
|
|
|
if m.Type != raftpb.MsgSnap {
|
|
if m.Type != raftpb.MsgSnap {
|
|
|
plog.Errorf("unexpected raft message type %s on snapshot path", m.Type)
|
|
plog.Errorf("unexpected raft message type %s on snapshot path", m.Type)
|
|
|
http.Error(w, "wrong raft message type", http.StatusBadRequest)
|
|
http.Error(w, "wrong raft message type", http.StatusBadRequest)
|
|
|
|
|
+ snapshotReceiveFailures.WithLabelValues(from).Inc()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -200,9 +210,10 @@ func (h *snapshotHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
msg := fmt.Sprintf("failed to save KV snapshot (%v)", err)
|
|
msg := fmt.Sprintf("failed to save KV snapshot (%v)", err)
|
|
|
plog.Error(msg)
|
|
plog.Error(msg)
|
|
|
http.Error(w, msg, http.StatusInternalServerError)
|
|
http.Error(w, msg, http.StatusInternalServerError)
|
|
|
|
|
+ snapshotReceiveFailures.WithLabelValues(from).Inc()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- receivedBytes.WithLabelValues(types.ID(m.From).String()).Add(float64(n))
|
|
|
|
|
|
|
+ receivedBytes.WithLabelValues(from).Add(float64(n))
|
|
|
plog.Infof("received and saved database snapshot [index: %d, from: %s] successfully", m.Snapshot.Metadata.Index, types.ID(m.From))
|
|
plog.Infof("received and saved database snapshot [index: %d, from: %s] successfully", m.Snapshot.Metadata.Index, types.ID(m.From))
|
|
|
|
|
|
|
|
if err := h.r.Process(context.TODO(), m); err != nil {
|
|
if err := h.r.Process(context.TODO(), m); err != nil {
|
|
@@ -215,12 +226,16 @@ func (h *snapshotHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
msg := fmt.Sprintf("failed to process raft message (%v)", err)
|
|
msg := fmt.Sprintf("failed to process raft message (%v)", err)
|
|
|
plog.Warningf(msg)
|
|
plog.Warningf(msg)
|
|
|
http.Error(w, msg, http.StatusInternalServerError)
|
|
http.Error(w, msg, http.StatusInternalServerError)
|
|
|
|
|
+ snapshotReceiveFailures.WithLabelValues(from).Inc()
|
|
|
}
|
|
}
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
// Write StatusNoContent header after the message has been processed by
|
|
// Write StatusNoContent header after the message has been processed by
|
|
|
// raft, which facilitates the client to report MsgSnap status.
|
|
// raft, which facilitates the client to report MsgSnap status.
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
|
+
|
|
|
|
|
+ snapshotReceive.WithLabelValues(from).Inc()
|
|
|
|
|
+ snapshotReceiveSeconds.WithLabelValues(from).Observe(time.Since(start).Seconds())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
type streamHandler struct {
|
|
type streamHandler struct {
|