Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions doc/admin-guide/configuration/hrw4u.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -710,9 +710,9 @@ Denied Sections
---------------

The ``sections`` list accepts any of the HRW4U section names listed in the
`Sections`_ table, plus ``VARS`` to deny the variable declaration block.
A denied section causes the entire block to be rejected; the body is not
validated.
`Sections`_ table, plus ``VARS`` and ``SESSION_VARS`` to deny the variable
declaration blocks. A denied section causes the entire block to be rejected;
the body is not validated.

Functions
---------
Expand Down Expand Up @@ -775,7 +775,7 @@ The ``language`` list accepts a fixed set of constructs:
Construct What it controls
================ ===================================================
``break`` The ``break;`` statement (early section exit)
``variables`` The entire ``VARS`` section and all variable usage
``variables`` The entire ``VARS`` and ``SESSION_VARS`` section and all variable usage
``else`` The ``else { ... }`` branch of conditionals
``elif`` The ``elif ... { ... }`` branch of conditionals
``in`` The ``in [...]`` and ``!in [...]`` set membership operators
Expand Down
106 changes: 78 additions & 28 deletions doc/admin-guide/files/records.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2033,13 +2033,15 @@ Origin Server Connect Attempts
this setting resolve to the same group -- that is, the same key under
:ts:cv:`proxy.config.http.per_server.connection.match` -- the transaction that creates the group
determines its metrics, and later transactions do not change them. A group is discarded once its
connection count reaches zero, so *raising* the level of publication is picked up the next time
that upstream is reopened: enabling metrics, or enabling the aggregates, takes effect as upstreams
reconnect. Lowering it does not. Metrics are never retired once published, so disabling this
setting, or switching
:ts:cv:`proxy.config.http.per_server.connection.metric_aggregate` to ``2``, leaves the names that
are already published in place, frozen at their last sampled value, until |TS| is restarted. This
affects only which metrics exist; enforcement of
connection count reaches zero, so a change is picked up the next time that upstream is reopened.
A group that never goes idle keeps whatever was in effect when it was created.

Disabling this setting does not retire metrics that are already published: they stay in place,
frozen at their last sampled value, until |TS| is restarted. Changing
:ts:cv:`proxy.config.http.per_server.connection.metric_aggregate` does retract what it no longer
asks for, as each group is rebuilt.

This affects only which metrics exist; enforcement of
:ts:cv:`proxy.config.http.per_server.connection.max` uses the group's own connection count and is
unaffected.

Expand All @@ -2051,24 +2053,30 @@ Origin Server Connect Attempts
:ts:cv:`proxy.config.http.per_server.connection.metric_enabled`. Has no effect when that setting
is ``0``.

A per hostname aggregate sums a counter across every group belonging to that hostname that has
aggregation enabled, and exists only for
There are two kinds of per hostname aggregate. The *sums* add ``current_connection``,
``total_connection`` and ``blocked_connection`` across every group belonging to that hostname
that has aggregation enabled. The *max* is ``current_connection.max``, the largest
``current_connection`` among those groups, which is the one that answers how close the busiest
group is to :ts:cv:`proxy.config.http.per_server.connection.max`. Both exist only for
:ts:cv:`match type <proxy.config.http.per_server.connection.match>` ``both``, since that is the
only match type whose group key carries the hostname. See :ref:`per-server-connection-metrics`.

===== ======================================================================================
Value Effect
===== ======================================================================================
``0`` No aggregates. The per group metrics are published under their own names.
``1`` Publish the per hostname aggregates and the per group metrics.
``2`` Publish only the per hostname aggregates. The per group metrics from which they are
computed are collected but not published, which keeps the number of published metrics
proportional to hostnames rather than to groups.
===== ======================================================================================
===== =========== ====== =====
Value Per group Sums Max
===== =========== ====== =====
``0`` published no no
``1`` published yes yes
``2`` hidden no yes
``3`` hidden yes yes
===== =========== ====== =====

``2`` is the smallest useful configuration: one metric per hostname. ``3`` adds that hostname's
totals. Both keep the number of published metrics proportional to hostnames rather than to
groups.

With value ``2``, a group that has no aggregate to belong to -- any match type other than
``both`` -- has its per group metrics published anyway, since otherwise nothing at all would be
reported for it.
With values ``2`` and ``3``, a group that has no aggregate to belong to -- any match type other
than ``both`` -- has its per group metrics published anyway, since otherwise nothing at all would
be reported for it.

