又收到了服务器的提醒,“资源快使用完了”,提示我快升级账户。
但想想 PAGENOTE 插件本身就是一个浏览器端软件,几乎不耗费服务端资源。猜测是官网网页导致的,因为官网的博客数据需要从 Notion 拉取,如果用户访问量大,也是有可能的。
分析流量
还以为迎来了一大批新的用户,从流量分析看,请求出现了比较明显的上涨,但是用户数却并没有增长,猜测也许是受到了攻击。但从 cloudflare 分析报告里没有发现任何异常,暂时排除了受到攻击的可能。
排查接口
细分接口,分析流量来源。发现
/user
接口有比较大的提升,同时这个接口产生的资源耗费占整体90%上。几乎可以定位是这个接口的问题。服务器的资源消耗,不仅受到请求数的影响,同时还受到该接口的运行所耗费的运行消耗(内存、CPU、运行时常)等。
可以简化的认为 服务器资源消耗 = 请求数 * 运行消耗
两个影响因素中其一运行消耗,直接受到代码逻辑的影响,排查最近几乎没有做任何修改,姑且认为此变量没有变化。但请求数的增加一定程度上也会影响运行消耗,如请求增加会导致运行锁时间增加、数据库压力增加,从而影响运行消耗的增加。
可以断定原因来自于
/user
接口。排查接口请求源
从业务代码中搜索该接口的调用并加以分析。该接口会在插件初始化调用一次,理论上也只会调用一次。但分析后台日志发现,同一个用户会频繁的调用该接口。
结合最近的上线内容发现问题:近期将浏览器插件由 MV2 升级到了 MV3 版本。这是一个较大的版本升级,直接影响了插件的运行逻辑。
MV3 最大的变更在于,将浏览器插件的后台脚本由原本的常驻程序改为了 service worker 会话模式运行。它将根据用户浏览器运行情况,自动销毁和重启。所以就出现了,接口被反复调用的情况。
修复方案
于普通前端网页相比,浏览器插件最大的优点,同时也是缺点:代码安装到用户端,无法由开发者快速的更新和维护。这给了用户极大的安全感,也给开发者提出了不小的挑战。每一个版本都需要向历史兼容,同时还要预留用户全部迁移到新版本上的时间。
如果此类问题发生在普通网页或者服务端上,只需要修改代码然后上线,用户刷新一下就能解决。但这类安装型软件解决起来就比较麻烦,所以很多开发者都会“留后门”,通过一系列的动态执行代码来解决,但 MV3 的标准也再逐渐关上这扇门 — 它不允许远程代码的实现方式。
从立即提升新版本到审核通过,用户更新,这个时间一般是2-3天,甚至更久。这期间流量还是一如既往的来,服务器资源很快就会被消耗殆尽。
针对本文中这个问题,可以通过缓存来一定程度上的实现“节流”的效果。
我在当
/user
请求来自对应的软件版本时,增加了缓存响应头,通过 http 协议,阻塞下一次的浏览器请求。极大程度的降低了服务器资源的消耗。当用户升级到修复版本后,将不再受缓存限制。if(req.version==='0.29.2'){ res.setHeader("Cache-Control", "max-age=1200,private"); }
当然,肯定会稍微影响用户获取最实时的数据,但也算是一个折中的方案了。
延展
大多数开发者会将缓存认为是只有前端资源才有机会用得上的协议,例如 css、js、图片这些资源。很少有人会将缓存协议用于接口请求中。除了在本文的修复场景中使用外,普通的业务逻辑也是用得上的,例如拉取一些服务器配置信息,数据是实时性没有那么高时,这是一个很不错的优化手段。