[CP][Bugfix][OBKV]fix session pool hold too much memory when login frequently

This commit is contained in:
WeiXinChan
2024-01-17 08:43:54 +00:00
committed by ob-robot
parent e8d0e454bf
commit 9002e5b34d
3 changed files with 23 additions and 13 deletions

View File

@ -33,7 +33,7 @@ int ObTableApiSessPoolMgr::mtl_init(ObTableApiSessPoolMgr *&mgr)
/* /*
start tableapi retired session task start tableapi retired session task
- 60 second interval - 5 second interval
- repeated - repeated
*/ */
int ObTableApiSessPoolMgr::start() int ObTableApiSessPoolMgr::start()
@ -45,7 +45,7 @@ int ObTableApiSessPoolMgr::start()
LOG_WARN("table api session pool mgr isn't inited", K(ret)); LOG_WARN("table api session pool mgr isn't inited", K(ret));
} else if (OB_FAIL(TG_SCHEDULE(MTL(omt::ObSharedTimer*)->get_tg_id(), } else if (OB_FAIL(TG_SCHEDULE(MTL(omt::ObSharedTimer*)->get_tg_id(),
elimination_task_, elimination_task_,
ELIMINATE_SESSION_DELAY/* 60s */, ELIMINATE_SESSION_DELAY/* 5s */,
true/* repeat */))) { true/* repeat */))) {
LOG_WARN("failed to schedule tableapi retired session task", K(ret)); LOG_WARN("failed to schedule tableapi retired session task", K(ret));
} else { } else {
@ -377,7 +377,7 @@ int ObTableApiSessPool::move_node_to_retired_list(ObTableApiSessNode *node)
1. remove session val in free_list. 1. remove session val in free_list.
2. remove session node from retired_nodes_ when node is empty. 2. remove session node from retired_nodes_ when node is empty.
3. free node memory. 3. free node memory.
4. delete 1000 session nodes per times 4. delete 2000 session nodes per times
*/ */
int ObTableApiSessPool::evict_retired_sess() int ObTableApiSessPool::evict_retired_sess()
{ {
@ -387,7 +387,7 @@ int ObTableApiSessPool::evict_retired_sess()
ObLockGuard<ObSpinLock> guard(retired_nodes_lock_); // lock retired_nodes_ ObLockGuard<ObSpinLock> guard(retired_nodes_lock_); // lock retired_nodes_
DLIST_FOREACH_REMOVESAFE_X(node, retired_nodes_, delete_count < BACKCROUND_TASK_DELETE_SESS_NUM) { DLIST_FOREACH_REMOVESAFE_X(node, retired_nodes_, delete_count < BACKCROUND_TASK_DELETE_SESS_NUM) {
if (cur_time - node->get_last_active_ts() < SESS_RETIRE_TIME) { if (cur_time - node->get_last_active_ts() < SESS_UPDATE_TIME_INTERVAL) {
// do nothing, this node maybe is from ObTableApiSessNodeReplaceOp, some threads maybe is using it. // do nothing, this node maybe is from ObTableApiSessNodeReplaceOp, some threads maybe is using it.
// we remove it next retire task. // we remove it next retire task.
} else if (OB_FAIL(node->remove_unused_sess())) { } else if (OB_FAIL(node->remove_unused_sess())) {
@ -545,23 +545,31 @@ int ObTableApiSessPool::create_and_add_node_safe(ObTableApiCredential &credentia
/* /*
1. only call in login 1. only call in login
2. move old to retired list when node exist, create new node otherwise. 2. move old to retired list when node exist, create new node otherwise.
3. if the update interval is less than 5 seconds, ignore this update.
*/ */
int ObTableApiSessPool::update_sess(ObTableApiCredential &credential) int ObTableApiSessPool::update_sess(ObTableApiCredential &credential)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
ObTableApiSessNode *node = nullptr; ObTableApiSessNode *node = nullptr;
const uint64_t key = credential.hash_val_; const uint64_t key = credential.hash_val_;
int64_t cur_time = ObTimeUtility::current_time();
if (OB_FAIL(get_sess_node(key, node))) { if (OB_FAIL(get_sess_node(key, node))) {
if (OB_HASH_NOT_EXIST == ret) { // not exist, create if (OB_HASH_NOT_EXIST == ret) { // not exist, create
if (OB_FAIL(create_and_add_node_safe(credential))) { if (OB_FAIL(create_and_add_node_safe(credential))) {
LOG_WARN("fail to create and add node", K(ret), K(credential)); LOG_WARN("fail to create and add node", K(ret), K(credential));
} else {
ATOMIC_STORE(&last_update_ts_, cur_time);
} }
} else { } else {
LOG_WARN("fail to get session node", K(ret), K(key)); LOG_WARN("fail to get session node", K(ret), K(key));
} }
} else if (cur_time - last_update_ts_ < SESS_UPDATE_TIME_INTERVAL) {
// if the update interval is less than 5 seconds, ignore this update.
} else if (OB_FAIL(replace_sess_node_safe(credential))) { // exist, create and replace old node } else if (OB_FAIL(replace_sess_node_safe(credential))) { // exist, create and replace old node
LOG_WARN("fail to replace session node", K(ret), K(credential)); LOG_WARN("fail to replace session node", K(ret), K(credential));
} else {
ATOMIC_STORE(&last_update_ts_, cur_time);
} }
return ret; return ret;

View File

@ -70,7 +70,7 @@ private:
int create_session_pool_safe(); int create_session_pool_safe();
int create_session_pool_unsafe(); int create_session_pool_unsafe();
private: private:
static const int64_t ELIMINATE_SESSION_DELAY = 60 * 1000 * 1000; // 60s static const int64_t ELIMINATE_SESSION_DELAY = 5 * 1000 * 1000; // 5s
bool is_inited_; bool is_inited_;
common::ObArenaAllocator allocator_; common::ObArenaAllocator allocator_;
ObTableApiSessPool *pool_; ObTableApiSessPool *pool_;
@ -87,13 +87,15 @@ class ObTableApiSessPool final
public: public:
// key is ObTableApiCredential.hash_val_ // key is ObTableApiCredential.hash_val_
typedef common::hash::ObHashMap<uint64_t, ObTableApiSessNode*> CacheKeyNodeMap; typedef common::hash::ObHashMap<uint64_t, ObTableApiSessNode*> CacheKeyNodeMap;
static const int64_t SESS_POOL_DEFAULT_BUCKET_NUM = 10; // 取决于客户端登录的用户数量 static const int64_t SESS_POOL_DEFAULT_BUCKET_NUM = 10; // default user number
static const int64_t SESS_RETIRE_TIME = 300 * 1000000; // 超过300s未被访问的session会被标记淘汰 static const int64_t SESS_RETIRE_TIME = 300 * 1000 * 1000; // marked as retired more than 300 seconds are not accessed
static const int64_t BACKCROUND_TASK_DELETE_SESS_NUM = 1000; // 后台任务每次删除淘汰的session node数量 static const int64_t BACKCROUND_TASK_DELETE_SESS_NUM = 2000; // number of eliminated session nodes in background task per time
static const int64_t SESS_UPDATE_TIME_INTERVAL = 5 * 1000 * 1000; // the update interval cannot exceed 5 seconds
public: public:
explicit ObTableApiSessPool() explicit ObTableApiSessPool()
: allocator_("TbSessPool", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()), : allocator_("TbSessPool", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()),
is_inited_(false) is_inited_(false),
last_update_ts_(0)
{} {}
~ObTableApiSessPool() { destroy(); }; ~ObTableApiSessPool() { destroy(); };
TO_STRING_KV(K_(is_inited), TO_STRING_KV(K_(is_inited),
@ -120,6 +122,7 @@ private:
// 前台login时、后台淘汰时都会操作retired_nodes_,因此需要加锁 // 前台login时、后台淘汰时都会操作retired_nodes_,因此需要加锁
common::ObDList<ObTableApiSessNode> retired_nodes_; common::ObDList<ObTableApiSessNode> retired_nodes_;
ObSpinLock retired_nodes_lock_; // for lock retired_nodes_ ObSpinLock retired_nodes_lock_; // for lock retired_nodes_
int64_t last_update_ts_;
private: private:
DISALLOW_COPY_AND_ASSIGN(ObTableApiSessPool); DISALLOW_COPY_AND_ASSIGN(ObTableApiSessPool);
}; };

View File

@ -170,8 +170,7 @@ TEST_F(TestTableSessPool, mgr_update_session)
ASSERT_NE(nullptr, mgr->pool_); ASSERT_NE(nullptr, mgr->pool_);
ASSERT_TRUE(mgr->pool_->is_inited_); ASSERT_TRUE(mgr->pool_->is_inited_);
ASSERT_EQ(1, mgr->pool_->key_node_map_.size()); ASSERT_EQ(1, mgr->pool_->key_node_map_.size());
ASSERT_EQ(1, mgr->pool_->retired_nodes_.size_); ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_);
ASSERT_EQ(node, mgr->pool_->retired_nodes_.get_last());
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->hash_val_, node)); ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->hash_val_, node));
ASSERT_NE(nullptr, node); ASSERT_NE(nullptr, node);
ASSERT_TRUE(node->sess_lists_.free_list_.is_empty()); ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());
@ -184,7 +183,7 @@ TEST_F(TestTableSessPool, mgr_update_session)
ASSERT_NE(nullptr, mgr->pool_); ASSERT_NE(nullptr, mgr->pool_);
ASSERT_TRUE(mgr->pool_->is_inited_); ASSERT_TRUE(mgr->pool_->is_inited_);
ASSERT_EQ(2, mgr->pool_->key_node_map_.size()); ASSERT_EQ(2, mgr->pool_->key_node_map_.size());
ASSERT_EQ(1, mgr->pool_->retired_nodes_.size_); ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_);
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->hash_val_, node)); ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->hash_val_, node));
ASSERT_NE(nullptr, node); ASSERT_NE(nullptr, node);
ASSERT_TRUE(node->sess_lists_.free_list_.is_empty()); ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());