Skip to content
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

PMM-12712 Shards collector. #762

Merged
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
6850049
PMM-12712 Shard ID and count.
JiriCtvrtka Dec 11, 2023
6eab6f0
PMM-12712 Name and count.
JiriCtvrtka Dec 11, 2023
650bdce
PMM-12712 Sharded collector.
JiriCtvrtka Dec 13, 2023
0bf0882
PMM-12712 Remove missed print.
JiriCtvrtka Dec 13, 2023
e926775
PMM-12712 Revert test changes.
JiriCtvrtka Dec 13, 2023
507245f
PMM-12712 Revert old not related changes.
JiriCtvrtka Dec 13, 2023
fcabf4b
PMM-12712 Another changes.
JiriCtvrtka Dec 14, 2023
91140c1
PMM-12712 Missed print.
JiriCtvrtka Dec 14, 2023
971594b
PMM-12712 Align naming with task description.
JiriCtvrtka Dec 14, 2023
11c7e0a
PMM-12712 Add mongos test client.
JiriCtvrtka Dec 14, 2023
4f4f5c3
PMM-12712 Lint.
JiriCtvrtka Dec 14, 2023
45c9e39
PMM-12712 Lint.
JiriCtvrtka Dec 14, 2023
f5ed91d
PMM-12712 Typo.
JiriCtvrtka Dec 14, 2023
f93cc38
PMM-12712 Lint.
JiriCtvrtka Dec 14, 2023
88451ba
PMM-12712 Test higher sleep.
JiriCtvrtka Dec 19, 2023
1cad77b
Revert "PMM-12712 Test higher sleep."
JiriCtvrtka Dec 19, 2023
c4d20eb
PMM-12712 Test of pipeline.
JiriCtvrtka Dec 19, 2023
78f775b
PMM-12712 Change.
JiriCtvrtka Dec 19, 2023
1727c19
PMM-12712 Test.
JiriCtvrtka Dec 19, 2023
3b97b99
PMM-12712 Test.
JiriCtvrtka Dec 19, 2023
c827122
PMM-12712 Test.
JiriCtvrtka Dec 19, 2023
c7dd46e
PMM-12712 Correct aggregation to get chunks info.
JiriCtvrtka Dec 20, 2023
33ef736
PMM-12712 Another progress.
JiriCtvrtka Dec 21, 2023
82d4c43
PMM-12702 Small refactor.
JiriCtvrtka Dec 21, 2023
3da2738
PMM-12712 Test.
JiriCtvrtka Dec 21, 2023
564efec
PMM-12712 Fix, tests.
JiriCtvrtka Dec 22, 2023
6863eb8
PMM-12712 Temp.
JiriCtvrtka Dec 22, 2023
5f33085
PMM-12712 Improve sharded test.
JiriCtvrtka Dec 22, 2023
7cfc273
PMM-12712 Change in workflow.
JiriCtvrtka Dec 22, 2023
21ddafb
PMM-12712 Remove print.
JiriCtvrtka Dec 22, 2023
09057de
PMM-12712 Init script changes.
JiriCtvrtka Dec 22, 2023
8a51df8
PMM-12712 Remove print.
JiriCtvrtka Dec 22, 2023
abfe3f5
PMM-12712 Bigger sleep.
JiriCtvrtka Dec 22, 2023
17cfccd
PMM-12712 Refactor.
JiriCtvrtka Jan 2, 2024
5949050
PMM-12712 Small refactor.
JiriCtvrtka Jan 2, 2024
e64dd93
PMM-12712 Another refactor.
JiriCtvrtka Jan 2, 2024
c4d6a07
PMM-12712 Fix after refactor.
JiriCtvrtka Jan 2, 2024
73fe6b7
PMM-12712 Alias.
JiriCtvrtka Jan 2, 2024
74745d6
PMM-12712 Alias for shell in older versions.
JiriCtvrtka Jan 2, 2024
c71ba2e
PMM-12712 Static test shard.
JiriCtvrtka Jan 2, 2024
bb18c39
PMM-12712 Fix another tests, mongo 4 shell script.
JiriCtvrtka Jan 2, 2024
9bab36e
PMM-12712 Big sleep test.
JiriCtvrtka Jan 2, 2024
20c1a98
PMM-12712 Michael's fix.
JiriCtvrtka Jan 5, 2024
ab69356
PMM-12712 Sleep.
JiriCtvrtka Jan 5, 2024
b526bf7
PMM-12712 Env.
JiriCtvrtka Jan 5, 2024
c96f816
Merge branch 'PMM-12510-correctly-recognize-arbiter-nodes' into PMM-1…
JiriCtvrtka Jan 8, 2024
55383a5
PMM-12712 Test.
JiriCtvrtka Jan 8, 2024
a6b1fec
PMM-12712 Fix test.
JiriCtvrtka Jan 8, 2024
a1cecd3
PMM-12712 Bigger sleep after changes.
JiriCtvrtka Jan 8, 2024
a80d80e
PMM-12712 Remove duplicate lines.
JiriCtvrtka Jan 8, 2024
aa72186
PMM-12712 Renaming from sharded to shards.
JiriCtvrtka Jan 8, 2024
39eed79
PMM-12712 Better script to detect proper mongo client.
JiriCtvrtka Jan 8, 2024
6517964
PMM-12712 Init script refactor.
JiriCtvrtka Jan 8, 2024
69caa3e
PMM-12712 Fix.
JiriCtvrtka Jan 8, 2024
26b2061
PMM-12712 Small refactor.
JiriCtvrtka Jan 8, 2024
424bc9d
Update main.go
JiriCtvrtka Jan 8, 2024
35b90c9
Update exporter/shards_collector.go
JiriCtvrtka Jan 8, 2024
4856289
PMM-12712 Remove mongo 6 for now, skip test for shards.
JiriCtvrtka Jan 9, 2024
16019a0
PMM-12712 Revert sleep length.
JiriCtvrtka Jan 9, 2024
1793719
PMM-12712 Mongo client based on vendor.
JiriCtvrtka Jan 9, 2024
a86f807
Merge branch 'PMM-12510-correctly-recognize-arbiter-nodes' into PMM-1…
JiriCtvrtka Jan 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ jobs:
image:
- mongo:4.4
- mongo:5.0
- mongo:6.0
- percona/percona-server-mongodb:4.4
- percona/percona-server-mongodb:5.0
- percona/percona-server-mongodb:6.0

