Как видно на изображении выше, у меня возникают проблемы с производительностью Redis после того, как он работал в течение продолжительного периода времени; особенно, 6 часов.
Я использую Redis для кэширования ответов от API, поэтому мне не нужно повторно извлекать десятки строк при каждом запросе, и я подумал - эй, это должно сработать. Очевидно, нет.
module.exports = (app, csrfProtection, jsonParser) => {
app.get("/api/steam/getPlayerSummaries", [steamRateLimits.getPlayerSummaries, jsonParser, csrfProtection], async(req, res) => {
redisClient.hmget("steam_user", req.query.steamids, (err, reply) => {
if(err) return res.status(500).send({ message: `Could not read from Redis with error ${err}`});
redisClient.hmget(`steam_user_expires_${req.query.steamids}`, "expires", (err, expire) => {
if(err) return res.status(500).send({ message: `Could not read from Redis with error ${err}`});
if(reply[0] && (CURRENT_UNIX_TIME - expire < REDIS_EXPIRE_LIMIT)) return res.status(200).send(JSON.parse(reply));
const queryParams = querystring.stringify({
key: process.env.STEAM_API_KEY,
steamids: req.query.steamids
}),
options = {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
};
http.get(`http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?${queryParams}`, options, response => {
const { statusCode } = response;
if(statusCode != 200) {
response.resume();
return res.status(statusCode).send({ message: `Could not fetch Steam API getPlayerSummaries with status code ${statusCode}`});
}
response.setEncoding("utf8");
let rawData = "";
response.on("data", chunk => rawData += chunk);
response.on("end", _ => {
try {
const parsedData = JSON.parse(rawData);
redisClient.hmset(["steam_user", req.query.steamids, rawData]);
redisClient.hmset([`steam_user_expires_${req.query.steamids}`, "expires", CURRENT_UNIX_TIME]);
return res.status(200).send(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on("error", e => {
console.error(`Got error: ${e.message}`);
return res.status(500).send(e);
});
});
});
});
}
Вот обзор хода выполнения того, что происходит в хронологическом порядке, когда пользователь пытается получить доступ к этому маршруту:
- Пользователь загружает веб-страницу индекса (по умолчанию). На этой странице может быть более 20 строк, для которых необходимо выполнить 20 запросов API от удаленного API (одна из причин, по которой я кеширую это).
- Проверить, не кэширован ли пользователь уже в redis
- Проверить, для указанного пользователя Steam существует ключ истечения срока действия (даже если он не существует).
- Если кеш существует и был извлечен менее чем за 15 минут go, отобразить результат из кэша Redis.
- Если кеша не существует, мы запрашиваем удаленный API.
- Если запрос был успешным, кешируем данные в Redis и возвращаем ответ.
По какой-то причине это получает захваченный сам по себе и через некоторое время работы Redis использует так много процессора и оперативной памяти, что это безумие, и я подумал, что справляюсь с этим должным образом.
Я также очищаю ВСЕ кеш один раз в день, используя скрипт оболочки и crontab.
redis-cli KEYS "steam_user*" | xargs redis-cli DEL
Почему он продолжает использовать больше ЦП и ОЗУ (даже если посетителей буквально нет, и я боюсь думать, что произойдет, если будет много посетителей), и как могу я работать вокруг этой проблемы, чтобы исправить это?