《Prometheus监控实战》第8章 监控应用程序

2019-12-19 16:36:08 浏览数 (1)

第8章 监控应用程序

  • 首先,考虑的一些高级设计模式和原则

8.1 应用程序监控入门

  • 应用程序开发中存在一种常见的反模式,即把监控和其他运维功能(如安全性)视为应用程序的增值组件而非核心功能。但监控(和安全性)应该是应用程序的核心功能。如果你要为应用程序构建规范或用户故事,则请把对应用程序每个组件的监控包含进去。不构建指标或监控将存在严重的业务和运营风险,这将导致
  1. 无法识别或诊断故障
  2. 无法衡量应用程序的运行性能
  3. 无法衡量应用程序或组件的业务指标以及成功与否,例如跟踪销售数据或交易价值
  • 另一种常见的反模式是监控力度不足,我们始终建议你尽全力监控应用程序。人们经常会抱怨数据太少,但很少会担心数据太多
  • 注意:在存储容量的限制范围内,因超出容量而导致监控停止工作显然是不可取的。一种有效的方法是首先关注并修改保留时间,以便在减少存储的同时又不丢失有用的信息
  • 第三点需要注意的是,如果你使用多个环境(例如开发、测试、预生产和生产),那么请确保为监控配置提供标签,以便明确数据来自哪个特定环境,这样就可以对监控和指标进行分区

8.1.1 从哪里开始

  • 开始为应用添加监控,一个不错的选择是程序的入口和出口。例如
  1. 测量请求和响应的数量和时间,例如特定网页或API端点。如果你正在监控现有应用程序,那么可以创建一个特定网页或端点的优先级列表,并按重要性顺序对其进行监控
  2. 测量对外部服务和API的调用次数和时间,例如,如果你的应用程序使用数据库、缓存或搜索服务,或者使用第三方服务(如支付网关)
  3. 测量作业调度、执行和其他周期性事件(如cron作业)的数量和时间
  4. 测量重要业务和功能性事件的数量和时间,例如正在创建的用户或者支付和销售等交易

8.1.2 监控分类

  • 你应该通过应用程序、方法、函数或类似票房对指标进行分类并清晰地标识它们,以便了解指标生成的内容和位置

8.2 指标

  • 我们使用以下两种类型的指标,尽管它们之间有很多重叠
  1. 应用程序指标:通常用于衡量应用程序代码的状态和性能
  2. 业务指标:通常用于衡量应用程序的价值,例如电子商务网站上的销售量
  • 这两种指标的示例,Prometheus会倾向于关注可即刻获取的指标。对于长期业务指标,在许多情况下,你可能会使用基于事件的系统

8.2.1 应用程序指标

  • 应用程序指标可以衡量应用程序的性能和状态,包括应用程序最终用户的体验,如延迟和响应时间
  • 提示:一些好的衡量应用程序性能的例子是之前提到的USE和RED方法,以及Google黄金指标
  • 我们还会查看应用程序的功能和状态,一个很好的例子可能是成功的登录,或者错误、崩溃和失败。我们还可以测量诸如作业 、电子邮件或其他异步活动等的数量和性能

8.2.2 业务指标

  • 业务指标是应用程序指标的更进一层,它们通常与应用程序指标同义。如果你考虑将对特定服务的请求数量作为应用程序指标进行测量,那么业务指标通常会对请求的内容执行某些操作

8.2.3 放置指标

  • 一旦知道了我们想要监控和测量的内容,就需要确定将指标放在何处。在绝大多数情况下,放置这些指标的最佳位置是在我们的代码中,尽可能接近试图监控或测量的操作
  • 我们想要创建一个实用程序库:一个允许我们从集中设置创建各种指标的函数。这有时被称为实用程序模式:一个metrics-utility类,它不需要实例化,只包含静态方法

