Skip to content

Commit 71e92ec

Browse files
committed
add big key detection
1 parent 9018370 commit 71e92ec

30 files changed

+842
-54
lines changed

conf/pika.conf

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ default-slot-num : 1024
494494
# The value option is [yes | no]
495495
# enable-blob-garbage-collection : no
496496

497-
# the cutoff that the GC logic uses to determine which blob files should be considered old.
497+
# the cutoff that the GC logic uses to determine which blob files should be considered "old".
498498
# This parameter can be tuned to adjust the trade-off between write amplification and space amplification.
499499
# blob-garbage-collection-age-cutoff : 0.25
500500

@@ -527,6 +527,25 @@ max-rsync-parallel-num : 4
527527
# The synchronization mode of Pika primary/secondary replication is determined by ReplicationID. ReplicationID in one replication_cluster are the same
528528
# replication-id :
529529

530+
# The maximum number of big keys to output in 'info' and log output.
531+
# This controls how many big key entries are shown at most for each type.
532+
# Default: 10
533+
BIGKEYS_SHOW_LIMIT = 10
534+
535+
# The threshold for member count to trigger big key detection
536+
# Default: 10000
537+
bigkeys_member_threshold : 10000
538+
539+
# The threshold for key and value length (in bytes)
540+
# to trigger big key detection (for string type).
541+
# Default: 1048576 (1MB)
542+
bigkeys_key_value_length_threshold : 1048576
543+
544+
# The interval (in minutes) for outputting big key statistics to the log.
545+
# Interval time for scanning expired big key threads.
546+
# Default: 1
547+
# When set to 0, big key logging will be disabled.
548+
bigkeys_log_interval : 1
530549
###################
531550
## Cache Settings
532551
###################

