Skip to content

Commit

Permalink
*: add query metric http api (#1957)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazycs520 authored and winkyao committed Nov 22, 2019
1 parent 85c7f39 commit 37ebd61
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 161 deletions.
6 changes: 6 additions & 0 deletions conf/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ interval = "15s"
## prometheus pushgateway address, leaves it empty will disable prometheus.
address = ""

[pd-server]
## the metric storage is the cluster metric storage. This is use for query metric data.
## Currently we use prometheus as metric storage, we may use PD/TiKV as metric storage later.
## For usability, recommended to temporarily set it to the prometheus address, eg: http://127.0.0.1:9090
metric-storage = ""

[schedule]
max-merge-region-size = 20
max-merge-region-keys = 200000
Expand Down
326 changes: 165 additions & 161 deletions docs/api.html

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions server/api/api.raml
Original file line number Diff line number Diff line change
Expand Up @@ -1299,3 +1299,98 @@ types:
description: The input is invalid.
500:
description: PD server failed to proceed the request.

/metric:
description: Query metric.
/query:
get:
description: Query instant metric api.
queryParameters:
query:
description: promQL query statement.
type: string
time?:
description: Evaluation timestamp, such as 2019-11-22T20:10:51.781Z.
type: string
timeout?:
description: Evaluation timeout, such as 15s.
type: string
responses:
200:
body:
application/json:
properties:
data: Metric data
500:
description: PD server failed to proceed the request.
post:
description: Query instant metric api.
body:
application/json:
properties:
query:
description: promQL query statement.
type: string
time?:
description: Evaluation timestamp, such as 2019-11-22T20:10:51.781Z.
type: string
timeout?:
description: Evaluation timeout, such as 15s.
type: string
responses:
200:
body:
application/json:
properties:
data: Metric data
500:
description: PD server failed to proceed the request.
/query_range:
get:
description: Query range metric api.
queryParameters:
query:
description: promQL query statement.
type: string
start:
description: Evaluation start timestamp, such as 2019-11-22T20:10:51.781Z.
type: string
end:
description: Evaluation end timestamp, such as 2019-11-22T20:10:51.781Z.
type: string
timeout?:
description: Evaluation timeout, such as 15s.
type: string
responses:
200:
body:
application/json:
properties:
data: Metric data
500:
description: PD server failed to proceed the request.
post:
description: Query range metric api.
body:
application/json:
properties:
query:
description: promQL query statement.
type: string
start:
description: Evaluation start timestamp, such as 2019-11-22T20:10:51.781Z.
type: string
end:
description: Evaluation end timestamp, such as 2019-11-22T20:10:51.781Z.
type: string
timeout?:
description: Evaluation timeout, such as 15s.
type: string
responses:
200:
body:
application/json:
properties:
data: Metric data
500:
description: PD server failed to proceed the request.
9 changes: 9 additions & 0 deletions server/api/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,21 @@ func (s *testConfigSuite) TestConfigAll(c *C) {
err = postJSON(addr, postData)
c.Assert(err, IsNil)

l = map[string]interface{}{
"metric-storage": "http://127.0.0.1:9090",
}
postData, err = json.Marshal(l)
c.Assert(err, IsNil)
err = postJSON(addr, postData)
c.Assert(err, IsNil)

newCfg := &config.Config{}
err = readJSON(addr, newCfg)
c.Assert(err, IsNil)
cfg.Replication.MaxReplicas = 5
cfg.Replication.LocationLabels = []string{"zone", "rack"}
cfg.Schedule.RegionScheduleLimit = 10
cfg.PDServerCfg.MetricStorage = "http://127.0.0.1:9090"
c.Assert(cfg, DeepEquals, newCfg)
}

Expand Down
54 changes: 54 additions & 0 deletions server/api/metric.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2019 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
"fmt"
"net/http"
"net/url"
"strings"

"github.com/pingcap/pd/server"
)

type queryMetric struct {
s *server.Server
}

func newQueryMetric(s *server.Server) *queryMetric {
return &queryMetric{s: s}
}

func (h *queryMetric) ServeHTTP(w http.ResponseWriter, r *http.Request) {
metricAddr := h.s.GetConfig().PDServerCfg.MetricStorage
if metricAddr == "" {
http.Error(w, "metric storage doesn't set", http.StatusInternalServerError)
return
}
u, err := url.Parse(metricAddr)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

switch u.Scheme {
case "http", "https":
// Replace the pd path with the prometheus http API path.
r.URL.Path = strings.Replace(r.URL.Path, "pd/api/v1/metric", "api/v1", 1)
newCustomReverseProxies([]url.URL{*u}).ServeHTTP(w, r)
default:
// TODO: Support read data by self after support store metric data in PD/TiKV.
http.Error(w, fmt.Sprintf("schema of metric storage address is no supported, address: %v", metricAddr), http.StatusInternalServerError)
}
}
3 changes: 3 additions & 0 deletions server/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ func createRouter(prefix string, svr *server.Server) *mux.Router {
rootRouter.Handle("/api/v1/health", newHealthHandler(svr, rd)).Methods("GET")
rootRouter.Handle("/api/v1/diagnose", newDiagnoseHandler(svr, rd)).Methods("GET")
rootRouter.HandleFunc("/api/v1/ping", func(w http.ResponseWriter, r *http.Request) {}).Methods("GET")
// metric query use to query metric data, the protocol is compatible with prometheus.
rootRouter.Handle("/api/v1/metric/query", newQueryMetric(svr)).Methods("GET", "POST")
rootRouter.Handle("/api/v1/metric/query_range", newQueryMetric(svr)).Methods("GET", "POST")

// Deprecated
rootRouter.Handle("/health", newHealthHandler(svr, rd)).Methods("GET")
Expand Down
3 changes: 3 additions & 0 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,9 @@ type PDServerConfig struct {
// KeyType is option to specify the type of keys.
// There are some types supported: ["table", "raw", "txn"], default: "table"
KeyType string `toml:"key-type" json:"key-type"`
// MetricStorage is the cluster metric storage.
// Currently we use prometheus as metric storage, we may use PD/TiKV as metric storage later.
MetricStorage string `toml:"metric-storage" json:"metric-storage"`
}

func (c *PDServerConfig) adjust(meta *configMetaData) error {
Expand Down
4 changes: 4 additions & 0 deletions server/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ func (s *testConfigSuite) TestAdjust(c *C) {
name = ""
lease = 0
[pd-server]
metric-storage = "http://127.0.0.1:9090"
[schedule]
max-merge-region-size = 0
enable-one-way-merge = true
Expand All @@ -129,6 +132,7 @@ leader-schedule-limit = 0
// When undefined, use default values.
c.Assert(cfg.PreVote, IsTrue)
c.Assert(cfg.Schedule.MaxMergeRegionKeys, Equals, uint64(defaultMaxMergeRegionKeys))
c.Assert(cfg.PDServerCfg.MetricStorage, Equals, "http://127.0.0.1:9090")

// Check undefined config fields
cfgData = `
Expand Down

0 comments on commit 37ebd61

Please sign in to comment.