Watcher 工作原理编辑

您可以添加 Watch,以便在满足特定条件时自动执行操作。条件通常基于您加载到 Watch 中的数据,也称为Watch Payload。此 Payload 可以从不同的来源加载 - 来自 Elasticsearch、外部 HTTP 服务,甚至两者结合。

例如,您可以配置一个 Watch,当日志数据中的搜索表明在过去 5 分钟内有太多 503 错误时,向系统管理员发送电子邮件。

本主题描述了 Watch 的元素以及 Watch 的操作方式。

Watch 定义编辑

一个 Watch 包含一个触发器输入条件操作。操作定义了满足条件后需要执行的操作。此外,您可以定义条件转换,以在执行操作之前处理和准备 Watch Payload。

触发器
确定何时检查 Watch。Watch 必须有一个触发器。
输入
将数据加载到 Watch Payload 中。如果未指定输入,则加载空 Payload。
条件
控制是否执行 Watch 操作。如果未指定条件,则条件默认为 always
转换
处理 Watch Payload 以将其准备用于 Watch 操作。您可以在 Watch 级别定义转换,也可以定义特定于操作的转换。可选。
操作
指定满足 Watch 条件时发生的情况。

例如,以下代码段显示了一个创建或更新 Watch 请求,该请求定义了一个查找日志错误事件的 Watch

PUT _watcher/watch/log_errors
{
  "metadata" : { 
    "color" : "red"
  },
  "trigger" : { 
    "schedule" : {
      "interval" : "5m"
    }
  },
  "input" : { 
    "search" : {
      "request" : {
        "indices" : "log-events",
        "body" : {
          "size" : 0,
          "query" : { "match" : { "status" : "error" } }
        }
      }
    }
  },
  "condition" : { 
    "compare" : { "ctx.payload.hits.total" : { "gt" : 5 }}
  },
  "transform" : { 
    "search" : {
        "request" : {
          "indices" : "log-events",
          "body" : {
            "query" : { "match" : { "status" : "error" } }
          }
        }
    }
  },
  "actions" : { 
    "my_webhook" : {
      "webhook" : {
        "method" : "POST",
        "host" : "mylisteninghost",
        "port" : 9200,
        "path" : "/{{watch_id}}",
        "body" : "Encountered {{ctx.payload.hits.total}} errors"
      }
    },
    "email_administrator" : {
      "email" : {
        "to" : "[email protected]",
        "subject" : "Encountered {{ctx.payload.hits.total}} errors",
        "body" : "Too many error in the system, see attached data",
        "attachments" : {
          "attached_data" : {
            "data" : {
              "format" : "json"
            }
          }
        },
        "priority" : "high"
      }
    }
  }
}

元数据 - 您可以将可选的静态元数据附加到 Watch。

触发器 - 此计划触发器每 5 分钟执行一次 Watch。

输入 - 此输入搜索 log-events 索引中的错误,并将响应加载到 Watch Payload 中。

条件 - 此条件检查是否有超过 5 个错误事件(搜索响应中的命中)。如果有,则继续执行所有 actions

转换 - 如果满足 Watch 条件,此转换将通过使用默认搜索类型 query_then_fetch 搜索错误,将所有错误加载到 Watch Payload 中。所有 Watch 操作都可以访问此 Payload。

操作 - 此 Watch 有两个操作。 my_webhook 操作通知第三方系统有关问题的信息。 email_administrator 操作向系统管理员发送高优先级电子邮件。包含错误的 Watch Payload 附加到电子邮件。

Watch 执行编辑

当您添加一个 Watch 时,Watcher 会立即将其触发器注册到相应的触发器引擎。具有 schedule 触发器的 Watch 会注册到 scheduler 触发器引擎。

