python 函数着色器设想

背景

跟食品一样,代码也有过期时间。但糟糕的是,食品出产时就已标明了何时过期,但是一段代码是否过期却不好判定。

我们通常有这样的经验,当一个资源地址(url)要下线时,我们会从 nginx 的请求日志里查看该接口在最近一段时间内有没有被访问。

函数也可以做类似的处理,要解决的问题是,由谁来充当 nginx 记录请求的角色。

现状

当前网络上已经有比较好的支持,最典型的实现有以下几类:

  1. python 用来性能调优的库,如 profile、hotshot 等
  2. 使用装饰器实现,每个要统计的对象都需要加装饰器,操作不够优雅且略笨拙
  3. 自己维护变量统计,这种人工成本较大

方案 2、3 成本都比较高,且实现不够优雅,难以在高层次上复用。

方案 1 是比较好的一种方式,但也存在着它的问题。

对于脚本来说,这种方式很具优势。但是,对于大型系统来说,这类库的接入成本不低,可操作性较差。

其次它的抽象程度不够,需要自己再做额外分析处理,很难做到开箱即用。

设想

基于以上原因,我们可以设想一种更为友好的方式,以一种系统的抽象粒度给出。

这里有一个很重要的指标需要评估,就是对系统性能的影响有多大。当然,这是个技术问题,可以从技术角度解决。

我们这里使用着色来形象地表达记录访问状态的动作。不考虑性能影响,我们的目标是可以针对某命名空间下的对象及其方法进行着色,并获得着色后的可视化效果,以辅助对旧的代码进行重构。

我们希望有一个开关来控制着色,并可以热启动和热停止,且停止后尽可能减少或彻底取消对性能的影响。

着色器记录的信息,包括函数的调用次数及耗时。我们希望可以对各层级进行比较,可以很简单地看出对象下哪个函数在近一个月没有调用过,或者一个函数调用的平均耗时。

更上一层次,我们希望该功能以一种成熟的第三方模块给出,仅需配置极少内容即可使用。如作为 django 的第三方模块。

实现细节

我们将使用钩子或其它技术手段,接管函数的调用逻辑。我们将记录函数的如下信息:

梯度时间 函数或属性 调用次数 平均耗时
2020-03-28 20:01 views.WelcomeView.get() 20 0.2
2020-03-28 20:01 views.WelcomeView.post() 3 0.5
2020-03-28 20:01 views.WelcomeView.var 2 0.5

由于请求量较大,可对数据做缓存处理,并定期刷新到数据库;由于数据量较大,可对过旧的数据进行压缩处理。

系统将对该数据制作报表,报表主要有两种:

第一种,一段时间内函数的调用次数热力图,并对不同函数按调用次数作升序排列。

第二种,一段时间内函数的调用耗时热力图,并对不同函数按调用平均耗时作降序排列。