- мы используем сервер приложений на базе Python Tornado в качестве службы API.
- мы настроили nginx так, что Tornado работает на 16 разных портах, и входящие запросы распределяются по этим портам. например: если конечной точкой базы запроса API является «api.ecom.in», то если мы получаем запрос на «api.ecom.in», тогда этот запрос назначается одному из работающих портов работающего приложения Tornado.
- мы используемornado-sqlalchemy для подключения к базе данных и создания пула. ниже приведен пример моего подключения и сеанса к базе данных.
Код: Выделить всё
from tornado_sqlalchemy import SQLAlchemy
from contextlib import contextmanager
db = SQLAlchemy(url=DATABASE_URL, session_options={'expire_on_commit': False}, engine_options={'pool_size': 100,'max_overflow': 1400, 'echo': False, 'pool_recycle':1200 ,'connect_args': {'connect_timeout': 20}})
@contextmanager
def session_scope():
session = None
try:
session = db.sessionmaker()
yield session
except Exception:
if session:
session.rollback()
raise
else:
session.commit()
finally:
if session:
# session.expunge_all()
session.close()
- ниже приведен пример моего обработчика:
Код: Выделить всё
@jwtauth
class GetSeasonalProductHandler(BaseHandler):
SUPPORTED_METHODS = ['GET']
async def get(self):
return self.send_response(data = await get_seasonal_product_service(self.request.query_arguments), status = 200)
@classmethod
def route_url(cls):
return [
(r'(?i)/api/v2/product_master/seasonal_product', cls, {})
]
- как вы можете видеть выше, есть функция, вызываемая с именем: "get_ Seasonal_product_service". Ниже приведен код функции:-< /li>
Код: Выделить всё
async def get_seasonal_product_service(request_args):
response_data = {}
region_id = request_args['region_id'][0].decode('utf8')
header_id = request_args['header_id'][0].decode('utf8') if 'header_id' in request_args else 1
customer_id = request_args['customer_id'][0].decode('utf8')
with session_scope() as session:
seasonal_products = session.execute(
"EXEC USP_ProductMasterSeasonal {region_id}, {header_id}, {customer_id}".format(
region_id = region_id,
header_id = header_id,
customer_id = customer_id
)
).fetchall()
product_list = []
for product in seasonal_products:
product_list.append(dict(product))
return product_list
Мое наблюдение: я заметил, что мои SQL-запросы занимают слишком много времени. Я заметил, что удаление некоторых ненужных вызовов в моей сервисной функции также немного помогло улучшить время отклика. но лично я считаю, что сокращение количества звонков — это не решение, а временное решение. Мне нужно понять, нужно ли что-то оптимизировать на уровне сервера Python Tornado. Пожалуйста, помогите мне, если вы видите что-то не так в архитектуре Python. Я сам заметил, что торнадо-sqlalchemy плохо оптимизирован для обработки асинхронных вызовов и даже контекстный менеджер тоже работает синхронно. Но поскольку теперь вся моя архитектура зависит от этого синхронного session_scope(), у меня возникают сомнения и проблемы с его изменением на что-то асинхронное.
Вещи, которые я пробовал до сих пор:
- На данный момент я удалил все ненужные вызовы БД из моей службы API.
- увеличил размер соединения с пулом. добавлена конфигурация перезапуска пула = 1200, добавлена db Connection_timeout = 20.
- увеличен номер рабочего порта сервера приложений Tornado.
- мы планируем использовать Redis для кэширования. некоторые ответы API для сокращения вызовов БД. (все еще работаем над этим)
Подробнее здесь: https://stackoverflow.com/questions/790 ... rver-issue