@@ -54,13 +54,13 @@ ABSL_FLAG(string, tiered_prefix, "",
54
54
55
55
ABSL_FLAG (bool , enable_heartbeat_eviction, true ,
56
56
" Enable eviction during heartbeat when memory is under pressure." );
57
-
57
+ ABSL_FLAG (bool , enable_heartbeat_rss_eviction, true ,
58
+ " Enable eviction during heartbeat when rss memory is under pressure. Evicition based "
59
+ " on used_memory will still be enabled." );
58
60
ABSL_FLAG (double , eviction_memory_budget_threshold, 0.1 ,
59
61
" Eviction starts when the free memory (including RSS memory) drops below "
60
62
" eviction_memory_budget_threshold * max_memory_limit." );
61
-
62
63
ABSL_FLAG (bool , background_heartbeat, false , " Whether to run heartbeat as a background fiber" );
63
-
64
64
ABSL_DECLARE_FLAG (uint32_t , max_eviction_per_heartbeat);
65
65
66
66
namespace dfly {
@@ -116,46 +116,6 @@ size_t CalculateHowManyBytesToEvictOnShard(size_t global_memory_limit, size_t gl
116
116
return shard_budget < shard_memory_threshold ? (shard_memory_threshold - shard_budget) : 0 ;
117
117
}
118
118
119
- /* Calculates the number of bytes to evict based on memory and rss memory usage. */
120
- size_t CalculateEvictionBytes () {
121
- const size_t shards_count = shard_set->size ();
122
- const double eviction_memory_budget_threshold = GetFlag (FLAGS_eviction_memory_budget_threshold);
123
-
124
- size_t limit = max_memory_limit.load (memory_order_relaxed);
125
- const size_t shard_memory_budget_threshold =
126
- size_t (limit * eviction_memory_budget_threshold) / shards_count;
127
-
128
- const size_t global_used_memory = used_mem_current.load (memory_order_relaxed);
129
-
130
- // Calculate how many bytes we need to evict on this shard
131
- size_t goal_bytes =
132
- CalculateHowManyBytesToEvictOnShard (limit, global_used_memory, shard_memory_budget_threshold);
133
-
134
- // TODO: Eviction due to rss usage is not working well as it causes eviction
135
- // of to many keys untill we finally see decrease in rss. We need to improve
136
- // this logic before we enable it.
137
- /*
138
- const double rss_oom_deny_ratio = ServerState::tlocal()->rss_oom_deny_ratio;
139
- // If rss_oom_deny_ratio is set, we should evict depending on rss memory too
140
- if (rss_oom_deny_ratio > 0.0) {
141
- const size_t max_rss_memory = size_t(rss_oom_deny_ratio * max_memory_limit);
142
- // We start eviction when we have less than eviction_memory_budget_threshold * 100% of free rss
143
- memory const size_t shard_rss_memory_budget_threshold =
144
- size_t(max_rss_memory * eviction_memory_budget_threshold) / shards_count;
145
-
146
- // Calculate how much rss memory is used by all shards
147
- const size_t global_used_rss_memory = rss_mem_current.load(memory_order_relaxed);
148
-
149
- // Try to evict more bytes if we are close to the rss memory limit
150
- goal_bytes = std::max(
151
- goal_bytes, CalculateHowManyBytesToEvictOnShard(max_rss_memory, global_used_rss_memory,
152
- shard_rss_memory_budget_threshold));
153
- }
154
- */
155
-
156
- return goal_bytes;
157
- }
158
-
159
119
} // namespace
160
120
161
121
__thread EngineShard* EngineShard::shard_ = nullptr ;
@@ -265,10 +225,7 @@ bool EngineShard::DefragTaskState::CheckRequired() {
265
225
if (res == 0 ) {
266
226
// finished checking.
267
227
last_check_time = time (nullptr );
268
- if (finfo.committed != finfo.committed_golden ) {
269
- LOG_FIRST_N (ERROR, 100 ) << " committed memory computed incorrectly: " << finfo.committed
270
- << " vs " << finfo.committed_golden ;
271
- }
228
+
272
229
const double waste_threshold = GetFlag (FLAGS_mem_defrag_waste_threshold);
273
230
if (finfo.wasted > size_t (finfo.committed * waste_threshold)) {
274
231
VLOG (1 ) << " memory fragmentation issue found: " << finfo.wasted << " " << finfo.committed ;
@@ -425,6 +382,8 @@ void EngineShard::StartPeriodicHeartbeatFiber(util::ProactorBase* pb) {
425
382
return ;
426
383
}
427
384
auto heartbeat = [this ]() { Heartbeat (); };
385
+
386
+ eviction_state_.rss_eviction_enabled_ = GetFlag (FLAGS_enable_heartbeat_rss_eviction);
428
387
std::chrono::milliseconds period_ms (*cycle_ms);
429
388
430
389
fb2::Fiber::Opts fb_opts{.priority = absl::GetFlag (FLAGS_background_heartbeat)
@@ -702,6 +661,7 @@ void EngineShard::RetireExpiredAndEvict() {
702
661
DbContext db_cntx;
703
662
db_cntx.time_now_ms = GetCurrentTimeMs ();
704
663
664
+ size_t deleted_bytes = 0 ;
705
665
size_t eviction_goal = GetFlag (FLAGS_enable_heartbeat_eviction) ? CalculateEvictionBytes () : 0 ;
706
666
707
667
for (unsigned i = 0 ; i < db_slice.db_array_size (); ++i) {
@@ -713,6 +673,7 @@ void EngineShard::RetireExpiredAndEvict() {
713
673
if (!expt->Empty ()) {
714
674
DbSlice::DeleteExpiredStats stats = db_slice.DeleteExpiredStep (db_cntx, ttl_delete_target);
715
675
676
+ deleted_bytes += stats.deleted_bytes ;
716
677
eviction_goal -= std::min (eviction_goal, size_t (stats.deleted_bytes ));
717
678
counter_[TTL_TRAVERSE].IncBy (stats.traversed );
718
679
counter_[TTL_DELETE].IncBy (stats.deleted );
@@ -734,9 +695,71 @@ void EngineShard::RetireExpiredAndEvict() {
734
695
<< " bytes. Max eviction per heartbeat: "
735
696
<< GetFlag (FLAGS_max_eviction_per_heartbeat);
736
697
698
+ deleted_bytes += evicted_bytes;
737
699
eviction_goal -= std::min (eviction_goal, evicted_bytes);
738
700
}
739
701
}
702
+
703
+ eviction_state_.deleted_bytes_before_rss_update += deleted_bytes;
704
+ }
705
+
706
+ size_t EngineShard::CalculateEvictionBytes () {
707
+ const size_t shards_count = shard_set->size ();
708
+ const double eviction_memory_budget_threshold = GetFlag (FLAGS_eviction_memory_budget_threshold);
709
+
710
+ // Calculate threshold for both used_memory and rss_memory
711
+ size_t limit = max_memory_limit.load (memory_order_relaxed);
712
+ const size_t shard_memory_budget_threshold =
713
+ size_t (limit * eviction_memory_budget_threshold) / shards_count;
714
+
715
+ const size_t global_used_memory = used_mem_current.load (memory_order_relaxed);
716
+
717
+ // Calculate how many bytes we need to evict on this shard
718
+ size_t goal_bytes =
719
+ CalculateHowManyBytesToEvictOnShard (limit, global_used_memory, shard_memory_budget_threshold);
720
+
721
+ VLOG_IF_EVERY_N (1 , goal_bytes > 0 , 50 )
722
+ << " Used memory goal bytes: " << goal_bytes << " , used memory: " << global_used_memory
723
+ << " , memory limit: " << max_memory_limit;
724
+
725
+ // Check for `enable_heartbeat_rss_eviction` flag since it dynamic. And reset
726
+ // state if flag has changed.
727
+ bool rss_eviction_enabled_flag = GetFlag (FLAGS_enable_heartbeat_rss_eviction);
728
+ if (eviction_state_.rss_eviction_enabled_ != rss_eviction_enabled_flag) {
729
+ eviction_state_.global_rss_memory_at_prev_eviction =
730
+ eviction_state_.deleted_bytes_before_rss_update = 0 ;
731
+ eviction_state_.rss_eviction_enabled_ = rss_eviction_enabled_flag;
732
+ }
733
+ if (eviction_state_.rss_eviction_enabled_ ) {
734
+ // Calculate how much rss memory is used by all shards
735
+ const size_t global_used_rss_memory = rss_mem_current.load (memory_order_relaxed);
736
+ auto & global_rss_memory_at_prev_eviction = eviction_state_.global_rss_memory_at_prev_eviction ;
737
+ auto & deleted_bytes_before_rss_update = eviction_state_.deleted_bytes_before_rss_update ;
738
+ if (global_used_rss_memory < eviction_state_.global_rss_memory_at_prev_eviction ) {
739
+ auto decrease_delete_bytes_before_rss_update =
740
+ std::min (deleted_bytes_before_rss_update,
741
+ (global_rss_memory_at_prev_eviction - global_used_rss_memory) / shards_count);
742
+ VLOG_EVERY_N (1 , 50 ) << " deleted_bytes_before_rss_update: " << deleted_bytes_before_rss_update
743
+ << " decrease_delete_bytes_before_rss_update: "
744
+ << decrease_delete_bytes_before_rss_update;
745
+ deleted_bytes_before_rss_update -= decrease_delete_bytes_before_rss_update;
746
+ }
747
+
748
+ global_rss_memory_at_prev_eviction = global_used_rss_memory;
749
+
750
+ // Try to evict more bytes if we are close to the rss memory limit
751
+ const size_t rss_goal_bytes = CalculateHowManyBytesToEvictOnShard (
752
+ limit, global_used_rss_memory - deleted_bytes_before_rss_update * shards_count,
753
+ shard_memory_budget_threshold);
754
+
755
+ VLOG_IF_EVERY_N (1 , rss_goal_bytes > 0 , 50 )
756
+ << " Rss memory goal bytes: " << rss_goal_bytes
757
+ << " , rss used memory: " << global_used_rss_memory << " , rss memory limit: " << limit
758
+ << " , deleted_bytes_before_rss_update: " << deleted_bytes_before_rss_update;
759
+
760
+ goal_bytes = std::max (goal_bytes, rss_goal_bytes);
761
+ }
762
+ return goal_bytes;
740
763
}
741
764
742
765
void EngineShard::CacheStats () {
0 commit comments