-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
nsqadmin/nsqd: optimize /stats #925
Conversation
nsqadmin/static/js/lib/ajax_setup.js
Outdated
@@ -7,6 +7,6 @@ $.ajaxPrefilter(function(options) { | |||
'X-UserAgent': USER_AGENT, | |||
'Accept': 'application/vnd.nsq; version=1.0' | |||
}); | |||
options['timeout'] = 20 * 1000; | |||
options['timeout'] = 120 * 1000; |
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.
I don't think we want to change this timeout. We never want to wait this long for something to load.
(I understand you need to increase it in order for it to work for your setup. I guess we'd hope to make the stats requests just not take so long somehow.)
nsqd/stats.go
Outdated
} | ||
} | ||
n.RUnlock() | ||
realTopic.RLock() |
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.
I think you have to handle the possibility that the topic does not exist.
nsqd/stats.go
Outdated
for _, c := range realChannels { | ||
c.RLock() | ||
clients := make([]ClientStats, 0, len(c.clients)) | ||
for _, client := range c.clients { |
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.
Another optimization that is possible here: For the Topic page we just need the count of clients, we don't need all their info. For the Channel page, we do need all the client info, but not for all Channels, just for the one.
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.
Hmm ... we'd need to add a new param, to omit the client connection details from the stats response, to keep compatibility with anything out there that depends on the full stats responses. Luckily, the /stats
endpoint will ignore params it is not expecting, so new nsqadmin will still work with old nsqd, it'll just get more info than it needs.
(The topic and channel params to /stats
have existed for quite a while, since nsqd 0.3.6)
There's a lot of duplication between |
@@ -387,7 +387,7 @@ func TestReconfigure(t *testing.T) { | |||
nsqd.triggerOptsNotification() | |||
test.Equal(t, 2, len(nsqd.getOpts().NSQLookupdTCPAddresses)) | |||
|
|||
time.Sleep(200 * time.Millisecond) | |||
time.Sleep(300 * time.Millisecond) |
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.
I've completed. If there is time, then again to help me review the code, thank you! |
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.
looking better!
totalClients += int64(len(cs.Clients)) | ||
} else { | ||
totalClients += int64(cs.ClientCount) | ||
} |
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.
rather than baking this logic into the client each time, we should just always return client_count
as an int, separately from clients
(the array).
@@ -530,7 +530,7 @@ func (c *ClusterInfo) GetNSQDTopicProducers(topic string, nsqdHTTPAddrs []string | |||
// | |||
// if selectedTopic is empty, this will return stats for *all* topic/channels | |||
// and the ChannelStats dict will be keyed by topic + ':' + channel | |||
func (c *ClusterInfo) GetNSQDStats(producers Producers, selectedTopic string) ([]*TopicStats, map[string]*ChannelStats, error) { | |||
func (c *ClusterInfo) GetNSQDStats(producers Producers, selectedTopic, selectChannel string) ([]*TopicStats, map[string]*ChannelStats, error) { |
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.
s/selectChannel/selectedChannel/
var ( | ||
state TopicStats | ||
stats []TopicStats | ||
) |
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.
minor: we don't typically declare variables like this, we instead prefer var
for each one.
stats := s.ctx.nsqd.GetStats() | ||
var ( | ||
state TopicStats | ||
stats []TopicStats |
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.
the state
variable is awkwardly named, how about we call these stats TopicStats
and allStats []TopicStats
?
} else { | ||
state, err = s.ctx.nsqd.GetChannelStats(topicName, channelName) | ||
} | ||
if nil != err { |
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.
minor: we typically prefer the variable in question to be on the left side of the comparison, e.g. if err != nil {
if nil != err { | ||
s.ctx.nsqd.logf(LOG_ERROR, "failed to get stats - %s", err) | ||
return nil, http_api.Err{404, "topic/channel is not found"} | ||
} else if nil == stats { |
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 doesn't need to be an else if
, because the block above returns. Also, same minor note applies here, please move the variable to the left side of the comparison.
} else if nil == stats { | ||
stats = []TopicStats{state} | ||
} | ||
|
||
health := s.ctx.nsqd.GetHealth() | ||
startTime := s.ctx.nsqd.GetStartTime() | ||
uptime := time.Since(startTime) |
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.
After these changes above, Is any of the topic/channel looping code necessary below this line?
n.RLock() | ||
var realTopic *Topic | ||
for _, t := range n.topicMap { | ||
if topic == t.name { |
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.
if t.name == topic {
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.
same applies to function below
} | ||
n.RUnlock() | ||
|
||
if nil == realTopic { |
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.
if realTopic == nil {
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.
same applies to function below
|
||
if nil == realTopic { | ||
return TopicStats{}, errors.New("the topic is not found.") | ||
} else { |
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.
since the above block returns, we can drop the else
and un-indent this block
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.
same applies to function below
@mreiferson @jinhailang @ploxiln I have not found this PR ahead. But, i also proposed a PR #929 to make stats query more efficient and some of the thoughts are the same with @jinhailang |
@jinhailang thanks for this, but going to close it in favor of #929! |
I'm really sorry that I plan to revise this weekend. I have modified it, but can not commit it, if necessary, it may be available as an alternative. |
Agreed with @ploxiln . @jinhailang The object is to make stats api for efficient. :) |
Ahh, I missed that, good catch. Yes, we should do that too but let's do it as a follow up at this point. |
Nsqd and nsqadmin are compatible with older versions.