调度程序跟踪时间并根据其计划触发 Watch。在包含一个或多个 .watches 分片的每个节点上,都会运行一个与 Watcher 生命周期绑定的调度程序。即使所有主分片和副本都已考虑在内,当触发 Watch 时,Watcher 也会确保每个 Watch 仅在一个分片上触发。您添加的副本分片越多,Watch 的执行分布就越分散。如果您添加或删除副本,则所有 Watch 都需要重新加载。如果分片被重新分配,则此特定分片的 primary 和所有副本都将重新加载。

由于 Watch 在包含 Watch 分片的节点上执行,因此您可以通过使用分片分配过滤来创建专用的 Watcher 节点。

您可以使用专用的 node.attr.role: watcher 属性配置节点,然后像这样配置 .watches 索引

response = client.indices.put_settings(
  index: '.watches',
  body: {
    'index.routing.allocation.include.role' => 'watcher'
  }
)
puts response
PUT .watches/_settings
{
  "index.routing.allocation.include.role": "watcher"
}

当 Watcher 服务停止时,调度程序也会随之停止。触发器引擎使用与执行 Watch 所使用的线程池不同的线程池。

当触发 Watch 时,Watcher 会将其排队以供执行。一个 watch_record 文档被创建并添加到 Watch 历史记录中,Watch 的状态被设置为 awaits_execution

当执行开始时,Watcher 会为 Watch 创建一个 Watch 执行上下文。执行上下文为脚本和模板提供了对 Watch 元数据、Payload、Watch ID、执行时间和触发器信息的访问权限。有关更多信息,请参阅Watch 执行上下文

在执行过程中,Watcher 会

  1. 将输入数据作为 Payload 加载到 Watch 执行上下文中。这使得数据可用于执行过程中的所有后续步骤。此步骤由 Watch 的输入控制。
  2. 评估 Watch 条件以确定是否继续处理 Watch。如果条件满足(评估为 true),则处理将进入下一步。如果条件不满足(评估为 false),则 Watch 的执行将停止。
  3. 将转换应用于 Watch Payload(如果需要)。
  4. 执行 Watch 操作,前提是条件满足并且 Watch 未被节流

当 Watch 执行完成时,执行结果将作为Watch 记录记录在 Watch 历史记录中。Watch 记录包括执行时间和持续时间、Watch 条件是否满足以及执行的每个操作的状态。

下图显示了 Watch 执行过程

watch execution

Watch 确认和节流编辑

Watcher 支持基于时间和基于确认的节流。这使您能够防止对同一事件重复执行操作。

默认情况下,Watcher 使用基于时间的节流,节流周期为 5 秒。这意味着,如果 Watch 每秒执行一次,其操作最多每 5 秒执行一次,即使条件始终满足也是如此。您可以在每个操作的基础上或在 Watch 级别配置节流周期。

基于确认的节流使您能够告诉 Watcher,只要条件满足,就不要再发送有关 Watch 的任何通知。一旦条件评估为 false,确认将被清除,Watcher 将恢复正常执行 Watch 操作。

有关更多信息,请参阅确认和节流

Watch 活动状态编辑

默认情况下,当您添加一个 Watch 时,它会立即设置为活动状态,注册到相应的触发器引擎,并根据其配置的触发器执行。

您也可以将 Watch 设置为非活动状态。非活动 Watch 不会注册到触发器引擎,也永远不会被触发。

要在创建 Watch 时将其设置为非活动状态,请将active 参数设置为inactive。要停用现有 Watch,请使用停用 Watch API。要重新激活非活动 Watch,请使用激活 Watch API

您可以使用执行 Watch API 强制执行 Watch,即使它处于非活动状态。

停用 Watch 在各种情况下很有用。例如,如果您有一个监控外部系统的 Watch,并且您需要将该系统停机以进行维护,您可以停用 Watch 以防止它在维护窗口期间错误地报告可用性问题。

停用 Watch 还使您能够保留它以备将来使用,而无需将其从系统中删除。

脚本和模板编辑

在定义 Watch 时,您可以使用脚本和模板。脚本和模板可以引用 Watch 执行上下文中的元素,包括 Watch Payload。执行上下文定义了您可以在脚本中使用的变量以及模板中的参数占位符。