runs-on: ubuntu-latest

Expand All @@ -39,6 +41,6 @@ jobs:
- name: Test
run: |
TEST_MONGODB_IMAGE=${{ matrix.image }} make test-cluster
sleep 10
sleep 300
make test-race
make test-cluster-clean
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ services:
- MONGO3=mongo-1-3
- ARBITER=mongo-1-arbiter
- RS=rs1
- VERSION=${TEST_MONGODB_IMAGE}
entrypoint: [ "/scripts/setup.sh" ]
networks:
- rs1
Expand Down Expand Up @@ -112,6 +113,7 @@ services:
- MONGO3=mongo-2-3
- ARBITER=mongo-2-arbiter
- RS=rs2
- VERSION=${TEST_MONGODB_IMAGE}
entrypoint: [ "/scripts/setup.sh" ]
networks:
- rs2
Expand Down Expand Up @@ -162,6 +164,7 @@ services:
- MONGO3=mongo-cnf-3
- RS=cnf-serv
- PORT=27017
- VERSION=${TEST_MONGODB_IMAGE}
entrypoint: [ "/scripts/setup.sh","cnf_servers" ]
networks:
- cnf-serv
Expand Down Expand Up @@ -205,6 +208,7 @@ services:
- PORT1=27017
- PORT2=27017
- PORT3=27017
- VERSION=${TEST_MONGODB_IMAGE}
entrypoint: [ "/scripts/init-shard.sh" ]
restart: on-failure:20

Expand Down
17 changes: 15 additions & 2 deletions docker/scripts/init-shard.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
#!/bin/bash

readarray -d . -t verarr <<< "${VERSION}"
readarray -d : -t version <<< "${verarr[0]}"
echo "Mongo version: ${version[1]}"

if ((${version[1]} <= 4))
then
echo -e 'mongo' > /usr/bin/mongosh && chmod +x /usr/bin/mongosh
JiriCtvrtka marked this conversation as resolved.
Show resolved Hide resolved
fi

mongodb1=`getent hosts ${MONGOS} | awk '{ print $1 }'`

mongodb11=`getent hosts ${MONGO11} | awk '{ print $1 }'`
Expand All @@ -17,16 +26,20 @@ mongodb33=`getent hosts ${MONGO33} | awk '{ print $1 }'`
port=${PORT:-27017}

