Skip to content

Commit 54bf93f

Browse files
authored
Merge pull request #148 from cashapp/ioberst-innodb_buffer_pool
Adding `innodb.buffer-pool` domain
2 parents e5f4a35 + 020b8de commit 54bf93f

File tree

6 files changed

+255
-80
lines changed

6 files changed

+255
-80
lines changed

docs/content/metrics/domains/innodb.buffer-pool/_index.md

Whitespace-only changes.
Lines changed: 11 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,25 @@
11
---
2-
title: "innodb"
2+
title: "innodb.buffer-pool"
33
---
44

5-
The `innodb` domain includes InnoDB metrics from [`INFORMATION_SCHEMA.INNODB_METRICS`](https://dev.mysql.com/doc/refman/en/information-schema-innodb-metrics-table.html).
5+
The `innodb.buffer-pool` domain includes InnoDB metrics from [`INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS`](https://dev.mysql.com/doc/refman/8.4/en/information-schema-innodb-buffer-pool-stats-table.html).
66

77
{{< toc >}}
88

99
## Usage
1010

11+
The metric values collected are aggregated over all buffer pools.
12+
1113
For example:
1214

1315
```
14-
mysql> SELECT * FROM innodb_metrics WHERE name='trx_rseg_history_len' LIMIT 1\G
16+
mysql> SELECT SUM(POOL_SIZE) POOL_SIZE, SUM(FREE_BUFFERS) FREE_BUFFERS FROM INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS\G
1517
*************************** 1. row ***************************
16-
NAME: trx_rseg_history_len
17-
SUBSYSTEM: transaction
18-
COUNT: 0
19-
MAX_COUNT: 0
20-
MIN_COUNT: 0
21-
AVG_COUNT: NULL
22-
COUNT_RESET: 0
23-
MAX_COUNT_RESET: 0
24-
MIN_COUNT_RESET: 0
25-
AVG_COUNT_RESET: NULL
26-
TIME_ENABLED: 2021-08-17 08:24:14
27-
TIME_DISABLED: NULL
28-
TIME_ELAPSED: 1905927
29-
TIME_RESET: NULL
30-
STATUS: enabled
31-
TYPE: value
32-
COMMENT: Length of the TRX_RSEG_HISTORY list
18+
POOL_SIZE: 95110
19+
FREE_BUFFERS: 9322
3320
```
3421

3522
The exact `NAME` value is used for the Blip metric name.
36-
In the example above, the Blip metric name is `trx_rseg_history_len`, even though this metric means history list length (HLL).
37-
Metric names are unique by `SUBSYSTEM`.
38-
39-
The [`status.global`]({{< ref "metrics/domains/status.global/" >}}) domain includes many of the same metrics because, historically, only `SHOW GLOBAL STATUS` existed.
40-
It's a best practice to collect InnoDB metrics with this domain and exclude them from [`status.global`]({{< ref "metrics/domains/status.global/" >}}).
41-
42-
As a starting point, these are good InnoDB metrics to collect:
43-
44-
```yaml
45-
plan:
46-
collect:
47-
innodb:
48-
metrics:
49-
# Transactions
50-
- "trx_active_transactions"
51-
52-
# Row locking
53-
- "lock_timeouts"
54-
- "lock_row_lock_current_waits"
55-
- "lock_row_lock_waits"
56-
- "lock_row_lock_time"
57-
58-
# Page flushing
59-
- "buffer_flush_adaptive_total_pages" # adaptive flushing
60-
- "buffer_LRU_batch_flush_total_pages" # LRU flushing
61-
- "buffer_flush_background_total_pages" # legacy flushing
62-
63-
# Transaction log utilization (%)
64-
- "log_lsn_checkpoint_age" # checkpoint age
65-
- "log_max_modified_age_async" # async flush point
66-
67-
# Transaction log -> storage waits
68-
- "innodb_os_log_pending_writes"
69-
- "innodb_log_waits"
70-
71-
# History List Length (HLL)
72-
- "trx_rseg_history_len"
73-
74-
# Deadlocks
75-
- "lock_deadlocks"
76-
```
7723

7824
## Derived Metrics
7925

@@ -85,33 +31,27 @@ None.
8531

8632
|Value|Default|Description|
8733
|-----|-------|-----------|
88-
|yes | |Collect _all_ 300+ metrics (not recommended)|
34+
|yes | |Collect _all_ 30+ metrics (not recommended)|
8935
|no |&check;|Collect only metrics listed in the plan|
90-
|enabled| |Collect metrics that are enabled by MySQL (`WHERE status='enabled'`)|
9136

9237
## Group Keys
9338

9439
None.
9540

9641
## Meta
9742

98-
|Key|Value|
99-
|---|-----|
100-
|`subsystem`|`SUBSYSTEM` column|
101-
102-
Technically InnoDB metric names are unique by subsystem, but currently they're unique for the whole table.
103-
It's probably safe to graph them by metric name alone, but if there's a name collision in the future, one metrics will be lost when reporting.
43+
None.
10444

10545
## Error Policies
10646

10747
None.
10848

10949
## MySQL Config
11050

111-
See [17.15.6 InnoDB INFORMATION_SCHEMA Metrics Table](https://dev.mysql.com/doc/refman/en/innodb-information-schema-metrics-table.html).
51+
None.
11252

11353
## Changelog
11454

11555
|Blip Version|Change|
11656
|------------|------|
117-
|v1.0.0 |Domain added|
57+
|TBD |Domain added|

docs/content/metrics/quick-ref.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ The rest are reserved for future use.
2929
|gr|MySQL Group Replication||
3030
|host|Host (client)||
3131
|[`innodb`](domains#innodb)|InnoDB metrics [`INFORMATION_SCHEMA.INNODB_METRICS`](https://dev.mysql.com/doc/refman/en/information-schema-innodb-metrics-table.html)|v1.0.0|
32+
|[`innodb.buffer-pool`](domains#innodbbuffer-pool)|InnoDB buffer pool metrics [`INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STAT`](https://dev.mysql.com/doc/refman/8.4/en/information-schema-innodb-buffer-pool-stats-table.html)|TBD|
3233
|innodb.mutex|InnoDB mutexes `SHOW ENGINE INNODB MUTEX`||
3334
|mariadb|MariaDB enhancements||
3435
|ndb|MySQL NDB Cluster||

metrics/factory.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@ import (
88
"sync"
99

1010
"github.com/cashapp/blip"
11-
"github.com/cashapp/blip/metrics/aws.rds"
11+
awsrds "github.com/cashapp/blip/metrics/aws.rds"
1212
"github.com/cashapp/blip/metrics/innodb"
13+
innodbbufferpool "github.com/cashapp/blip/metrics/innodb.buffer-pool"
1314
"github.com/cashapp/blip/metrics/percona"
14-
"github.com/cashapp/blip/metrics/query.response-time"
15+
queryresponsetime "github.com/cashapp/blip/metrics/query.response-time"
1516
"github.com/cashapp/blip/metrics/repl"
16-
"github.com/cashapp/blip/metrics/repl.lag"
17-
"github.com/cashapp/blip/metrics/size.binlog"
18-
"github.com/cashapp/blip/metrics/size.database"
19-
"github.com/cashapp/blip/metrics/size.table"
20-
"github.com/cashapp/blip/metrics/status.global"
17+
repllag "github.com/cashapp/blip/metrics/repl.lag"
18+
sizebinlog "github.com/cashapp/blip/metrics/size.binlog"
19+
sizedatabase "github.com/cashapp/blip/metrics/size.database"
20+
sizetable "github.com/cashapp/blip/metrics/size.table"
21+
statusglobal "github.com/cashapp/blip/metrics/status.global"
2122
"github.com/cashapp/blip/metrics/stmt.current"
2223
"github.com/cashapp/blip/metrics/tls"
2324
"github.com/cashapp/blip/metrics/trx"
24-
"github.com/cashapp/blip/metrics/var.global"
25-
"github.com/cashapp/blip/metrics/wait.io.table"
25+
varglobal "github.com/cashapp/blip/metrics/var.global"
26+
waitiotable "github.com/cashapp/blip/metrics/wait.io.table"
2627
)
2728

2829
// Register registers a factory that makes one or more collector by domain name.
@@ -260,6 +261,8 @@ func (f *factory) Make(domain string, args blip.CollectorFactoryArgs) (blip.Coll
260261
return awsrds.NewRDS(awsrds.NewCloudWatchClient(awsConfig)), nil
261262
case "innodb":
262263
return innodb.NewInnoDB(args.DB), nil
264+
case "innodb.buffer-pool":
265+
return innodbbufferpool.NewBufferPoolStats(args.DB), nil
263266
case "percona.response-time":
264267
return percona.NewQRT(args.DB), nil
265268
case "query.response-time":
@@ -295,6 +298,7 @@ func (f *factory) Make(domain string, args blip.CollectorFactoryArgs) (blip.Coll
295298
var builtinCollectors = []string{
296299
"aws.rds",
297300
"innodb",
301+
"innodb.buffer-pool",
298302
"percona.response-time",
299303
"query.response-time",
300304
"repl",
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright 2024 Block, Inc.
2+
3+
package innodbbufferpool
4+
5+
import (
6+
"context"
7+
"database/sql"
8+
"fmt"
9+
"strings"
10+
11+
"github.com/cashapp/blip"
12+
"github.com/cashapp/blip/sqlutil"
13+
)
14+
15+
// Table collects buffer pool data from information_schema.innodb_buffer_pool_stats.
16+
// https://dev.mysql.com/doc/refman/8.4/en/information-schema-innodb-buffer-pool-stats-table.html
17+
18+
const (
19+
DOMAIN = "innodb.buffer-pool"
20+
OPT_ALL = "all"
21+
22+
BASE_QUERY = "SELECT %s FROM information_schema.innodb_buffer_pool_stats"
23+
)
24+
25+
var (
26+
columnNames = []string{
27+
"pool_size",
28+
"free_buffers",
29+
"database_pages",
30+
"old_database_pages",
31+
"modified_database_pages",
32+
"pending_decompress",
33+
"pending_reads",
34+
"pending_flush_lru",
35+
"pending_flush_list",
36+
"pages_made_young",
37+
"pages_not_made_young",
38+
"pages_made_young_rate",
39+
"pages_made_not_young_rate",
40+
"number_pages_read",
41+
"number_pages_created",
42+
"number_pages_written",
43+
"pages_read_rate",
44+
"pages_create_rate",
45+
"pages_written_rate",
46+
"number_pages_get",
47+
"hit_rate",
48+
"young_make_per_thousand_get",
49+
"not_young_make_per_thousand_get",
50+
"number_pages_read_ahead",
51+
"number_read_ahead_evicted",
52+
"read_ahead_rate",
53+
"read_ahead_evicted_rate",
54+
"lru_io_total",
55+
"lru_io_current",
56+
"uncompress_total",
57+
"uncompress_current",
58+
}
59+
60+
columnSum map[string]string
61+
)
62+
63+
func init() {
64+
columnSum = make(map[string]string, len(columnNames))
65+
for _, name := range columnNames {
66+
columnSum[name] = fmt.Sprintf("SUM(%s) as %s", name, name)
67+
}
68+
}
69+
70+
// BufferPoolStats collections from the information_schema.innodb_buffer_pool_stats table.
71+
type BufferPoolStats struct {
72+
db *sql.DB
73+
query map[string]string
74+
}
75+
76+
// Verify collector implements blip.Collector interface.
77+
var _ blip.Collector = &BufferPoolStats{}
78+
79+
// NewTable makes a new Table collector,
80+
func NewBufferPoolStats(db *sql.DB) *BufferPoolStats {
81+
return &BufferPoolStats{
82+
db: db,
83+
query: map[string]string{},
84+
}
85+
}
86+
87+
// Domain returns the Blip metric domain name (DOMAIN const).
88+
func (t *BufferPoolStats) Domain() string {
89+
return DOMAIN
90+
}
91+
92+
// Help returns the output for blip --print-domains.
93+
func (t BufferPoolStats) Help() blip.CollectorHelp {
94+
return blip.CollectorHelp{
95+
Domain: DOMAIN,
96+
Description: "Buffer Pool Stats (summed over all pools)",
97+
Options: map[string]blip.CollectorHelpOption{
98+
OPT_ALL: {
99+
Name: OPT_ALL,
100+
Desc: "Collect metrics from all columns in the information_schema.innodb_buffer_pool_stats table.",
101+
Default: "no",
102+
Values: map[string]string{
103+
"yes": "All metrics (ignore metrics list)",
104+
"no": "Specified metrics",
105+
},
106+
},
107+
},
108+
}
109+
}
110+
111+
// Prepare prepares the collector for the given plan.
112+
func (c BufferPoolStats) Prepare(ctx context.Context, plan blip.Plan) (func(), error) {
113+
LEVEL:
114+
for _, level := range plan.Levels {
115+
dom, ok := level.Collect[DOMAIN]
116+
if !ok {
117+
continue LEVEL // not collected at this level
118+
}
119+
120+
sumFields := make([]string, 0, len(dom.Metrics))
121+
all := strings.ToLower(dom.Options[OPT_ALL])
122+
switch all {
123+
case "all":
124+
for _, column := range columnNames {
125+
sumFields = append(sumFields, columnSum[column])
126+
}
127+
default:
128+
for _, metric := range dom.Metrics {
129+
value, ok := columnSum[metric]
130+
if !ok {
131+
return nil, fmt.Errorf("invalid metric %q", metric)
132+
}
133+
134+
sumFields = append(sumFields, value)
135+
}
136+
}
137+
138+
c.query[level.Name] = fmt.Sprintf("SELECT %s FROM information_schema.innodb_buffer_pool_stats", strings.Join(sumFields, ", "))
139+
blip.Debug("%s: innodb metrics at %s: %s", plan.MonitorId, level.Name, c.query[level.Name])
140+
}
141+
return nil, nil
142+
}
143+
144+
func (t BufferPoolStats) Collect(ctx context.Context, levelName string) ([]blip.MetricValue, error) {
145+
o, ok := t.query[levelName]
146+
if !ok {
147+
return nil, nil
148+
}
149+
150+
results, err := sqlutil.RowToTypedMap[float64](ctx, t.db, o)
151+
if err != nil {
152+
return nil, err
153+
}
154+
155+
metrics := make([]blip.MetricValue, 0, len(results))
156+
for name, value := range results {
157+
m := blip.MetricValue{
158+
Name: name,
159+
Type: blip.CUMULATIVE_COUNTER,
160+
Value: value,
161+
}
162+
163+
if deltas[name] {
164+
m.Type = blip.DELTA_COUNTER
165+
}
166+
167+
metrics = append(metrics, m)
168+
}
169+
170+
return metrics, nil
171+
}
172+
173+
// deltas is a list of known delta metrics in information_schema.innodb_buffer_pool_stats.
174+
var deltas = map[string]bool{
175+
"pages_made_young_rate": true,
176+
"pages_made_not_young_rate": true,
177+
"pages_read_rate": true,
178+
"pages_create_rate": true,
179+
"pages_written_rate": true,
180+
"read_ahead_rate": true,
181+
"read_ahead_evicted_rate": true,
182+
}

0 commit comments

Comments
 (0)