Skip to content

[core][gcs] Add a bounded TableName label to GCS Store count and latency metrics - #65583

Merged
rueian merged 4 commits into
ray-project:masterfrom
zzchun:ray-16-gcs-store-table-name-label
Oct 13, 2026
Merged

rueian merged 4 commits into
ray-project:masterfrom
zzchun:ray-16-gcs-store-table-name-label

Conversation

@zzchun

@zzchun zzchun commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

Description

gcs_storage_operation_count and gcs_storage_operation_latency_ms are labeled by Operation only, so a slow GetAll on the actor table can't be told apart from one on the job table without correlating logs.

ObservableStoreClient already receives a table_name on every call. This PR:

  • records it as a bounded TableName label on both metrics, for Put, Get, GetAll, MultiGet, Delete, BatchDelete, GetKeys and Exists;
  • instruments GetNextJobID, the one storage operation the wrapper used to skip;
  • measures latency on the monotonic clock instead of wall time;
  • documents both metrics in system-metrics.md.

Exporting these metrics on the external-Redis backend, where they don't exist today, was split out of this PR at review into #66882.

Related issues

Closes #65582.

Additional information

Label cardinality

StoreClient accepts any string as a table name (the shared test base passes "test_table"), so the label is bounded explicitly: NormalizeTableNameLabel keeps names from the rpc::TablePrefix enum and maps anything else to OTHER.

In practice the GCS produces seven values: JOB, ACTOR, ACTOR_TASK_SPEC, PLACEMENT_GROUP, NODE, WORKERS and KV. The hard upper bound is 161 Operation × TableName combinations per GCS process (8 table operations × 20 values, plus GetNextJobID × JobCounter), independent of cluster size or actor count.

No user-controlled string reaches a label: the internal KV puts the user's namespace in the key (MakeKey in store_client_kv.cc), not in the table name. NoUserDataInLabels covers this.

GetNextJobID

It addresses a counter key rather than a table, so it reports the JobCounter sentinel. It can't simply leave TableName unset: tag_keys is the tag allowlist on both metric stacks, and a declared tag that a call site doesn't record is exported as an empty string, so it would show up as TableName="".

Latency clock

Latency used to be the difference of two NowUnixNanos() readings, which is wall time, so an NTP step could record a negative or inflated value. Every recording site is rewritten here anyway, so they now use SteadyNow(), which ClockInterface documents as the clock for durations.

Compatibility / release note

This changes series identity: each Operation now has up to seven series instead of one, and GetNextJobID is a new Operation value. Label matchers are unaffected. A dashboard or alert that assumed one series per operation can aggregate the new label away:

sum without (TableName) (rate(ray_gcs_storage_operation_count_total[5m]))

Use without (TableName) rather than by (Operation), because by also drops SessionName, Component and the other global labels. Aggregations sensitive to series count (avg, max, count) still change.

Not a duplicate

Searching open PRs for "TableName gcs_storage_operation", "observable store client", "gcs_storage_operation redis" and "MaybeObserve" finds no other PR labeling these metrics. #66847 edits the same Record call sites to move recording onto a separate io_context. It changes where recording runs, not what is recorded, so the two compose and whichever lands second rebases.

Testing

bazel test //src/ray/gcs/store_client/tests:table_name_label_test \
  //src/ray/gcs/store_client/tests:observable_store_client_test \
  //src/ray/gcs/store_client/tests:in_memory_store_client_test
# Executed 3 out of 3 tests: 3 tests pass.

pre-commit run --from-ref upstream/master --to-ref HEAD
# All hooks passed.

AI assistance (Claude Code) was used to prepare this change. I reviewed every changed line and ran the tests above locally.

@zzchun
zzchun requested review from a team as code owners August 19, 2026 05:06

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances GCS storage metrics by adding a TableName label to both operation count and latency metrics, allowing breakdowns by specific GCS tables. It introduces a normalization helper to map table names to a closed domain, preventing unbounded label cardinality, and adds a configuration flag to toggle these metrics on the external Redis backend. The review feedback points out that since clock_.NowUnixNanos() is non-monotonic, the latency calculation could occasionally yield negative values, and suggests guarding against this by using std::max with zero.

Comment thread src/ray/gcs/store_client/observable_store_client.cc
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch 2 times, most recently from 2181c67 to c7e643b Compare August 19, 2026 05:15

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit c7e643b. Configure here.