echo "Waiting for startup.."
until mongo --host ${mongodb1}:${port} --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)' &>/dev/null; do
until mongosh --host ${mongodb1}:${port} --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)' &>/dev/null; do
printf '.'
sleep 1
done

echo "Started.."

echo init-shard.sh time now: `date +"%T" `
mongo --host ${mongodb1}:${port} <<EOF
mongosh --host ${mongodb1}:${port} <<EOF
sh.addShard( "${RS1}/${mongodb11}:${PORT1},${mongodb12}:${PORT2},${mongodb13}:${PORT3}" );
sh.addShard( "${RS2}/${mongodb21}:${PORT1},${mongodb22}:${PORT2},${mongodb23}:${PORT3}" );
use test;
db.createCollection("shard");
sh.enableSharding("test");
sh.shardCollection( "test.shard", { id: "hashed" }, false, { numInitialChunks: 500, collation: { locale: "simple" }} );
sh.status();
EOF
14 changes: 11 additions & 3 deletions docker/scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
#!/bin/bash
readarray -d . -t verarr <<< "${VERSION}"
readarray -d : -t version <<< "${verarr[0]}"
echo "Mongo version: ${version[1]}"

if ((${version[1]} <= 4))
then
echo -e 'mongo' > /usr/bin/mongosh && chmod +x /usr/bin/mongosh
fi

mongodb1=`getent hosts ${MONGO1} | awk '{ print $1 }'`
mongodb2=`getent hosts ${MONGO2} | awk '{ print $1 }'`
Expand All @@ -8,7 +16,7 @@ arbiter=`getent hosts ${ARBITER} | awk '{ print $1 }'`
port=${PORT:-27017}

echo "Waiting for startup.."
until mongo --host ${mongodb1}:${port} --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)' &>/dev/null; do
until mongosh --host ${mongodb1}:${port} --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)' &>/dev/null; do
printf '.'
sleep 1
done
Expand All @@ -20,7 +28,7 @@ echo setup.sh time now: `date +"%T" `

function cnf_servers() {
echo "setup cnf servers on ${MONGO1}(${mongodb1}:${port})"
mongo --host ${mongodb1}:${port} <<EOF
mongosh --host ${mongodb1}:${port} <<EOF
var cfg = {
"_id": "${RS}",
"version": 1,
Expand Down Expand Up @@ -48,7 +56,7 @@ EOF

function general_servers() {
echo "setup servers on ${MONGO1}(${mongodb1}:${port})"
mongo --host ${mongodb1}:${port} <<EOF
mongosh --host ${mongodb1}:${port} <<EOF
var cfg = {
"_id": "${RS}",
"protocolVersion": 1,
Expand Down
10 changes: 10 additions & 0 deletions exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type Opts struct {
EnableIndexStats bool
EnableCollStats bool
EnableProfile bool
EnableSharded bool

EnableOverrideDescendingIndex bool

Expand Down Expand Up @@ -163,6 +164,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
e.opts.EnableIndexStats = true
e.opts.EnableCurrentopMetrics = true
e.opts.EnableProfile = true
e.opts.EnableSharded = true
}

// arbiter only have isMaster privileges
Expand All @@ -175,6 +177,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
e.opts.EnableIndexStats = false
e.opts.EnableCurrentopMetrics = false
e.opts.EnableProfile = false
e.opts.EnableSharded = false
}

// If we manually set the collection names we want or auto discovery is set.
Expand Down Expand Up @@ -230,6 +233,11 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
registry.MustRegister(rsgsc)
}

if e.opts.EnableSharded && requestOpts.EnableSharded {
sc := newShardedCollector(ctx, client, e.opts.Logger, e.opts.CompatibleMode)
registry.MustRegister(sc)
}

return registry
}

Expand Down Expand Up @@ -304,6 +312,8 @@ func (e *Exporter) Handler() http.Handler {
requestOpts.EnableCollStats = true
case "profile":
requestOpts.EnableProfile = true
case "sharded":
requestOpts.EnableSharded = true
}
}

Expand Down
189 changes: 189 additions & 0 deletions exporter/sharded_collector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// mongodb_exporter
// Copyright (C) 2017 Percona LLC
//
// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exporter

import (
"context"
"fmt"
"strings"

"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)

type shardedCollector struct {
JiriCtvrtka marked this conversation as resolved.
Show resolved Hide resolved
ctx context.Context
base *baseCollector
compatible bool
}

// newShardedCollector creates collector collecting metrics about chunks for sharded Mongo.
func newShardedCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger, compatibleMode bool) *shardedCollector {
return &shardedCollector{
ctx: ctx,
base: newBaseCollector(client, logger),
compatible: compatibleMode,
}
}

