OldCola


  • 首页

  • 归档

alertmanger HA 方法

发表于 2017-11-08

alertmanager 启动时添加mesh相关配置

1
2
3
./alertmanager -config.file simple.yml -mesh.peer=am-1:6783 -mesh.peer=am-2:6783 -mesh.peer=am-3:6783
./alertmanager -config.file simple.yml -mesh.peer=am-1:6783 -mesh.peer=am-2:6783 -mesh.peer=am-3:6783
./alertmanager -config.file simple.yml -mesh.peer=am-1:6783 -mesh.peer=am-2:6783 -mesh.peer=am-3:6783

prometheus 节点添加alertmanager相关配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#在prome-1上编辑prometheus配置并启动
cat > prometheus.yml << EOF
global:
external_labels:
dc: cn1
alerting:
alert_relabel_configs:
- source_labels: [dc] #将容易产生报警区别的label置成相同label
regex: (.+)\d+
target_label: dc
alertmanagers:
- static_configs:
- targets: ['am-1:9093', 'am-2:9093', am-3:6783]
# 其他配置和正常prometheus配置相同
EOF
./prometheus
#在prome-2上编辑prometheus配置并启动
cat > prometheus.yml << EOF
global:
external_labels:
dc: cn2
alerting:
alert_relabel_configs:
- source_labels: [dc]
regex: (.+)\d+
target_label: dc
alertmanagers:
- static_configs:
- targets: ['am-1:9093', 'am-2:9093', am-3:6783]
# 其他配置和正常prometheus配置相同
EOF
./prometheus
#在prome-3上编辑prometheus配置并启动
cat > prometheus.yml << EOF
global:
external_labels:
dc: cn3
alerting:
alert_relabel_configs:
- source_labels: [dc]
regex: (.+)\d+
target_label: dc
alertmanagers:
- static_configs:
- targets: ['am-1:9093', 'am-2:9093', am-3:6783]
# 其他配置和正常prometheus配置相同
EOF
./prometheus

启动后查看各alertmanager后台,会发现报警信息已同步。

1
2
3
am-1:9093/#/alerts
am-2:9093/#/alerts
am-3:9093/#/alerts

prometheus 落地实践

发表于 2017-09-12

这是我之前在「dbaplus 社群」的分享,已经转载到过「hulk一线技术杂谈」

初衷

最近参与的几个项目,无一例外对监控都有极强的要求,需要对项目中各组件进行详细监控,如服务端API的请求次数,响应时间,到达率,接口错误率,分布式存储中的集群IOPS,节点在线情况,偏移量等。比较常见的方式是写日志,将日志采集到远端进行分析和绘图,或写好本地监控脚本进行数据采集后,通过监控系统客户端push到监控系统中进行打点。基本上我们需要的都能覆盖,但仍然有一些问题在使用上不太舒服,如在大规模请求下日志采集和分析的效率比较难控制或push打点的粒度和维度以及查询不够灵活等。
后来在同事对《Google SRE》这本书中的一些运维思想进行一番安利,抱着试一试的态度,开始尝试使用prometheus做为几个项目的监控解决方案。

prometheus的特点

• 多维数据模型(时序数据由 metric 名和一组 k/v 标签构成)。
• 灵活强大的查询语句(PromQL)。
• 不依赖存储,支持 local 和 remote 不同模型。
• 采用 http 协议,使用 pull 模式采集数据。
• 监控目标,可以采用服务发现或静态配置的方式。
• 支持多种统计数据模型,图形化友好。

数据类型

Counter

  • Counter 表示收集的数据是按照某个趋势(增加/减少)一直变化的。

Gauge

  • Gauge 表示搜集的数据是一个瞬时的,与时间没有关系,可以任意变高变低。

Histogram

  • Histogram 可以理解为直方图,主要用于表示一段时间范围内对数据进行采样,(通常是请求持续时间或响应大小),并能够对其指定区间以及总数进行统计,通常我们用它计算分位数的直方图。