include/pika_admin.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ class InfoCmd : public Cmd {
267267
kInfoAll,
268268
kInfoDebug,
269269
kInfoCommandStats,
270-
kInfoCache
270+
kInfoCache,
271+
kInfoBigKeys
271272
};
272273
InfoCmd(const std::string& name, int arity, uint32_t flag) : Cmd(name, arity, flag) {}
273274
void Do() override;
@@ -277,6 +278,7 @@ class InfoCmd : public Cmd {
277278
void Execute() override;
278279

279280
private:
281+
int bigkeys_limit_ = 0;
280282
InfoSection info_section_;
281283
bool rescan_ = false; // whether to rescan the keyspace
282284
bool off_ = false;
@@ -295,15 +297,19 @@ class InfoCmd : public Cmd {
295297
const static std::string kDebugSection;
296298
const static std::string kCommandStatsSection;
297299
const static std::string kCacheSection;
300+
const static std::string kBigKeysSection;
298301

299302
void DoInitial() override;
300303
void Clear() override {
301304
rescan_ = false;
302305
off_ = false;
303306
keyspace_scan_dbs_.clear();
307+
info_section_ = kInfoErr;
308+
bigkeys_limit_ = 0;
304309
}
305310

306311
void InfoServer(std::string& info);
312+
void InfoBigKeys(std::string& info);
307313
void InfoClients(std::string& info);
308314
void InfoStats(std::string& info);
309315
void InfoExecCount(std::string& info);

include/pika_conf.h

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,23 @@ class PikaConf : public pstd::BaseConf {
160160
std::shared_lock l(rwlock_);
161161
return binlog_writer_num_;
162162
}
163+
//big keys
164+
int bigkeys_show_limit() {
165+
std::shared_lock l(rwlock_);
166+
return bigkeys_show_limit_;
167+
}
168+
int bigkeys_member_threshold() {
169+
std::shared_lock l(rwlock_);
170+
return bigkeys_member_threshold_;
171+
}
172+
int bigkeys_key_value_length_threshold() {
173+
std::shared_lock l(rwlock_);
174+
return bigkeys_key_value_length_threshold_;
175+
}
176+
int bigkeys_log_interval() {
177+
std::shared_lock l(rwlock_);
178+
return bigkeys_log_interval_;
179+
}
163180
bool slotmigrate() {
164181
std::shared_lock l(rwlock_);
165182
return slotmigrate_;
@@ -729,7 +746,23 @@ class PikaConf : public pstd::BaseConf {
729746
log_net_activities_.store(false);
730747
}
731748
}
732-
749+
//big keys
750+
void SetBigkeysShowLimit(const int value) {
751+
std::lock_guard l(rwlock_);
752+
bigkeys_show_limit_ = value;
753+
}
754+
void SetBigkeysKeyValueLengthThreshold(const int value) {
755+
std::lock_guard l(rwlock_);
756+
bigkeys_key_value_length_threshold_ = value;
757+
}
758+
void SetBigkeysMemberCountThreshold(const int value) {
759+
std::lock_guard l(rwlock_);
760+
bigkeys_member_threshold_ = value;
761+
}
762+
void SetBigkeysLogInterval(const int value) {
763+
std::lock_guard l(rwlock_);
764+
bigkeys_log_interval_ = value;
765+
}
733766
// Rsync Rate limiting configuration
734767
void SetThrottleBytesPerSecond(const int value) {
735768
std::lock_guard l(rwlock_);
@@ -895,6 +928,11 @@ class PikaConf : public pstd::BaseConf {
895928
int thread_pool_size_ = 0;
896929
int slow_cmd_thread_pool_size_ = 0;
897930
int admin_thread_pool_size_ = 0;
931+
//big keys
932+
int bigkeys_show_limit_ = 10;
933+
int bigkeys_member_threshold_ = 10000;
934+
int bigkeys_key_value_length_threshold_ = 1048576;
935+
int bigkeys_log_interval_ = 60;
898936
std::unordered_set<std::string> slow_cmd_set_;
899937
// Because the exporter of Pika_exporter implements Auth authentication
900938
// with the Exporter of Pika, and the Exporter authenticates the Auth when

include/pika_db.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class DB : public std::enable_shared_from_this<DB>, public pstd::noncopyable {
128128

129129
void SetCompactRangeOptions(const bool is_canceled);
130130

131+
// Update big keys configuration
132+
void UpdateStorageBigKeysConfig(uint32_t log_interval, uint64_t member_threshold, uint64_t key_value_length_threshold, size_t show_limit);
133+
131134
std::shared_ptr<pstd::lock::LockMgr> LockMgr();
132135
/*
133136
* Cache used

include/pika_server.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ class PikaServer : public pstd::noncopyable {
145145
void DBSetMaxCacheStatisticKeys(uint32_t max_cache_statistic_keys);
146146
void DBSetSmallCompactionThreshold(uint32_t small_compaction_threshold);
147147
void DBSetSmallCompactionDurationThreshold(uint32_t small_compaction_duration_threshold);
148+
void UpdateDBBigKeysConfig();
148149
bool GetDBBinlogOffset(const std::string& db_name, BinlogOffset* boffset);
149150
pstd::Status DoSameThingEveryDB(const TaskType& type);
150151

@@ -527,6 +528,8 @@ class PikaServer : public pstd::noncopyable {
527528
void AutoDeleteExpiredDump();
528529
void AutoUpdateNetworkMetric();
529530
void PrintThreadPoolQueueStatus();
531+
void LogBigKeysInfo();
532+
void CleanExpiredBigKeys();
530533
void StatDiskUsage();
531534
int64_t GetLastSaveTime(const std::string& dump_dir);
532535

src/pika.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ int main(int argc, char* argv[]) {
211211
g_pika_rm = std::make_unique<PikaReplicaManager>();
212212
g_network_statistic = std::make_unique<net::NetworkStatistic>();
213213
g_pika_server->InitDBStruct();
214+
g_pika_server->UpdateDBBigKeysConfig();
214215
//the cmd table of g_pika_cmd_table_manager must be inited before calling PikaServer::InitStatistic(CmdTable* )
215216
g_pika_server->InitStatistic(g_pika_cmd_table_manager->GetCmdTable());
216217
auto status = g_pika_server->InitAcl();

src/pika_admin.cc

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ const std::string InfoCmd::kRocksDBSection = "rocksdb";
884884
const std::string InfoCmd::kDebugSection = "debug";
885885
const std::string InfoCmd::kCommandStatsSection = "commandstats";
886886
const std::string InfoCmd::kCacheSection = "cache";
887-
887+
const std::string InfoCmd::kBigKeysSection = "bigkeys";
888888

889889
const std::string ClientCmd::KILLTYPE_NORMAL = "normal";
890890
const std::string ClientCmd::KILLTYPE_PUBSUB = "pubsub";
@@ -910,6 +910,8 @@ void InfoCmd::DoInitial() {
910910
keyspace_scan_dbs_ = g_pika_server->GetAllDBName();
911911
} else if (strcasecmp(argv_[1].data(), kServerSection.data()) == 0) {
912912
info_section_ = kInfoServer;
913+
} else if (strcasecmp(argv_[1].data(), "bigkeys") == 0) {
914+
info_section_ = kInfoBigKeys;
913915
} else if (strcasecmp(argv_[1].data(), kClientsSection.data()) == 0) {
914916
info_section_ = kInfoClients;
915917
} else if (strcasecmp(argv_[1].data(), kStatsSection.data()) == 0) {
@@ -994,6 +996,9 @@ void InfoCmd::Do() {
994996
InfoReplication(info);
995997
info.append("\r\n");
996998
InfoKeyspace(info);
999+
info.append("\r\n");
1000+
InfoBigKeys(info);
1001+
info.append("\r\n");
9971002
break;
9981003
case kInfoAll:
9991004
InfoServer(info);
@@ -1017,6 +1022,9 @@ void InfoCmd::Do() {
10171022
InfoKeyspace(info);
10181023
info.append("\r\n");
10191024
InfoRocksDB(info);
1025+
info.append("\r\n");
1026+
InfoBigKeys(info);
1027+
info.append("\r\n");
10201028
break;
10211029
case kInfoServer:
10221030
InfoServer(info);
@@ -1054,6 +1062,9 @@ void InfoCmd::Do() {
10541062
case kInfoCache:
10551063
InfoCache(info, db_);
10561064
break;
1065+
case kInfoBigKeys:
1066+
InfoBigKeys(info);
1067+
break;
10571068
default:
10581069
// kInfoErr is nothing
10591070
break;
@@ -1094,7 +1105,21 @@ void InfoCmd::InfoServer(std::string& info) {
10941105

10951106
info.append(tmp_stream.str());
10961107
}
1097-
1108+
void InfoCmd::InfoBigKeys(std::string& info) {
1109+
std::stringstream tmp_stream;
1110+
std::shared_lock db_rwl(g_pika_server->dbs_rw_);
1111+
for (const auto& db_item : g_pika_server->dbs_) {
1112+
if (!db_item.second) {
1113+
continue;
1114+
}
1115+
std::vector<storage::BigKeyInfo> bigkeys;
1116+
db_item.second->storage()->GetBigKeyStatistics(&bigkeys);
1117+
std::string bigkey_info;
1118+
storage::FormatBigKeyStatistics(bigkeys, &bigkey_info, g_pika_conf->bigkeys_show_limit());
1119+
tmp_stream << bigkey_info;
1120+
}
1121+
info.append(tmp_stream.str());
1122+
}
10981123
void InfoCmd::InfoClients(std::string& info) {
10991124
std::stringstream tmp_stream;
11001125
tmp_stream << "# Clients"
@@ -1833,7 +1858,27 @@ void ConfigCmd::ConfigGet(std::string& ret) {
18331858
EncodeString(&config_body, "max-cache-statistic-keys");
18341859
EncodeNumber(&config_body, g_pika_conf->max_cache_statistic_keys());
18351860
}
1836-
1861+
//big keys
1862+
if (pstd::stringmatch(pattern.data(), "BIGKEYS_SHOW_LIMIT", 1)) {
1863+
elements += 2;
1864+
EncodeString(&config_body, "BIGKEYS_SHOW_LIMIT");
1865+
EncodeNumber(&config_body, g_pika_conf->bigkeys_show_limit());
1866+
}
1867+
if (pstd::stringmatch(pattern.data(), "bigkeys_member_threshold", 1)) {
1868+
elements += 2;
1869+
EncodeString(&config_body, "bigkeys_member_threshold");
1870+
EncodeNumber(&config_body, g_pika_conf->bigkeys_member_threshold());
1871+
}
1872+
if (pstd::stringmatch(pattern.data(), "bigkeys_key_value_length_threshold", 1)) {
1873+
elements += 2;
1874+
EncodeString(&config_body, "bigkeys_key_value_length_threshold");
1875+
EncodeNumber(&config_body, g_pika_conf->bigkeys_key_value_length_threshold());
1876+
}
1877+
if (pstd::stringmatch(pattern.data(), "bigkeys_log_interval", 1)) {
1878+
elements += 2;
1879+
EncodeString(&config_body, "bigkeys_log_interval");
1880+
EncodeNumber(&config_body, g_pika_conf->bigkeys_log_interval());
1881+
}
18371882
if (pstd::stringmatch(pattern.data(), "small-compaction-threshold", 1) != 0) {
18381883
elements += 2;
18391884
EncodeString(&config_body, "small-compaction-threshold");
@@ -2963,6 +3008,35 @@ void ConfigCmd::ConfigSet(std::shared_ptr<DB> db) {
29633008
}
29643009
g_pika_conf->SetMaxConnRbufSize(static_cast<int>(ival));
29653010
res_.AppendStringRaw("+OK\r\n");
3011+
//big keys
3012+
} else if (set_item == "BIGKEYS_SHOW_LIMIT") {
3013+
if (!pstd::string2int(value.data(), value.size(), &ival) || ival < 0) {
3014+
res_.AppendStringRaw("-ERR Invalid argument '" + value + "' for CONFIG SET 'BIGKEYS_SHOW_LIMIT'\r\n");
3015+
return;
3016+
}
3017+
g_pika_conf->SetBigkeysShowLimit(ival);
3018+
res_.AppendStringRaw("+OK\r\n");
3019+
} else if (set_item == "bigkeys_member_threshold") {
3020+
if (!pstd::string2int(value.data(), value.size(), &ival) || ival < 0) {
3021+
res_.AppendStringRaw("-ERR Invalid argument '" + value + "' for CONFIG SET 'bigkeys_member_threshold'\r\n");
3022+
return;
3023+
}
3024+
g_pika_conf->SetBigkeysMemberCountThreshold(ival);
3025+
res_.AppendStringRaw("+OK\r\n");
3026+
} else if (set_item == "bigkeys_key_value_length_threshold") {
3027+
if (!pstd::string2int(value.data(), value.size(), &ival) || ival < 0) {
3028+
res_.AppendStringRaw("-ERR Invalid argument '" + value + "' for CONFIG SET 'bigkeys_key_value_length_threshold'\r\n");
3029+
return;
3030+
}
3031+
g_pika_conf->SetBigkeysKeyValueLengthThreshold(ival);
3032+
res_.AppendStringRaw("+OK\r\n");
3033+
} else if (set_item == "bigkeys_log_interval") {
3034+
if (!pstd::string2int(value.data(), value.size(), &ival) || ival < 0) {
3035+
res_.AppendStringRaw("-ERR Invalid argument '" + value + "' for CONFIG SET 'bigkeys_log_interval'\r\n");
3036+
return;
3037+
}
3038+
g_pika_conf->SetBigkeysLogInterval(ival);
3039+
res_.AppendStringRaw("+OK\r\n");
29663040
} else {
29673041
res_.AppendStringRaw("-ERR Unsupported CONFIG parameter: " + set_item + "\r\n");
29683042
}

src/pika_conf.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,22 @@ int PikaConf::Load() {
6161
if (root_connection_num_ < 0) {
6262
root_connection_num_ = 2;
6363
}
64-
64+
GetConfInt("bigkeys_show_limit", &bigkeys_show_limit_);
65+
if (bigkeys_show_limit_ <= 0) {
66+
bigkeys_show_limit_ = 10;
67+
}
68+
GetConfInt("bigkeys_key_value_length_threshold", &bigkeys_key_value_length_threshold_);
69+
if (bigkeys_key_value_length_threshold_ <= 0) {
70+
bigkeys_key_value_length_threshold_ = 1048576;
71+
}
72+
GetConfInt("bigkeys_member_threshold", &bigkeys_member_threshold_);
73+
if (bigkeys_member_threshold_ <= 0) {
74+
bigkeys_member_threshold_ = 10000;
75+
}
76+
GetConfInt("bigkeys_log_interval", &bigkeys_log_interval_);
77+
if (bigkeys_log_interval_ < 0) {
78+
bigkeys_log_interval_ = 1;
79+
}
6580
std::string swe;
6681
GetConfStr("slowlog-write-errorlog", &swe);
6782
slowlog_write_errorlog_.store(swe == "yes" ? true : false);
@@ -805,6 +820,11 @@ int PikaConf::ConfigRewrite() {
805820
SetConfInt64("thread-migrate-keys-num", thread_migrate_keys_num_);
806821
// slaveof config item is special
807822
SetConfStr("slaveof", slaveof_);
823+
//big keys
824+
SetConfInt("bigkeys_show_limit", bigkeys_show_limit_);
825+
SetConfInt("bigkeys_key_value_length_threshold", bigkeys_key_value_length_threshold_);
826+
SetConfInt("bigkeys_member_threshold", bigkeys_member_threshold_);
827+
SetConfInt("bigkeys_log_interval", bigkeys_log_interval_);
808828
// cache config
809829
SetConfStr("cache-index-and-filter-blocks", cache_index_and_filter_blocks_ ? "yes" : "no");
810830
SetConfInt("cache-model", cache_mode_);

src/pika_db.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ void DB::SetCompactRangeOptions(const bool is_canceled) {
194194
storage_->SetCompactRangeOptions(is_canceled);
195195
}
196196

197+
void DB::UpdateStorageBigKeysConfig(uint32_t log_interval, uint64_t member_threshold, uint64_t key_value_length_threshold, size_t show_limit) {
198+
if (!opened_) {
199+
return;
200+
}
201+
storage_->UpdateBigKeysConfig(log_interval, member_threshold, key_value_length_threshold, show_limit);
202+
}
203+
197204
DisplayCacheInfo DB::GetCacheInfo() {
198205
std::lock_guard l(cache_info_rwlock_);
199206
return cache_info_;

0 commit comments

Comments
 (0)