背景
sentinel控制台的实时监控数据,默认仅存储 5 分钟以内的数据(数据存储在机器的内存),无法持久化数据。
2. 实时监控流程(默认)
整体的流程图如下:
-
前端页面定时请求(10秒)
-
sentinel控制台 定时任务每秒执行一次,控制台向该appId的每台机器发送http请求获取监控数据,循环AppId的每个节点并向其发送http请求获取监控数据;并将每台获取的数据进行累加计算。
控制台实际调用客户端暴露服务接口,并将各个节点数据汇总。并把数据存储到 控制台服务的内存(allMetrics )
内存中监控的存储结构如下:
{app -> resource -> timestamp -> metric}
Map<String, Map<String, LinkedHashMap<Long, MetricEntity>>> allMetrics = new ConcurrentHashMap<>();
- 客户端监控日志落盘,定时任务在FlowRuleManager初始化时启动,每秒钟执行一次,并将监控数据按格式写入日志。
代码坐标:FlowRuleManager#static
资源的秒级日志:
所有资源的秒级监控日志(metric 日志)在 ${home}/logs/csp/${appName}-metrics.log.${date}.xx。例如,该日志的名字可能为 my-service-metrics.log.2018-06-22.1。日志示例:
1529573107000|2018-06-21 17:25:07|sayHello(java.lang.String,long)|10|3601|10|0|2|0|0|1
格式说明:
| 1 | 1529573107000 | 时间戳 |
|---|---|---|
| 2 | 2018-06-21 17:25:07 | 日期 |
| 3 | sayHello(java.lang.String,long) | 资源名称 |
| 4 | 10 | 每秒通过的资源请求个数 (pass QPS) |
| 5 | 3601 | 每秒资源被拦截的个数 (block QPS) |
| 6 | 10 | 每秒完成调用的资源个数 (complete QPS),包括正常结束和异常结束的情况 |
| 7 | 0 | 每秒资源的异常个数 (error QPS) |
| 8 | 2 | 资源平均响应时间(ms) |
| 9 | 0 | 该秒占用未来请求的数目(since 1.5.0) |
| 10 | 0 | 该秒的最大并发,预留用 |
| 11 | 1 | 资源分类(since 1.7.0) |
3. sentinel控制台
sentinel-dashboard是一个单独的web应用(前端使用AngularJS),通过spring-boot进行启动,主要提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。
3.1. 客户端接入控制台
控制台启动后,客户端需要按照以下步骤接入到控制台。
3.1.1. 引入客户端jar包
通过 pom.xml 引入 jar 包:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>
3.1.2. 配置启动参数
启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。
若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx 指定客户端监控 API 的端口(默认是 8719)
除了修改 JVM 参数,也可以通过配置文件取得同样的效果。
3.1.3. 触发客户端初始化
确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。
sentinel-dashboard是一个独立的web应用,可以接受客户端的连接,然后与客户端之间进行通讯,他们之间使用http协议进行通讯。他们之间的关系如下图所示:
4. 初始实现方式
如上所示监控数据存放在控制台内存中,无法持久化,所以初始改造方式是把控制台的监控数据 放入数据库中(Mysql、Influxdb)。
- 自行扩展实现 MetricsRepository 接口;
- 注册成 Spring Bean 并在相应位置通过 @Qualifier 注解指定对应的 bean name 即可。
推荐使用InfluxDB来进行持久化。
如果客户端不多,可以考虑采取该方式。
不足:因为控制台需要向所有客户端拉取数据并统计,如果客户端数量增加,sentinel控制台的压力会变大,sentinel控制台服务扛不住。
5. 优化后实现方式
- 接入leelen-crm-sentinel的监控组件,会将监控的信息写入到user.home目录下名为xxxx.metrics.log.yyyy-MM-dd日志文件中
- filebeat监听读取日志文件中的内容,并将内容输出到指定的logstash中
- logstash接收filebeat传来的日志信息,通过logstash的过滤(filter)功能,对日志进行过滤、筛选、处理,最后将日志输出(ouptut)到influxdb
- 后台通过连接influxdb,来获取metric信息,将监控信息传到web端进行展示
小结:相当于把原来sentinel控制台拉取所有客户端监控数据及保存的工作,交给了filebeat 跟 logstatsh。
6. Filebeat 介绍
Filebeat 是使用 Golang 实现的轻量型日志采集器,也是 Elasticsearch stack 里面的一员,可以安装在各个节点上,根据配置读取对应位置的日志,并上报到相应的地方去。
filebeat 内置了常用的 Output 组件, 例如 kafka、ElasticSearch、redis,logstash 等,出于调试考虑,也可以输出到 console 和 file 。
- 日志采集器:也就是可以从不同的地方读取日志信息
- 可以安装在各个节点上:也就是可以单独部署在各自的机器上
- 根据配置读取对应位置的日志:就是通过filebeat.yml文件的input属性,对不同日志来源的收集
- 并上报到相应的地方:也就是日志读取之后,需要发送到某个地方(eg:logstash、elasticsearch,file等)
6.1. logstash 和filebeat 关系
相同点
- logstash和filebeat都具有日志收集功能
- logstash和filebeat都具有input和output属性
差异点
-
filebeat是利用golang写,其官方的说法是为了替代logstash-forwardm,因此filebeat更轻量,占用资源更少
-
logstash是使用Java编写利用jvm跑的,插件是使用jruby编写,对机器的资源要求会比较高
-
logstash 具有filter功能,能过滤分析日志
一般结构都是filebeat采集日志,然后发送到消息队列,redis,kafaka。然后logstash去获取,利用filter功能过滤分析,然后存储到elasticsearch、influxdb,kafka、redis等
6.2. 工作原理
filebeat主要由两个组件构成prospector(探测器)和harvester(收集器),这两类组件一起协作完成Filebeat的工作。当开启Filebeat程序的时候,它会启动一个或多个探测器去检测指定的日志目录或文件。
对于探测器找出的每一个日志文件,Filebeat会启动收集进程,每一个收集进程读取一个日志文件的内容,然后将这些日志数据发送到后台处理程序,后台处理程序会集合这些事件,最后发送集合的数据到output指定的目的地。
对于这句话怎么理解呢?
它会启动一个或多个探测器去检测指定的日志目录或文件。对于探测器找出的每一个日志文件,Filebeat会启动收集进程
按照我个人的理解:例如filebeat.yml配置文件的inputs属性下的一个type代表一个探测器,paths:底下的文件数代表着收集进程数,每个文件启动一个 harvester,harvester 负责打开和关闭文件,
如果文件在读取时被删除或重命名,Filebeat 将继续读取文件。
filebeat.inputs:
- type: log
paths:
- /var/log/system.log
- /var/log/wifi.log
- type: log
paths:
- "/var/log/apache2/*"
fields:
apache: true
fields_under_root: true
如下面这张图一样,input1启动一个探测器,探测器底下启动两个收集器来监听文件的变化
整个 filebeat 主要包含以下重要组件:
- Crawler:负责管理和启动各个 Input
- Input:负责管理和解析输入源的信息,以及为每个文件启动 Harvester。可由配置文件指定输入源信息。input 有两个非常重要的状态 offer与finished
- offset: 代表文件当前读取的 offset,从 Registrar 中初始化。Harvest 读取文件后,会同时修改 offset。
- finished: 代表该文件对应的 Harvester 是否已经结束,Harvester 开始时置为 false,结束时置为 False。
对于每次定时扫描到的文件,概括来说,会有三种大的情况:
- 如果 offset 大于当前文件大小:说明文件被 被删除过,此时按做一个新文件处理,直接从头开始解析该文件
- 如果 offset 小于当前文件大小,说明文件内容有新增,则从上次 offset 处继续读即可。
-
Harvester[ˈhɑːrvɪstər]: Harvester 负责逐行读取一个文件的信息,并更新该文件暂时在 Input 中的文件偏移量(缓存中,Registrar是持久化到磁盘)
-
prospector[ˈprɑːspektər]:prospector 的主要职责是管理 harvester 并找到所有要读取的文件来源
-
Pipeline[ˈpaɪplaɪn]: 负责管理缓存、Haveseter 会将数据写入缓存中,而另一方面 Output 会从缓存将数据读走,整个生产消费的过程都是由 Pipeline 进行调度的,是 Filebeat 最核心的组件。
-
Output: 输出源,可由配置文件指定输出源信息。
-
Registrar:管理记录每个文件处理状态,包括偏移量、文件名等信息。当Filebeat 刚启动时,Input 都会载入 Registrar 中记录的文件状态,作为初始状态。
Registrar中的offer什么时候修改呢?
Ack 机制就是,当 Output Publish 成功之后会调用 ACK,最终 Registrar 会收到 ACK,并修改偏移量。
6.3. filebeat配置文件详解
filebeat.prospectors:
- type: log
paths: #必选项,读取文件的路径,基于glob匹配语法 blog.csdn.net/qq_42679415…
- /var/log/*.log
include_lines: ['trace','Trace'] #包含匹配列表中的正则表达式
exclude_lines: ["^OK"] # 排除匹配列表中的正则表达式
exclude_files: ['.idx'] #排除的文件,匹配正则表达式的列表
multiline: #多行合并匹配规则,匹配正则表达式
pattern: '^Trace[[0-9]+]'
negate: false #true 或 false(默认是false),false表示匹配pattern的行合并到上一行;true表示不匹配pattern的行合并到上一行
match: after #true 或 false(默认是false),false表示匹配pattern的行合并到上一行;true表示不匹配pattern的行合并到上一行
fields:
host_name: localhost #可选的附加字段key-value
fields_under_root: true #设置为true,则自定义字段将作为顶级字段存储在输出文档中,如果自定义字段名与Filebeat添加的其他字段名冲突,则自定义字段将覆盖其他字段
scan_frequency: 10s #默认每10秒钟扫描一次目录,更新通配符匹配上的文件列表
ignore_older: 6h #超过 6 小时没更新内容的文件不再监听
#close_*配置选项用于指定在达到某一标准或时间后关闭采集器。关闭采集器意味着关闭文件处理程序。如果在采集器关闭后更新文件,则文件将在scan_frequency经过后再次被采集。但是,如果在采集器关闭时移动或删除文件,Filebeat将无法再次采集该文件,并且采集器尚未读取的任何数据都将丢失
#close_inactive: 5m #默认5m 启用该选项后,如果在指定的时间内没有收获文件,Filebeat会关闭文件句柄,如果已关闭的文件再次发生变化,则会启动一个新的采集器,并在scan_frequency过后接收最新的变化
#close_rename: true #启用此选项后,Filebeat 会在文件重命名时关闭文件处理程序。例如,在旋转文件时就会发生这种情况。默认情况下,采集器保持打开并继续读取文件,因为文件处理程序不依赖于文件名。如果close_renamed选项被启用,并且文件被重命名或移动,以至于它不再与指定的文件模式相匹配,那么文件将不会被再次拾取。Filebeat将不会完成对文件的读取
#close_removed:true #当这个选项被启用时,Filebeat会在文件被删除时关闭采集器。通常情况下,一个文件只有在close_inactive指定的时间内不活动后才会被删除。然而,如果一个文件被提前删除,而你又没有启用close_removed,Filebeat会保持文件打开,以确保采集器已经完成。如果这个设置导致文件因为太早从磁盘上删除而无法完全读取,请禁用这个选项
#clean_removed: true #Filebeat会在文件被删除时关闭采集器,
#clean_inactive: 2h #启用此选项后,经过指定的不活动时间后,Filebeat会删除文件的状态,该clean_inactive设置必须大于ignore_older + scan_frequency,因为 clean_inactive删除了Filebeat检测到的文件的状态。如果文件已更新或再次出现,则会从头开始读取文件。
#harvester_buffer_size:16384 #单个文件采集器harvester每次读取文件的大小,默认的大小是16K。
tags: ["crm", "sentinel"] #标记tag,可用于分组
output.logstash:
enabled: true #启动该模式输出
hosts:["localhost:5044"] #logstash的地址
#bulk_max_size:50 #每次filebeat默认只会发送50行数据
#worker:1 #指定filebeat使用多高的并发来发送数据 默认1
#compression_level:3 #提高压缩级别将减少网络使用量,但会增加CPU使用量。默认值为3。
#loadbalance:true #负载均衡开关,在不同的logstash间负载 默认true
#index:'filebeat' #可选配置,索引名称,默认为filebea
7. influxdb介绍
influxdb是一个由go语言开发的、用于存储和分析时间序列数据的开源数据库。特点如下:
-
专为时间序列数据编写的自定义高性能数据存储。 TSM引擎允许高摄取速度和数据压缩
-
内置HTTP接口,使用方便
-
标签允许对系列进行索引以实现快速有效的查询
-
类SQL的查询语句
-
安装管理很简单,并且读写数据很高效
-
能够实时查询,数据在写入时被索引后就能够被立即查出
-
支持数据存储策略(RP)和数据归档(CQ), 保留策略有效地自动使过时数据过期
优化:
1.查询语句里面有很多 select *尽量不用,生产库上不要随意执行sql,一旦sql导致内存使用过多,容易导致Influxdb oom
2.配置优化
grep -v "^$" /etc/influxdb/influxdb.conf|grep -v "#"|grep -v "###"
reporting-disabled = true #关闭上报功能
[meta]
dir = "/var/lib/influxdb/meta" #meta数据存放目录
[data]
dir = "/var/lib/influxdb/data" #存储最终数据(TSM文件)的目录,此目录可能会更改。
wal-dir = "/var/lib/influxdb/wal" #预写日志(WAL)文件的存储目录。
index-version = "tsi1" #基于时间序列(TSI)磁盘的索引,请将其值设置为tsi1。默认inmem 内存分片索引
trace-logging-enabled = false #是否开启跟踪(trace)日志,默认值:false。
cache-max-memory-size = "1g" #用于限定shard最大值,大于该值时会拒绝写入
cache-snapshot-memory-size = "25m" #设置快照大小,大于该值时数据会刷新到tsm文件,默认值:25MB
compact-full-write-cold-duration = "4h" #如果没有收到写或删除操作,TSM引擎将压缩一个分片中的所有TSM文件的时间间隔
max-series-per-database = 0 #限制数据库的series数,该值为0时取消限制,默认值:1000000
max-values-per-tag = 0 #一个tag最大的value数,该值为0时取消限制,默认值:100000
series-id-set-cache-size = 100 #TSI索引中用于存储先前计算的系列结果的内部缓存的大小,0禁用缓存,
[coordinator]
write-timeout = "10s" #写操作超时时间
max-concurrent-queries = 0 #最大并发查询数
query-timeout = "60s" #查询操作超时时间
log-queries-after = "0s" #慢查询超时时间
max-select-point = 0 #select语句可以处理的最大点数
max-select-series = 0 #SELECT语句可以处理的最大级数
max-select-buckets = 0 #select语句可以处理的最大"GROUP BY time()"的时间周期
[retention]
[shard-precreation]
advance-period = "10m" #预创建分区的最大提前时间,默认值 :30m
[monitor]
store-enabled = false #是否启用该模块,默认值 :true。
[http]
log-enabled = false #是否开启http请求日志,默认值:true。
max-row-limit = 10000 #系统在非分块查询中可以返回的最大行数。 默认设置(0)允许无限制的行数
[logging]
[subscriber]
[[graphite]]
[[collectd]]
[[opentsdb]]
[[udp]]
[continuous_queries]
log-enabled = true #是否开启日志,默认值:true。
[tls]
min-version = "tls1.2" #将协商的tls协议的最低版本
max-version = "tls1.3" #将协商的tls协议的最大版本
InfluxDB被设计运行在SSD上,InfluxData团队不会在HDD和网络存储上测试InfluxDB,所以不太建议在生产上这么去使用。在机械磁盘上性能会下降一个数量级甚至在中等负载下系统都可能死掉。
为了最好的结果,InfluxDB至少需要磁盘提供1000 IOPS的性能。而每秒1000的读写能力 ,只有固态硬盘才能做到。
7.1. InfluxDB与关系型数据库的比较
InfluxDB是一个时间序列数据库,主要存储的是以时间为序存储的数据。其实,SQL数据库是可以提供时序的功能,只要将时间作为主键,就能够将SQL数据库当作时序数据库来处理。
简而言之,InfluxDB用于存储大量的时间序列数据,并对这些数据进行快速的实时分析。而SQL数据库虽然可以有时序的功能,但是效率并不高。
InfluxDB的measurement(foodships)和SQL数据库里的table类似;
InfluxDB的tag(park_id和planet)类似于SQL数据库里有索引的列;有索引代表查询速度快。
InfluxDB中的field(#_foodships)类似于SQL数据库里没有索引的列;
InfluxDB中的Point:类似SQL中一行记录,而并不是一个点。
7.2. InfluxDB与MySQL的性能测试
一、单线程插入查询对比
注:批量插入,每批1万条
配置:
CPU:16 Intel(R) Xeon(R) Silver 4110 CPU @ 2.10GHz
内存:16G
磁盘:4T
MySQL: V5.7
InfluxDB: V1.8.0
结论:插入速度InfluxDB是MySQL的两倍,查询速度InfluxDB是MySQL的45倍(查询数据量很少的情况,大约1000条左右)
8. 源码结构
- sentinel-core 核心模块,限流、降级、系统保护等都在这里实现
- sentinel-dashboard 一个通过 spring boot 实现的 web 应用,相当于是 Sentinel 的 OPS 工具,通过 dashboard 我们可以更方便的对规则进行调整、
查询实时统计信息等,但是这并不是必须的,没有 dashboard 我们也能使用 Sentinel,甚至我们可以通过 Sentinel 提供的 api 来实现自己的 dashboard。
- sentinel-transport 一个 sentinel-core 和 sentinel-dashboard 通讯的桥梁,如果我们的应用接入了 Sentinel,并且也想通过 dashboard 来管理的话,那就需要引入 sentinel-transport 模块。
- sentinel-extension 扩展模块,主要对DataSource进行了部分扩展实现
- sentinel-adapter 适配器模块,主要实现了对一些常见框架的适配
- sentinel-demo 样例模块,可参考怎么使用sentinel进行限流、降级等
- sentinel-benchmark 基准测试模块,对核心代码的精确性提供基准测试