Summary

  • Summary和Histogram十分相似,主要用于表示一段时间范围内对数据进行采样,(通常是请求持续时间或响应大小),它直接存储了 quantile 数据,而不是根据统计区间计算出来的。

在我们的使用场景中,大部分监控使用Counter来记录,例如借口请求次数,消息队列数量,重试操作次数等。一小部分使用Gauge,如在线人数,协议流量,包大小等。还有一小部分使用Histogram和Summary,用于统计平均延迟,请求延迟占比和分布律。另外针对Historgram,不论是打点还是查询对服务器的cpu消耗比较高,通过查询时查询结果的返回耗时会有十分直观的感受。

时序数据-打点-查询

我们知道每条时序数据都是由 metric(指标名称),一个或一组label(标签),以及float64的值组成的。
标准格式为 <metric name>{<label name>=<label value>, ...}
例如:

1
2
3
4
5
rpc_invoke_cnt_c{code="0",method="Session.GenToken",job="Center"} 5
rpc_invoke_cnt_c{code="0",method="Relation.GetUserInfo",job="Center"} 12
rpc_invoke_cnt_c{code="0",method="Message.SendGroupMsg",job="Center"} 12
rpc_invoke_cnt_c{code="4",method="Message.SendGroupMsg",job="Center"} 3
rpc_invoke_cnt_c{code="0",method="Tracker.Tracker.Get",job="Center"} 70

这是一组用于统计rpc接口处理次数的监控数据
其中rpc_invoke_cnt_c为指标名称,每条监控数据包含三个标签 code 表示错误码,service表示该指标所属的服务,method表示该指标所属的方法.
针对这个例子,我们共有四个维度(一个指标名称,三个标签),这样我们便可以利用prometheus强大的查询语言PromQL进行极为复杂的查询

PromQL

PromQL (Prometheus Query Language) 是 Prometheus 自己开发的数据查询 DSL 语言,语言表现力非常丰富,支持条件查询、操作符、并且内建了大量内置函,供我们针对监控数据的各种维度进行查询。
我们想统计Center组件Relation.GetUserInfo的频率:

1
rate(rpc_invoke_cnt_c{method="Relation.GetUserInfo",job="Center"}[1m])

DraggedImage

或者基于方法和错误码统计Center的整体 rpc 请求错误频率:

1
sum by (method, code) (rate(rpc_invoke_cnt_c{job="Center",code!="0"}[1m]))

DraggedImage-1

如果我们想统计Center各方法的接口耗时:

1
rate(rpc_invoke_time_h_sum{job="Center"}[1m]) / rate(rpc_invoke_time_h_count{job="Center"}[1m])

另外,配合查询在打点时metric和labal名称的定义也有一定技巧。
比如在我们的项目中:

  • rpc_invoke_cnt_c 表示rpc调用统计
  • center_api_req_num_cv 表示http api调用统计
  • group_msg_queue_cnt_c 表示对列长度统计

尽可能将使用各服务或者组建通用的名称定义metric然后通过各种lable进行区分。
最开始我们的使用方式是这样的,比如我们有三个组件center,gateway,message。rpc调用统计的metric相应的命名成了三个:

  • center_rpc_invoke_cnt_c
  • gateway_rpc_invoke_cnt_c
  • message_rpc_invoke_cnt_c

这种命名方式,对于个组件的开发同学可能读起来会比较直观,但是在实际查询过程中,这三个metric相当于三个不同的监控项。
例如我们查询基于method统计所有组件rpc请求错误频率,如果我们使用通用名称定义metric名,查询语句是这样的。
‘’sum by (method, code) (rate(rpc_invoke_cnt_c{code!=”0”}[1m]))
但如果我们各个组件各自定义了名称的话,这条查询需要写多条。虽然我们可以通过 {__name__=~".*rpc_invoke_cnt_c"} 的方式来规避这个问题,但在实际使用和操作时体验会差很多。

同时通过前面的各类查询例子也会发现,我们在使用label时也针对不同的意义进行了区分如 method=GroupJoin|GetUserInfo|PreSignGet|... 来区分调用的函数方法 code=0|1|4|1004|...来区分接口返回值。

