作者简介
秦超(生举)
2013年毕业于河海大学,计算机科学与技术,硕士学位。
前携程集团技术专家。
从0到1 建立和携程机票出票系统、验票系统,著有《机票订单的出票方法及系统》、《通用航空电子票验票方法》等专利。
负责携程机票保险出、退、改、理赔系统。集团很大一部分营收都是靠这个系统, 系统需要极致的稳定性。
负责携程机票支付网关系统,升级了携程机票支付网关模型,项目涉及4个BU,100+开发,改造后的模型,支撑了很多客户、公司、航司三赢的场景。
现在淘菜菜物流域做运输的排线、调度、实操、以及司机的分层治理。
监控在整个微服务体系中的地位
这是市场上现有的微服务整理方案的一个选型。每个技术点都有很多替换的方案。
监控的种类和比较
出处:
Go for Industrial Programming
https://peter.bourgon.org/go-for-industrial-programming/
监控可用分为三类:Logging、Metrics、Tracing。
Logging
现在阿里一般用的是sls,外面一般是elk,也就是elastic search + logstash + kibana。
其中es负责日志的存储、查询。
logstash负责日志的收集。
kibana负责日志的展示。
Tracing
主要是做调用链监控
现在市面上可选的tracing系统有很多,
2002年, ebay做了一个第一个调用链监控系统 CAL。
2010年, google发了一篇论文,叫做《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》
2011年,吴其敏在美团写了CAT。
2012年,twiter实现了dapper的开源版本,zipkin。
2014年,阿里也实现了dapper,也就是eagleye。
最近一些年 社区又有了很多其他类似的调用链监控, 但是基本都是基于dapper的实现,比如uber的jaeger, open tracing。
《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》的原文和译文地址:
https://github.com/AlphaWang/alpha-dapper-translation-zh
Metrics
阿里的metrics监控, 是用的sunfire,外面我接触过的是prometheus+grafana。
prometheus负责收集、存储和查询。
grafana 负责展示。
metris监控, 一般由几个部分组成:
1、metrics收集器
2、metrics查询引擎
3、metrics存储
4、用于展示的dashboard
5、用于告警的alerts。
时间序列数据库
时间序列数据库存什么内容?
时间序列数据就是一个数据源会每隔一段时间产生一条数据,除了时间戳和值不一样,其他都相同。比如一个cpu的使用率,随着时间的变化不断变化,那么它产生的数据就是时间序列数据。
比如一个典型的时间序列的数据:
http_requests_total{endpoint="/login",status="500",} 44545.0 http_requests_total{endpoint="/register",status="500",} 12781.0 http_requests_total{endpoint="/login",status="200",} 4434300.0 http_requests_total{endpoint="/register",status="200",} 1268621.0 http_requests_total{endpoint="/users/{id}",status="500",} 6397.0 http_requests_total{endpoint="/logout",status="200",} 2532440.0 http_requests_total{endpoint="/users/{id}",status="200",} 633429.0 http_requests_total{endpoint="/users",status="200",} 1899649.0 http_requests_total{endpoint="/users",status="500",} 19298.0 http_requests_total{endpoint="/logout",status="500",} 25668.0
其中http_requests_total 一般叫做metric name。 用{}扩起来的code 和 path, 一般叫做label或者tag。后面是其具体的值。时间一般在记录的时候插入进去。
为什么不能直接用关系型数据库来存?
1、metric 和 tag是动态变化的,传统的关系型数据库无法快速响应变化。
2、需要对tag做大量的聚合操作,物化视图 和实时聚合 传统的关系型数据库都做的不够好。
3、数据的结构,决定了时间序列数据,可以在存储上做大量的优化,从而减少存储的空间、支持更高的写入。比如利用LSM树(Log Structured Merge Tree)可以提高写入的速度。
Prometheus 的存储层在展现出卓越的性能,单一服务器每秒就能够摄入上百万个时间序列样本,同时只占用了很少的磁盘空间。
常见的时间序列数据库有:influxdb, opentsdb,prometheus。
时间序列数据库对比
趋势对比
数据来源:
https://db-engines.com/en/ranking_trend/time+series+dbms
什么是prometheus
1、开源的时间序列数据库,2016年加入云原生基金会, 是继 Kubernetes之后的第二个加入的host project。
2、监控工具,和grafana完美集成,同时提供了PromQL语言
3、soundcloud研发, 源自google的borgmon
4、白盒、黑盒监控都支持。
5、社区生态非常丰富,提供了丰富的exporters,alerts,dashboard。
6、单机性能高:每秒支持百万级的时间序列,能同时支持上千个targets。
官网地址:https://prometheus.io/
一个典型的prometheus+grafana的监控如下:
prometheus的架构
整体架构如下:
来源:
https://prometheus.io/docs/introduction/overview/
Prometheus 提供了两种存储方式, local 和remote。
详情参见:
https://prometheus.io/docs/prometheus/latest/storage/
https://github.com/prometheus-junkyard/tsdb/blob/master/docs/format/README.md
https://ganeshvernekar.com/blog/prometheus-tsdb-persistent-block-and-its-index/
《技术分享:Prometheus是怎么存储数据的(陈皓)》https://www.bilibili.com/video/BV1a64y1X7ys?from=search&seid=16300830048851003304&spm_id_from=333.337.0.0
存储结构如下:
持久化文件结构
Local storage的最小单位是block,每个block是最近两个小时的数据。
block里面是多个chunk、meta.json、index、tombstones。
tombstones, 用来标记哪些chunk文件被删除了。
chunk存的是具体的数据
meta.json存的是用来存block的元数据, 比如开始时间, 结束时间等等。
index存储索引, 用于索引chunk里的数据, 用于快速查找。
先建立一个symblo table, 把所有的label,都映射成 一个排序的id, 然后通过倒排索引,来加快搜索。
比如前面例子中提到的
1-http_requests_total{endpoint="/login",status="500",}
2-http_requests_total{endpoint="/register",status="500",}
3-http_requests_total{endpoint="/login",status="200",}
4-http_requests_total{endpoint="/register",status="200",}
5-http_requests_total{endpoint="/users/{id}",status="500",}
6-http_requests_total{endpoint="/logout",status="200",}
7-http_requests_total{endpoint="/users/{id}",status="200",}
8-http_requests_total{endpoint="/users",status="200",}
9-http_requests_total{endpoint="/users",status="500",}
10-http_requests_total{endpoint="/logout",status="500",}
然后建立一个倒排索引:
endpoint="/login" [1,3]
status="500" [1,2,5,6,10]
那么我想找endpoint="/login" 并且 status="500" 就能通过交集很快的找到对应的label的索引
但是这个里面会涉及到一个求交集or 并集的问题。
大家可以思考一下,如果普通的算法, 求endpoint="/login" 并且 status="500" , 复杂度是不是o(m*n)。借助内外的空间, 把其中一个转成hash, 时间复杂度可以变为o(m+n)。那如何不借助额外的空间做到这一点呢?
至于每个文件里面的存储的结构, 大家可以去看上面给出的文档。
我们注意到还会有一个wal文件夹,write ahead log , 预写日志。
prometheus抓取的数据不会立即刷盘,而是放在内存中。想象一下如果这时候宕机了,数据岂不丢了。wal日志的作用就是防止这个的。很多数据库现在都有这个wal的使用。
metrics采集
Exporters
详情参见:
https://prometheus.io/docs/instrumenting/exporters/
Alerts
详情参见:
实验
安装prometheus
•brew install Grafana
•cd /usr/local/Cellar/prometheus/2.31.1/bin/
•./prometheus --config.file=/usr/local/etc/prometheus.yml
•访问:http://localhost:9090/
安装grafana
brew install Grafana
cd /usr/local/Cellar/grafana/8.3.2
grafana-server --config=/usr/local/etc/grafana/grafana.ini --homepath /usr/local/share/grafana --packaging=brew cfg:default.paths.logs=/usr/local/var/log/grafana cfg:default.paths.data=/usr/local/var/lib/grafana cfg:default.paths.plugins=/usr/local/var/lib/grafana/plugins
访问:http://localhost:3000/
启动模拟程序
open /usr/local/etc/prometheus.yml
添加以下内容
- job_name: "simulator"
metrics_path: /prometheus
static_configs:
- targets: ["localhost:8080"]
在8080,启动http-simulator:
同时, 访问http://localhost:9090/, 查看prometheus的targets, 状态为up。
给grafana添加数据源
安装node_exporter
brew install node_exporter
node_exporter
#采集node exporter监控数据
- job_name: "node_exporter"
static_configs:
- targets: ["localhost:9100"]
使用grafana dashboard
在grafana 里输入dashboard, 然后找到想要的exporter对应的dashboard。