Values ``0`` and ``1`` can produce a very large number of metrics when the match type includes the
address or port, since there is then one set per address and port rather than one per hostname.
Expand All @@ -2079,12 +2087,17 @@ Origin Server Connect Attempts
upstream had aggregation enabled, so mappings that disagree for one hostname produce an aggregate
that covers only part of it.

The reload is one-directional for the same reason given under
:ts:cv:`proxy.config.http.per_server.connection.metric_enabled`. Raising the value takes effect
as upstreams reconnect, but moving to ``2`` does not hide per group metrics that are already
published, and moving from ``1`` to ``0`` does not stop the hostname aggregates from publishing.
Reducing the number of published metrics therefore requires a restart, which matters most for
``2``, the value chosen specifically to bound that number.
A change in either direction takes effect as upstreams reconnect: a group publishes what the
new value asks for and withdraws what it does not, when that group is next rebuilt. Metrics
withdrawn this way stop appearing in :program:`traffic_ctl` output and in the other metric
consumers; they are not destroyed, and moving back republishes them with their accumulated
values intact.

The per group metrics belong to a single group, so raising the value withdraws them as that group
is rebuilt. The sums and the max are named per hostname and shared by its groups, so a group
rebuilt for a value that does not publish them only stops contributing; they are withdrawn once
no group of that hostname publishes them. Mappings that disagree for one hostname therefore
cannot hide each other's aggregate.

.. ts:cv:: CONFIG proxy.config.http.per_server.connection.metric_prefix STRING NULL
:reloadable:
Expand Down Expand Up @@ -2761,11 +2774,48 @@ Cache Control
using the newest key generation. This might be temporarily necessary
if a large cache was created by the previous version of ATS but the new
version changed the way cache keys are generated. If this is turned on,
a metric called `proxy.process.http.cache.compat_key_reads` will be
a metric called ``proxy.process.http.cache.compat_key_reads`` will be
incremented any time the compat cache lookup successfully finds the object.
You can monitor this metric and know when its safe to turn this feature off
as the cache wraps around.

Three costs come with enabling this. Every cache miss performs a second
lookup, so a tier with a low hit ratio roughly doubles its cache lookup
load for the duration. Every request that invalidates a cached copy
(``DELETE``, ``PURGE``, ``PUT``, and ``POST`` unless
:ts:cv:`proxy.config.http.cache.post_method` is enabled) issues a second
remove under the previous key, because a migrated object exists under both
keys until the old copy ages out. That remove takes the whole object under
the previous key, so anything that invalidates one variant of a resource
that varies on a request header, including a revalidation whose response
cannot be cached, also removes every other variant still held under the
previous key. Those variants are fetched from the origin again when next
requested. And an object found under the previous
key cannot be revalidated with a ``304``, because the write that would carry
the update is a create under the new key rather than an update of the old
one. When a ``GET`` needs such an object revalidated, |TS| sends the request
without conditional headers, neither its own nor the client's, even when
:ts:cv:`proxy.config.http.cache.when_to_revalidate` is ``4``. The origin
returns the full response, which is stored under the new key, and the copy
under the previous key is left to age out. The client still receives a
``304`` if its conditions match the full response. A ``HEAD`` or a range
request revalidates as usual instead, since neither response is stored:
when the origin answers ``304`` the object stays under the previous key to
be migrated by the next full ``GET``, and when it answers with a changed
object the copy under the previous key is removed.
Each object pays this once, but on a large cache the aggregate is a
bandwidth event worth sizing before enabling the setting in production.

For the same reason a plugin cannot modify such an object in place.
``TSHttpTxnUpdateCachedObject`` still returns ``TS_SUCCESS`` and the client
receives the modified headers, but they are not stored, as when an update
cannot get the cache write lock.

Objects whose path contains a ``;`` are unaffected. The previous algorithm
hashed the path and the deprecated ``;params`` segment as separate
components, which produces the same string the current algorithm produces
for such a path, so no compatibility lookup is issued for them.

.. ts:cv:: CONFIG proxy.config.http.cache.range.lookup INT 1
:overridable:

