A cache key needs a version or you cannot ship a change

Changing the shape of a cached value makes every existing entry wrong, and there is no way to clear them selectively without knowing every key that exists.

private const SCHEMA = 'v3';

private function key(int $id): string
{
    return sprintf('orders:%s:%d:total', self::SCHEMA, $id);
}

// bumping the constant orphans every old entry, which then expires
// on its own. no flush, no coordination, no stale reads.

A full flush is the alternative and it is a stampede by another name — every key gone at once on a busy system. Versioning in the key means the change is safe during a rolling release, where old and new instances run simultaneously and each reads its own entries. The orphaned entries occupy memory until they expire, which is the small cost and is the reason to have an eviction policy configured.