更多的metric和label相关的技巧可以参考官方文档[https://prometheus.io/docs/practices/naming/]`

服务发现

在使用初期,参与的几个项目的prometheus都是各自独立部署和维护的。其配置也是按照官方文档中的标准配置来操作。机器数量少的时候维护简单,增删机器之后简单的reload一下即可。例如
DraggedImage-3

但随着服务器量级增长,业务整合到同一组prometheus的时候,每次上下线实例都是一个十分痛苦的过程。所以我们尝试使用了prometheus的服务发现功能。
从配置文档中不难发现prometheus对服务发现进行了大量的支持,例如大家喜闻乐见的consul和k8s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<scrape_config>
<tls_config>
<azure_sd_config>
<consul_sd_config>
<dns_sd_config>
<ec2_sd_config>
<openstack_sd_config>
<file_sd_config>
<gce_sd_config>
<kubernetes_sd_config>
<marathon_sd_config>
<nerve_sd_config>
<serverset_sd_config>
<triton_sd_config>

由于最近参与的几个项目深度使用公司内部的配置管理服务gokeeper,虽然不是prometheus原生支持,但是通过简单适配也是同样能满足服务发现的需求的。我们最终选择file_sd_config作为服务发现的配置。

file_sd_config 接受json格式的配置文件进行服务发现。每次json文件的内容发生变更,prometheus会自动刷新target列表,不需要手动触发reload操作。所以我们针对gokeeper编写了一个小工具,定时到gokeeper中采集服务分类及分类中的服务器列表,并按照file_sd_config的要求生成对应的json格式。
下面是一个测试服务生成的json文件样例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"targets": [
"10.10.10.1:65160",
"10.10.10.2:65160"
],
"labels": {
"job": "Center",
"service": "qtest"
}
},
{
"targets": [
"10.10.10.3:65110",
"10.10.10.4:65110"
],
"labels": {
"job": "Gateway",
"service": "qtest"
}
}
]

prometheus配置文件中将file_sd_configs的路径指向json文件即可。

1
2
3
4
- job_name: 'qtest'
scrape_interval: 5s
file_sd_configs:
- files: ['/usr/local/prometheus/qtestgroups/*.json']

高可用

高可用目前暂时没有太好的方案。官方给出的方案可以对数据做shard然后通过federation来实现高可用方案,但是边缘节点和global节点依然是单点。
使用方法比较简单,例如我们一个机房有三个prometheus节点用语shard,我们希望global节点采集归档数据用于绘图。首先需要在shard节点进行一些配置。

prometheus.yml:

1
2
3
4
5
6
global:
external_labels:
slave: 0 #给每一个节点指定一个编号 三台分别标记为0,1,2
rule_files:
- node_rules/zep.test.rules #指定rulefile的路径

node_rules/zep.test.rules:

1
job:center_rpc_invoke_cnt:sum:rate:1m=sum by (method, code) (rate(center_rpc_invoke_cnt_c{code!="0"}[1m]))

在这里job:center_rpc_invoke_cnt:sum:rate:1m将作为metric名,用来存放查询语句的结果。

在global节点prometheus.yml也需要进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
- job_name: slaves
honor_labels: true
scrape_interval: 5s
metrics_path: /federate
params:
match[]:
- '{__name__=~"job:.*"}'
static_configs:
- targets:
- 10.10.10.150:9090
- 10.10.10.151:9090
- 10.10.10.152:9090

在这里我们只采集了聚合数据用于绘图,不建议将shard节点的所有数据采集过来存储再进行查询和报警的操作。这样不但会使shard节点计算和查询的压力增大(通过http读取原始数据会造成大量IO和网络开销),同时所有数据写入global节点也会使其很快达到单prometheus节点的承载能力上限。
另外部分敏感报警尽量不要通过global节点触发,毕竟从shard节点到global节点传输链路的稳定性会影响数据到达的效率,进而导致报警实效降低。例如服务updown状态,api请求异常这类报警我们都放在shard节点进行报警。

