nodeexporter编译
❶ 如何用sublimeText3编写less并用Nodejs自动编译成css
1、安装Sublime 插件
(1)安装LESS插件:
因为Sublime不支持Less语法高亮,
所以,先安装这个插件,
方法1: ctrl+shift+p>install Package>输入less按Enter
方法2:直接下载后 解压文件 放到插件文件夹下(首选项-浏览插件 打开文件夹)
下载地址:https://github.com/danro/LESS-sublime
(2)安装LESS2CSS插件:
less2css的读音 其实就是less to css
这个插件的作用是
当保存less文件的时候自动生成同名的css文件;
当保存less文件的时候提示编译错误信息;
批量编译项目目录下的所有less文件为css文件。
安装:
方法1:ctrl+shift+p>install Package>输入less2css按Enter
方法2:直接下载:https://github.com/timdouglas/sublime-less2css
解压文件 放到插件文件夹下
但是我们还要让sublime支持less并自动编译,所以还需以下步骤:
2、安装Node.js
首先先配置一下环境,
less需要nodejs支持,
所以我们先要安装一下nodejs
到nodejs官网下载就可以了:https://nodejs.org/en/
3、安装less
运行-cmd:
输入命令行:
npm install less -g
-g 代表着全局安装less
之后在 Sublime 里面建less文件时,会有一个错误
LESS: Unable to interpret argument clean-css
这是因为还需要一个插件
less-plugin-clean-css插件的安装
命令行为:
npm install less-plugin-clean-css -g
接着重启一下sublime,就搞定啦!
❷ 如何编写 Node.js 扩展
一、编写Node.js原生扩展
Node.js是一个强大的平台,理想状态下一切都都可以用javascript写成。然而,你可能还会用到许多遗留的库和系统,这样的话使用c++编写Node.JS扩展会是一个不错的注意。
以下所有例子的源代码可在node扩展示例中找到 。
编写Node.js C + +扩展很大程度上就像是写V8的扩展; Node.js增加了一些接口,但大部分时间你都是在使原始的V8数据类型和方法,为了理解以下的代码,你必须首先阅读V8引擎嵌入指南。
Javascript版本的Hello World
在讲解C++版本的例子之前,先让我们来看看在Node.js中用Javascript编写的等价模块是什么样子。这是一个最简单的Hello World,也不是通过HTTP,但它展示了node模块的结构,而其接口也和大多数C++扩展要提供的接口差不多:
HelloWorldJs = function() {
this.m_count = 0;
};
HelloWorldJs.prototype.hello = function()
{
this.m_count++;
return “Hello World”;
};
exports.HelloWorldJs = HelloWorldJs;
正如你所看到的,它使用prototype为HelloWorldJs类创建了一个新的方法。请注意,上述代码通过将HelloWorldJS添加到exports变量来暴露构造函数。
要在其他地方使用该模块,请使用如下代码:
var helloworld = require(‘helloworld_js’);
var hi = new helloworld.HelloWorldJs();
console.log(hi.hello()); // prints “Hello World” to stdout
C++版本的Hello World
要开始编写C++扩展,首先要能够编译Node.js(请注意,我们使用的是Node.js 2.0版本)。本文所讲内容应该兼容所有未来的0.2.x版本。一旦编译安装完node,编译模块就不在需要额外的东西了。
完整的源代码可以在这里找到 。在使用Node.js或V8之前,我们需要包括相关的头文件:
#include <v8.h>
#include <node.h>
using namespace node;
using namespace v8;
在本例子中我直接使用了V8和node的命名空间,使代码更易于阅读。虽然这种用法和谷歌的自己的C++编程风格指南相悖,但由于你需要不停的使用V8定义的类型,所以目前为止的大多数node的扩展仍然使用了V8的命名空间。
接下来,声明HelloWorld类。它继承自node::ObjectWrap类 ,这个类提供了几个如引用计数、在V8内部传递contex等的实用功能。一般来说,所有对象应该继承ObjectWrap:
class HelloWorld: ObjectWrap
{
private:
int m_count;
public:
声明类之后,我们定义了一个静态成员函数,用来初始化对象并将其导入Node.js提供的target对象中。设个函数基本上是告诉Node.js和V8你的类是如何创建的,和它将包含什么方法:
static Persistent<FunctionTemplate> s_ct;
static void Init(Handle<Object> target)
{
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
s_ct = Persistent<FunctionTemplate>::New(t);
s_ct->InstanceTemplate()->SetInternalFieldCount(1);
s_ct->SetClassName(String::NewSymbol(“HelloWorld”));
NODE_SET_PROTOTYPE_METHOD(s_ct, “hello”, Hello);
target->Set(String::NewSymbol(“HelloWorld”),
s_ct->GetFunction());
}
在上面这个函数中target参数将是模块对象,即你的扩展将要载入的地方。(译着:这个函数将你的对象及其方法连接到
这个模块对象,以便外界可以访问)首先我们为New方法创建一个FunctionTemplate,将于稍后解释。我们还为该对象添加一个内部字段,并命
名为HelloWorld。然后使用NODE_SET_PROTOTYPE_METHOD宏将hello方法绑定到该对象。最后,一旦我们建立好这个函数模板后,将他分配给target对象的HelloWorld属性,将类暴露给用户。
接下来的部分是一个标准的C++构造函数:
HelloWorld() :
m_count(0)
{
}
~HelloWorld()
{
}
接下来,在::New 方法中V8引擎将调用这个简单的C++构造函数:
static Handle<Value> New(const Arguments& args)
{
HandleScope scope;
HelloWorld* hw = new HelloWorld();
hw->Wrap(args.This());
return args.This();
}
此段代码相当于上面Javascript代码中使用的构造函数。它调用new HelloWorld
创造了一个普通的C++对象,然后调用从ObjectWrap继承的Wrap方法,
它将一个C++HelloWorld类的引用保存到args.This()的值中。在包装完成后返回args.This(),整个函数的行为和
javascript中的new运算符类似,返回this指向的对象。
现在我们已经建立了对象,下面介绍在Init函数中被绑定到hello的函数:
static Handle<Value> Hello(const Arguments& args)
{
HandleScope scope;
HelloWorld* hw = ObjectWrap::Unwrap<HelloWorld>(args.This());
hw->m_count++;
Local<String> result = String::New(“Hello World”);
return scope.Close(result);
}
函数中首先使用ObjectWrap模板的方法提取出指向HelloWorld类的指针,然后和javascript版本的HelloWorld一样递增计数器。我们新建一个内容为“HelloWorld”的v8字符串对象,然后在关闭本地作用域的时候返回这个字符串。
上面的代码实际上只是针对v8的接口,最终我们还需要让Node.js知道如何动态加载我们的代码。为了使Node.js的扩展可以在执行时从动态链接库加载,需要有一个dlsym函数可以识别的符号,所以执行编写如下代码:
extern “C” {
static void init (Handle<Object> target)
{
HelloWorld::Init(target);
}
NODE_MODULE(helloworld, init);
}
由于c++的符号命名规则,我们使用extern
C,以便该符号可以被dysym识别。init方法是Node.js加载模块后第一个调用的函数,如果你有多个类型,请全部在这里初始化。
NODE_MODULE宏用来填充一个用于存储模块信息的结构体,存储的信息如模块使用的API版本。这些信息可以用来防止未来因API不兼容导致的崩
溃。
到此,我们已经完成了一个可用的C++ NodeJS扩展。
Node.js也提供了一个用于构建模块的简单工具:
node-waf首先编写一个包含扩展编译方法的wscript文件,然后执行node-waf configure &&
node-waf build完成模块的编译和链接工作。对于这个helloworld的例子来说,wscript内容如下:
def set_options(opt):
opt.tool_options(“compiler_cxx”)
def configure(conf):
conf.check_tool(“compiler_cxx”)
conf.check_tool(“node_addon”)
def build(bld):
obj = bld.new_task_gen(“cxx”, “shlib”, “node_addon”)
obj.cxxflags = [“-g”, “-D_FILE_OFFSET_BITS=64”, “-D_LARGEFILE_SOURCE”, “-Wall”]
obj.target = “helloworld”
obj.source = “helloworld.cc”
异步IO的HelloWorld
对于实际的应用来说,HelloWorld的示例太过简单了一些,Node.js主要的优势是提供异步IO。
Node.js内部通过libeio将会产生阻塞的操作全都放入线程池中执行。如果需要和遗留的c库交互,通常需要使用异步IO来为javascript
代码提供回调接口。
通常的模式是提供一个回调,在异步操作完成时被调用——你可以在整个Node.js的API中看到这种模式。
Node.js的filesystem模块提供了一个很好的例子,其中大多数的函数都在操作完成后通过调用回调函数来传递数据。和许多传统的GUI框架一
样,Node.js只在主线程中执行JavaScript,因此主线程以外的任何操作都不应该直接和V8或Javascript交互。
同样helloworld_eio.cc源代码在GitHub上。我只强调和原来HelloWorld之间的差异,其中大部分代码保持不变,变化集中在Hello方法中:
static Handle<Value> Hello(const Arguments& args)
{
HandleScope scope;
REQ_FUN_ARG(0, cb);
HelloWorldEio* hw = ObjectWrap::Unwrap<HelloWorldEio>(args.This());
在Hello函数的入口处 ,我们使用宏从参数列表的第一个位置获取回调函数,在下一节中将详细介绍。然后,我们使用相同的Unwarp方法提取指向类对象的指针。
hello_baton_t *baton = new hello_baton_t();
baton->hw = hw;
baton->increment_by = 2;
baton->sleep_for = 1;
baton->cb = Persistent<Function>::New(cb);
这里我们创建一个baton结构,并将各种参数保存在里面。请注意,我们为回调函数创建了一个永久引用,因为我们想要在超出当前函数作用域的地方使用它。如果不这么做,在本函数结束后将无法再调用回调函数。
hw->Ref();
eio_custom(EIO_Hello, EIO_PRI_DEFAULT, EIO_AfterHello, baton);
ev_ref(EV_DEFAULT_UC);
return Undefined();
}
如下代码是真正的重点。首先,我们增加HelloWorld对象的引用计数,这样在其他线程执行的时候他就不会被回收。
函数eio_custom接受两个函数指针作为参数。EIO_Hello函数将在线程池中执行,然后EIO_AfterHello函数将回到在“主线程”
中执行。我们的baton结构也被传递进各函数,这些函数可以使用baton结构中的数据完成相关的操作。同时,我们也增加event
loop的引用。这很重要,因为如果event
loop无事可做,Node.js就会退出。最终,函数返回Undefined,因为真正的工作将在其他线程中完成。
static int EIO_Hello(eio_req *req)
{
hello_baton_t *baton = static_cast<hello_baton_t *>(req->data);
sleep(baton->sleep_for);
baton->hw->m_count += baton->increment_by;
return 0;
}
这个回调函数将在libeio管理的线程中执行。首先,解析出baton结构,这样可以访问之前设置的各种参数。然后
sheep
baton->sleep_for秒,这么做是安全的,因为这个函数运行在独立的线程中并不会阻塞主线程中javascript的执行。然后我们的
增计数器,在实际的系统中,这些操作通常需要使用Lock/Mutex进行同步。
当上述方法返回后,libeio将会通知主线程它需要在主线成上执行代码,此时EIO_AfterHello将会被调用。
static int EIO_AfterHello(eio_req *req)
{
HandleScope scope;
hello_baton_t *baton = static_cast<hello_baton_t *>(req->data);
ev_unref(EV_DEFAULT_UC);
baton->hw->Unref();
进度此函数时,我们提取出baton结构,删除事件循环的引用,并减少HelloWorld对象的引用。
Local<Value> argv[1];
argv[0] = String::New(“Hello World”);
TryCatch try_catch;
baton->cb->Call(Context::GetCurrent()->Global(), 1, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
新建要传递给回调函数的字符串参数,并放入字符串数组中。然后我们调用回调传递一个参数,并检测可能抛出的异常。
baton->cb.Dispose();
delete baton;
return 0;
}
在执行过回调之后,应该销毁持久引用,然后删除之前创建的baton结构。
最后,你可以使用如下形式在Javascript中使用该模块:
var helloeio = require(‘./helloworld_eio’);
hi = new helloeio.HelloWorldEio();
hi.hello(function(data){
console.log(data);
});
参数传递与解析
除了HelloWorld之外,你还需要理解最后一个问题:参数的处理。在helloWorld EIO例子中,我们使用一个REQ_FUN_ARG宏,然我们看看这个宏到底都做些什么。
#define REQ_FUN_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsFunction()) \
return ThrowException(Exception::TypeError( \
String::New(“Argument ” #I ” must be a function”))); \
Local<Function> VAR = Local<Function>::Cast(args[I]);
就像Javascript中的argument变量,v8使用数组传递所有的参数。由于没有严格的类型限制,所以传递给函数的参数数目可能和期待的不同。为了对用户友好,使用如下的宏检测一下参数数组的长度并判断参数是否是正确的类型。如果传递了错误的参数类型,该宏将会抛出TypeError异常。为简化参数的解析,目前为止大多数的Node.js扩展都有一些本地作用域内的宏,用于特定类型参数的检测。
二、揭秘node.js事件
要使用NodeJS,你需要知道一个重要的东西:事件(events)。Node中有很多对象都可以触发事件,Node
的文档中有很多示例。但文档也许并不能清晰的讲解如何编写自定义事件以及监听函数。对于一些简单的程序你可以不使用自定义事件,但这样很难应对复杂的应
用。那么如何编写自定义事件?首先需要了解的是在node.js中的’events’模块。
快速概览
要访问此模块,只需使用如下语句:
require(‘events’)
requires(‘events’).EventEmitter
特别说明,node中所有能触发事件的对象基本上都是后者的实例。让我们创建一个简单的演示程序Dummy:
mmy.js
view plain to clipboardprint?
// basic imports
var events = require(‘events’);
// for us to do a require later
mole.exports = Dummy;
function Dummy() {
events.EventEmitter.call(this);
}
10.
11. // inherit events.EventEmitter
12. Dummy.super_ = events.EventEmitter;
13. Dummy.prototype = Object.create(events.EventEmitter.prototype, {
14. constructor: {
15. value: Dummy,
16. enumerable: false
17. }
18. });
// basic imports
var events = require(‘events’);
// for us to do a require later
mole.exports = Dummy;
function Dummy() {
events.EventEmitter.call(this);
}
// inherit events.EventEmitter
Dummy.super_ = events.EventEmitter;
Dummy.prototype = Object.create(events.EventEmitter.prototype, {
constructor: {
value: Dummy,
enumerable: false
}
});
上述代码中重点展示如何使用EventEmitter扩充对象,并从中继承所有的原型对象,方法…等等。
现在,我们假设Dummy有一个cooking()的方法,一旦把食物做熟之后它会触发’cooked’事件,并调用一个名为’eat’的回调函数。
mmy-cooking.js
view plain to clipboardprint?
Dummy.prototype.cooking = function(chicken) {
var self = this;
self.chicken = chicken;
self.cook = cook(); // assume mmy function that’ll do the cooking
self.cook(chicken, function(cooked_chicken) {
self.chicken = cooked_chicken;
self.emit(‘cooked’, self.chicken);
});
10. return self;
11. }
Dummy.prototype.cooking = function(chicken) {
var self = this;
self.chicken = chicken;
self.cook = cook(); // assume mmy function that’ll do the cooking
self.cook(chicken, function(cooked_chicken) {
self.chicken = cooked_chicken;
self.emit(‘cooked’, self.chicken);
});
return self;
}
❸ 普罗米修斯怎么监控主机oom detect
一、监控主机(其他主机一样)
1、被监控服务器需要安装node_exporter
(1)下载node_exporter-1.1.2.linux-amd64.tar.gz,解压到/usr/local目录下并重命名node_exporter
(2)启动 node_exporter
2、添加grafana服务器监控节点信息并重启,重启prometheus
3、查看是否添加成功打开浏览器输入:http://IP:9090/
4、访问grafana,添加图像界面浏览器访问IP:3000端口
1、添加数据源5、导入模板,模板可以到官网下载,docker 主机监控模板:193Liunx主机监控模板:9276
二、监控docker容器1、添加监控节点同理
2、在被监控服务器部署cadvisor容器
3、验证浏览器访问http://IP:8082/
4、添加数据源同理
5、导入模板同理。
❹ vue: WebStorm设置快速编译运行的方法
WebSorm是一款优秀的前端开发工具,而Vue项目可以使用Node进行编译运行,平常我们可以通过命令行部署项目进行调试。
本文介绍设置Webstorm进行快速部署Vue项目。
第一步
点击启动快捷按钮旁边的向下小箭头,在列表中选择Edit选项:
第二步
打开启动设置页面后,点击左上角的加号添加新的运行方式:
第三步
在弹出的选择框中,选择node.js启动模式:
第四步
在新打开的设置页面中,在红色圈中的地方设置如图路径的文件:
至此设置成功,直接点启动按钮就可以部署项目。
以上这篇vue:
WebStorm设置快速编译运行的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:webstorm添加*.vue文件支持webstorm添加vue.js支持的方法教程webstorm中vue语法的支持详解webstorm和.vue中es6语法报错的解决方法详解Webstorm
新建.vue文件支持高亮vue语法和es6语法
❺ node_exporter修改启动端口
https://blog.csdn.net/weixin_44723434/article/details/89237202
❻ 运行在服务端的Node.js代码需要编译吗
首先实现一个处理静态资源的函数,其实就是对本地文件的读取操作,这个方法已满足了上面说的静态资源的处理。
//处理静态资源
function staticResHandler(localPath, ext, response) {
fs.readFile(localPath, "binary", function (error, file) {
if (error) {
response.writeHead(500, { "Content-Type": "text/plain" });
response.end("Server Error:" + error);
} else {
response.writeHead(200, { "Content-Type": getContentTypeByExt(ext) });
response.end(file, "binary");
}
});
}
❼ 如何用命令行编译nodejs文件
在window平台,.js文件默认是cscript运行的。
你可以用node 空格 js文件名的方式用nodejs运行js文件,不能直接运行。
❽ 2020-08-25
Prometheus 实现邮件告警(Prometheus+Alertmanager+QQ邮箱或者网易163邮箱,目前测试过这两种邮箱都可以发送告警邮件)
Prometheus实现邮件告警原理如下:
Prometheus官方有一个附带的中间件:alertmanager,通过设置rules规则和路由转发可以实现邮件告警,前提是你需要有一个可以发送邮件的邮件服务端(可以自建或者使用互联网公司提供的免费邮箱)
告警原理图
Prometheus完整架构图
我之前得出的错误结论如下:
推荐直接在虚拟机操作系统上直接安装Prometheus和Alertmanager,不推荐其中任何一方在容器中运行,因为测试过在容器中运行Prometheus和alertmanager,结果出现如下错误情况
第一种情况是:我的node-exporter掉线跌机了(手动关机,模拟突然掉线跌机),Prometheus却提示节点依然在线?有时候却能够正常显示节点掉线跌机,生成告警发送邮件
第二种情况是:我的node-exporter掉线跌机了(手动关机,模拟突然掉线跌机),Prometheus提示节点掉线,告警生成,但是没有发送邮件,我手动恢复node-exporter后,告警解除,邮件能正常发送邮件提示告警已经解除。。。。
第三种情况是:我的node-exporter掉线跌机了(手动关机,模拟突然掉线跌机),Prometheus提示节点掉线,告警生成,正常成功发送邮件,我手动恢复node-exporter后,告警解除,邮件没有发送出来。。。。
以上三种情况之前经常出现,当时第一步以为是自己设置的scrape_interval不合理导致的,结果调试几次,问题没有解决,第二步以为是自己的服务器时间没有做到精确同步,然后我去设置和阿里云的ntp服务器同步,结果问题依然没有解决,第三步,换个方向,把alertmanager迁移到虚拟机操作系统上安装运行,问题解决!
北京时间是GMT+8小时,有些同志的时间可能是UTC的,但是如果是在要求不太十分精确的情况下,UTC时间是刚刚好等于GMT时间
为了避免时区的混乱,prometheus所有的组件内部都强制使用Unix时间,对外展示使用GMT时间。
要改时区有两个办法
1 .修改源码,重新编译。
2. 使用 docker 运行 Prometheus,挂载本地时区文件
docker run --restart always -e TZ=Asia/Shanghai --hostname prometheus --name prometheus-server -d -p 9090:9090 -v /data/prometheus/server/data:/prometheus -v /data/prometheus/server/conf/prometheus.yml:/etc/prometheus/prometheus.yml -u root prom/prometheus:v2.5.0
正文开始
安装alertmanager
容器安装方式:
docker run -d --name alertmanager -p 9093:9093 -v /usr/local/Prometheus/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml prom/alertmanager:latest
先在宿主机/usr/local/Prometheus下创建一个文件夹alertmanager,然后在文件夹里创建alertmanager.yml配置文件,待会才能映射到alertmanager容器里的/etc/alertmanager目录下
global:全局配置
resolve_timeout: 问题解决的超时时间
smtp_from: 发送告警邮件的邮箱账号
smtp_smarthost: 邮箱 SMTP 服务地址,这里是以QQ邮箱为例,也可以用网易163邮箱,这个和我之前设置zabbix邮件告警时的配置一样
smtp_auth_username: 如果没有设置邮箱别名,那就是账户名
smtp_auth_password: 邮箱的授权码,不是 账户密码,你可以在QQ邮箱或者网易163邮箱网页端设置,开启 POP3/SMTP 服务时会提示,和配置zabbix邮件告警的时候几乎一样
smtp_require_tls: 是否使用 tls,根据环境不同,来选择开启和关闭。如果提示报错 email.loginAuth failed: 530 Must issue a STARTTLS command first,那么就需要设置为 true。着重说明一下,如果开启了 tls,提示报错 starttls failed: x509: certificate signed by unknown authority,需要在 email_configs 下配置 insecure_skip_verify: true 来跳过 tls 验证。
templates: 告警模板目录,可以不编写模板,有默认模板
Subject: '{{ template "email.default.subject" . }}'
html: '{{ template "email.default.html" . }}'
route:报警的分发设置
group_by:分组
group_wait: 分组等待时间
group_interval: 5m 每组时间间隔
repeat_interval: 10m 重复间隔
receiver: 接收方式,请注意!这里的名字要对应下面receivers中的任何一个名字,不然会报错,这里其实就是选择方式,有邮箱,企业微信,wehook,victorops等等
receivers:接受方式汇总,即告警方式汇总
例子:
receivers:
- name:'default-receiver'
email_configs:
- to:'[email protected]'
html: '{{ template "alert.html" . }}'
headers: { Subject: "[WARN] 报警邮件test"}
inhibit_rules: 抑制规则
当存在与另一组匹配的警报(源)时,抑制规则将禁用与一组匹配的警报(目标)。
包括源匹配和目标匹配
alertmanager官方是这样说的
Inhibition
Inhibition is a concept of suppressing notifications for certain alerts if certain other alerts are already firing.
Example: An alert is firing that informs that an entire cluster is not reachable. Alertmanager can be configured to mute all other alerts concerning this cluster if that particular alert is firing. This prevents notifications for hundreds or thousands of firing alerts that are unrelated to the actual issue.
Inhibitions are configured through the Alertmanager's configuration file.
当存在与另一组匹配器匹配的警报(源)时,禁止规则会使与一组匹配器匹配的警报(目标)静音。目标警报和源警报的equal列表中的标签名称都必须具有相同的标签值。
在语义上,缺少标签和带有空值的标签是同一件事。因此,如果equal源警报和目标警报都缺少列出的所有标签名称,则将应用禁止规则。
为了防止警报禁止自身,与规则的目标和源端 都 匹配的警报不能被警报(包括其本身)为真来禁止。但是,我们建议选择目标匹配器和源匹配器,以使警报永远不会同时匹配双方。这很容易进行推理,并且不会触发此特殊情况。
接着是规则rules
不解释了,自己研究官方文档
alertmanager的非容器安装方式是
wget https://github.com/prometheus/alertmanager/releases/download/v0.20.0/alertmanager-0.20.0.linux-amd64.tar.gz
tar xf alertmanager-0.20.0.linux-amd64.tar.gz
mv alertmanager-0.20.0.linux-amd64 /usr/local/alertmanager
vim /usr/lib/systemd/system/alertmanager.service
[Unit]
Description=alertmanager
Documentation=https://github.com/prometheus/alertmanager
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/alertmanager/alertmanager --config.file=/usr/local/alertmanager/alertmanager.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alertmanager 安装目录下默认有 alertmanager.yml 配置文件,可以创建新的配置文件,在启动时指定即可。
其余方式和上面一样
接着是Prometheus,我之前的博客里有写了容器安装和非容器安装的方法,自己去翻阅
然后是在prometheus.yml里修改相关配置
首先去掉alertmanager的注释,改成IP加你设置的端口号,默认是9093
接着在rule_files: 下面写下规则文件的绝对路径,可以是具体文件名,也可以是*,也可以分几级文件,*默认是全部匹配
接着是被监控项的设置,这里设置完成可以在Prometheus网页里的targets里看得到
请注意,这里设置的参数名字要和rule规则中设置的参数名字一模一样,否则你的prometheus服务会无法启动,然后报错
如果不在特定的job下设置scrape_interval(优先级高于全局),则默认采用gobal下的scrape_interval
最后模拟节点掉线,手动关闭node-exporter或者Cadvisor
docker stop node-exporter 或者容器ID
docker stop cadvisor 或者容器ID
或者把up{{job='prometheus'}} == 1 设置成1,反向设置,不用关掉服务,就可以看看告警成不成功
说明一下 Prometheus Alert 告警状态有三种状态:Inactive、Pending、Firing。
Inactive:非活动状态,表示正在监控,但是还未有任何警报触发。
Pending:表示这个警报必须被触发。由于警报可以被分组、压抑/抑制或静默/静音,所以等待验证,一旦所有的验证都通过,则将转到 Firing 状态。
Firing:将警报发送到 AlertManager,它将按照配置将警报的发送给所有接收者。一旦警报解除,则将状态转到 Inactive,如此循环。
没有配置告警模板时的默认告警格式是这样的
节点恢复后邮件告知是这样的
写了模板后是这样的
还要重新映射模板文件夹路径到alertmanager容器里的相对路径,然后重启alertmanager,当然,如果目录下没有模板文件,则不显示
告警模板
在alertmanager.yml中修改相关设置
重启alertmanager
docker restart alertmanager
最终效果不是很好
❾ Prometheus的四大指标类型
Prometheus有4大指标类型(Metrics Type),分别是Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)和Summary(摘要)。
这是在Prometheus客户端(目前主要有Go、Java、Python、Ruby等语言版本)中提供的4种核心指标类型,但是Prometheus的服务端并不区分指标类型,而是简单地把这些指标统一视为无类型的时间序列。
注意:
<font color=red>上面这句话应该这么理解,四个指标类型,实际上就是客户端采集数据的四个维度,采集这四个维度的指标数据,但是最终汇总到服务端那里,则是对这四个维度无感的,只是简单的作为时间序列存储起来。</font>
计数器表示一种单调递增的指标,除非发生重置的情况下下只增不减,其样本值应该是不断增大的。例如,可以使用Counter类型的指标来表示服务的请求数、已完成的任务数、错误发生的次数等。
但是,计数器计算的总数对用户来说大多没有什么用,大家千万不要将计数器类型应用于样本数据非单调递增的指标上,比如当前运行的进程数量、当前登录的用户数量等应该使用仪表盘类型。
为了能够更直观地表示样本数据的变化情况,往往需要计算样本的增长速率,这时候通常使用PromQL的rate、topk、increase和irate等函数,如下所示:
如上所示,速率的输出rate(v range-vector)也应该用仪表盘来承接结果。
在上面的案例中,如果有一个标签是Device,那么在统计每台机器每秒接受的HTTP请求数时,可以用如下的例子进行操作。
补充
这背后与rate()的实现方式有关,rate()在设计上假定对应的指标是一个计数器,也就是只有<font color=red>incr(增加)和reset(归零)</font>两种行为。而执行了sum()或其他聚合操作之后,得到的就不再是一个计数器了。举个例子,比如sum()的计算对象中有一个归零了,那整体的和会下降,而不是归零,这会影响rate()中判断reset(归零)的逻辑,从而导致错误的结果。
increase(v range-vector)函数传递的参数是一个区间向量,increase函数获取区间向量中的第一个和最后一个样本并返回其增长量。下面的例子可以查询Counter类型指标的增长速率,可以获取http_requests_total在最近5分钟内的平均样本,其中300代表300秒。
rate和increase函数计算的增长速率容易陷入<font color=red>长尾效应中</font>。比如在 某一个由于访问量或者其他问题导致CPU占用100%的情况中,通过计算在时间窗口内的平均增长速率是无法反映出该问题的 。
为什么监控和性能测试中,我们更关注p95/p99位?就是因为长尾效应。由于个别请求的响应时间需要1秒或者更久,<font color=red>传统的响应时间的平均值就体现不出响应时间中的尖刺了</font>,去尖刺也是数据采集中一个很重要的工序,这就是所谓的长尾效应。p95/p99就是长尾效应的分割线,如表示99%的请求在XXX范围内,或者是1%的请求在XXX范围之外。99%是一个范围,意思是99%的请求在某一延迟内,剩下的1%就在延迟之外了。只是正推与逆推而已,是一种概念的两种不同描述。
irate(v range-vector)是PromQL针对长尾效应专门提供的灵敏度更高的函数。irate同样用于计算区间向量的增长速率,但是其反映出的是瞬时增长速率。irate函数是通过区间向量中最后两个样本数据来计算区间向量的增长速率的。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度。通过irate函数绘制的图标能够更好地反映样本数据的瞬时变化状态。irate的调用命令如下所示。
irate函数相比于rate函数提供了更高的灵敏度,不过分析长期趋势时或者在告警规则中,irate的这种灵敏度反而容易造成干扰。因此,在长期趋势分析或者告警中更推荐使用rate函数。
仪表盘类型代表一种<font color=red>样本数据可以任意变化的指标,即可增可减</font>。它可以理解为状态的快照,Gauge通常用于表示温度或者内存使用率这种指标数据,也可以表示能随时增加或减少的“总数”,例如当前并发请求的数量node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)等。在使用Gauge时,用户往往希望使用它们<font color=red>求和、取平均值、最小值、最大值</font>等。
以Prometheus经典的Node Exporter的指标node_filesystem_size_bytes为例,它可以报告从node_filesystem_size_bytes采集来的文件系统大小,包含device、fstype和mountpoint等标签。如果想要对每一台机器上的总文件系统大小求和(sum),可以使用如下PromQL语句。
without可以让sum指令根据相同的标签进行求和,但是忽略without涵盖的标签。如果在实际工作中需要忽略更多标签,可以根据实际情况在without里传递更多指标。
补充 :
node_filesystem_size_bytes指标查询
device, fstype, mountpoint都是他的标签。
sum without(device, fstype, mountpoint)(node_filesystem_size_bytes)查询
如果要根据Node Exporter的指标node_filesystem_size_bytes计算每台机器上最大的文件安装系统大小,只需要将上述案例中的sum函数改为max函数,如下所示。
除了求和、求最大值等,利用Gauge的函数求最小值和平均值等原理是类似的。除了基本的操作外,Gauge经常结合PromQL的predict_linear和delta函数使用。
predict_linear(v range-vector,t scalar)函数可以预测时间序列v在t秒后的值,就是使用线性回归的方式,预测样本数据的Gauge变化趋势。例如,基于2小时的样本数据,预测未来24小时内磁盘是否会满,如下所示:
PromQL还有一个内置函数delta(),它可以获取样本在一段时间内的变化情况,也通常作用于Gauge。例如,计算磁盘空间在2小时内的差异,如下所示。
Histogram是一个对数据分布情况的图形表示,由一系列高度不等的长条图(bar)或线段表示,用于展示单个测度得知的分布。
[图片上传失败...(image-3e55f2-1622153155462)]
上边界、样本值总和、样本总数
例子
这三个查询一起看
所有样本值的总和,命名为<basename>_sum。
prometheus_http_request_ration_seconds_sum{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}0.405075955 表示12 次http请求的总响应时间是0.405075955
命名为<basename>_count,其值和<basename>_bucket{le="+Inf"}相同(所有)。
prometheus_http_request_ration_seconds_count{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}12 表示总共发生了12次请求
sum函数和count函数相除,可以得到一些平均值,比如Prometheus一天内的平均压缩时间,可由查询结果除以instance标签数量得到,如下所示。
除了Prometheus内置的压缩时间,prometheus_local_storage_series_chunks_persisted表示Prometheus中每个时序需要存储的chunk数量,也可以用于计算待持久化的数据的分位数。
Histogram可以用于观察样本数据的分布情况。Histogram的分位数计算需要通过histogram_quantile(φfloat,b instant-vector)函数进行计算,但是histogram_quantile计算所得并非精确值。其中,φ(0<φ<1)表示需要计算的分位数(这个值主要是通过prometheus_http_request_ration_seconds_bucket和prometheus_http_request_ration_seconds_sum两个指标得到的,是一个近似值)。
例子如下。
与Histogram类型类似,摘要用于表示一段时间内的数据采样的结果(通常是请求持续时间或响应大小等),但它直接存储了分位数(通过客户端计算,然后展示出来),而非通过区间来计算(Histogram的分位数需要通过histogram_quantile(φfloat,b instant-vector)函数计算得到)。因此,对于分位数的计算,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之,对于客户端而言,Histogram消耗的资源更少。在选择这两种方式时,用户应该根据自己的实际场景选择。
Histogram是在服务端计算的,Summary是在客户端计算的。
安装并启动Prometheus后,在访问 http://localhost:9090/metrics 时可以看到Prometheus自带的一些Summary信息,这些信息和Histogram一样在注释中(#HELP和#TYPE)也会显示,如下所示。
在上述例子中,可以看到基于Go语言编写的Prometheus的gc总次数是1907,耗时0.193642882s,其中中位数(quantile=0.5)计算的耗时为4.8366e-05s,代表1907次中50%的次数是小于4.8366e-05s的。
Summary类型的样本也会提供3种指标,假设指标名称为<basename>。
Summary和Histogram的异同
Summary的强大之处就是可以利用除法去计算时间的平均值。如果要从Histogram和Summary中计算最近5分钟内的平均请求持续时间http_request_ration_seconds,可以用如下表达式进行。
count本质上是一个计数器,sum通常情况下也会像计数器那样工作。但是<font color=red>Summary和Histogram可能观察到负值,比如温度(-20℃),这种情况下会导致观察的总量下降,无法再使用rate函数</font>。
比如下面的例子就可以计算过去5分钟内每次响应中返回的平均字节数。
关于这个例子,我们需要注意几点。
·因为http_response_size_bytes_count和http_response_size_bytes_sum是计数器类型,所以必须在计算前先使用rate等函数。
·因为Prometheus的API会有很多handler,所以可以使用without过滤掉handler的返回值。
·PromQL要先执行rate()再执行sum(),不能先执行sum()再执行rate()。
·在统计学上,尤其是计算平均值时,要先进行sum等求和运算再做除法。对一个平均值再求平均是不正确的,如下所示。
count的例子
案例一:计算所有的实例CPU核心数。
count by (instance) ( count by (instance,cpu) (node_cpu_seconds_total{mode=
"system"}) )
案例二:计算单个实例192.168.1.1的CPU核心数。
count by (instance) ( count by (instance,cpu) (node_cpu_seconds_total{mode="system",
instance="192.168.1.1"})