@@ -251,6 +251,16 @@ inline CommandId::Handler3 HandlerFunc(ServerFamily* se, EngineFunc f) {
251
251
return [=](CmdArgList args, const CommandContext& cntx) { return (se->*f)(args, cntx); };
252
252
}
253
253
254
+ // Captured memory peaks
255
+ struct {
256
+ std::atomic<size_t > used = 0 ;
257
+ std::atomic<size_t > rss = 0 ;
258
+ } glob_memory_peaks;
259
+
260
+ size_t FetchRssMemory (const io::StatusData& sdata) {
261
+ return sdata.vm_rss + sdata.hugetlb_pages ;
262
+ }
263
+
254
264
using CI = CommandId;
255
265
256
266
struct CmdArgListFormatter {
@@ -670,11 +680,11 @@ bool ReadProcStats(io::StatusData* sdata) {
670
680
return false ;
671
681
}
672
682
673
- size_t total_rss = FetchRssMemory (sdata_res. value () );
683
+ size_t total_rss = FetchRssMemory (* sdata_res);
674
684
rss_mem_current.store (total_rss, memory_order_relaxed);
675
- if (rss_mem_peak. load (memory_order_relaxed) < total_rss) {
676
- rss_mem_peak .store (total_rss, memory_order_relaxed);
677
- }
685
+ if (total_rss > glob_memory_peaks. rss . load (memory_order_relaxed))
686
+ glob_memory_peaks. rss .store (total_rss, memory_order_relaxed);
687
+
678
688
*sdata = *sdata_res;
679
689
return true ;
680
690
}
@@ -1028,51 +1038,35 @@ void ServerFamily::Shutdown() {
1028
1038
}
1029
1039
1030
1040
bool ServerFamily::HasPrivilegedInterface () {
1031
- for (auto * listener : listeners_) {
1032
- if (listener->IsPrivilegedInterface ()) {
1033
- return true ;
1034
- }
1035
- }
1036
- return false ;
1041
+ return any_of (listeners_.begin (), listeners_.end (),
1042
+ [](auto * l) { return l->IsPrivilegedInterface (); });
1037
1043
}
1038
1044
1039
1045
void ServerFamily::UpdateMemoryGlobalStats () {
1040
- ShardId sid = EngineShard::tlocal ()->shard_id ();
1041
- if (sid != 0 ) { // This function is executed periodicaly on all shards. To ensure the logic
1042
- // bellow runs only on one shard we return is the shard is not 0.
1046
+ // Called from all shards, but one updates global stats below
1047
+ if (EngineShard::tlocal ()->shard_id () > 0 )
1043
1048
return ;
1044
- }
1045
1049
1050
+ // Update used memory peak
1046
1051
uint64_t mem_current = used_mem_current.load (std::memory_order_relaxed);
1047
- if (mem_current > used_mem_peak.load (memory_order_relaxed)) {
1048
- used_mem_peak.store (mem_current, memory_order_relaxed);
1049
- }
1052
+ if (mem_current > glob_memory_peaks.used .load (memory_order_relaxed))
1053
+ glob_memory_peaks.used .store (mem_current, memory_order_relaxed);
1050
1054
1051
1055
io::StatusData status_data;
1052
- bool success = ReadProcStats (&status_data);
1056
+ bool success = ReadProcStats (&status_data); // updates glob_memory_peaks.rss
1053
1057
if (!success)
1054
1058
return ;
1055
1059
1056
1060
size_t total_rss = FetchRssMemory (status_data);
1061
+
1062
+ // Decide on stopping or accepting new connections based on oom deny ratio
1057
1063
double rss_oom_deny_ratio = ServerState::tlocal ()->rss_oom_deny_ratio ;
1058
1064
if (rss_oom_deny_ratio > 0 ) {
1059
1065
size_t memory_limit = max_memory_limit * rss_oom_deny_ratio;
1060
- if (total_rss > memory_limit && accepting_connections_ && HasPrivilegedInterface ()) {
1061
- for (auto * listener : listeners_) {
1062
- if (!listener->IsPrivilegedInterface ()) {
1063
- listener->socket ()->proactor ()->Await ([listener]() { listener->pause_accepting (); });
1064
- }
1065
- }
1066
- accepting_connections_ = false ;
1067
-
1068
- } else if (total_rss < memory_limit && !accepting_connections_) {
1069
- for (auto * listener : listeners_) {
1070
- if (!listener->IsPrivilegedInterface ()) {
1071
- listener->socket ()->proactor ()->Await ([listener]() { listener->resume_accepting (); });
1072
- }
1073
- }
1074
- accepting_connections_ = true ;
1075
- }
1066
+ if (total_rss > memory_limit && accepting_connections_ && HasPrivilegedInterface ())
1067
+ ChangeConnectionAccept (false );
1068
+ else if (total_rss < memory_limit && !accepting_connections_)
1069
+ ChangeConnectionAccept (true );
1076
1070
}
1077
1071
}
1078
1072
@@ -1409,8 +1403,8 @@ void PrintPrometheusMetrics(uint64_t uptime, const Metrics& m, DflyCmd* dfly_cmd
1409
1403
bool success = ReadProcStats (&sdata);
1410
1404
AppendMetricWithoutLabels (" memory_used_bytes" , " " , m.heap_used_bytes , MetricType::GAUGE,
1411
1405
&resp->body ());
1412
- AppendMetricWithoutLabels (" memory_used_peak_bytes" , " " , used_mem_peak. load (memory_order_relaxed) ,
1413
- MetricType::GAUGE, &resp->body ());
1406
+ AppendMetricWithoutLabels (" memory_used_peak_bytes" , " " , m. used_mem_peak , MetricType::GAUGE ,
1407
+ &resp->body ());
1414
1408
AppendMetricWithoutLabels (" memory_fiberstack_vms_bytes" ,
1415
1409
" virtual memory size used by all the fibers" , m.worker_fiber_stack_size ,
1416
1410
MetricType::GAUGE, &resp->body ());
@@ -2061,6 +2055,14 @@ void ServerFamily::ClientUnPauseCmd(CmdArgList args, SinkReplyBuilder* builder)
2061
2055
builder->SendOk ();
2062
2056
}
2063
2057
2058
+ void ServerFamily::ChangeConnectionAccept (bool accept) {
2059
+ DCHECK_NE (accept, accepting_connections_);
2060
+ auto h = accept ? &ListenerInterface::resume_accepting : &ListenerInterface::pause_accepting;
2061
+ for (auto * listener : GetNonPriviligedListeners ())
2062
+ listener->socket ()->proactor ()->Await ([listener, h]() { (listener->*h)(); });
2063
+ accepting_connections_ = accept;
2064
+ }
2065
+
2064
2066
void ClientHelp (SinkReplyBuilder* builder) {
2065
2067
string_view help_arr[] = {
2066
2068
" CLIENT <subcommand> [<arg> [value] [opt] ...]. Subcommands are:" ,
@@ -2452,13 +2454,19 @@ Metrics ServerFamily::GetMetrics(Namespace* ns) const {
2452
2454
2453
2455
// Update peak stats. We rely on the fact that GetMetrics is called frequently enough to
2454
2456
// update peak_stats_ from it.
2455
- util::fb2::LockGuard lk{peak_stats_mu_};
2456
- UpdateMax (&peak_stats_.conn_dispatch_queue_bytes ,
2457
- result.facade_stats .conn_stats .dispatch_queue_bytes );
2458
- UpdateMax (&peak_stats_.conn_read_buf_capacity , result.facade_stats .conn_stats .read_buf_capacity );
2457
+ {
2458
+ util::fb2::LockGuard lk{peak_stats_mu_};
2459
+ UpdateMax (&peak_stats_.conn_dispatch_queue_bytes ,
2460
+ result.facade_stats .conn_stats .dispatch_queue_bytes );
2461
+ UpdateMax (&peak_stats_.conn_read_buf_capacity ,
2462
+ result.facade_stats .conn_stats .read_buf_capacity );
2463
+ result.peak_stats = peak_stats_;
2464
+ }
2459
2465
2460
2466
result.peak_stats = peak_stats_;
2461
2467
result.cmd_latency_map = service_.mutable_registry ()->LatencyMap ();
2468
+ result.used_mem_peak = glob_memory_peaks.used .load (memory_order_relaxed);
2469
+ result.used_mem_rss_peak = glob_memory_peaks.rss .load (memory_order_relaxed);
2462
2470
2463
2471
uint64_t delta_ms = (absl::GetCurrentTimeNanos () - start) / 1'000'000 ;
2464
2472
if (delta_ms > 30 ) {
@@ -2547,9 +2555,8 @@ string ServerFamily::FormatInfoMetrics(const Metrics& m, std::string_view sectio
2547
2555
auto add_mem_info = [&] {
2548
2556
append (" used_memory" , m.heap_used_bytes );
2549
2557
append (" used_memory_human" , HumanReadableNumBytes (m.heap_used_bytes ));
2550
- const auto ump = used_mem_peak.load (memory_order_relaxed);
2551
- append (" used_memory_peak" , ump);
2552
- append (" used_memory_peak_human" , HumanReadableNumBytes (ump));
2558
+ append (" used_memory_peak" , m.used_mem_peak );
2559
+ append (" used_memory_peak_human" , HumanReadableNumBytes (m.used_mem_peak ));
2553
2560
2554
2561
// Virtual memory size, upper bound estimation on the RSS memory used by the fiber stacks.
2555
2562
append (" fibers_stack_vms" , m.worker_fiber_stack_size );
@@ -2562,7 +2569,7 @@ string ServerFamily::FormatInfoMetrics(const Metrics& m, std::string_view sectio
2562
2569
append (" used_memory_rss" , rss);
2563
2570
append (" used_memory_rss_human" , HumanReadableNumBytes (rss));
2564
2571
}
2565
- append (" used_memory_peak_rss" , rss_mem_peak .load (memory_order_relaxed));
2572
+ append (" used_memory_peak_rss" , glob_memory_peaks. used .load (memory_order_relaxed));
2566
2573
2567
2574
append (" maxmemory" , max_memory_limit);
2568
2575
append (" maxmemory_human" , HumanReadableNumBytes (max_memory_limit));
0 commit comments