Почему Telegram Бот на aiogram на сервере потребляет много ОЗУ?
Создал тг бота для работы с google sheets api. (python, aiogram). Запускаю, все норм. Купил VPS сервер с 1 гб озу. Через время вся память оказалась забита и бот остановился. При каждом запросе к боту используется от 10 до 100 мб оперативы. В чем проблема? Может, дело в коде бота? Если учитывать, что на локальном пк оператива не расходуется вообще (при запуске бот берет 150 мб и дальше, расходует, но тут же освобождает)? Не пойму. Попробовал после каждого обращения к боту удалять переменные, которые использовались в процессе выполнения команды. Не помогло.
Возможно связано с количеством сеансов пользователей. Если каждый сеанс потребляет 20Мб то после захода 50 пользователей одновременно так они и выходит 1Гб.
Сильно зависит от того, что бот делает. Если он на каждого пользователя создаёт большой объект и хранит его в памяти (например, если он берёт аватарку каждого обращающегося пользователя), то вполне может распухать. Без кода бота здесь трудно что-либо комментировать.
Навскидку, проблема вот в этой части - "При каждом запросе к боту используется от 10 до 100 мб оперативы". Если бот у вас видео не транскодирует, конечно, и речь не распознаёт.
PVkolos, мало информации. Ты вот что, дружище. Давай публикуй исходники и какой-то memory analyze. Я уверен что твой прикладной код является причиной распухания.
mayton2019, ок, приведу пару функций и сколько памяти они жрут.
async def analytic(spreadsheet_id):
service = build('sheets', 'v4', credentials=credentials)
req1 = []
req1.append({'addSheet': {'properties': {'title': 'Аналитика'}}})
body1 = {'requests': req1}
try:
service.spreadsheets().batchUpdate(spreadsheetId=spreadsheet_id, body=body1).execute()
except HttpError:
pass
body_values = []
body_values.append(['Месяц записи', ' ', 'Раздел'])
deletsheet(spreadsheet_id)
r = await read_new('Категории и разделы', spreadsheet_id)
buttons = [' ']
total = dict()
for el in r:
if el[0] not in buttons and el[0] != 'Раздел':
buttons.append(el[0])
total[el[0]] = 0
buttons.append('Итого')
body_values.append(buttons)
sheet = await read('Записи бота', spreadsheet_id, 'ROWS')
ms = {'1': 'январь', "2": "февраль", "3": "март", "4": "апрель", "5": "май", "6": "июнь", "7": "июль", "8": "август",
"9": "сентябрь", "10": "октябрь", "11": "ноябрь", "12": "декабрь"}
my_ms = []
my_keys = {}
for i in range(1, len(sheet)):
try:
if ms[str(int(sheet[i][0].split('-')[1]))] not in my_ms:
my_ms.append(ms[str(int(sheet[i][0].split('-')[1]))])
my_keys[sheet[i][0].split('-')[1]] = {el: 0 for el in buttons[:-1] if el not in " Раздел"}
except KeyError:
print('Дурак, ты, наерное, отредактировал дату записи, поэтому бот ее не понимает')
my_ms.append('Всего')
for el in sheet[1:]:
total[el[2]] += int(el[4])
for el in sheet[1:]:
my_keys[el[0].split('-')[1]][el[2]] += int(el[4])
for i in range(len(my_ms) - 1):
body_values.append([my_ms[i], *list(my_keys[f'0{i + 1}'].values()), sum(list(my_keys[f'0{i + 1}'].values()))])
body_values.append(['Всего', *list(total.values())])
print(sys.getsizeof(body_values) + sys.getsizeof(my_keys) + sys.getsizeof(my_ms) + sys.getsizeof(sheet) + sys.getsizeof(buttons))
body = {'values': body_values}
range_ = f'{"Аналитика"}!A1'
service.spreadsheets().values().update(spreadsheetId=spreadsheet_id, range=range_, valueInputOption='USER_ENTERED',
body=body).execute()
del body, body1, body_values, service, my_ms, my_keys, total, r, sheet, buttons, ms, req1, range_
Это код из отдельного файла, в боте я просто асинхронно ее вызываю
@dp.message_handler(commands=['analytics'])
async def analytics(message):
try:
if db.get_id_sheets(message.from_user.id) != 'none': # Проверка, что юзер указал ссыклу на GOOGLE SHEETS
tb_name = await table(db.get_id_sheets(message.from_user.id)) # Получение ссылки на таблицу
await send(message.from_user.id, message.from_user.first_name + ", аналитика ваших записей может занять много времени. Когда аналитика окончится, "
" бот пришлет вам сообщение об этом. Результаты появятся в вашей таблице на листе <b>Аналитика</b>. ")
id_sh = db.get_id_sheets(message.from_user.id) # Получение id google sheets юзера
await analytic(id_sh) # Проводим аналитику
await send(message.from_user.id, "Аналитика завершена. ЕЕ вы можете найти <a href='" + tb_name[1] + "'>в своей google sheets таблице</a> на листе <b>Аналитика</b>")
else:
await send(message.from_user.id, message.from_user.first_name + ', Вы не указали таблицу google sheets.\n'
'Чтобы указать таблицу для записей введите команду /set_table')
except Exception as e:
print('Error analytic: ', e)
PVkolos, Хоть я и удаляю все переменные, но за вызов такой функции расходуется от 50 до 100 мб озу. Ладно расходуется, но эта память потом не очищается и так и остается занятой
mayton2019, я использовал машину состояний в aiogram, в которой использую озу для хранения данных от пользователя. Это может как-то сильно отразиться на состоянии памяти?
PVkolos, мы теряем время. Что такое aiogram я всё равно не знаю. Да и никто тебе не скажет. Зачем тут астрология? Надо точнее. Сделай отчет профилирования и он покажет какая стока в коде сколько памяти сожрала.
mayton2019, тут дело в том, что на локальном пк сборщик мусора все очищает и все идет классно, только вот на сервере убунту сборщик работает крайне криво