《设计模式之美》实战二(下):如何实现一个支持各种统计规则的性能计数器?

王争《设计模式之美》学习笔记

小步快跑、逐步迭代

  • 数据采集:负责打点采集原始数据,包括记录每次接口请求的响应时间。
  • 存储:负责将采集的原始数据保存下来,以便之后做聚合统计。数据的存储方式有很多种,我们暂时只支持 Redis 这一种存储方式,并且,采集与存储两个过程同步执行。
  • 聚合统计:负责将原始数据聚合为统计数据,包括响应时间的最大值、最小值、平均值、99.9 百分位值、99 百分位值,以及接口请求的次数和 tps。
  • 显示:负责将统计数据以某种格式显示到终端,暂时只支持主动推送给命令行和邮件。命令行间隔 n 秒统计显示上 m 秒的数据(比如,间隔 60s 统计上 60s 的数据)。邮件每日统计上日的数据。

面向对象设计与实现

划分职责进而识别出有哪些类

  • MetricsCollector 类负责提供 API,来采集接口请求的原始数据。我们可以为 MetricsCollector 抽象出一个接口,但这并不是必须的,因为暂时我们只能想到一个 MetricsCollector 的实现方式。
  • MetricsStorage 接口负责原始数据存储,RedisMetricsStorage 类实现 MetricsStorage 接口。这样做是为了今后灵活地扩展新的存储方法,比如用 HBase 来存储。
  • Aggregator 类负责根据原始数据计算统计数据。
  • ConsoleReporter 类、EmailReporter 类分别负责以一定频率统计并发送统计数据到命令行和邮件。至于ConsoleReporter 和 EmailReporter 是否可以抽象出可复用的抽象类,或者抽象出一个公共的接口,我们暂时还不能确定。

定义类及类与类之间的关系

  • 接下来就是定义类及属性和方法,定义类与类之间的关系。这两步没法分得很开。
  • MetricsStorage 接口定义存取数据相关的属性和方法。RedisMetricsStorage 类实现 MetricsStorage 接口,填充具体的方法和属性。
  • MetricsCollector 类在构造函数中,以依赖注入的方式引入 MetricsStorage 接口,并在类内部的方法中得以调用数据存取的方法。
  • 统计显示所要完成的功能逻辑细分位下面 4 点:
    1. 根据给定的时间区间,从数据库中拉取数据
    2. 根据原始数据,计算得到统计数据
    3. 将统计数据显示到终端(命令行或邮件)
    4. 定时触发以上 3 个过程的执行
  • 面向对象设计和实现要做的事情,就是把合适的代码放到合适的类中。让代码尽量地满足低耦合、高内聚、单一职责、对扩展开放对修改关闭等之前讲到的各种设计原则和思想,尽量地让设计满足代码易复用、易读、易扩展、易维护。
  • 我们暂时选择把第 1、3、4 逻辑放到 ConsoleReporter 或 EmailReporter 类中,把第 2 个逻辑放到 Aggregator 类中。
  • Aggregator 类负责的逻辑比较简单,我们把它设计成只包含静态方法的工具类。静态方法中有统计方式,比如加和、取最大最小等,使用RequestStat 类中的 set 方法赋值给 RequestStat 类定义的这些统计属性。
  • ConsoleReporter 类相当于一个上帝类,定时根据给定的时间区间,从数据库中取出数据,借助 Aggregator 类完成统计工作,并将统计结果输出到命令行。也就是在 4 中定时触发 1、2、3 代码的执行。

将类组装起来并提供执行入口

  • 一个是 MetricsCollector 类,提供了一组 API 来采集原始数据。
  • 另一个是 ConsoleReporter 类和 EmailReporter 类,用来触发统计显示。

Review 设计与实现

  • MetricsCollector 负责采集和存储数据,职责相对来说还算比较单一。它基于接口而非实现编程,通过依赖注入的方式来传递 MetricsStorage 对象,可以在不需要修改代码的情况下,灵活地替换不同的存储方式,满足开闭原则。
  • RedisMetricsStorageMetricsStorage 的设计比较简单。当我们需要实现新的存储方式的时候,只需要实现 MetricsStorage 接口即可。其他接口函数调用的地方都不需要改动,满足开闭原则。
  • Aggregator 类是一个工具类,里面只有一个静态函数,有 50 行左右的代码量,负责各种统计数据的计算。一旦越来越多的统计功能添加进来之后,这个函数的代码量会持续增加,可读性、可维护性就变差了。这个类的设计可能存在职责不够单一、不易扩展等问题,需要在之后的版本中,对其结构做优化。
  • ConsoleReporterEmailReporter 中存在问题较多:
    • 从数据库中取数据、做统计的逻辑都是相同的,可以抽取出来复用,违反了 DRY 原则。
    • 整个类负责的事情比较多,职责不单一。特别是显示部分的代码,可能会比较复杂(比如 Email 的展示方式),最好是将显示部分的代码逻辑拆分成独立的类。
    • 因为代码中涉及线程操作,并且调用了 Aggregator 的静态函数,所以代码的可测试性不好。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值