-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Node redirection #2154
Merged
Node redirection #2154
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next
Next commit
Handle broker and data node endpoints regardless of role
This is a pre-requisite for #1934. When running separate broker and data nodes, you currently need to know what role a host is performing. This complicates cluster setup in that you must configure separate broker URLs and data node URLs. This change allows a broker only node to redirect data nodes endpoints to a valid data node and a data only node to redirect broker endpoints to a valid broker.
- Loading branch information
commit 6d4c7e9cd52948bd16cdd328766d5f9daa317093
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,116 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/influxdb/influxdb" | ||
"github.com/influxdb/influxdb/httpd" | ||
"github.com/influxdb/influxdb/messaging" | ||
"github.com/influxdb/influxdb/raft" | ||
) | ||
|
||
// Handler represents an HTTP handler for InfluxDB node. | ||
// Depending on its role, it will serve many different endpoints. | ||
type Handler struct { | ||
brokerHandler http.Handler | ||
serverHandler http.Handler | ||
Log *raft.Log | ||
Broker *influxdb.Broker | ||
Server *influxdb.Server | ||
Config *Config | ||
} | ||
|
||
// NewHandler returns a new instance of Handler. | ||
func NewHandler(bh, sh http.Handler) *Handler { | ||
return &Handler{ | ||
brokerHandler: bh, | ||
serverHandler: sh, | ||
} | ||
func NewHandler() *Handler { | ||
return &Handler{} | ||
} | ||
|
||
// ServeHTTP responds to HTTP request to the handler. | ||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
// Route raft and messaging paths to the broker. | ||
if strings.HasPrefix(r.URL.Path, "/raft") || strings.HasPrefix(r.URL.Path, "/messaging") { | ||
if h.brokerHandler == nil { | ||
http.NotFound(w, r) | ||
return | ||
if strings.HasPrefix(r.URL.Path, "/raft") { | ||
h.serveRaft(w, r) | ||
return | ||
} | ||
if strings.HasPrefix(r.URL.Path, "/messaging") { | ||
h.serveMessaging(w, r) | ||
return | ||
} | ||
|
||
h.serveData(w, r) | ||
} | ||
|
||
// serveMessaging responds to broker requests | ||
func (h *Handler) serveMessaging(w http.ResponseWriter, r *http.Request) { | ||
if h.Broker == nil && h.Server == nil { | ||
log.Println("no broker or server configured to handle messaging endpoints") | ||
http.Error(w, "server unavailable", http.StatusServiceUnavailable) | ||
return | ||
} | ||
|
||
// If we're running a broker, handle the broker endpoints | ||
if h.Broker != nil { | ||
mh := &messaging.Handler{ | ||
Broker: h.Broker.Broker, | ||
RaftHandler: &raft.Handler{Log: h.Log}, | ||
} | ||
mh.ServeHTTP(w, r) | ||
return | ||
} | ||
|
||
// Redirect to a valid broker to handle the request | ||
h.redirect(h.Server.BrokerURLs(), w, r) | ||
} | ||
|
||
h.brokerHandler.ServeHTTP(w, r) | ||
// serveRaft responds to raft requests. | ||
func (h *Handler) serveRaft(w http.ResponseWriter, r *http.Request) { | ||
if h.Log == nil && h.Server == nil { | ||
log.Println("no broker or server configured to handle messaging endpoints") | ||
http.Error(w, "server unavailable", http.StatusServiceUnavailable) | ||
return | ||
} | ||
|
||
// Route all other paths to the server. | ||
if h.serverHandler == nil { | ||
http.NotFound(w, r) | ||
if h.Log != nil { | ||
rh := raft.Handler{Log: h.Log} | ||
rh.ServeHTTP(w, r) | ||
return | ||
} | ||
h.serverHandler.ServeHTTP(w, r) | ||
|
||
// Redirect to a valid broker to handle the request | ||
h.redirect(h.Server.BrokerURLs(), w, r) | ||
} | ||
|
||
// serveData responds to data requests | ||
func (h *Handler) serveData(w http.ResponseWriter, r *http.Request) { | ||
if h.Broker == nil && h.Server == nil { | ||
log.Println("no broker or server configured to handle messaging endpoints") | ||
http.Error(w, "server unavailable", http.StatusServiceUnavailable) | ||
return | ||
} | ||
|
||
if h.Server != nil { | ||
sh := httpd.NewHandler(h.Server, h.Config.Authentication.Enabled, version) | ||
sh.WriteTrace = h.Config.Logging.WriteTracing | ||
sh.ServeHTTP(w, r) | ||
return | ||
} | ||
|
||
// Redirect to a valid data URL to handle the request | ||
h.redirect(h.Broker.Topic(influxdb.BroadcastTopicID).DataURLs(), w, r) | ||
} | ||
|
||
// redirect redirects a request to URL in u. If u is an empty slice, | ||
// a 503 is returned | ||
func (h *Handler) redirect(u []url.URL, w http.ResponseWriter, r *http.Request) { | ||
// No valid URLs, return an error | ||
if len(u) == 0 { | ||
http.Error(w, "service unavailable", http.StatusServiceUnavailable) | ||
return | ||
} | ||
|
||
// TODO: Log to internal stats to track how frequently this is happening. If | ||
// this is happening frequently, the clients are using a suboptimal endpoint | ||
|
||
// Redirect the client to a valid data node that can handle the request | ||
http.Redirect(w, r, u[0].String()+r.RequestURI, http.StatusTemporaryRedirect) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This is an "internal error" right?
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 possible that a data node could ask a broker a data node question, and that specific broker did not know about any data nodes. In that case, the urls would be empty, and you could return this error. This should only happen with a mis-configured cluster. However, since it is outside of our control, we have to check for it.