8.2.4 实用程序模式

  • 常见的模式是使用客户端创建实用程序库或模块(https://prometheus.io/docs/instrumenting/clientlibs/)。实用程序库将暴露一个允许 我们创建和增加指标的API
  • 我们创建了一些Ruby风格的代码来演示,假设已经创建了一个名为Metric的实用程序库
  • 代码清单:一个付款方法的示例
代码语言:javascript复制
include Metric
def pay_user(user, amount)
  pay(user.account, amount)
  Metric.increment 'payment'
  Metric.increment "payment-amount, #{amount.to_i}"
  send_payment_notification(user.email)
end

def send_payment_notification(email)
    send_email(payment, email)
  Metric.increment 'email-payment'
end
  • 第一个方法中增加两个指标的值
  1. payment指标:在每次付款时都会增加指标的值
  2. payment-amount指标:该指标按金额记录每笔付款
  • 第二种方法send_payment_notification来发送一封电子邮件,其中增加了第三个指标email-payment的值。email-payment指标用于计算发送的付款电子邮件的数量

8.2.5 外部模式

  • 如果你不能控制代码库,无法在代码中插入监控或测量内容,或者可能无法更改或更新旧应用程序,那么该怎么办?你需要找到距离应用程序最近的位置。最显著的地方是应用程序周围的输出和外部子系统,例如数据库或缓存
  • 如果应用程序发出日志,那么可以识别日志包含的内容,并查看是否可以使用这些内容来衡量应用程序的行为

8.2.6 监控应用程序示例

  • mwp-rails应用程序例子:https://github.com/turnbullpress/mwp-rails
  • 首先需要使用基于Ruby的客户端添加对Prometheus的支持(https://github.com/prometheus/client_ruby)
添加客户端
  • 代码清单:mwp-rails Gemfile
代码语言:javascript复制
source 'https://rubygems.org'
ruby '2.4.2'
gem 'rails', '5.1.5'
...
gem 'prometheus-client'
...
  • 然后使用bundle命令安装新的gem
  • 代码清单:使用bundle命令安装prometheus-client
  • 然后可以使用Rails控制台来测试客户端,现在通过rails c命令启动一个客户端
  • 代码清单:使用Rails控制台测试Prometheus客户端
  • 已经启动一个控制台,并使用以下代码创建一个Prometheus注册表(registry)
  • 代码清单:创建Prometheus注册表
代码语言:javascript复制
prometheus = Prometheus::Client.registry
  • 注册表是Prometheus应用程序监控的核心,你创建的每个指标都需要先注册。我们已创建了一个名为prometheus的注册表,现在可以在此注册表中创建指标
  • 代码清单:注册Prometheus指标
代码语言:javascript复制
test_counter = prometheus.count(:test_count, 'A test counter')
  • 使用increment方法来增加指标的值
  • 代码清单:增加指标的值
代码语言:javascript复制
test_counter.increment
  • 代码清单:查询指标的值
代码语言:javascript复制
test_counter.get
1.0
  • 可以注册多种类型的指标,包括摘要和直方图
  • 代码清单:基本的Prometheus client_ruby指标
代码语言:javascript复制
test_counter = prometheus.counter(:test_counter, 'A test counter')
test_gauge = prometheus.gauge(:test_gauge, 'A test gauge')
test_histogram = prometheus.histogram(:test_histogram, 'A test histogram')
test_summary = prometheus.summary(:test_summary, 'A test summary')
将监控添加到Rails
  • 我们不希望每次记录指标时,都需要手动创建注册表和指标,所以用实用程序代码来执行此操作
  • 代码清单:创建Metrics模块
代码语言:javascript复制
touch lib/metrics.rb
  • 代码清单:Metrics模块
代码语言:javascript复制
module Metrics
  def self.counter(name, docstring, base_labels = {})
    provide_metric(name) || registry.counter(name, docstring, base_labels)
  end

  def self.summary(name, docstring, base_labels = {})
    provide_metric(name) || registry.summary(name, docstring, base_labels)
  end

  def self.gauge(name, docstring, base_labels = {})
    provide_metric(name) || registry.summary(name, docstring, base_labels)
  end

  def self.histogram(name, docstring, base_labels = {}, buckets = ::Prometheus::Clien::Histogram::DEFAULT_BUCKETS)
    provide_metric(name) || registry.histogram(name, docstring, base_labels, buckets)
  end

  private

  def self.provide_metrics(name)
    registry.get(name)
  end

  def. self.registry
    @registry || ::Prometheus::Client.registry
  end

end
  • 需要扩展Rails以加载metrics库,有几种方法可以做到这一点,但我最喜欢使用添加初始化程序的方式
  • 代码清单:为metrics库创建初始化程序
代码语言:javascript复制
touch config/initializers/lib.rb
  • 然后在程序中添加对metrics库的依赖
  • 代码清单:文件/config/initializers/lib.rb
代码语言:javascript复制
require 'metrics'
  • 我们可以为一些方法添加指标,让我们从删除用户的计数器开始
  • 代码清单:删除用户的计数器
代码语言:javascript复制
def destroy
  user = User.find(params[:id])
  user.destroy
  Metrics.counter(:users_deletes_counter, "Deletes users counter").increment
  redirect_to users_path, :notice => "User deleted."
end
  • 还可以使用increment方法添加标签或者指定增量,如下所示
代码语言:javascript复制
.increment({service: 'foo'}, 2)
  • 还可以为所建用户构建另一个计数器并添加到User模型
  • 代码清单:创建用户的计数器
代码语言:javascript复制
class User < ActiveRecord::Base
    enum role: [:user, :vip, :admin]
  after_initialize :set_default, :if => :new_record?
  after_create do
    Metrics.counter(:user_created_counter, "Users created counter").increment
  end
end
  • 我们需要暴露要抓取的指标,还将启用Rack中间件来自动创建一些有关HTTP请求的有用指标。在示例中,我们通过以config.ru文件内添加exporter(和中间件收集器)来启用指标端点
  • 代码清单:将Prometheus添加到config.ru文件中
代码语言:javascript复制
require 'prometheus/middleware/collector'
require 'prometheus/middleware/exporter'
use Prometheus::Middleware::Collector
use Prometheus::Middleware::Exporter
  • exporter会创建一个路径/metrics,其中包含由应用程序定义的Prometheus注册表中指定的所有指标。惧器将一些HTTP服务器指标添加到通过Rack中间件收集的端点
  • 代码清单:Rails的/metrics端点
使用指标
  • 现在应用程序已生成指标,我们可以在Prometheus中使用它们。让我们创建一个作业来抓取/metrics端点,然后把Rails服务器添加到基于文件的服务发现中,按主机名添加3个Rails服务器
  • 代码清单:Rails服务器的服务发现
  • 接下来通过prometheus.yml配置文件创建新的作业
代码语言:javascript复制
- job_name: rails
  file_sd_configs:
    - files:
      - targets/rails/*.json
      refresh_interval: 5m
  • Rails服务器目标
  • 可在仪表板中查看新指标

0 人点赞