func (d *shardedCollector) Describe(ch chan<- *prometheus.Desc) {
d.base.Describe(d.ctx, ch, d.collect)
}

func (d *shardedCollector) Collect(ch chan<- prometheus.Metric) {
d.base.Collect(ch)
}

func (d *shardedCollector) collect(ch chan<- prometheus.Metric) {
defer measureCollectTime(ch, "mongodb", "sharded")()

client := d.base.client
logger := d.base.logger
prefix := "sharded collection chunks"

databaseNames, err := client.ListDatabaseNames(d.ctx, bson.D{})
if err != nil {
logger.Errorf("cannot get database names: %s", err)
}
for _, database := range databaseNames {
collections := d.getCollectionsForDBName(database)
for _, row := range collections {
if len(row) == 0 {
continue
}

var ok bool
if _, ok = row["_id"]; !ok {
continue
}
var rowID string
if rowID, ok = row["_id"].(string); !ok {
continue
}

chunks := d.getChunksForCollection(row)
for _, c := range chunks {
labels, chunks, success := d.getInfoForChunk(c, database, rowID)
if !success {
continue
}
for _, metric := range makeMetrics(prefix, primitive.M{"count": chunks}, labels, d.compatible) {
ch <- metric
}
}
}
}
}

func (d *shardedCollector) getInfoForChunk(c primitive.M, database, rowID string) (map[string]string, int32, bool) {
var ok bool
if _, ok = c["dropped"]; ok {
if dropped, ok := c["dropped"].(bool); ok && dropped {
return nil, 0, false
}
}

labels := make(map[string]string)
labels["database"] = database
labels["collection"] = strings.Replace(rowID, fmt.Sprintf("%s.", database), "", 1)

if _, ok = c["shard"]; !ok {
return nil, 0, ok
}
var shard string
if shard, ok = c["shard"].(string); !ok {
return nil, 0, ok
}
labels["shard"] = shard

logger := d.base.logger
logger.Debug("$sharded metrics for config.chunks")
debugResult(logger, primitive.M{database: c})

if _, ok = c["nChunks"]; !ok {
return nil, 0, ok
}
var chunks int32
if chunks, ok = c["nChunks"].(int32); !ok {
return nil, 0, ok
}

return labels, chunks, true
}

func (d *shardedCollector) getCollectionsForDBName(database string) []primitive.M {
client := d.base.client
logger := d.base.logger

cursor := client.Database("config").Collection("collections")
rs, err := cursor.Find(d.ctx, bson.M{"_id": bson.M{"$regex": fmt.Sprintf("^%s.", database), "$options": "i"}})
if err != nil {
logger.Errorf("cannot find _id starting with \"%s.\":%s", database, err)
return nil
}

var decoded []bson.M
err = rs.All(d.ctx, &decoded)
if err != nil {
logger.Errorf("cannot decode collections:%s", err)
return nil
}

return decoded
}

func (d *shardedCollector) getChunksForCollection(row primitive.M) []bson.M {
var chunksMatchPredicate bson.M
if _, ok := row["timestamp"]; ok {
if uuid, ok := row["uuid"]; ok {
chunksMatchPredicate = bson.M{"uuid": uuid}
}
} else {
if id, ok := row["_id"]; ok {
chunksMatchPredicate = bson.M{"_id": id}
}
}

aggregation := bson.A{
bson.M{"$match": chunksMatchPredicate},
bson.M{"$group": bson.M{"_id": "$shard", "cnt": bson.M{"$sum": 1}}},
bson.M{"$project": bson.M{"_id": 0, "shard": "$_id", "nChunks": "$cnt"}},
bson.M{"$sort": bson.M{"shard": 1}},
}

client := d.base.client
logger := d.base.logger

cur, err := client.Database("config").Collection("chunks").Aggregate(context.Background(), aggregation)
if err != nil {
logger.Errorf("cannot get $sharded cursor for collection config.chunks: %s", err)
return nil
}

var chunks []bson.M
err = cur.All(context.Background(), &chunks)
if err != nil {
logger.Errorf("cannot decode $sharded for collection config.chunks: %s", err)
return nil
}

return chunks
}

var _ prometheus.Collector = (*shardedCollector)(nil)
Loading
Loading