必须更新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 */)