Watcher 使用 Elasticsearch 脚本基础设施,该基础设施支持内联存储的。脚本和模板由 Elasticsearch 编译和缓存,以优化重复执行。还支持自动加载。有关更多信息,请参阅脚本如何编写脚本

Watch 执行上下文编辑

以下代码段显示了Watch 执行上下文的基本结构

{
  "ctx" : {
    "metadata" : { ... }, 
    "payload" : { ... }, 
    "watch_id" : "<id>", 
    "execution_time" : "20150220T00:00:10Z", 
    "trigger" : { 
      "triggered_time" : "20150220T00:00:10Z",
      "scheduled_time" : "20150220T00:00:00Z"
    },
    "vars" : { ... } 
}

Watch 定义中指定的任何静态元数据。

当前 Watch Payload。

正在执行的 Watch 的 ID。

显示 Watch 执行开始时间的日期戳。

有关触发器事件的信息。对于 schedule 触发器,这包括 triggered_time(触发 Watch 的时间)和 scheduled_time(计划触发 Watch 的时间)。

在执行过程中,不同构造可以设置和访问的动态变量。这些变量的作用域限于单个执行(即它们不会持久化,并且不能在同一观察的不同的执行之间使用)。

使用脚本编辑

您可以使用脚本定义 条件转换。默认脚本语言是 Painless

从 5.0 开始,Elasticsearch 附带了新的 Painless 脚本语言。Painless 是专门为在 Elasticsearch 中使用而创建和设计的。除了提供广泛的功能集之外,它最大的特点是它被正确地沙箱化,并且可以在系统中的任何地方安全使用(包括在 Watcher 中),而无需启用动态脚本。

脚本可以引用观察执行上下文中的任何值,或者通过脚本参数显式传递的值。

例如,如果观察元数据包含一个 color 字段(例如 "metadata" : {"color": "red"}),您可以通过 ctx.metadata.color 变量访问它的值。如果您在条件或转换定义中传递一个 color 参数(例如 "params" : {"color": "red"}),您可以通过 color 变量访问它的值。

使用模板编辑

您可以使用模板为观察定义动态内容。在执行时,模板会从观察执行上下文中提取数据。例如,您可以使用模板使用存储在观察有效负载中的数据填充 email 操作的 subject 字段。模板还可以访问通过模板参数显式传递的值。

您可以使用 Mustache 脚本语言指定模板。

例如,以下代码段显示了模板如何在发送的电子邮件中启用动态主题

{
  "actions" : {
    "email_notification" : {
      "email" : {
        "subject" : "{{ctx.metadata.color}} alert"
      }
    }
  }
}
内联模板和脚本编辑

要定义内联模板或脚本,您只需在字段的值中直接指定它。例如,以下代码段使用引用上下文元数据中 color 值的内联模板配置 email 操作的主题。

"actions" : {
  "email_notification" : {
     "email" : {
       "subject" : "{{ctx.metadata.color}} alert"
     }
   }
  }
}

对于脚本,您只需将内联脚本指定为 script 字段的值。例如

"condition" : {
  "script" : "return true"
}

您也可以通过使用正式的对象定义作为字段值来显式指定内联类型。例如

"actions" : {
  "email_notification" : {
    "email" : {
      "subject" : {
         "source" : "{{ctx.metadata.color}} alert"
      }
    }
  }
}

脚本的正式对象定义将是

"condition" : {
  "script" : {
    "source": "return true"
  }
}
存储的模板和脚本编辑

如果您 存储您的模板和脚本,您可以通过 ID 引用它们。

要引用存储的脚本或模板,请使用正式的对象定义并在 id 字段中指定其 ID。例如,以下代码段引用了 email_notification_subject 模板

{
  ...
  "actions" : {
    "email_notification" : {
      "email" : {
        "subject" : {
          "id" : "email_notification_subject",
          "params" : {
            "color" : "red"
          }
        }
      }
    }
  }
}