Skip to content

Commit 498da76

Browse files
committed
[manager] add cache location lookup metrics
1 parent 6e3d187 commit 498da76

8 files changed

Lines changed: 498 additions & 26 deletions

File tree

kv_cache_manager/manager/cache_manager.cc

Lines changed: 160 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <memory>
1111
#include <optional>
1212
#include <set>
13+
#include <shared_mutex>
1314
#include <string>
1415
#include <string_view>
1516
#include <thread>
@@ -89,6 +90,82 @@ namespace kv_cache_manager {
8990
} while (0)
9091

9192
namespace {
93+
class LocationLookupMetricsGuard {
94+
public:
95+
LocationLookupMetricsGuard(MetricsRegistry *registry,
96+
std::string api_name,
97+
std::string instance_id,
98+
std::size_t request_key_count)
99+
: registry_(registry)
100+
, api_name_(std::move(api_name))
101+
, instance_id_(std::move(instance_id))
102+
, request_key_count_(request_key_count) {}
103+
104+
~LocationLookupMetricsGuard() {
105+
if (!completed_) {
106+
Complete(0, 0, 0, request_key_count_);
107+
}
108+
}
109+
110+
void SetRequestKeyCount(std::size_t count) { request_key_count_ = count; }
111+
112+
void Complete(std::size_t hit_count,
113+
std::size_t miss_count,
114+
std::size_t filtered_count,
115+
std::size_t error_count) {
116+
try {
117+
if (registry_ != nullptr) {
118+
const MetricsTags base_tags{{"api_name", api_name_}, {"instance_id", instance_id_}};
119+
++registry_->GetCounter("manager.location_lookup.requests_total", base_tags);
120+
if (request_key_count_ > 0) {
121+
registry_->GetCounter("manager.location_lookup.request_keys_total", base_tags) +=
122+
request_key_count_;
123+
const auto record = [this, &base_tags](const char *result, std::size_t count) {
124+
if (count == 0) {
125+
return;
126+
}
127+
auto tags = base_tags;
128+
tags.emplace("result", result);
129+
registry_->GetCounter("manager.location_lookup.keys_total", tags) += count;
130+
};
131+
record("hit", hit_count);
132+
record("miss", miss_count);
133+
record("filtered", filtered_count);
134+
record("error", error_count);
135+
}
136+
}
137+
} catch (...) {
138+
// Monitoring must never change the location-query result.
139+
}
140+
completed_ = true;
141+
}
142+
143+
private:
144+
MetricsRegistry *registry_;
145+
std::string api_name_;
146+
std::string instance_id_;
147+
std::size_t request_key_count_;
148+
bool completed_ = false;
149+
};
150+
151+
std::size_t CountUnmaskedKeys(const CacheManager::KeyVector &keys, const BlockMask &block_mask) {
152+
std::size_t count = 0;
153+
for (std::size_t index = 0; index < keys.size(); ++index) {
154+
if (!IsIndexInMaskRange(block_mask, index)) {
155+
++count;
156+
}
157+
}
158+
return count;
159+
}
160+
161+
std::size_t CountLocations(const CacheLocationVector &locations, bool require_location_spec = false) {
162+
return static_cast<std::size_t>(
163+
std::count_if(locations.begin(), locations.end(), [require_location_spec](const auto &location) {
164+
return location && !location->id().empty() &&
165+
(!require_location_spec || !location->location_specs().empty());
166+
}));
167+
}
168+
92169
CacheManager::KeyVector GenKeyVector(const CacheManager::TokenIdsVector &tokens, int64_t block_size) {
93170
std::vector<int64_t> block_keys;
94171
size_t total_blocks = tokens.size() / block_size;
@@ -760,22 +837,40 @@ ErrorCode CacheManager::PerformCacheLocationQuery(RequestContext *request_contex
760837
const BlockMask &block_mask,
761838
int32_t sw_size,
762839
KeyVector &query_keys,
763-
CacheLocationVector &cache_locations) const {
840+
CacheLocationVector &cache_locations,
841+
std::size_t *out_lookup_error_key_count) const {
764842
SPAN_TRACER(request_context);
765843
const std::string &trace_id = request_context->trace_id();
844+
if (out_lookup_error_key_count != nullptr) {
845+
*out_lookup_error_key_count = 0;
846+
}
766847
ErrorCode ec = EC_ERROR;
767848
if (!keys.empty()) {
768849
KVCM_METRICS_COLLECTOR_SET_METRICS(service_metrics_collector, manager, request_key_count, keys.size());
769-
ec = GetCacheLocationByQueryType(
770-
meta_searcher, request_context, instance_id, query_type, keys, block_mask, sw_size, cache_locations);
850+
ec = GetCacheLocationByQueryType(meta_searcher,
851+
request_context,
852+
instance_id,
853+
query_type,
854+
keys,
855+
block_mask,
856+
sw_size,
857+
cache_locations,
858+
out_lookup_error_key_count);
771859
} else {
772860
auto [ec_temp, block_size] = GetBlockSize(request_context, instance_id);
773861
RETURN_IF_EC_NOT_OK_WITH_LOG(WARN, ec_temp, "get block_size failed");
774862
auto gen_keys = GenKeyVector(tokens, block_size);
775863
KVCM_METRICS_COLLECTOR_SET_METRICS(service_metrics_collector, manager, request_key_count, gen_keys.size());
776864
query_keys = gen_keys;
777-
ec = GetCacheLocationByQueryType(
778-
meta_searcher, request_context, instance_id, query_type, gen_keys, block_mask, sw_size, cache_locations);
865+
ec = GetCacheLocationByQueryType(meta_searcher,
866+
request_context,
867+
instance_id,
868+
query_type,
869+
gen_keys,
870+
block_mask,
871+
sw_size,
872+
cache_locations,
873+
out_lookup_error_key_count);
779874
}
780875
return ec;
781876
}
@@ -791,9 +886,19 @@ CacheManager::GetCacheLocation(RequestContext *request_context,
791886
const std::vector<std::string> &location_spec_names) {
792887
SPAN_TRACER(request_context);
793888
const std::string &trace_id = request_context->trace_id();
889+
// Keep a valid instance alive until the dynamic metric write completes.
890+
// RemoveInstance holds the same lifecycle fence exclusively before it
891+
// purges instance-tagged series.
892+
std::shared_lock<std::shared_mutex> metrics_lifecycle_guard(metrics_lifecycle_->mut_);
794893
auto *service_metrics_collector = dynamic_cast<ServiceMetricsCollector *>(request_context->metrics_collector());
795894
auto [ec, meta_searcher] = CheckInputAndGetMetaSearcher(request_context, instance_id, keys, tokens);
796895
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(WARN, ec, CacheLocationViewVecWrapper, "check input or get meta searcher failed");
896+
if (registry_manager_->GetInstanceInfo(request_context, instance_id) == nullptr) {
897+
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(
898+
WARN, EC_INSTANCE_NOT_EXIST, CacheLocationViewVecWrapper, "instance not found");
899+
}
900+
LocationLookupMetricsGuard location_metrics(
901+
metrics_registry_.get(), "GetCacheLocation", instance_id, keys.size());
797902
if (query_type == QueryType::QT_UNSPECIFIED) {
798903
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(WARN, EC_ERROR, CacheLocationViewVecWrapper, "unknown query type");
799904
}
@@ -802,6 +907,7 @@ CacheManager::GetCacheLocation(RequestContext *request_context,
802907
: KVCM_METRICS_COLLECTOR_CHRONO_SCOPE(service_metrics_collector, ManagerPrefixMatch);
803908
CacheLocationVector cache_locations;
804909
KeyVector query_keys = keys;
910+
std::size_t lookup_error_key_count = 0;
805911
ec = PerformCacheLocationQuery(request_context,
806912
service_metrics_collector,
807913
meta_searcher,
@@ -812,8 +918,13 @@ CacheManager::GetCacheLocation(RequestContext *request_context,
812918
block_mask,
813919
sw_size,
814920
query_keys,
815-
cache_locations);
921+
cache_locations,
922+
&lookup_error_key_count);
816923
query_scope = ChronoScopeGuard{};
924+
const std::size_t lookup_key_count = query_type == QueryType::QT_PREFIX_MATCH
925+
? CountUnmaskedKeys(query_keys, block_mask)
926+
: query_keys.size();
927+
location_metrics.SetRequestKeyCount(lookup_key_count);
817928
// prefix_match_len: count actual hits (non-empty id), not total returned entries.
818929
// BatchGet/ReverseRollSW pad misses with empty CacheLocation objects.
819930
{
@@ -847,7 +958,16 @@ CacheManager::GetCacheLocation(RequestContext *request_context,
847958
query_counter += query_count;
848959
hit_counter += hit_count;
849960
}
961+
const std::size_t pre_filter_hit_count = CountLocations(cache_locations);
850962
FilterLocationSpecByName(cache_locations, location_spec_names);
963+
const std::size_t hit_count = CountLocations(cache_locations, !location_spec_names.empty());
964+
const std::size_t filtered_count = pre_filter_hit_count - hit_count;
965+
const std::size_t unresolved_count = lookup_key_count > pre_filter_hit_count
966+
? lookup_key_count - pre_filter_hit_count
967+
: 0;
968+
const std::size_t error_count = std::min(lookup_error_key_count, unresolved_count);
969+
const std::size_t miss_count = unresolved_count - error_count;
970+
location_metrics.Complete(hit_count, miss_count, filtered_count, error_count);
851971

852972
auto cache_get_event = std::make_shared<CacheGetEvent>(instance_id);
853973
cache_get_event->SetEventTriggerTime();
@@ -886,9 +1006,16 @@ CacheManager::GetCacheLocationsByBackend(RequestContext *request_context,
8861006
const std::vector<BackendSelector> &backend_selectors) {
8871007
SPAN_TRACER(request_context);
8881008
const std::string &trace_id = request_context->trace_id();
1009+
std::shared_lock<std::shared_mutex> metrics_lifecycle_guard(metrics_lifecycle_->mut_);
8891010
auto *service_metrics_collector = dynamic_cast<ServiceMetricsCollector *>(request_context->metrics_collector());
8901011
auto [ec, meta_searcher] = CheckInputAndGetMetaSearcher(request_context, instance_id, keys, tokens);
8911012
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(WARN, ec, BatchLocationsView, "check input or get meta searcher failed");
1013+
auto instance_info = registry_manager_->GetInstanceInfo(request_context, instance_id);
1014+
if (instance_info == nullptr) {
1015+
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(WARN, EC_INSTANCE_NOT_EXIST, BatchLocationsView, "instance not found");
1016+
}
1017+
LocationLookupMetricsGuard location_metrics(
1018+
metrics_registry_.get(), "GetCacheLocationsByBackend", instance_id, keys.size());
8921019
if (query_type != QueryType::QT_BATCH_GET) {
8931020
request_context->error_tracer()->AddErrorMsg("GetCacheLocationsByBackend only supports QT_BATCH_GET");
8941021
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(
@@ -915,6 +1042,8 @@ CacheManager::GetCacheLocationsByBackend(RequestContext *request_context,
9151042
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(
9161043
WARN, EC_BADARGS, BatchLocationsView, "block_mask must match the number of query keys");
9171044
}
1045+
const std::size_t lookup_key_count = CountUnmaskedKeys(query_keys, block_mask);
1046+
location_metrics.SetRequestKeyCount(lookup_key_count);
9181047

9191048
if (!location_spec_names.empty()) {
9201049
if (location_spec_names.size() != query_keys.size() ||
@@ -966,13 +1095,15 @@ CacheManager::GetCacheLocationsByBackend(RequestContext *request_context,
9661095
}
9671096

9681097
LocationsPerKey locations_per_key;
1098+
std::vector<bool> had_usable_locations;
9691099
ec = meta_searcher->BatchGetBestLocationByBackend(request_context,
9701100
query_keys,
9711101
locations_per_key,
9721102
policy.get(),
9731103
backend_selectors,
9741104
location_spec_names,
975-
block_mask);
1105+
block_mask,
1106+
&had_usable_locations);
9761107
query_scope = ChronoScopeGuard{};
9771108
// prefix_match_len: count keys with at least one hit (non-empty id).
9781109
// Miss keys have empty CacheLocation objects with no id.
@@ -990,11 +1121,6 @@ CacheManager::GetCacheLocationsByBackend(RequestContext *request_context,
9901121
}
9911122
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(WARN, ec, BatchLocationsView, "batch get multi locations failed");
9921123

993-
auto instance_info = registry_manager_->GetInstanceInfo(request_context, instance_id);
994-
if (instance_info == nullptr) {
995-
request_context->error_tracer()->AddErrorMsg("instance not found");
996-
RETURN_IF_EC_NOT_OK_WITH_TYPE_LOG(WARN, EC_INSTANCE_NOT_EXIST, BatchLocationsView, "instance not found");
997-
}
9981124
for (auto &key_locs : locations_per_key) {
9991125
FillEmptyLocationSpecs(instance_info->location_spec_infos(), key_locs);
10001126
}
@@ -1004,6 +1130,24 @@ CacheManager::GetCacheLocationsByBackend(RequestContext *request_context,
10041130
}
10051131
}
10061132

1133+
std::size_t hit_count = 0;
1134+
std::size_t filtered_count = 0;
1135+
for (std::size_t i = 0; i < locations_per_key.size(); ++i) {
1136+
if (IsIndexInMaskRange(block_mask, i)) {
1137+
continue;
1138+
}
1139+
if (CountLocations(locations_per_key[i], !location_spec_names.empty()) > 0) {
1140+
++hit_count;
1141+
} else if (i < had_usable_locations.size() && had_usable_locations[i]) {
1142+
++filtered_count;
1143+
}
1144+
}
1145+
const std::size_t classified_count = hit_count + filtered_count;
1146+
const std::size_t miss_count = lookup_key_count > classified_count
1147+
? lookup_key_count - classified_count
1148+
: 0;
1149+
location_metrics.Complete(hit_count, miss_count, filtered_count, 0);
1150+
10071151
auto cache_get_event = std::make_shared<CacheGetEvent>(instance_id);
10081152
cache_get_event->SetEventTriggerTime();
10091153
cache_get_event->SetAddtionalArgs(
@@ -4279,7 +4423,8 @@ ErrorCode CacheManager::GetCacheLocationByQueryType(MetaSearcher *meta_searcher,
42794423
const KeyVector &keys,
42804424
const BlockMask &block_mask,
42814425
int32_t sw_size,
4282-
CacheLocationVector &cache_locations) const {
4426+
CacheLocationVector &cache_locations,
4427+
std::size_t *out_prefix_error_key_count) const {
42834428
SPAN_TRACER(request_context);
42844429
const std::string &trace_id = request_context->trace_id();
42854430
auto policy = genSelectLocationPolicy(request_context, instance_id);
@@ -4293,7 +4438,8 @@ ErrorCode CacheManager::GetCacheLocationByQueryType(MetaSearcher *meta_searcher,
42934438
break;
42944439
}
42954440
case QueryType::QT_PREFIX_MATCH: {
4296-
ec = meta_searcher->PrefixMatch(request_context, keys, block_mask, cache_locations, policy.get());
4441+
ec = meta_searcher->PrefixMatch(
4442+
request_context, keys, block_mask, cache_locations, policy.get(), out_prefix_error_key_count);
42974443
break;
42984444
}
42994445
case QueryType::QT_REVERSE_ROLL_SW_MATCH: {

kv_cache_manager/manager/cache_manager.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ class CacheManager {
357357
const KeyVector &keys,
358358
const BlockMask &block_mask,
359359
int32_t sw_size,
360-
CacheLocationVector &cache_locations) const;
360+
CacheLocationVector &cache_locations,
361+
std::size_t *out_prefix_error_key_count = nullptr) const;
361362
ErrorCode PerformCacheLocationQuery(RequestContext *request_context,
362363
ServiceMetricsCollector *service_metrics_collector,
363364
MetaSearcher *meta_searcher,
@@ -368,7 +369,8 @@ class CacheManager {
368369
const BlockMask &block_mask,
369370
int32_t sw_size,
370371
KeyVector &query_keys,
371-
CacheLocationVector &cache_locations) const;
372+
CacheLocationVector &cache_locations,
373+
std::size_t *out_lookup_error_key_count = nullptr) const;
372374
std::unique_ptr<SelectLocationPolicy> genSelectLocationPolicy(RequestContext *request_context,
373375
const std::string &instance_id) const;
374376
CheckLocDataExistFunc GetCheckLocDataExistFunc(const std::string &instance_id) const;

0 commit comments

Comments
 (0)