Skip to content

Commit 8a18ed6

Browse files
committed
refactor: Optimize connection pool
1 parent 42d8c82 commit 8a18ed6

1 file changed

Lines changed: 72 additions & 11 deletions

File tree

backend/apps/db/db.py

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
from common.core.config import settings
3636
import sqlglot
3737
from sqlglot import expressions as exp
38-
from sqlalchemy.pool import NullPool
3938
from pyhive import hive
4039

4140
try:
@@ -144,37 +143,49 @@ def get_engine(ds: CoreDatasource, timeout: int = 0) -> Engine:
144143
if timeout > 0:
145144
conf.timeout = timeout
146145

146+
db_config = {
147+
'pool_size': conf.poolSize if conf.poolSize else 5,
148+
'max_overflow': 20,
149+
'pool_recycle': 3600
150+
}
151+
147152
if equals_ignore_case(ds.type, "pg"):
148153
if conf.dbSchema is not None and conf.dbSchema != "":
149154
engine = create_engine(get_uri(ds),
150155
connect_args={"options": f"-c search_path={urllib.parse.quote(conf.dbSchema)}",
151-
"connect_timeout": conf.timeout}, poolclass=NullPool)
156+
"connect_timeout": conf.timeout}, **db_config)
152157
else:
153-
engine = create_engine(get_uri(ds), connect_args={"connect_timeout": conf.timeout}, poolclass=NullPool)
158+
engine = create_engine(get_uri(ds), connect_args={"connect_timeout": conf.timeout}, **db_config)
154159
elif equals_ignore_case(ds.type, 'sqlServer'):
155160
engine = create_engine('mssql+pymssql://', creator=lambda: get_origin_connect(ds.type, conf),
156-
poolclass=NullPool)
161+
**db_config)
157162
elif equals_ignore_case(ds.type, 'oracle'):
158-
engine = create_engine(get_uri(ds), poolclass=NullPool)
163+
engine = create_engine(get_uri(ds), **db_config)
159164
elif equals_ignore_case(ds.type, 'mysql'): # mysql
160165
ssl_mode = {"require": True} if conf.ssl else None
161166
engine = create_engine(get_uri(ds), connect_args={"connect_timeout": conf.timeout, "ssl": ssl_mode},
162-
poolclass=NullPool)
167+
**db_config)
163168
else: # ck
164-
engine = create_engine(get_uri(ds), connect_args={"connect_timeout": conf.timeout}, poolclass=NullPool)
169+
engine = create_engine(get_uri(ds), connect_args={"connect_timeout": conf.timeout}, **db_config)
165170
return engine
166171

167172

173+
def get_connection(ds: CoreDatasource | AssistantOutDsSchema, db_config):
174+
pass
175+
176+
168177
def get_session(ds: CoreDatasource | AssistantOutDsSchema):
169178
# engine = get_engine(ds) if isinstance(ds, CoreDatasource) else get_ds_engine(ds)
170179
if isinstance(ds, AssistantOutDsSchema):
171180
out_conf = get_out_ds_conf(ds, 30)
172181
ds.configuration = out_conf
173182

174-
engine = get_engine(ds)
175-
session_maker = sessionmaker(bind=engine)
176-
session = session_maker()
177-
return session
183+
# engine = get_engine(ds)
184+
# session_maker = sessionmaker(bind=engine)
185+
186+
# get session from pool
187+
session = pool_manager.get_pool(ds=ds, **{})
188+
return session()
178189

179190

180191
def check_connection(trans: Optional[Trans], ds: CoreDatasource | AssistantOutDsSchema, is_raise: bool = False):
@@ -992,3 +1003,53 @@ def checkParams(extraParams: str, illegalParams: List[str]):
9921003
k, v = kv.split('=')
9931004
if k in illegalParams:
9941005
raise HTTPException(status_code=500, detail=f'Illegal Parameter: {k}')
1006+
1007+
1008+
import threading
1009+
from collections import OrderedDict
1010+
1011+
1012+
class ConnectionPoolManager:
1013+
def __init__(self, max_pools=500):
1014+
"""
1015+
init
1016+
:param max_pools: max pool
1017+
"""
1018+
self.max_pools = max_pools
1019+
self._pools = OrderedDict() # 使用有序字典实现 LRU
1020+
self._lock = threading.Lock() # 保证多线程安全
1021+
1022+
def get_pool(self, ds: CoreDatasource | AssistantOutDsSchema, **db_config):
1023+
"""
1024+
get connection pool(lazy load + LRU update)
1025+
"""
1026+
with self._lock:
1027+
if ds.id:
1028+
# 1. 如果连接池已存在,将其移动到字典末尾(标记为最近使用)
1029+
if ds.id in self._pools:
1030+
self._pools.move_to_end(ds.id)
1031+
print(f"[LRU] return: {ds.id}")
1032+
return self._pools[ds.id]
1033+
1034+
# 2. 如果连接池不存在,检查是否达到上限,若达到则淘汰最久未使用的(字典头部)
1035+
if len(self._pools) >= self.max_pools:
1036+
oldest_id, oldest_pool = self._pools.popitem(last=False)
1037+
oldest_pool.close() # 安全关闭被驱逐的连接池
1038+
print(f"[LRU] remove oldest: {oldest_id}")
1039+
1040+
# 3. 创建新连接池并放入字典末尾
1041+
engine = get_engine(ds)
1042+
new_pool = sessionmaker(bind=engine)
1043+
self._pools[ds.id] = new_pool
1044+
print(f"[LRU] create: {ds.id}")
1045+
return new_pool
1046+
1047+
def close_all(self):
1048+
"""stop"""
1049+
with self._lock:
1050+
for pool in self._pools.values():
1051+
pool.close()
1052+
self._pools.clear()
1053+
1054+
1055+
pool_manager = ConnectionPoolManager(max_pools=500)

0 commit comments

Comments
 (0)