Проблемы производительности / масштабируемости при обновлении документа MongoDB
каждый раз, когда есть запрос - это возможно или я столкнусь с проблемой
когда приложение растет?
Определенно. Вскоре вы столкнетесь с большим трафиком на mongoDB, и это приведет к снижению производительности. На мой взгляд, вы должны использовать более быструю базу данных в памяти, такую как Redis , чтобы справиться с ситуацией. Вы даже можете использовать Redis как session-store
, что уменьшит нагрузку на MongoDB. Таким образом, MongoDB можно использовать для других бизнес-запросов.
Сброс счетчика - если это ежедневный хрен, который смотрит на
метка времени регистрации каждого пользователя, если вычисляется месяц
передал и сбросил распределенные запросы соответственно, или есть
лучший способ создать что-то вроде этого?
Лучшим способом было бы добиться сброса в самом промежуточном программном обеспечении.
Вот код, объясняющий мое решение.
Пример проекта Quota
объекта будет:
{
type: "FREE_USER", /** or "PREMIUM_USER" */
access_limit: 100, /** or 5000 */
exhausted_requests: 42 /** How many requests the user has made so far this month */
last_reset_timestamp: 1547796508728 /** When was the exhausted_requests set to 0 last time */
}
С этим дизайном. Ваше промежуточное ПО, которое проверяет квоту, будет выглядеть примерно так:
const checkQuota = async (req, res, next) => {
const user = req.user;
const userQuotaStr = await redis.getAsync(user.id)
let userQuota;
/** Check if we have quota information about user */
if (userQuotaStr != null) {
/** We have previously saved quota information */
userQuota = JSON.parse(userQuotaStr);
/**
* Check if we should reset the exhausted_requests
* Assuming that all the requests are reset on the First Day of each month.
*/
if ( isStartOfMonth() ) {
/**
* It is First Day of the month. We might need to reset the `exhausted_requests`
* Check the difference between `Date.now()` and `userQuota.last_reset_timestamp`
* to determine whether we should reset or not
*/
if ( shouldResetTimeStamp(userQuota.last_reset_timestamp) ) {
userQuota.exhausted_requests = 0
userQuota.last_reset_timestamp = Date.now()
}
}
} else {
/** We do not have previously saved quota information. Prepare one */
userQuota = {
type: user.type,
access_limit: user.access_limit,
exhausted_requests: 0,
last_reset_timestamp: Date.now()
}
}
/** Incredement the counter to account the current request */
userQuota.exhausted_requests++
/** Update in database */
redis.set(user.id, JSON.stringify(userQuota))
if ( userQuota.exhausted_requests >= userQuota.access_limit ) {
/** User has reached the quota limit. Deny the request. set with 401 or 403 status code */
} else {
/** User can access the API. call next() */
}
}
Конечно, фрагмент является неполным. Это просто дает вам представление о том, как приступить к написанию этого промежуточного программного обеспечения.
Вот как вы можете использовать промежуточное ПО для своих API:
/** If requests to routes are under the quota */
app.get("/api/quota-routes", requireAuth, checkQuota, /** Mount the actual middleware here */)
/** If requests to routes are unlimited, just remove the checkQuota middleware */
app.get("/api/unlimited-routes", requireAuth, /** Mount the actual middleware here */)