简化统计数据的记录与发现

在将统计数据存储到Redis里面之后,接下来我们该做些什么呢?说的更详细一点,在知道了访问每个页面所需的时间之后,我们要怎样才能找到那些生成速度较慢的网页?或者说,当某个页面的生成速度变得比以往要慢的时候,我们如何才能知悉这一情况?简单的说,为了发现以上提到的这些情况,我们需要存储更多信息,而具体的方法将这一节里面介绍。

要记录页面的访问时长,程序就必须在页面被访问时进行计时。为了做到这一点,我们可以在各个不同的页面设置计时器,并添加代码来记录计时的结果,但最好的办法是直接实现一个能够进行计时并将计时结果存储起来的东西,让它将平均访问速度最慢的页面都记录到一个有序集合里面,并向我们报告哪些页面的载入时间变得比以前更长了。

为了计算和记录访问时长,我们会编写一个Python上下文管理器,并使用这个上下文管理器来包裹那些需要计算并记录访问时长的代码。

在Python里面,一个上下文管理器就是一个专门定义的函数或者类,这个函数或者类的不同部分可以在一段代码执行之前以及执行之后分别执行。上下文管理器使得用户可以很容易地实现类似【自动关闭已打开的文件】这样的功能。

下面代码展示了用于计算和记录访问时长的上下文管理器:程序首先会取得当前时间,接着执行被包裹的代码,然后计算这些代码的执行时长,并将结果记录到
Redis里面;除此之外,程序还会对记录当前上下文最大访问的时间的有序集合进行更新。

import contextlib
import time

#将这个Python生成器用作上下文管理器
@contextlib.contextmanager
def access__time(conn,context):
    #记录代码块执行前的时间
    start=time.time()
    #运行被包裹的代码块
    yield

    #计算代码块的执行时长
    data=time.time()-start
    #更新这一上下文的统计数据
    stats=update_stats(conn,context,'AccessTime',data)
    #计算页面的平局访问时长
    average=stats[1]/stats[0]

    pipe=conn.pipeline(True)
    #将页面的平均访问时长添加到记录最长访问时间的有序集合里面
    pipe.zadd('slowest:AccessTime',context,average)
    #AccessTime有序集合只会保留最慢的100条记录
    pipe.zremrangebyrank('slowessTime',0,-101)
    pipe.execute()

因为access__time()上下文管理器里面有一些没办法只用三言两语来解释的概念,所以我们最好还是直接通过使用这个管理器来了解它是如何运作的。接下来的这段代码展示了使用access__time()上下文管理器记录web页面访问时长的方法,负责处理被记录页面的是一个回调函数:

#这个视图接收一个Redis连接以及一个生成内容的回调函数作为参数
def process_view(conn,callback):
    #计算并记录访问时长的上下文管理器就是这一包裹代码块的
    with access_time(conn,request.path):
        #当上下文管理器中的yield语句被执行时,这个语句就会被执行
        return callback()

如果还不理解,看下面简单的实例:

import contextlib


@contextlib.contextmanager
def mark():
    print("1")
    yield
    print(2)

def test(callback):
    with mark():
        return callback()


def xxx():
    print('xxx')

if __name__ == '__main__':
    test(xxx)

运行结果:

1
xxx
2

在看过这个例子之后,即使读者没有学过上下文管理器的创建方法,但是至少也已经知道该如何去使用它了。这个例子使用了访问时间上下文管理器来计算生成一个页面需要花费时多长时间,此外,同样的上下文管理器还可以用于计算数据库查询花费的时长,或者用来计算渲染一个模板所需的时长。作为练习,你能否构思一些其他种类的上下文管理器,并使用它们来记录有用的统计信息呢?另外,你能否让程序在页面的访问时长比平均情况要高出两个标注差或以上时,在recent_log()函数里面记录这一情况呢?

对现实世界中的统计数据进行收集和计数

尽管本书已经花费了好几页篇幅来讲述该如何收集生产系统运作时产生的相当重要的统计信息,但是别忘了已经有很多现成的软件包可以用于收集并绘制计数器以及统计数据,我个人最喜欢的是Graphite,在时间尝试构建自己的数据绘图库之前,不妨先试试这个。

在学会了如何将应用程序相关的各种重要信息存储到Redis之后,在接下来一节中,我们将了解更多与访客有关的信息,这些信息可以帮助我们处理其他问题。

results matching ""

    No results matching ""