Expand Down
20 changes: 11 additions & 9 deletions doc/admin-guide/monitoring/statistics/core/http-connection.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -234,21 +234,23 @@ blocked_connection
Counter. The total number of connection attempts to the group blocked by
:ts:cv:`proxy.config.http.per_server.connection.max`. Never decreases.

For a hostname aggregate, ``<counter>`` is one of those three, each summed across the groups of that
hostname which have aggregation enabled, plus:
For a hostname aggregate there are two kinds. The *sums* are those same three counters, each added
across the groups of that hostname which have aggregation enabled, published at
:ts:cv:`metric_aggregate <proxy.config.http.per_server.connection.metric_aggregate>` ``1`` and
``3``. The *max*, published at ``1``, ``2`` and ``3``, is:

current_connection_max
current_connection.max
Gauge. The largest ``current_connection`` value among the groups of that hostname at the moment
of sampling, so the maximum rather than the sum of the groups' current counts. This is useful
because :ts:cv:`proxy.config.http.per_server.connection.max` is enforced per group rather than
per hostname, so the busiest group is what determines whether connections are about to be
blocked. Like ``current_connection`` it rises and falls with traffic and is not a high-water
mark. There is no per group ``current_connection_max``; it exists only as a hostname aggregate.
mark. There is no per group ``current_connection.max``; it exists only as a hostname aggregate.

Because :ts:cv:`proxy.config.http.per_server.connection.metric_aggregate` is overridable, a group
joins its hostname's aggregate only if the mapping that first opened that upstream had aggregation
enabled. Mappings that disagree for one hostname therefore produce an aggregate over part of it: the
sums cover a subset of the groups and ``current_connection_max`` takes its maximum over that same
sums cover a subset of the groups and ``current_connection.max`` takes its maximum over that same
subset, with nothing in the metric to indicate it. Keeping the setting uniform across the mappings
for a hostname avoids this.

Expand All @@ -261,13 +263,13 @@ Every published per server metric is recomputed periodically, currently every 5
on every connection event, so a reader sees a value up to that interval old. This is true of the
hostname aggregates and of the published per group metrics alike: those are
mirrored from the internal ones by the same periodic mechanism, not written as connections open and
close. It applies to ``current_connection_max`` too, which reports the maximum across groups as of
close. It applies to ``current_connection.max`` too, which reports the maximum across groups as of
the last sample rather than a running peak. To obtain the peak over a longer window, compute a
maximum over time from this gauge in the monitoring system.

At :ts:cv:`metric_aggregate <proxy.config.http.per_server.connection.metric_aggregate>` value ``2``
the per group metrics still exist internally, since the aggregates are computed from them, but are not
published. They can be listed with ``traffic_ctl metric match per_server --include-hidden``, which
At :ts:cv:`metric_aggregate <proxy.config.http.per_server.connection.metric_aggregate>` values
``2`` and ``3`` the per group metrics still exist internally, since the aggregates are computed from
them, but are not published. They can be listed with ``traffic_ctl metric match per_server --include-hidden``, which
reads them directly and so is not subject to the sampling delay above. That visibility is intended
for debugging and is not a stable interface: the existence, granularity and naming of the per group
metrics may change independently of the published aggregates.
Expand Down
66 changes: 66 additions & 0 deletions doc/developer-guide/internal-libraries/Metrics.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ never as a side effect of a broad query.
renamed or removed between releases without notice. Do not build monitoring on them; use the
published aggregate instead.

Enumerating metrics
===================

``for_each`` visits every listed metric of a store, in creation order:

.. code-block:: cpp

ts::Metrics::instance().for_each([](std::string_view name, ts::Metrics::MetricType type, int64_t value) {
// ...
});

This is the only way to enumerate a store. There is no public iterator, and deliberately so:
enumeration is always the whole store, so nothing can hold a cursor across changes to the store or
name a position the walk would skip. Reach a single metric by name with ``lookup`` instead.

The callback must not create a metric, which would be an attempt to grow the store from inside a
pass over it.

Derived metrics
===============

Expand Down Expand Up @@ -153,6 +171,18 @@ Adding a source that is already registered for that derived metric is a no-op, s
re-register the same source, such as one recreating an object for the same key, need not track that
itself. The ``type`` and ``op`` arguments are ignored if the derived metric already exists.

``ts::Metrics::Derived::remove_source()`` is the counterpart, for a contributor that goes away or
stops wanting the aggregate published:

.. code-block:: cpp

