必须更新 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() */
}
}
当然,sn-p 是不完整的。它只是让您了解如何编写该中间件。
以下是您如何将中间件用于您的 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 */)