Skip to content

Commit

Permalink
Merge pull request #77594 from koorosh/backport21.2-74377-76877-77330…
Browse files Browse the repository at this point in the history
…-77487-77533

release-21.2: ui: Add Hot Ranges page
  • Loading branch information
koorosh committed Mar 21, 2022
2 parents 0bbda59 + d9b4f0e commit 2401516
Show file tree
Hide file tree
Showing 30 changed files with 3,277 additions and 641 deletions.
90 changes: 89 additions & 1 deletion docs/generated/http/full.md
Original file line number Diff line number Diff line change
Expand Up @@ -3007,7 +3007,9 @@ of ranges currently considered “hot” by the node(s).

| Field | Type | Label | Description | Support status |
| ----- | ---- | ----- | ----------- | -------------- |
| node_id | [string](#cockroach.server.serverpb.HotRangesRequest-string) | | NodeID indicates which node to query for a hot range report. It is posssible to populate any node ID; if the node receiving the request is not the target node, it will forward the request to the target node.<br><br>If left empty, the request is forwarded to every node in the cluster. | [alpha](#support-status) |
| node_id | [string](#cockroach.server.serverpb.HotRangesRequest-string) | | NodeID indicates which node to query for a hot range report. It is possible to populate any node ID; if the node receiving the request is not the target node, it will forward the request to the target node.<br><br>If left empty, the request is forwarded to every node in the cluster. | [alpha](#support-status) |
| page_size | [int32](#cockroach.server.serverpb.HotRangesRequest-int32) | | | [reserved](#support-status) |
| page_token | [string](#cockroach.server.serverpb.HotRangesRequest-string) | | | [reserved](#support-status) |



Expand Down Expand Up @@ -3087,6 +3089,92 @@ target node(s) selected in a HotRangesRequest.
| ----- | ---- | ----- | ----------- | -------------- |
| desc | [cockroach.roachpb.RangeDescriptor](#cockroach.server.serverpb.HotRangesResponse-cockroach.roachpb.RangeDescriptor) | | Desc is the descriptor of the range for which the report was produced.<br><br>TODO(knz): This field should be removed. See: https://github.com/cockroachdb/cockroach/issues/53212 | [reserved](#support-status) |
| queries_per_second | [double](#cockroach.server.serverpb.HotRangesResponse-double) | | QueriesPerSecond is the recent number of queries per second on this range. | [alpha](#support-status) |
| leaseholder_node_id | [int32](#cockroach.server.serverpb.HotRangesResponse-int32) | | LeaseholderNodeID indicates the Node ID that is the current leaseholder for the given range. | [reserved](#support-status) |






## HotRangesV2

`POST /_status/v2/hotranges`



Support status: [reserved](#support-status)

#### Request Parameters




HotRangesRequest queries one or more cluster nodes for a list
of ranges currently considered “hot” by the node(s).


| Field | Type | Label | Description | Support status |
| ----- | ---- | ----- | ----------- | -------------- |
| node_id | [string](#cockroach.server.serverpb.HotRangesRequest-string) | | NodeID indicates which node to query for a hot range report. It is possible to populate any node ID; if the node receiving the request is not the target node, it will forward the request to the target node.<br><br>If left empty, the request is forwarded to every node in the cluster. | [alpha](#support-status) |
| page_size | [int32](#cockroach.server.serverpb.HotRangesRequest-int32) | | | [reserved](#support-status) |
| page_token | [string](#cockroach.server.serverpb.HotRangesRequest-string) | | | [reserved](#support-status) |







#### Response Parameters




HotRangesResponseV2 is a response payload returned by `HotRangesV2` service.


| Field | Type | Label | Description | Support status |
| ----- | ---- | ----- | ----------- | -------------- |
| ranges | [HotRangesResponseV2.HotRange](#cockroach.server.serverpb.HotRangesResponseV2-cockroach.server.serverpb.HotRangesResponseV2.HotRange) | repeated | Ranges contain list of hot ranges info that has highest number of QPS. | [reserved](#support-status) |
| errors_by_node_id | [HotRangesResponseV2.ErrorsByNodeIdEntry](#cockroach.server.serverpb.HotRangesResponseV2-cockroach.server.serverpb.HotRangesResponseV2.ErrorsByNodeIdEntry) | repeated | errors contains any errors that occurred during fan-out calls to other nodes. | [reserved](#support-status) |
| next_page_token | [string](#cockroach.server.serverpb.HotRangesResponseV2-string) | | NextPageToken represents next pagination token to request next slice of data. | [reserved](#support-status) |






<a name="cockroach.server.serverpb.HotRangesResponseV2-cockroach.server.serverpb.HotRangesResponseV2.HotRange"></a>
#### HotRangesResponseV2.HotRange

HotRange message describes a single hot range, ie its QPS, node ID it belongs to, etc.

| Field | Type | Label | Description | Support status |
| ----- | ---- | ----- | ----------- | -------------- |
| range_id | [int32](#cockroach.server.serverpb.HotRangesResponseV2-int32) | | range_id indicates Range ID that's identified as hot range. | [reserved](#support-status) |
| node_id | [int32](#cockroach.server.serverpb.HotRangesResponseV2-int32) | | node_id indicates the node that contains the current hot range. | [reserved](#support-status) |
| qps | [double](#cockroach.server.serverpb.HotRangesResponseV2-double) | | qps (queries per second) shows the amount of queries that interact with current range. | [reserved](#support-status) |
| table_name | [string](#cockroach.server.serverpb.HotRangesResponseV2-string) | | table_name indicates the SQL table that the range belongs to. | [reserved](#support-status) |
| database_name | [string](#cockroach.server.serverpb.HotRangesResponseV2-string) | | database_name indicates on database that has current hot range. | [reserved](#support-status) |
| index_name | [string](#cockroach.server.serverpb.HotRangesResponseV2-string) | | index_name indicates the index name for current range. | [reserved](#support-status) |
| replica_node_ids | [int32](#cockroach.server.serverpb.HotRangesResponseV2-int32) | repeated | replica_node_ids specifies the list of node ids that contain replicas with current hot range. | [reserved](#support-status) |
| leaseholder_node_id | [int32](#cockroach.server.serverpb.HotRangesResponseV2-int32) | | leaseholder_node_id indicates the Node ID that is the current leaseholder for the given range. | [reserved](#support-status) |
| schema_name | [string](#cockroach.server.serverpb.HotRangesResponseV2-string) | | schema_name provides the name of schema (if exists) for table in current range. | [reserved](#support-status) |
| store_id | [int32](#cockroach.server.serverpb.HotRangesResponseV2-int32) | | store_id indicates the Store ID where range is stored. | [reserved](#support-status) |





<a name="cockroach.server.serverpb.HotRangesResponseV2-cockroach.server.serverpb.HotRangesResponseV2.ErrorsByNodeIdEntry"></a>
#### HotRangesResponseV2.ErrorsByNodeIdEntry



| Field | Type | Label | Description | Support status |
| ----- | ---- | ----- | ----------- | -------------- |
| key | [int32](#cockroach.server.serverpb.HotRangesResponseV2-int32) | | | |
| value | [string](#cockroach.server.serverpb.HotRangesResponseV2-string) | | | |



Expand Down
1 change: 1 addition & 0 deletions docs/generated/http/hotranges-other.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ Support status: [alpha](#support-status)
| ----- | ---- | ----- | ----------- | -------------- |
| desc | [cockroach.roachpb.RangeDescriptor](#cockroach.roachpb.RangeDescriptor) | | Desc is the descriptor of the range for which the report was produced.<br><br>TODO(knz): This field should be removed. See: https://github.com/cockroachdb/cockroach/issues/53212 | [reserved](#support-status) |
| queries_per_second | [double](#double) | | QueriesPerSecond is the recent number of queries per second on this range. | [alpha](#support-status) |
| leaseholder_node_id | [int32](#int32) | | LeaseholderNodeID indicates the Node ID that is the current leaseholder for the given range. | [reserved](#support-status) |


4 changes: 3 additions & 1 deletion docs/generated/http/hotranges-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Support status: [alpha](#support-status)

| Field | Type | Label | Description | Support status |
| ----- | ---- | ----- | ----------- | -------------- |
| node_id | [string](#string) | | NodeID indicates which node to query for a hot range report. It is posssible to populate any node ID; if the node receiving the request is not the target node, it will forward the request to the target node.<br><br>If left empty, the request is forwarded to every node in the cluster. | [alpha](#support-status) |
| node_id | [string](#string) | | NodeID indicates which node to query for a hot range report. It is possible to populate any node ID; if the node receiving the request is not the target node, it will forward the request to the target node.<br><br>If left empty, the request is forwarded to every node in the cluster. | [alpha](#support-status) |
| page_size | [int32](#int32) | | | [reserved](#support-status) |
| page_token | [string](#string) | | | [reserved](#support-status) |


67 changes: 59 additions & 8 deletions docs/generated/swagger/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,12 @@
},
"x-go-package": "github.com/cockroachdb/cockroach/pkg/server/serverpb"
},
"RangeID": {
"type": "integer",
"format": "int64",
"title": "A RangeID is a unique ID associated to a Raft consensus group.",
"x-go-package": "github.com/cockroachdb/cockroach/pkg/roachpb"
},
"RangeProblems": {
"type": "object",
"title": "RangeProblems describes issues reported by a range. For internal use only.",
Expand Down Expand Up @@ -1707,6 +1713,54 @@
},
"x-go-package": "github.com/cockroachdb/cockroach/pkg/server"
},
"hotRangeInfo": {
"description": "(ie its range ID, QPS, table name, etc.).",
"type": "object",
"title": "Hot range details struct describes common information about hot range,",
"properties": {
"database_name": {
"type": "string",
"x-go-name": "DatabaseName"
},
"index_name": {
"type": "string",
"x-go-name": "IndexName"
},
"leaseholder_node_id": {
"$ref": "#/definitions/NodeID"
},
"node_id": {
"$ref": "#/definitions/NodeID"
},
"qps": {
"type": "number",
"format": "double",
"x-go-name": "QPS"
},
"range_id": {
"$ref": "#/definitions/RangeID"
},
"replica_node_ids": {
"type": "array",
"items": {
"$ref": "#/definitions/NodeID"
},
"x-go-name": "ReplicaNodeIDs"
},
"schema_name": {
"type": "string",
"x-go-name": "SchemaName"
},
"store_id": {
"$ref": "#/definitions/StoreID"
},
"table_name": {
"type": "string",
"x-go-name": "TableName"
}
},
"x-go-package": "github.com/cockroachdb/cockroach/pkg/server"
},
"hotRangesResponse": {
"type": "object",
"title": "Response struct for listHotRanges.",
Expand All @@ -1716,15 +1770,12 @@
"type": "string",
"x-go-name": "Next"
},
"ranges_by_node_id": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"$ref": "#/definitions/rangeDescriptorInfo"
}
"ranges": {
"type": "array",
"items": {
"$ref": "#/definitions/hotRangeInfo"
},
"x-go-name": "RangesByNodeID"
"x-go-name": "Ranges"
},
"response_error": {
"type": "array",
Expand Down
1 change: 1 addition & 0 deletions pkg/server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ go_library(
"//pkg/spanconfig/spanconfigkvaccessor",
"//pkg/spanconfig/spanconfigmanager",
"//pkg/sql",
"//pkg/sql/catalog",
"//pkg/sql/catalog/bootstrap",
"//pkg/sql/catalog/catalogkeys",
"//pkg/sql/catalog/catconstants",
Expand Down
62 changes: 37 additions & 25 deletions pkg/server/api_v2_ranges.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"context"
"fmt"
"net/http"
"sort"
"strconv"
"strings"

Expand Down Expand Up @@ -415,13 +414,30 @@ type responseError struct {
//
// swagger:model hotRangesResponse
type hotRangesResponse struct {
RangesByNodeID map[string][]rangeDescriptorInfo `json:"ranges_by_node_id"`
Errors []responseError `json:"response_error,omitempty"`
Ranges []hotRangeInfo `json:"ranges"`
Errors []responseError `json:"response_error,omitempty"`
// Continuation token for the next paginated call. Use as the `start`
// parameter.
Next string `json:"next,omitempty"`
}

// Hot range details struct describes common information about hot range,
// (ie its range ID, QPS, table name, etc.).
//
// swagger:model hotRangeInfo
type hotRangeInfo struct {
RangeID roachpb.RangeID `json:"range_id"`
NodeID roachpb.NodeID `json:"node_id"`
QPS float64 `json:"qps"`
LeaseholderNodeID roachpb.NodeID `json:"leaseholder_node_id"`
TableName string `json:"table_name"`
DatabaseName string `json:"database_name"`
IndexName string `json:"index_name"`
SchemaName string `json:"schema_name"`
ReplicaNodeIDs []roachpb.NodeID `json:"replica_node_ids"`
StoreID roachpb.StoreID `json:"store_id"`
}

// swagger:operation GET /ranges/hot/ listHotRanges
//
// List hot ranges
Expand Down Expand Up @@ -464,9 +480,7 @@ func (a *apiV2Server) listHotRanges(w http.ResponseWriter, r *http.Request) {
nodeIDStr := r.URL.Query().Get("node_id")
limit, start := getRPCPaginationValues(r)

response := &hotRangesResponse{
RangesByNodeID: make(map[string][]rangeDescriptorInfo),
}
response := &hotRangesResponse{}
var requestedNodes []roachpb.NodeID
if len(nodeIDStr) > 0 {
requestedNodeID, _, err := a.status.parseNodeID(nodeIDStr)
Expand All @@ -484,32 +498,30 @@ func (a *apiV2Server) listHotRanges(w http.ResponseWriter, r *http.Request) {
remoteRequest := serverpb.HotRangesRequest{NodeID: "local"}
nodeFn := func(ctx context.Context, client interface{}, nodeID roachpb.NodeID) (interface{}, error) {
status := client.(serverpb.StatusClient)
resp, err := status.HotRanges(ctx, &remoteRequest)
resp, err := status.HotRangesV2(ctx, &remoteRequest)
if err != nil || resp == nil {
return nil, err
}
rangeDescriptorInfos := make([]rangeDescriptorInfo, 0)
for _, store := range resp.HotRangesByNodeID[nodeID].Stores {
for _, hotRange := range store.HotRanges {
var r rangeDescriptorInfo
r.init(&hotRange.Desc)
r.StoreID = int32(store.StoreID)
r.QueriesPerSecond = hotRange.QueriesPerSecond
rangeDescriptorInfos = append(rangeDescriptorInfos, r)

var hotRangeInfos = make([]hotRangeInfo, len(resp.Ranges))
for i, r := range resp.Ranges {
hotRangeInfos[i] = hotRangeInfo{
RangeID: r.RangeID,
NodeID: r.NodeID,
QPS: r.QPS,
LeaseholderNodeID: r.LeaseholderNodeID,
TableName: r.TableName,
DatabaseName: r.DatabaseName,
IndexName: r.IndexName,
ReplicaNodeIDs: r.ReplicaNodeIds,
SchemaName: r.SchemaName,
StoreID: r.StoreID,
}
}
sort.Slice(rangeDescriptorInfos, func(i, j int) bool {
if rangeDescriptorInfos[i].StoreID == rangeDescriptorInfos[j].StoreID {
return rangeDescriptorInfos[i].RangeID < rangeDescriptorInfos[j].RangeID
}
return rangeDescriptorInfos[i].StoreID < rangeDescriptorInfos[j].StoreID
})
return rangeDescriptorInfos, nil
return hotRangeInfos, nil
}
responseFn := func(nodeID roachpb.NodeID, resp interface{}) {
if hotRangesResp, ok := resp.([]rangeDescriptorInfo); ok {
response.RangesByNodeID[nodeID.String()] = hotRangesResp
}
response.Ranges = append(response.Ranges, resp.([]hotRangeInfo)...)
}
errorFn := func(nodeID roachpb.NodeID, err error) {
response.Errors = append(response.Errors, responseError{
Expand Down
17 changes: 4 additions & 13 deletions pkg/server/api_v2_ranges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,16 @@ func TestHotRangesV2(t *testing.T) {
require.NoError(t, json.NewDecoder(resp.Body).Decode(&hotRangesResp))
require.NoError(t, resp.Body.Close())

if len(hotRangesResp.RangesByNodeID) == 0 {
if len(hotRangesResp.Ranges) == 0 {
t.Fatalf("didn't get hot range responses from any nodes")
}
if len(hotRangesResp.Errors) > 0 {
t.Errorf("got an error in hot range response from n%d: %v",
hotRangesResp.Errors[0].NodeID, hotRangesResp.Errors[0].ErrorMessage)
}

for nodeID, nodeResp := range hotRangesResp.RangesByNodeID {
if len(nodeResp) == 0 {
t.Fatalf("didn't get hot range response from node n%s", nodeID)
}
// We don't check for ranges being sorted by QPS, as this hot ranges
// report does not use that as its sort key (for stability across multiple
// pagination calls).
for _, r := range nodeResp {
if r.RangeID == 0 || (len(r.StartKey) == 0 && len(r.EndKey) == 0) {
t.Errorf("unexpected empty/unpopulated range descriptor: %+v", r)
}
for _, r := range hotRangesResp.Ranges {
if r.RangeID == 0 || r.NodeID == 0 {
t.Errorf("unexpected empty/unpopulated range descriptor: %+v", r)
}
}
}
Expand Down
Loading

0 comments on commit 2401516

Please sign in to comment.