ts::Metrics::Derived::remove_source("proxy.process.example.total", per_thing_metric);

A derived metric is shared by its sources, so this does not unlist it while any remain. Removing the
last source leaves nothing to report, so the name is unlisted; adding a source again relists it.
Removing a source that is not registered, or naming a derived metric that does not exist, is a
no-op.

A hidden source can feed a published aggregate:

.. code-block:: cpp
Expand Down Expand Up @@ -188,6 +218,42 @@ sampling point*, not the true peak. There are two ways to arrange this, with dif

Which is appropriate depends on whether the consumer needs to aggregate over time downstream.

Unlisting a metric
==================

A metric can be taken out of the store's listing after the fact. An unlisted metric is skipped by
iteration, so it disappears from ``traffic_ctl metric match``, the JSONRPC record lookup and
``stats_over_http``, without either of those consumers needing to know about it:

.. code-block:: cpp

auto &m = ts::Metrics::instance();

m.unlist(id); // by id
m.unlist("proxy.process.example"); // or by name

m.relist(id); // put it back

The slot, the name and the atomic all survive: an unlisted number that still rings. An unlisted
metric still resolves through ``lookup``, so an exact name query, a logging field reference and
``TSStatFindName`` all continue to work, and its value may still be read and written. Creating the
same name again relists it and returns the same id with its accumulated value intact, so a metric
that comes and goes with a configuration setting costs nothing to bring back.

This exists because the decision to publish a name is otherwise made once, when the metric is first
created, and can never be revisited. Any metric whose name or publication policy depends on a
runtime changeable setting needs a way to retract a name it has already published.

.. important::

Unlisting hides; it does not free. The slot and the name remain allocated against the storage
limit below. Unlisting does not make an unbounded naming scheme safe.

.. note::

The set walked is fixed when ``for_each`` begins, so a metric created while it runs is not
visited.

Storage limits
==============

Expand Down
20 changes: 16 additions & 4 deletions doc/developer-guide/release-process/index.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,22 @@ Build
#. Check the version in ``CMakeLists.txt``. There is a ``project`` line near the
top with the version number. Make sure that is correct for the release.

#. Generate or update the CHANGELOG for the next release. ::

./tools/git/changelog.pl -o apache -r trafficserver -m X.Y.Z >
CHANGELOG-X.Y.Z
#. Generate or update the CHANGELOG for the next release. This needs
`uv <https://docs.astral.sh/uv/>`__, and ``--use-gh`` additionally needs the
`GitHub CLI <https://cli.github.com/>`__ already authenticated with
``gh auth login``. ::

uv run --project tools/changelog python tools/changelog/changelog.py \
-o apache -r trafficserver -m X.Y.Z --use-gh > CHANGELOG-X.Y.Z

Without the GitHub CLI, omit ``--use-gh`` and supply a token through the
``GH_TOKEN`` environment variable instead. A token is not optional here: an
unauthenticated run exceeds the GitHub API rate limit partway through a
release-sized milestone and exits without writing a changelog. ::

GH_TOKEN=<token> uv run --project tools/changelog \
python tools/changelog/changelog.py \
-o apache -r trafficserver -m X.Y.Z > CHANGELOG-X.Y.Z

#. Commit this file to the repository and push it to the release branch.

Expand Down
19 changes: 19 additions & 0 deletions doc/release-notes/upgrading.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ Plugins
configuration load time rather than at runtime. A configuration that was
previously accepted and failed later will now fail to load.

``ts::Metrics``, in the installed ``tsutil/Metrics.h``, no longer has an
iterator. ``Metrics::iterator``, ``begin()``, ``end()`` and ``find()`` are
removed, and enumeration is now ``Metrics::for_each(func)``, which invokes
``func(name, type, value)`` for each metric:

.. code-block:: cpp

ts::Metrics::instance().for_each([](std::string_view name, ts::Metrics::MetricType type, int64_t value) {
// ...
});

Handing out a position let a caller name a slot the store was free to change
underneath them, which is what the iterator could not be made safe against.
Reaching a single metric by name is ``lookup()``.

``Metrics::Storage::createSpan()`` and ``Metrics::rename()`` are also removed.
Spans handed out unnamed slots that only ``rename()`` could name, and
``rename()`` mutated a name that the lock free readers hand out views of.

Build
-----

Expand Down
Loading