此外我们还尝试编写一个实验性质的prometheus proxy工具,代替global节点接收查询请求,然后将查询语句拆解,到各shard节点抓取基础数据,然后再在proxy这里进行prometheus内建的函数和聚合操作,最后将计算数据抛给浏览器。这样便可以直接节约掉global节点和大量存储资源,并且proxy节点由于不需要存储数据,接受请求和计算数据,横向扩展十分方便。当然问题还是有的,由于每次查询proxy到shard节点拉取的都是未经计算的原始数据,当查询的metric数据量比较大的时候,网络和磁盘IO开销巨大。因此在绘图时我们对查询语句限制比较严格,基本不允许进行无label限制的模糊查询。

报警

prometheus的报警功能目前来看相对计较简单。主要是利用alertmanager这个组件。配合rules_file中编辑的查询出发条件,prometheus会主动通知alertmanager然后发出报警。由于我们公司内使用的自研的qalarm报警系统,接口比较丰富,和alertmanager的webhook简单对接即可使用。alertmanager也内建了一部分报警方式,如email和第三方的slack,初期我们的存储集群报警使用的就是slack,响应速度还是很不错的。

需要注意的是,如果报警已经触发,但是由于一些原因,比如删除业务监控节点,使报警恢复的规则一直不能触发,那么已出发的报警会按照alertmanager配置的周期一直重复发送,要么从后台silence掉,要么想办法使报警恢复。例如前段时间我们缩容ceph集群,操作前没有关闭报警,触发了几个osddown的报警,报警刷新周期2小时,那么没过两小时alertmanager都会发来一组osddown的报警短信。对应编号的osd由于已经删掉已经不能再写入up对应的监控值。索性停掉osddown报警项,直接重启ceph_exporter,再调用prometheus api删掉对应osd编号的osdupdown监控项,随后在启用osddown报警项才使报警恢复。

如下图的报警详情页面,红色的是已触发的报警,绿色的是未触发报警
DraggedImage-4

绘图展示

对于页面展示,我们使用的是grafana,如下面两张图,是两个不同服务的dashboard,可以做非常多的定制化,同时grafana的template也可以作为参数传到查询语句中,对多维度定制查询提供了极大的便利。
DraggedImage-5
DraggedImage-6

openstack镜像结合ceph存储后的一些远端操作方法和思考

发表于 2017-03-06

随着ceph在线上更深入的使用,以及多机房的场景。以往虚拟机镜像修改上传的模式逐渐成为了负担。实际上,我们可以根据ceph存储的特性,将过去对镜像线下本地处理的操作改为直接在远端处理。

准备

1.镜像在ceph中存储的路径一般为 {pool_name}/{uuid}的形式,通常情况下该{uuid}和镜像的ID是相同的,为避免一些历史原因导致的镜像ID与ceph image uuid有差异,打开glance image-show中的location信息。

修改 glance-api.conf,添加如下内容,打开rbd路径的详情。

1
2
3
enable_v2_api =True
show_multiple_locations = True
filesystem_store_metadata_file = filePath

2.对准备操作glance中镜像的设备做libvirt同ceph的验证准备。

定义secret文件

1
2
3
4
5
6
7
cat > secret.xml <<EOF
<secret ephemeral='no' private='no'>
<usage type='ceph'>
<name>client.libvirt secret</name>
</usage>
</secret>
EOF

libvirt添加secret配置

1
2
3
4
virsh secret-define --file secret.xml
#这里会生成一个uuid 用在下面命令的 --secret 后,以及xml里的auth
cat /etc/ceph/ceph.client.glance.keyring
sudo virsh secret-set-value --secret 453cf8e2-02b4-4744-9455-5544601bb043 --base64 AQBkGYZX/tuDMxAANVznwk/+MkrhsEBlZAJlLg==

对镜像操作的两个思路

1. qcow2镜像存储中转换格式,修改大小,并在glance中生成新镜像。