Comment thread src/ray/gcs/store_client/observable_store_client.h Outdated
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch from c7e643b to 74ca549 Compare August 19, 2026 07:05
@ray-gardener ray-gardener Bot added docs An issue or change related to documentation core Issues that should be addressed in Ray Core community-contribution Contributed by the community labels Aug 19, 2026
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch from 74ca549 to f259409 Compare September 3, 2026 09:50
@zzchun
zzchun requested a review from a team as a code owner September 3, 2026 09:50
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch from f259409 to b2c1744 Compare September 14, 2026 05:52
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had
any activity for 14 days. It will be closed in another 14 days if no further activity occurs.
Thank you for your contributions.

You can always ask for help on our discussion forum or Ray's public slack channel.

If you'd like to keep this open, just leave any comment, and the stale label will be removed.

@github-actions github-actions Bot added the stale The issue is stale. It will be closed within 7 days unless there are further conversation label Sep 28, 2026
@zzchun

zzchun commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

Hi @karticam , could you please help to review #65583 when you have a moment, thank you !

@github-actions github-actions Bot added unstale A PR that has been marked unstale. It will not get marked stale again if this label is on it. and removed stale The issue is stale. It will be closed within 7 days unless there are further conversation labels Sep 29, 2026
dstrodtman added a commit that referenced this pull request Oct 5, 2026
…m RST to MyST (#66673)

## Why are these changes needed?

This PR converts the remaining prose pages under `ray-observability/`,
`ray-more-libs/`, `ray-references/`, and `ray-air/` from
reStructuredText to MyST Markdown. It continues the RST-to-MyST
conversion that already landed for `ray-core/` (#66430), `data/`
(#66375), and the doctest-wired pages (#66461). The conversion is format
only: the goal is for each page's rendered HTML to match `/en/master`.

There are five commits:

1. **Conversion.** This commit converts 25 pages, `git rm`s the `.rst`
sources, and adds one `doc/BUILD.bazel` exclude, which commit 5 reverts.
Prose keeps its source line wrapping, so the diff lines up with the
`.rst` line by line.
2. **Soft-wrap.** This commit reflows whitespace only, to one line per
paragraph and list item. `verify.py` from `ray-soft-wrap` confirms that
the non-whitespace bytes and the rendered HTML don't change on all 25
files.
3. **Render fixes.** This commit fixes six regressions that the render
diff against `/en/master` caught, even though the build was green. In
`modin`, two bare-word RST link references (`Modin_`, `documentation_`)
rendered as literal text. In `getting-started`, a bold URL was
autolinked. In `system-metrics`, a URL in a table cell lost its link. In
`dask-on-ray`, `_not_` rendered as italics. In `glossary`, the inline
`.. TODO: RLlib` text, which `/en/master` shows, had become a comment.
The commit also adds compat anchors to five headings with apostrophes
(see below).
4. **Pseudo-lists.** This commit restores three pseudo-lists that the
soft-wrap merged into one line.
5. **Review feedback.** This commit removes the glossary's placeholder
TODO entries, reverts the `doc/BUILD.bazel` change so the PR stays
docs-only, and fixes defects that the review flagged in the `.rst`
sources: a stray definition list in `dask-on-ray`, an unconverted link
in `system-metrics`, an extra parenthesis in `debug-failures`, typos in
`debug-hangs` and `optimize-performance`, a grammar slip in
`ray-debugging`, and em-dash pseudo-list items in `general-debugging`,
which are now a bulleted list.

### Scope

- `ray-air/`: `getting-started` and `deployment`, converted together.
`getting-started` includes `deployment`, and the include now points at
`deployment.md`.
- `ray-observability/`: 14 pages, including `user-guides/debug-apps/`
and `reference/system-metrics`.
- `ray-more-libs/`: 9 pages.
- `ray-references/`: `glossary` and `faq`.

**Left as RST:** `ray-observability/reference/api.rst` (`autosummary`)
and `ray-observability/reference/cli.rst` (`click`). They're API
reference pages, so they stay RST along with the other `*/api/`
reference trees.

### Construct notes for reviewers

- **Glossary.** The glossary is a native MyST `{glossary}` directive,
not RST wrapped in `{eval-rst}`. Sphinx's `glossary` directive parses
each definition with the host parser, so the definitions are Markdown
now. The glossary's placeholder `.. TODO:` entries are removed. Missing
terms can be identified separately.
- **Glossary doctest.** Nothing ran the glossary's `.. doctest::` block
as `.rst`: `pytest-sphinx` doesn't execute `doctest` sections, and
`--doctest-glob='*.md'` doesn't match `.rst`. As `.md`, the stock
doctest parser would start running its five `>>>` prompts, and the
`[[0],[1],...,[3],[4]]` output can't pass without `ELLIPSIS`. Each
prompt now carries `# doctest: +SKIP`, which keeps coverage the same as
master without a `doc/BUILD.bazel` change. Sphinx's default
`trim_doctest_flags` strips the flag from the rendered page, as in
`data/working-with-tensors.md`. If you'd rather fix the expected output
and start testing it, I can do that in a follow-up.
- **FAQ.** `faq.md` includes `_includes/_help-links.md`, the Markdown
copy of `_help.rst` that #66417 added. `_help.rst` stays, because
`cluster/vms/user-guides/community/yarn.rst` and `tune/key-concepts.rst`
still include it.
- **Comparison table.** The grid table in
`ray-collective-custom-backend` is now a native `{list-table}`.
- **Line blocks.** The line blocks in `dask-on-ray`'s version table are
now Markdown hard line breaks. This is an expected render difference:
`<p>` with `<br>` instead of `div.line-block`.

### Dead links fixed on the way

These links were broken on `/en/master` and fail `fail_on_warning` when
they're transcribed into MyST:

- `joblib` and `multiprocessing` linked to relative `actors.html` and
`installation.html`, which resolve under `ray-more-libs/` and return
404. They now link to `{doc}` `/ray-core/actors` and
`/ray-overview/installation`.
- `ray-collective` linked to `#api-reference`, but the heading's anchor
is `#api-references`.

### Open PRs that edit these pages

Each of these PRs needs to move its change onto the `.md` file: #66363
(`ray-event-export`), #65693 and #65583 (`system-metrics`), and #64957
(`joblib`, `multiprocessing`). #65321 edits `reference/cli.rst`, which
this PR doesn't convert.

## Related issue number

None.

## Checks

- [x] I've signed off every commit (`git commit -s`).
- [x] Duplicate check: no open PR converts these pages. I searched open
PRs for MyST, observability, glossary, and more-libs, and for open PRs
that edit these files.
- **Doctest parity:** `doctest_parity.py` (the `pytest-sphinx` parser,
run against `upstream/master`) reports the same sections and examples on
all 25 pages, before and after the soft-wrap: 12 examples before, 12
after.
- **Local doctest:** `pytest --doctest-modules --doctest-glob='*.md' -c
NO_PYTEST_CONFIG -p doctest_pytest_plugin` on the 24 converted pages in
the main target, with Ray nightly `bc900c2` on Python 3.10: 5 passed.
Those are the 5 files with examples. The glossary, now in the target
too, reports 1 skipped: the stock parser finds 5 examples and all 5
carry `+SKIP`.
- **Static checks:** frontmatter parses, fences balance, every label is
preserved, and there's no leftover RST outside fences or directives.
- **RtD preview:** green under `fail_on_warning` on all three commits.
- **Render diff** (`render_diff.py`, preview against `/en/master`,
filtering the two class-only differences every MyST page shows): 11 of
25 pages are identical. Every difference on the other 14 is one of
these:
- RST comments now emit `<!-- ... -->` HTML comments, which readers
don't see. Pages: `ray-air/*`, `ray-more-libs/index`, `ray-collective`,
`getting-started`, `general-debugging`, `glossary`.
- The `dask-on-ray` version table: Markdown hard line breaks (`<p>` with
`<br>`) replace RST line blocks (`div.line-block`).
- The `dask-on-ray` "Why use Dask on Ray?" item keeps its
definition-list structure. MyST adds a `myst` class to the `<dl>`, and
the class has no styling.
- Same-page fragment and `{doc}` links render as `reference internal`
instead of `reference external`. Pages: `ray-collective`, `joblib`,
`multiprocessing`. This list also includes the dead links fixed above.
- Headings with an apostrophe get a new anchor, because MyST drops the
apostrophe where docutils turned it into a hyphen. For example,
`#what-s-the-out-of-memory-error` becomes
`#whats-the-out-of-memory-error`. Five of these headings had no label,
so each gets a compat target with the old slug, which keeps existing
links working. The sixth, in `optimize-performance`, already carries the
`dashboard-cprofile` label.

This PR was written with AI assistance (Claude Code). I reviewed the
changes and ran the checks above.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Douglas Strodtman <douglas@anyscale.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@karticam

karticam commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Hi @karticam , could you please help to review #65583 when you have a moment, thank you !

Sorry for the delay. Was caught up with something else. I will do it by today/tomorrow.

nadongjun pushed a commit to nadongjun/ray that referenced this pull request Oct 6, 2026
…m RST to MyST (ray-project#66673)

## Why are these changes needed?

This PR converts the remaining prose pages under `ray-observability/`,
`ray-more-libs/`, `ray-references/`, and `ray-air/` from
reStructuredText to MyST Markdown. It continues the RST-to-MyST
conversion that already landed for `ray-core/` (ray-project#66430), `data/`
(ray-project#66375), and the doctest-wired pages (ray-project#66461). The conversion is format
only: the goal is for each page's rendered HTML to match `/en/master`.

There are five commits:

1. **Conversion.** This commit converts 25 pages, `git rm`s the `.rst`
sources, and adds one `doc/BUILD.bazel` exclude, which commit 5 reverts.
Prose keeps its source line wrapping, so the diff lines up with the
`.rst` line by line.
2. **Soft-wrap.** This commit reflows whitespace only, to one line per
paragraph and list item. `verify.py` from `ray-soft-wrap` confirms that
the non-whitespace bytes and the rendered HTML don't change on all 25
files.
3. **Render fixes.** This commit fixes six regressions that the render
diff against `/en/master` caught, even though the build was green. In
`modin`, two bare-word RST link references (`Modin_`, `documentation_`)
rendered as literal text. In `getting-started`, a bold URL was
autolinked. In `system-metrics`, a URL in a table cell lost its link. In
`dask-on-ray`, `_not_` rendered as italics. In `glossary`, the inline
`.. TODO: RLlib` text, which `/en/master` shows, had become a comment.
The commit also adds compat anchors to five headings with apostrophes
(see below).
4. **Pseudo-lists.** This commit restores three pseudo-lists that the
soft-wrap merged into one line.
5. **Review feedback.** This commit removes the glossary's placeholder
TODO entries, reverts the `doc/BUILD.bazel` change so the PR stays
docs-only, and fixes defects that the review flagged in the `.rst`
sources: a stray definition list in `dask-on-ray`, an unconverted link
in `system-metrics`, an extra parenthesis in `debug-failures`, typos in
`debug-hangs` and `optimize-performance`, a grammar slip in
`ray-debugging`, and em-dash pseudo-list items in `general-debugging`,
which are now a bulleted list.

### Scope

- `ray-air/`: `getting-started` and `deployment`, converted together.
`getting-started` includes `deployment`, and the include now points at
`deployment.md`.
- `ray-observability/`: 14 pages, including `user-guides/debug-apps/`
and `reference/system-metrics`.
- `ray-more-libs/`: 9 pages.
- `ray-references/`: `glossary` and `faq`.

**Left as RST:** `ray-observability/reference/api.rst` (`autosummary`)
and `ray-observability/reference/cli.rst` (`click`). They're API
reference pages, so they stay RST along with the other `*/api/`
reference trees.

### Construct notes for reviewers

- **Glossary.** The glossary is a native MyST `{glossary}` directive,
not RST wrapped in `{eval-rst}`. Sphinx's `glossary` directive parses
each definition with the host parser, so the definitions are Markdown
now. The glossary's placeholder `.. TODO:` entries are removed. Missing
terms can be identified separately.
- **Glossary doctest.** Nothing ran the glossary's `.. doctest::` block
as `.rst`: `pytest-sphinx` doesn't execute `doctest` sections, and
`--doctest-glob='*.md'` doesn't match `.rst`. As `.md`, the stock
doctest parser would start running its five `>>>` prompts, and the
`[[0],[1],...,[3],[4]]` output can't pass without `ELLIPSIS`. Each
prompt now carries `# doctest: +SKIP`, which keeps coverage the same as
master without a `doc/BUILD.bazel` change. Sphinx's default
`trim_doctest_flags` strips the flag from the rendered page, as in
`data/working-with-tensors.md`. If you'd rather fix the expected output
and start testing it, I can do that in a follow-up.
- **FAQ.** `faq.md` includes `_includes/_help-links.md`, the Markdown
copy of `_help.rst` that ray-project#66417 added. `_help.rst` stays, because
`cluster/vms/user-guides/community/yarn.rst` and `tune/key-concepts.rst`
still include it.
- **Comparison table.** The grid table in
`ray-collective-custom-backend` is now a native `{list-table}`.
- **Line blocks.** The line blocks in `dask-on-ray`'s version table are
now Markdown hard line breaks. This is an expected render difference:
`<p>` with `<br>` instead of `div.line-block`.

### Dead links fixed on the way

These links were broken on `/en/master` and fail `fail_on_warning` when
they're transcribed into MyST:

- `joblib` and `multiprocessing` linked to relative `actors.html` and
`installation.html`, which resolve under `ray-more-libs/` and return
404. They now link to `{doc}` `/ray-core/actors` and
`/ray-overview/installation`.
- `ray-collective` linked to `#api-reference`, but the heading's anchor
is `#api-references`.

### Open PRs that edit these pages

Each of these PRs needs to move its change onto the `.md` file: ray-project#66363
(`ray-event-export`), ray-project#65693 and ray-project#65583 (`system-metrics`), and ray-project#64957
(`joblib`, `multiprocessing`). ray-project#65321 edits `reference/cli.rst`, which
this PR doesn't convert.

## Related issue number

None.

## Checks

- [x] I've signed off every commit (`git commit -s`).
- [x] Duplicate check: no open PR converts these pages. I searched open
PRs for MyST, observability, glossary, and more-libs, and for open PRs
that edit these files.
- **Doctest parity:** `doctest_parity.py` (the `pytest-sphinx` parser,
run against `upstream/master`) reports the same sections and examples on
all 25 pages, before and after the soft-wrap: 12 examples before, 12
after.
- **Local doctest:** `pytest --doctest-modules --doctest-glob='*.md' -c
NO_PYTEST_CONFIG -p doctest_pytest_plugin` on the 24 converted pages in
the main target, with Ray nightly `bc900c2` on Python 3.10: 5 passed.
Those are the 5 files with examples. The glossary, now in the target
too, reports 1 skipped: the stock parser finds 5 examples and all 5
carry `+SKIP`.
- **Static checks:** frontmatter parses, fences balance, every label is
preserved, and there's no leftover RST outside fences or directives.
- **RtD preview:** green under `fail_on_warning` on all three commits.
- **Render diff** (`render_diff.py`, preview against `/en/master`,
filtering the two class-only differences every MyST page shows): 11 of
25 pages are identical. Every difference on the other 14 is one of
these:
- RST comments now emit `<!-- ... -->` HTML comments, which readers
don't see. Pages: `ray-air/*`, `ray-more-libs/index`, `ray-collective`,
`getting-started`, `general-debugging`, `glossary`.
- The `dask-on-ray` version table: Markdown hard line breaks (`<p>` with
`<br>`) replace RST line blocks (`div.line-block`).
- The `dask-on-ray` "Why use Dask on Ray?" item keeps its
definition-list structure. MyST adds a `myst` class to the `<dl>`, and
the class has no styling.
- Same-page fragment and `{doc}` links render as `reference internal`
instead of `reference external`. Pages: `ray-collective`, `joblib`,
`multiprocessing`. This list also includes the dead links fixed above.
- Headings with an apostrophe get a new anchor, because MyST drops the
apostrophe where docutils turned it into a hyphen. For example,
`#what-s-the-out-of-memory-error` becomes
`#whats-the-out-of-memory-error`. Five of these headings had no label,
so each gets a compat target with the old slug, which keeps existing
links working. The sixth, in `optimize-performance`, already carries the
`dashboard-cprofile` label.

This PR was written with AI assistance (Claude Code). I reviewed the
changes and ran the checks above.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Douglas Strodtman <douglas@anyscale.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@karticam

karticam commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Hi @zzchun . Thanks for the PR and the detailed writeup. I went through the changes and it seems like this PR is trying to solve two issues:

  1. Adding table name to existing metrics which is the tag_keys change and other related changes.
  2. Exporting these metrics on redis backend which is the MaybeObserve plus the addition of the new flag.

I think this can be split into two PRs. It would be much easier to review them separately.

Also, I see some optimizations around string_view and string, which seem quite complex. Did you do any benchmarking to see what are the benefits to use string_view over string in this case?

@zzchun

zzchun commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@karticam Thanks for taking the time to go through it !

Splitting: Agreed, the two changes are independent. I'll keep this PR scoped to the TableName label, plus the switch to the monotonic clock for latency since it touches the same lines. The Redis backend wrapping moves to a separate PR: MaybeObserve, the gcs_redis_storage_metrics_enabled flag and the shared_ptr ownership change. I'll link it here once it's up.

string_view vs std::string: Good question. I didn't benchmark it, and looking at it again I don't think the difference would be measurable. The table names are short enough to fit in SSO, MetricTags already allocates a vector on every Record, and both costs are negligible next to the storage round trip itself. So the extra complexity isn't justified. I'll capture the label as a plain std::string and drop the lifetime/SSO comments and the tests that only existed to support the string_view. The enum-based normalization stays, since that's what keeps the TableName label bounded.

zzchun added a commit to zzchun/ray that referenced this pull request Oct 9, 2026
…ring

Address review on ray-project#65583:

- Move the Redis-backend wrapping (MaybeObserve, the
  gcs_redis_storage_metrics_enabled flag, and the shared_ptr delegate
  change) out of this PR into a separate one.
- NormalizeTableNameLabel now returns a std::string and the latency
  callbacks capture it by value. The string_view-into-static-storage
  design saved at most one SSO copy per operation, which is not
  measurable next to the storage round trip, so drop it along with the
  lifetime/SSO comments and the tests that only existed to support it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: zzchun <zzchun8@gmail.com>
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch from b2c1744 to 0600ecf Compare October 9, 2026 10:33
zzchun added a commit to zzchun/ray that referenced this pull request Oct 9, 2026
…ring

Address review on ray-project#65583:

- Move the Redis-backend wrapping (MaybeObserve, the
  gcs_redis_storage_metrics_enabled flag, and the shared_ptr delegate
  change) out of this PR into a separate one.
- NormalizeTableNameLabel now returns a std::string and the latency
  callbacks capture it by value. The string_view-into-static-storage
  design saved at most one SSO copy per operation, which is not
  measurable next to the storage round trip, so drop it along with the
  lifetime/SSO comments and the tests that only existed to support it.

Signed-off-by: zzchun <zzchun8@gmail.com>
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch from 0600ecf to 3549453 Compare October 9, 2026 12:16
@zzchun

zzchun commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor Author

@karticam I've addressed your comments. Please take another look when you have time, thanks!

Splitting: Done. This PR now only adds the TableName label, plus moving latency onto the monotonic clock since that touches the same lines. The Redis backend wrapping (MaybeObserve, the gcs_redis_storage_metrics_enabled flag and the shared_ptr ownership change) is now #66882.

string_view: No, I didn't benchmark it, and I don't think a benchmark would show anything: the table names fit in SSO, MetricTags already allocates a vector on every Record, and all of it is dwarfed by the storage round trip. It wasn't worth the complexity, so the label is now a plain std::string captured by value, and the comments and tests that supported the string_view are gone. The enum-based normalization stays, since that's what keeps the label bounded.

I also rebased onto master to resolve a conflict (the metrics doc moved to system-metrics.md), so the force-push diff includes unrelated master changes. The review changes are all in the last commit, 3549453.

zzchun added a commit to zzchun/ray that referenced this pull request Oct 9, 2026
RedisStoreClient is the only StoreClient that GcsServer never wraps in
ObservableStoreClient, so gcs_storage_operation_count and
gcs_storage_operation_latency_ms are not exported at all when the GCS
uses external Redis.

Route both REDIS_PERSIST construction sites (cluster tables and internal
KV) through a new gcs::MaybeObserve helper, gated by
gcs_redis_storage_metrics_enabled (default true) so the new Record calls
can be rolled back. ObservableStoreClient and StoreClientInternalKV now
hold their delegate as a shared_ptr, because GcsServer keeps a concrete
RedisStoreClient pointer for the periodic health check; health-check
PINGs keep bypassing the wrapper.

Split out of ray-project#65583 at review.

Signed-off-by: zzchun <zzchun8@gmail.com>
Comment thread src/ray/gcs/store_client/table_name_label.cc Outdated
Comment thread src/ray/gcs/store_client/table_name_label.h Outdated
Comment thread src/ray/gcs/store_client/tests/table_name_label_test.cc Outdated
@karticam

karticam commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

These changes LGTM besides a few nits. Also wanted to make sure that the string_view v/s string optimizations were only for the table name strings right (and they are all pretty small right)

…ncy metrics

gcs_storage_operation_count and gcs_storage_operation_latency_ms were labeled by
operation only, so a slow GetAll on the actor table and the same operation on the
job table were indistinguishable. ObservableStoreClient now also records the
table name it already receives.

TableName is normalized through the rpc::TablePrefix enum: StoreClient accepts an
arbitrary string, so this bounds the label domain by construction instead of by
convention, and returns a view into static storage that the latency observer can
capture without copying. Unknown names collapse to OTHER. AsyncGetNextJobID,
previously uninstrumented, reports JobCounter. The tag is declared in the metric
factories too -- tag_keys is the allowlist on both metric stacks, so recording
without declaring is a no-op.

RedisStoreClient was the only StoreClient never wrapped in ObservableStoreClient,
so neither metric existed on the external-Redis backend. Both REDIS_PERSIST
branches now go through gcs::MaybeObserve, gated by
gcs_redis_storage_metrics_enabled (default true). ObservableStoreClient and
StoreClientInternalKV hold their delegate as a shared_ptr for this, because
AsyncCheckHealth is not on the StoreClient interface and GcsServer must keep a
concrete pointer for the health check; call sites pass unique_ptr rvalues and
convert implicitly.

Series identity changes: one series per Operation becomes up to seven, and
sum by (Operation) (...) reproduces the previous series. On Redis the change is
purely additive. Both metrics were undocumented; system-metrics.rst now covers
them.

Signed-off-by: zzchun <zzchun8@gmail.com>
…ring

Address review on ray-project#65583:

- Move the Redis-backend wrapping (MaybeObserve, the
  gcs_redis_storage_metrics_enabled flag, and the shared_ptr delegate
  change) out of this PR into a separate one.
- NormalizeTableNameLabel now returns a std::string and the latency
  callbacks capture it by value. The string_view-into-static-storage
  design saved at most one SSO copy per operation, which is not
  measurable next to the storage round trip, so drop it along with the
  lifetime/SSO comments and the tests that only existed to support it.

Signed-off-by: zzchun <zzchun8@gmail.com>
Signed-off-by: zzchun <zzchun8@gmail.com>
@zzchun
zzchun force-pushed the ray-16-gcs-store-table-name-label branch from 3549453 to 176eb4e Compare October 10, 2026 02:56
@zzchun

zzchun commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

@karticam Thanks for the review! Rebased onto the latest master and updated the copyright year to 2026 in all three new files (176eb4e).

On string_view: yes, the optimization only ever applied to the TableName label value, and that is now a plain std::string captured by value. The values come from the rpc::TablePrefix enum names (plus OTHER / JobCounter), so they're all short and fit in SSO. The string_view that remains in the diff is just the conventional parameter type for MetricTags / the test helpers and the two constexpr label constants, not an optimization.

@karticam

Copy link
Copy Markdown
Contributor

Thanks for the PR. LGTM

@dstrodtman dstrodtman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs-side style and grammar pass from Douglas Strodtman (Ray docs team), drafted with Claude Code assistance. I've read and stand behind the comment.

Scope is prose and docs conventions on system-metrics.md only. The metric semantics, label domain, and backend behavior are for the GCS maintainers, and I didn't change any of them. The latency row reads cleanly as written. The docs side has no objection to merging.

Comment thread doc/source/ray-observability/reference/system-metrics.md Outdated
Signed-off-by: Douglas Strodtman <douglas@anyscale.com>
@dstrodtman dstrodtman added the go add ONLY when ready to merge, run all tests label Oct 13, 2026
@rueian
rueian enabled auto-merge (squash) October 13, 2026 21:06
@rueian
rueian merged commit 027aa6a into ray-project:master Oct 13, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Contributed by the community core Issues that should be addressed in Ray Core docs An issue or change related to documentation go add ONLY when ready to merge, run all tests unstale A PR that has been marked unstale. It will not get marked stale again if this label is on it.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GCS] Add a bounded TableName label to GCS Store count and latency metrics

4 participants