mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-10 21:39:02 +08:00
Perf: Increase database connection pool size (#7559)
### What problem does this PR solve? 1. The MySQL instance is configured with max_connections=1000, but our connection pool was limited to max_connections: 100. This mismatch caused connection pool exhaustion during performance testing. 2. Increase stale_timeout to resolve #6548 ### Type of change - [x] Performance Improvement
This commit is contained in:
parent
5b626870d0
commit
6bd7d572ec
@ -18,57 +18,57 @@ from datetime import datetime
|
|||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
from api.db.db_models import DB
|
from api.db.db_models import DB
|
||||||
from api.utils import datetime_format, current_timestamp, get_uuid
|
from api.utils import current_timestamp, datetime_format, get_uuid
|
||||||
|
|
||||||
|
|
||||||
class CommonService:
|
class CommonService:
|
||||||
"""Base service class that provides common database operations.
|
"""Base service class that provides common database operations.
|
||||||
|
|
||||||
This class serves as a foundation for all service classes in the application,
|
This class serves as a foundation for all service classes in the application,
|
||||||
implementing standard CRUD operations and common database query patterns.
|
implementing standard CRUD operations and common database query patterns.
|
||||||
It uses the Peewee ORM for database interactions and provides a consistent
|
It uses the Peewee ORM for database interactions and provides a consistent
|
||||||
interface for database operations across all derived service classes.
|
interface for database operations across all derived service classes.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
model: The Peewee model class that this service operates on. Must be set by subclasses.
|
model: The Peewee model class that this service operates on. Must be set by subclasses.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = None
|
model = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def query(cls, cols=None, reverse=None, order_by=None, **kwargs):
|
def query(cls, cols=None, reverse=None, order_by=None, **kwargs):
|
||||||
"""Execute a database query with optional column selection and ordering.
|
"""Execute a database query with optional column selection and ordering.
|
||||||
|
|
||||||
This method provides a flexible way to query the database with various filters
|
This method provides a flexible way to query the database with various filters
|
||||||
and sorting options. It supports column selection, sort order control, and
|
and sorting options. It supports column selection, sort order control, and
|
||||||
additional filter conditions.
|
additional filter conditions.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
cols (list, optional): List of column names to select. If None, selects all columns.
|
cols (list, optional): List of column names to select. If None, selects all columns.
|
||||||
reverse (bool, optional): If True, sorts in descending order. If False, sorts in ascending order.
|
reverse (bool, optional): If True, sorts in descending order. If False, sorts in ascending order.
|
||||||
order_by (str, optional): Column name to sort results by.
|
order_by (str, optional): Column name to sort results by.
|
||||||
**kwargs: Additional filter conditions passed as keyword arguments.
|
**kwargs: Additional filter conditions passed as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
peewee.ModelSelect: A query result containing matching records.
|
peewee.ModelSelect: A query result containing matching records.
|
||||||
"""
|
"""
|
||||||
return cls.model.query(cols=cols, reverse=reverse,
|
return cls.model.query(cols=cols, reverse=reverse, order_by=order_by, **kwargs)
|
||||||
order_by=order_by, **kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def get_all(cls, cols=None, reverse=None, order_by=None):
|
def get_all(cls, cols=None, reverse=None, order_by=None):
|
||||||
"""Retrieve all records from the database with optional column selection and ordering.
|
"""Retrieve all records from the database with optional column selection and ordering.
|
||||||
|
|
||||||
This method fetches all records from the model's table with support for
|
This method fetches all records from the model's table with support for
|
||||||
column selection and result ordering. If no order_by is specified and reverse
|
column selection and result ordering. If no order_by is specified and reverse
|
||||||
is True, it defaults to ordering by create_time.
|
is True, it defaults to ordering by create_time.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
cols (list, optional): List of column names to select. If None, selects all columns.
|
cols (list, optional): List of column names to select. If None, selects all columns.
|
||||||
reverse (bool, optional): If True, sorts in descending order. If False, sorts in ascending order.
|
reverse (bool, optional): If True, sorts in descending order. If False, sorts in ascending order.
|
||||||
order_by (str, optional): Column name to sort results by. Defaults to 'create_time' if reverse is specified.
|
order_by (str, optional): Column name to sort results by. Defaults to 'create_time' if reverse is specified.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
peewee.ModelSelect: A query containing all matching records.
|
peewee.ModelSelect: A query containing all matching records.
|
||||||
"""
|
"""
|
||||||
@ -80,27 +80,25 @@ class CommonService:
|
|||||||
if not order_by or not hasattr(cls, order_by):
|
if not order_by or not hasattr(cls, order_by):
|
||||||
order_by = "create_time"
|
order_by = "create_time"
|
||||||
if reverse is True:
|
if reverse is True:
|
||||||
query_records = query_records.order_by(
|
query_records = query_records.order_by(cls.model.getter_by(order_by).desc())
|
||||||
cls.model.getter_by(order_by).desc())
|
|
||||||
elif reverse is False:
|
elif reverse is False:
|
||||||
query_records = query_records.order_by(
|
query_records = query_records.order_by(cls.model.getter_by(order_by).asc())
|
||||||
cls.model.getter_by(order_by).asc())
|
|
||||||
return query_records
|
return query_records
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def get(cls, **kwargs):
|
def get(cls, **kwargs):
|
||||||
"""Get a single record matching the given criteria.
|
"""Get a single record matching the given criteria.
|
||||||
|
|
||||||
This method retrieves a single record from the database that matches
|
This method retrieves a single record from the database that matches
|
||||||
the specified filter conditions.
|
the specified filter conditions.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Filter conditions as keyword arguments.
|
**kwargs: Filter conditions as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Model instance: Single matching record.
|
Model instance: Single matching record.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
peewee.DoesNotExist: If no matching record is found.
|
peewee.DoesNotExist: If no matching record is found.
|
||||||
"""
|
"""
|
||||||
@ -110,13 +108,13 @@ class CommonService:
|
|||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def get_or_none(cls, **kwargs):
|
def get_or_none(cls, **kwargs):
|
||||||
"""Get a single record or None if not found.
|
"""Get a single record or None if not found.
|
||||||
|
|
||||||
This method attempts to retrieve a single record matching the given criteria,
|
This method attempts to retrieve a single record matching the given criteria,
|
||||||
returning None if no match is found instead of raising an exception.
|
returning None if no match is found instead of raising an exception.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Filter conditions as keyword arguments.
|
**kwargs: Filter conditions as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Model instance or None: Matching record if found, None otherwise.
|
Model instance or None: Matching record if found, None otherwise.
|
||||||
"""
|
"""
|
||||||
@ -129,13 +127,13 @@ class CommonService:
|
|||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def save(cls, **kwargs):
|
def save(cls, **kwargs):
|
||||||
"""Save a new record to database.
|
"""Save a new record to database.
|
||||||
|
|
||||||
This method creates a new record in the database with the provided field values,
|
This method creates a new record in the database with the provided field values,
|
||||||
forcing an insert operation rather than an update.
|
forcing an insert operation rather than an update.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Record field values as keyword arguments.
|
**kwargs: Record field values as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Model instance: The created record object.
|
Model instance: The created record object.
|
||||||
"""
|
"""
|
||||||
@ -146,13 +144,13 @@ class CommonService:
|
|||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def insert(cls, **kwargs):
|
def insert(cls, **kwargs):
|
||||||
"""Insert a new record with automatic ID and timestamps.
|
"""Insert a new record with automatic ID and timestamps.
|
||||||
|
|
||||||
This method creates a new record with automatically generated ID and timestamp fields.
|
This method creates a new record with automatically generated ID and timestamp fields.
|
||||||
It handles the creation of create_time, create_date, update_time, and update_date fields.
|
It handles the creation of create_time, create_date, update_time, and update_date fields.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Record field values as keyword arguments.
|
**kwargs: Record field values as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Model instance: The newly created record object.
|
Model instance: The newly created record object.
|
||||||
"""
|
"""
|
||||||
@ -169,10 +167,10 @@ class CommonService:
|
|||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def insert_many(cls, data_list, batch_size=100):
|
def insert_many(cls, data_list, batch_size=100):
|
||||||
"""Insert multiple records in batches.
|
"""Insert multiple records in batches.
|
||||||
|
|
||||||
This method efficiently inserts multiple records into the database using batch processing.
|
This method efficiently inserts multiple records into the database using batch processing.
|
||||||
It automatically sets creation timestamps for all records.
|
It automatically sets creation timestamps for all records.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data_list (list): List of dictionaries containing record data to insert.
|
data_list (list): List of dictionaries containing record data to insert.
|
||||||
batch_size (int, optional): Number of records to insert in each batch. Defaults to 100.
|
batch_size (int, optional): Number of records to insert in each batch. Defaults to 100.
|
||||||
@ -182,16 +180,16 @@ class CommonService:
|
|||||||
d["create_time"] = current_timestamp()
|
d["create_time"] = current_timestamp()
|
||||||
d["create_date"] = datetime_format(datetime.now())
|
d["create_date"] = datetime_format(datetime.now())
|
||||||
for i in range(0, len(data_list), batch_size):
|
for i in range(0, len(data_list), batch_size):
|
||||||
cls.model.insert_many(data_list[i:i + batch_size]).execute()
|
cls.model.insert_many(data_list[i : i + batch_size]).execute()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def update_many_by_id(cls, data_list):
|
def update_many_by_id(cls, data_list):
|
||||||
"""Update multiple records by their IDs.
|
"""Update multiple records by their IDs.
|
||||||
|
|
||||||
This method updates multiple records in the database, identified by their IDs.
|
This method updates multiple records in the database, identified by their IDs.
|
||||||
It automatically updates the update_time and update_date fields for each record.
|
It automatically updates the update_time and update_date fields for each record.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data_list (list): List of dictionaries containing record data to update.
|
data_list (list): List of dictionaries containing record data to update.
|
||||||
Each dictionary must include an 'id' field.
|
Each dictionary must include an 'id' field.
|
||||||
@ -200,8 +198,7 @@ class CommonService:
|
|||||||
for data in data_list:
|
for data in data_list:
|
||||||
data["update_time"] = current_timestamp()
|
data["update_time"] = current_timestamp()
|
||||||
data["update_date"] = datetime_format(datetime.now())
|
data["update_date"] = datetime_format(datetime.now())
|
||||||
cls.model.update(data).where(
|
cls.model.update(data).where(cls.model.id == data["id"]).execute()
|
||||||
cls.model.id == data["id"]).execute()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
@ -212,12 +209,6 @@ class CommonService:
|
|||||||
# data: Updated field values
|
# data: Updated field values
|
||||||
# Returns:
|
# Returns:
|
||||||
# Number of records updated
|
# Number of records updated
|
||||||
try:
|
|
||||||
if not DB.is_connection_usable():
|
|
||||||
DB.connect()
|
|
||||||
except Exception:
|
|
||||||
DB.close()
|
|
||||||
DB.connect()
|
|
||||||
data["update_time"] = current_timestamp()
|
data["update_time"] = current_timestamp()
|
||||||
data["update_date"] = datetime_format(datetime.now())
|
data["update_date"] = datetime_format(datetime.now())
|
||||||
num = cls.model.update(data).where(cls.model.id == pid).execute()
|
num = cls.model.update(data).where(cls.model.id == pid).execute()
|
||||||
@ -263,7 +254,7 @@ class CommonService:
|
|||||||
# Returns:
|
# Returns:
|
||||||
# Number of records deleted
|
# Number of records deleted
|
||||||
return cls.model.delete().where(cls.model.id == pid).execute()
|
return cls.model.delete().where(cls.model.id == pid).execute()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def delete_by_ids(cls, pids):
|
def delete_by_ids(cls, pids):
|
||||||
@ -310,13 +301,12 @@ class CommonService:
|
|||||||
# List of tuples containing chunks
|
# List of tuples containing chunks
|
||||||
length = len(tar_list)
|
length = len(tar_list)
|
||||||
arr = range(length)
|
arr = range(length)
|
||||||
result = [tuple(tar_list[x:(x + n)]) for x in arr[::n]]
|
result = [tuple(tar_list[x : (x + n)]) for x in arr[::n]]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def filter_scope_list(cls, in_key, in_filters_list,
|
def filter_scope_list(cls, in_key, in_filters_list, filters=None, cols=None):
|
||||||
filters=None, cols=None):
|
|
||||||
# Get records matching IN clause filters with optional column selection
|
# Get records matching IN clause filters with optional column selection
|
||||||
# Args:
|
# Args:
|
||||||
# in_key: Field name for IN clause
|
# in_key: Field name for IN clause
|
||||||
@ -331,22 +321,12 @@ class CommonService:
|
|||||||
res_list = []
|
res_list = []
|
||||||
if cols:
|
if cols:
|
||||||
for i in in_filters_tuple_list:
|
for i in in_filters_tuple_list:
|
||||||
query_records = cls.model.select(
|
query_records = cls.model.select(*cols).where(getattr(cls.model, in_key).in_(i), *filters)
|
||||||
*
|
|
||||||
cols).where(
|
|
||||||
getattr(
|
|
||||||
cls.model,
|
|
||||||
in_key).in_(i),
|
|
||||||
*
|
|
||||||
filters)
|
|
||||||
if query_records:
|
if query_records:
|
||||||
res_list.extend(
|
res_list.extend([query_record for query_record in query_records])
|
||||||
[query_record for query_record in query_records])
|
|
||||||
else:
|
else:
|
||||||
for i in in_filters_tuple_list:
|
for i in in_filters_tuple_list:
|
||||||
query_records = cls.model.select().where(
|
query_records = cls.model.select().where(getattr(cls.model, in_key).in_(i), *filters)
|
||||||
getattr(cls.model, in_key).in_(i), *filters)
|
|
||||||
if query_records:
|
if query_records:
|
||||||
res_list.extend(
|
res_list.extend([query_record for query_record in query_records])
|
||||||
[query_record for query_record in query_records])
|
|
||||||
return res_list
|
return res_list
|
||||||
|
@ -105,7 +105,7 @@ class TenantLLMService(CommonService):
|
|||||||
if model_config:
|
if model_config:
|
||||||
model_config = model_config.to_dict()
|
model_config = model_config.to_dict()
|
||||||
llm = LLMService.query(llm_name=mdlnm) if not fid else LLMService.query(llm_name=mdlnm, fid=fid)
|
llm = LLMService.query(llm_name=mdlnm) if not fid else LLMService.query(llm_name=mdlnm, fid=fid)
|
||||||
if not llm and fid: # for some cases seems fid mismatch
|
if not llm and fid: # for some cases seems fid mismatch
|
||||||
llm = LLMService.query(llm_name=mdlnm)
|
llm = LLMService.query(llm_name=mdlnm)
|
||||||
if llm:
|
if llm:
|
||||||
model_config["is_tools"] = llm[0].is_tools
|
model_config["is_tools"] = llm[0].is_tools
|
||||||
@ -163,12 +163,6 @@ class TenantLLMService(CommonService):
|
|||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def increase_usage(cls, tenant_id, llm_type, used_tokens, llm_name=None):
|
def increase_usage(cls, tenant_id, llm_type, used_tokens, llm_name=None):
|
||||||
try:
|
|
||||||
if not DB.is_connection_usable():
|
|
||||||
DB.connect()
|
|
||||||
except Exception:
|
|
||||||
DB.close()
|
|
||||||
DB.connect()
|
|
||||||
e, tenant = TenantService.get_by_id(tenant_id)
|
e, tenant = TenantService.get_by_id(tenant_id)
|
||||||
if not e:
|
if not e:
|
||||||
logging.error(f"Tenant not found: {tenant_id}")
|
logging.error(f"Tenant not found: {tenant_id}")
|
||||||
@ -366,7 +360,7 @@ class LLMBundle:
|
|||||||
|
|
||||||
ans = ""
|
ans = ""
|
||||||
chat_streamly = self.mdl.chat_streamly
|
chat_streamly = self.mdl.chat_streamly
|
||||||
total_tokens = 0
|
total_tokens = 0
|
||||||
if self.is_tools and self.mdl.is_tools:
|
if self.is_tools and self.mdl.is_tools:
|
||||||
chat_streamly = self.mdl.chat_streamly_with_tools
|
chat_streamly = self.mdl.chat_streamly_with_tools
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ mysql:
|
|||||||
password: 'infini_rag_flow'
|
password: 'infini_rag_flow'
|
||||||
host: 'localhost'
|
host: 'localhost'
|
||||||
port: 5455
|
port: 5455
|
||||||
max_connections: 100
|
max_connections: 900
|
||||||
stale_timeout: 30
|
stale_timeout: 300
|
||||||
minio:
|
minio:
|
||||||
user: 'rag_flow'
|
user: 'rag_flow'
|
||||||
password: 'infini_rag_flow'
|
password: 'infini_rag_flow'
|
||||||
|
@ -7,8 +7,8 @@ mysql:
|
|||||||
password: '${MYSQL_PASSWORD:-infini_rag_flow}'
|
password: '${MYSQL_PASSWORD:-infini_rag_flow}'
|
||||||
host: '${MYSQL_HOST:-mysql}'
|
host: '${MYSQL_HOST:-mysql}'
|
||||||
port: 3306
|
port: 3306
|
||||||
max_connections: 100
|
max_connections: 900
|
||||||
stale_timeout: 30
|
stale_timeout: 300
|
||||||
minio:
|
minio:
|
||||||
user: '${MINIO_USER:-rag_flow}'
|
user: '${MINIO_USER:-rag_flow}'
|
||||||
password: '${MINIO_PASSWORD:-infini_rag_flow}'
|
password: '${MINIO_PASSWORD:-infini_rag_flow}'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user