Metrics for measuring monorepo performance

To measure server-side performance of your monorepo, use these metrics. While they are general metrics to measure the performance of Gitaly, they are especially relevant to large repositories.

Clones and fetches are the most frequent expensive operations. When taken as a percentage of system resources consumed, these operations often contribute to 90% or more of system resources on Gitaly nodes. Your logs and metrics provide clues to the health of your repository.

CPU and memory

Two main RPCs (remote procedure calls) handle clones and fetches. Use these fields in your Gitaly logs to inspect how much repository clones and fetches are consuming system resources. Filter your Gitaly logs by any of these fields to learn more:

Log field Values to filter on Description
json.grpc.method PostReceivePack The RPC that handles HTTP clones and fetches.
json.grpc.method SSHReceivePack The RPC that handles SSH clones and fetches.
json.grpc.code OK Whether the RPC served its request successfully.
json.grpc.code Canceled Can show if the client killed the connection. Often due to a timeout.
json.grpc.code ResourceExhausted Indicates if the machine is spawning too many Git processes simultaneously.
json.user_id The user_id initiating the clone or fetch, in the form user-<user_id>, like user-22345 Find excessive clone or fetch operations spawned by a single user.
json.username The username who initiated the clone or fetch. Find excessive clone or fetch operations spawned by a single user.
json.grpc.request.glRepository A repository, in the form of project-<project_id>, like project-214 Find the total clones and fetches for a single repository.
json.grpc.request.glProjectPath A repository, in the form of a project path, like my-org/coolproject Find the total clones and fetches for a given repository.

These log entry fields give information about CPU and memory:

Log field to inspect Description
json.command.cpu_time_ms CPU time used by subprocesses spawned from this RPC.
json.command.maxrss Memory consumption from subprocesses spawned from this RPC.

In this example, log message json.command.cpu_time_ms was 420, and json.command.maxrss was 3342152:

{
    "command.count":2,
    "command.cpu_time_ms":420,
    "command.inblock":0,
    "command.majflt":0,
    "command.maxrss":3342152,
    "command.minflt":24316,
    "command.oublock":56,
    "command.real_time_ms":626,
    "command.spawn_token_fork_ms":4,
    "command.spawn_token_wait_ms":0,
    "command.system_time_ms":172,
    "command.user_time_ms":248,
    "component":"gitaly.StreamServerInterceptor",
    "correlation_id":"20HCB3DAEPLV08UGNIYT9HJ4JW",
    "environment":"gprd",
    "feature_flags":"",
    "fqdn":"file-99-stor-gprd.c.gitlab-production.internal",
    "grpc.code":"OK",
    "grpc.meta.auth_version":"v2",
    "grpc.meta.client_name":"gitlab-workhorse",
    "grpc.meta.deadline_type":"none",
    "grpc.meta.method_operation":"mutator",
    "grpc.meta.method_scope":"repository",
    "grpc.meta.method_type":"bidi_stream",
    "grpc.method":"PostReceivePack",
    "grpc.request.fullMethod":"/gitaly.SmartHTTPService/PostReceivePack",
    "grpc.request.glProjectPath":"r2414/revenir/development/machinelearning/protein-ddg",
    "grpc.request.glRepository":"project-47506374",
    "grpc.request.payload_bytes":911,
    "grpc.request.repoPath":"@hashed/db/ab/dbabf83f57affedc9a001dc6c6f6b47bb431bd47d7254edd1daf24f0c38793a9.git",
    "grpc.request.repoStorage":"nfs-file99",
    "grpc.response.payload_bytes":54,
    "grpc.service":"gitaly.SmartHTTPService",
    "grpc.start_time":"2023-10-16T20:40:08.836",
    "grpc.time_ms":631.486,
    "hostname":"file-99-stor-gprd",
    "level":"info",
    "msg":"finished streaming call with code OK",
    "pid":1741362,
    "remote_ip":"108.163.136.48",
    "shard":"default",
    "span.kind":"server",
    "stage":"main",
    "system":"grpc",
    "tag":"gitaly",
    "tier":"stor",
    "time":"2023-10-16T20:40:09.467Z",
    "trace.traceid":"AAB3QAeD8G+H9VNmzOi2CztMAcJv1+g4+l1cAgA=",
    "type":"gitaly",
    "user_id":"user-14857500",
    "username":"ctx_ckottke",
  }

Read distribution

To check the number of reads to each Gitaly node, check gitaly_praefect_read_distribution. This Prometheus metric is a counter, and has two vectors:

Metric name Vector Description
gitaly_praefect_read_distribution virtual_storage The virtual storage name.
gitaly_praefect_read_distribution storage The Gitaly storage name.

Pack objects cache

To check the pack objects cache, check your logs and your Prometheus metrics:

Log field name Description
pack_objects_cache.hit Whether the current pack-objects cache was hit. (true or false)
pack_objects_cache.key Cache key used for the pack-objects cache.
pack_objects_cache.generated_bytes Size in bytes of the new cache being written.
pack_objects_cache.served_bytes Size in bytes of the cache being served.
pack_objects.compression_statistics Statistics for pack-objects generation.
pack_objects.enumerate_objects_ms Total time, in ms, spent enumerating objects sent by clients.
pack_objects.prepare_pack_ms Total time, in ms, spent preparing the packfile before sending it back to the client
pack_objects.write_pack_file_ms Total time, in ms, spent sending the packfile back to the client. Highly dependent on the client’s internet connection.
pack_objects.written_object_count Total number of objects Gitaly sent back to the client.

Example log message:

{
"bytes":26186490,
"correlation_id":"01F1MY8JXC3FZN14JBG1H42G9F",
"grpc.meta.deadline_type":"none",
"grpc.method":"PackObjectsHook",
"grpc.request.fullMethod":"/gitaly.HookService/PackObjectsHook",
"grpc.request.glProjectPath":"root/gitlab-workhorse",
"grpc.request.glRepository":"project-2",
"grpc.request.repoPath":"@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git",
"grpc.request.repoStorage":"default",
"grpc.request.topLevelGroup":"@hashed",
"grpc.service":"gitaly.HookService",
"grpc.start_time":"2021-03-25T14:57:52.747Z",
"level":"info",
"msg":"finished unary call with code OK",
"peer.address":"@",
"pid":20961,
"span.kind":"server",
"system":"grpc",
"time":"2021-03-25T14:57:53.543Z",
"pack_objects.compression_statistics": "Total 145991 (delta 68), reused 6 (delta 2), pack-reused 145911",
"pack_objects.enumerate_objects_ms": 170,
"pack_objects.prepare_pack_ms": 7,
"pack_objects.write_pack_file_ms": 786,
"pack_objects.written_object_count": 145991,
"pack_objects_cache.generated_bytes": 49533030,
"pack_objects_cache.hit": "false",
"pack_objects_cache.key": "123456789",
"pack_objects_cache.served_bytes": 49533030,
"peer.address": "127.0.0.1",
"pid": 8813,
}
Prometheus metric name Vector Description
gitaly_pack_objects_served_bytes_total Size (in bytes) of the cache being served.
gitaly_pack_objects_cache_lookups_total result Whether a cache lookup resulted in a hit or miss.