以老的镜像制作方式为基础

这里是一个习惯问题,如果读者对本文中的操作进行实验后其实很容易直接在存储中直接制作镜像,可以省去不少麻烦。

我们会生成一个3g大小,为了便于上传经过压缩(virt-sparsify --compress)和清理多余信息(virt-sysprep)后的镜像。

####将镜像上传到glance后,我们需要先拿到镜像对应的rbd地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
glance --os-image-api-version 2 image-show 79db316e-9012-4296-9226-dec141a1210c
+------------------+----------------------------------------------------------------------------------+
| Property | Value |
+------------------+----------------------------------------------------------------------------------+
| checksum | d355054e1f038d4898fddd03b506ad1f |
| container_format | bare |
| created_at | 2016-09-23T02:09:29Z |
| direct_url | rbd://5f3cb911-4f76-4421-a3fd- |
| | fcd2d7c5104a/images/e6c01758-b7ad-4097-9400-570cc1ceed43/snap |
| disk_format | raw |
| id | e6c01758-b7ad-4097-9400-570cc1ceed43 |
| locations | [{"url": "rbd://5f3cb911-4f76-4421-a3fd- |
| | fcd2d7c5104a/images/e6c01758-b7ad-4097-9400-570cc1ceed43/snap", "metadata": {}}] |
| min_disk | 0 |
| min_ram | 0 |
| name | imagetest-qcow2-20160923 |
| owner | 176e6938dadd45dcaa847d8242778321 |
| protected | False |
| size | 962461696 |
| status | active |
| tags | [] |
| updated_at | 2016-09-23T02:09:56Z |
| virtual_size | None |
| visibility | public |
+------------------+----------------------------------------------------------------------------------+

其中,location字段是这样的
[{"url": "rbd://5f3cb911-4f76-4421-a3fd-d2d7c5104a/images/e6c01758-b7ad-4097-9400-570cc1ceed43/snap", "metadata": {}}]

这个字段中我们只需要一小段内容:
images/e6c01758-b7ad-4097-9400-570cc1ceed43
在rbd中对应的是
pool_name/image_uuid

####转换镜像格式
raw的特性和在ceph中的优势在这里就不再复述了,具体操作如下。

1
2
3
4
5
#生成新的uuid
[]# uuidgen
b0b6bb99-7693-4614-b6f1-01b602d69f54
#转换qcow2倒raw
[]# qemu-img convert -O raw rbd:images/e6c01758-b7ad-4097-9400-570cc1ceed43 rbd:images/b0b6bb99-7693-4614-b6f1-01b602d69f54

####对rbd中的image扩容
qemu-img resize rbd:images/b0b6bb99-7693-4614-b6f1-01b602d69f54 50G

resize 完成后需要先boot一下,确认系统盘大小为50g。并提前完成resize2fs的操作。随后再进行一次清理操作。

之所以resize后要先boot一下是因为在我们的使用场景中,基础镜像生成的虚拟机根磁盘是固定不变的,为了免去每次开机时resize2fs对ceph后端的压力,故做此操作。读者们请酌情选择。

这里我们直接通过libvirt挂载glance中的image,磁盘设备在xml文件中的配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<disk type='network' device='disk'>
<driver name='qemu' type='raw' cache='writeback' discard='unmap'/>
# username 为 ceph 中给 glance 授权的用户名
<auth username='glance'>
# 上文中生成的secret的uuid
<secret type='ceph' uuid='453cf8e2-02b4-4744-9455-5544601bb043'/>
</auth>
#镜像在ceph中的地址
<source protocol='rbd' name='rbd:images/b0b6bb99-7693-4614-b6f1-01b602d69f54'>
<host name='10.10.10.84' port='6789'/>
<host name='10.10.10.102' port='6789'/>
<host name='10.10.10.110' port='6789'/>
</source>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</disk>

注意上面的auth

  • username 与线上不同,应为glance
  • uuid 为我们为glance创建的secret,通过 virsh secret-list 可以查看列表
  • name 为镜像地址,可以通过 glance --os-image-api-version 2 image-show {uuid} 查看,

完成以上步骤后即可继续操作

  • 开机并等待虚拟机resize2fs并进入操作系统
  • 可选择性的手动清理虚拟机内的日志等无用文件
  • 关机
  • 删除镜像中的其他复杂遗留信息

删除关机后遗留信息也是直接操作rbd

1
2
export LIBGUESTFS_BACKEND=direct
virt-sysprep -d {domain_name}

#####在glance中创建新镜像并指向我们前面初始化后的最终的rbd地址

由于glance中镜像指向的地址为实际镜像的快照,为了符合要求,我们也需要对上面操作过的镜像做快照处理。

1
2
3
4
对镜像创建snap
[]# rbd -p images snap create --snap snap-20160922 b0b6bb99-7693-4614-b6f1-01b602d69f54
保护snap,以免误删。
[]# rbd -p images snap protect --image b0b6bb99-7693-4614-b6f1-01b602d69f54 --snap snap

创建新镜像并将location指到我们新生成的snap上

1
glance image-create --id {NEW_UUID} --name {NEW_IMAGE_NAME} --store rbd --disk-format raw --container-format bare --location rbd://$(sudo ceph fsid)/images/b0b6bb99-7693-4614-b6f1-01b602d69f54/snap-20160922

至此整个过程完成

###在线修改glance中镜像
如果发现glance中的镜像内配置文件有问题怎么办?答案当然也是直接改。

这次我们利用guestfish来操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
guestfish
Welcome to guestfish, the guest filesystem shell for
editing virtual machine filesystems and disk images.
Type: 'help' for help on commands
'man' to read the manual
'quit' to quit the shell
#添加需要 guestfish识别的rbd磁盘
#username为glance protocol类型为rbd 格式为raw secret密钥为ceph glance的keyring, 一般在 /etc/ceph/ceph.client.glance.keyring
><fs> add-drive images/b0b6bb99-7693-4614-b6f1-01b602d69f54 username:glance protocol:rbd format:raw secret:AQBkGYZX/tuDMxAANVznwk/+MkrhsEBlZAJlLg==
><fs> run
><fs> list-filesystems
/dev/sda1: ext4
><fs> mount /dev/sda1 /
#比如我们要修改开机磁盘挂载的配置
><fs> edit /etc/fstab
><fs> exit

再执行一次上文提到的glance指向新snap的操作。

1
2
3
4
5
6
7
8
9
nova image-list
# 看一下当前已有的snap
rbd -p images snap ls b0b6bb99-7693-4614-b6f1-01b602d69f54
# 创建snap
rbd -p images snap create --snap snap-20160924 b0b6bb99-7693-4614-b6f1-01b602d69f54
# 保护snap
rbd -p images snap protect --image b0b6bb99-7693-4614-b6f1-01b602d69f54 --snap snap-20160924
# 生成新镜像
glance --debug image-create --id {NEW_UUID} --name {NEW_IMAGE_NAME} --store rbd --disk-format raw --container-format bare --location rbd://$(sudo ceph fsid)/images/b0b6bb99-7693-4614-b6f1-01b602d69f54/snap-20160924

至此过程完成。

小记

使用ceph存储后对镜像的操作异常方便。
从基础镜像的生成,修改,镜像扩容,格式转换等,全部可以在远端完成。并且操作速度的体验要优于传统的在本地磁盘的操作。
上面介绍的步骤略显复杂,主要是为了清楚的介绍几种镜像操作的可能遇到情形和处理过程中对一些小细节的处理。读者完全可以根据自己的需求拼凑出适合自己的步骤。
另外上面这些步骤也可通过简单修改nova和glance或自家平台代码的形式,直接包装到虚拟机及镜像相关自动化流程中。在此本文只做基本方法的介绍,希望能够抛砖引玉,令读者们能在自己的生产环境中发现实际的应用方式。

Tinytub

3 日志
© 2017 Tinytub
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.3