Skip to content

Commit

Permalink
pgwire: create a framework for pre-serve connection logic
Browse files Browse the repository at this point in the history
This commit introduces `PreServeConnHandler`, which will
handle the preparation of a SQL connection prior to handing it off to
a specific tenant server.

Release note (ops changes): The count of network bytes sent
to report re-authentication errors to a SQL client is now
reported via the metric `sql.pre_serve.bytesout` (instead of
`sql.bytesout` previously). The count of pre-authentication errors
is now reported via the metric `sql.pre_serve.conn.failures` (instead
of `sql.conn.failures` previously).

Release note (ops changes): The count of new SQL connections
is now also reported on `sql.pre_serve.new_conns`.
  • Loading branch information
knz committed Nov 28, 2022
1 parent caa5296 commit fd47111
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 17 deletions.
1 change: 1 addition & 0 deletions pkg/sql/pgwire/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ go_library(
"conn.go",
"hba_conf.go",
"ident_map_conf.go",
"pre_serve.go",
"role_mapper.go",
"server.go",
"types.go",
Expand Down
126 changes: 126 additions & 0 deletions pkg/sql/pgwire/pre_serve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package pgwire

import (
"context"
"net"

"github.com/cockroachdb/cockroach/pkg/settings"
"github.com/cockroachdb/cockroach/pkg/util/metric"
)

// Fully-qualified names for metrics.
var (
MetaPreServeNewConns = metric.Metadata{
Name: "sql.pre_serve.new_conns",
Help: "Counter of the number of SQL connections created prior to routine the connection a specific tenant",
Measurement: "Connections",
Unit: metric.Unit_COUNT,
}
MetaPreServeBytesIn = metric.Metadata{
Name: "sql.pre_serve.bytesin",
Help: "Number of SQL bytes received prior to routing the connection to a specific tenant",
Measurement: "SQL Bytes",
Unit: metric.Unit_BYTES,
}
MetaPreServeBytesOut = metric.Metadata{
Name: "sql.pre_serve.bytesout",
Help: "Number of SQL bytes sent prior to routing the connection to a specific tenant",
Measurement: "SQL Bytes",
Unit: metric.Unit_BYTES,
}
MetaPreServeConnFailures = metric.Metadata{
Name: "sql.pre_serve.conn.failures",
Help: "Number of SQL connection failures prior to routing the connection to a specific tenant",
Measurement: "Connections",
Unit: metric.Unit_COUNT,
}
)

// PreServeConnHandler implements the early initialization of an incoming
// SQL connection, before it is routed to a specific tenant. It is
// tenant-independent, and thus cannot rely on tenant-specific connection
// or state.
type PreServeConnHandler struct {
errWriter errWriter
cfg struct {
}
tenantIndependentMetrics tenantIndependentMetrics
}

// MakePreServeConnHandler creates a PreServeConnHandler.
// sv refers to the setting values "outside" of the current tenant - i.e. from the storage cluster.
func MakePreServeConnHandler(sv *settings.Values) PreServeConnHandler {
metrics := makeTenantIndependentMetrics()
return PreServeConnHandler{
errWriter: errWriter{
sv: sv,
msgBuilder: newWriteBuffer(metrics.PreServeBytesOutCount),
},
tenantIndependentMetrics: metrics,
}
}

// tenantIndependentMetrics is the set of metrics for the
// pre-serve part of connection handling, before the connection
// is routed to a specific tenant.
type tenantIndependentMetrics struct {
PreServeBytesInCount *metric.Counter
PreServeBytesOutCount *metric.Counter
PreServeConnFailures *metric.Counter
PreServeNewConns *metric.Counter
}

func makeTenantIndependentMetrics() tenantIndependentMetrics {
return tenantIndependentMetrics{
PreServeBytesInCount: metric.NewCounter(MetaPreServeBytesIn),
PreServeBytesOutCount: metric.NewCounter(MetaPreServeBytesOut),
PreServeNewConns: metric.NewCounter(MetaPreServeNewConns),
PreServeConnFailures: metric.NewCounter(MetaPreServeConnFailures),
}
}

// Metrics returns the set of metrics structs.
func (s *PreServeConnHandler) Metrics() (res []interface{}) {
return []interface{}{&s.tenantIndependentMetrics}
}

// PrepareConn serves a single connection, up to and including the
// point status parameters are read from the client (which happens
// pre-authentication). This logic is tenant-independent. Once the
// status parameters are known, the connection can be routed to a
// particular tenant.
func (s *PreServeConnHandler) PrepareConn(
ctx context.Context, conn net.Conn, socketType SocketType,
) (err error) {
defer func() {
if err != nil {
s.tenantIndependentMetrics.PreServeConnFailures.Inc(1)
}
}()
s.tenantIndependentMetrics.PreServeNewConns.Inc(1)

return nil
}

// sendErr sends errors to the client during the connection startup
// sequence. Later error sends during/after authentication are handled
// in conn.go.
func (s *PreServeConnHandler) sendErr(ctx context.Context, conn net.Conn, err error) error {
// We could, but do not, report server-side network errors while
// trying to send the client error. This is because clients that
// receive error payload are highly correlated with clients
// disconnecting abruptly.
_ /* err */ = s.errWriter.writeErr(ctx, err, conn)
_ = conn.Close()
return err
}
37 changes: 20 additions & 17 deletions pkg/sql/pgwire/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ type Server struct {
SQLServer *sql.Server
execCfg *sql.ExecutorConfig

// preServeHandler is under Server for now, until this issue is addressed:
// https://github.com/cockroachdb/cockroach/issues/84585
preServeHandler PreServeConnHandler

tenantMetrics tenantSpecificMetrics

mu struct {
Expand Down Expand Up @@ -333,10 +337,15 @@ func MakeServer(
executorConfig *sql.ExecutorConfig,
) *Server {
server := &Server{
AmbientCtx: ambientCtx,
cfg: cfg,
execCfg: executorConfig,
AmbientCtx: ambientCtx,
cfg: cfg,
execCfg: executorConfig,

tenantMetrics: makeTenantSpecificMetrics(sqlMemMetrics, histogramWindow),

// We are initializing preServeHandler here until the following issue is resolved:
// https://github.com/cockroachdb/cockroach/issues/84585
preServeHandler: MakePreServeConnHandler(&st.SV),
}
server.sqlMemoryPool = mon.NewMonitor("sql",
mon.MemoryResource,
Expand Down Expand Up @@ -426,7 +435,12 @@ func (s *Server) IsDraining() bool {

// Metrics returns the set of metrics structs.
func (s *Server) Metrics() (res []interface{}) {
return []interface{}{
// We declare the metrics from preServeHandler here
// until this issue is resolved:
// https://github.com/cockroachdb/cockroach/issues/84585
res = s.preServeHandler.Metrics()

return append(res, []interface{}{
&s.tenantMetrics,
&s.SQLServer.Metrics.StartedStatementCounters,
&s.SQLServer.Metrics.ExecutedStatementCounters,
Expand All @@ -439,7 +453,7 @@ func (s *Server) Metrics() (res []interface{}) {
&s.SQLServer.ServerMetrics.StatsMetrics,
&s.SQLServer.ServerMetrics.ContentionSubsystemMetrics,
&s.SQLServer.ServerMetrics.InsightsMetrics,
}
}...)
}

// Drain prevents new connections from being served and waits the duration of
Expand Down Expand Up @@ -1386,18 +1400,7 @@ func (s *Server) readVersion(
// sequence. Later error sends during/after authentication are handled
// in conn.go.
func (s *Server) sendErr(ctx context.Context, conn net.Conn, err error) error {
// NB: this errWriter definition will be removed in the next commit.
w := errWriter{
sv: &s.execCfg.Settings.SV,
msgBuilder: newWriteBuffer(s.tenantMetrics.BytesOutCount),
}
// We could, but do not, report server-side network errors while
// trying to send the client error. This is because clients that
// receive error payload are highly correlated with clients
// disconnecting abruptly.
_ /* err */ = w.writeErr(ctx, err, conn)
_ = conn.Close()
return err
return s.preServeHandler.sendErr(ctx, conn, err)
}

func newAdminShutdownErr(msg string) error {
Expand Down
25 changes: 25 additions & 0 deletions pkg/ts/catalog/chart_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,31 @@ var charts = []sectionDescription{
},
},
},
{
Organization: [][]string{{SQLLayer, "SQL"}},
Charts: []chartDescription{
{
Title: "New Connections, prior to tenant selection",
Metrics: []string{
"sql.pre_serve.new_conns",
},
},
{
Title: "Connection Failures, prior to tenant selection",
Metrics: []string{
"sql.pre_serve.conn.failures",
},
AxisLabel: "Failures",
},
{
Title: "Byte I/O, prior to tenant selection",
Metrics: []string{
"sql.pre_serve.bytesin",
"sql.pre_serve.bytesout",
},
},
},
},
{
Organization: [][]string{{SQLLayer, "SQL"}},
Charts: []chartDescription{
Expand Down

0 comments on commit fd47111

Please sign in to comment.