开源项目: prome_shard :consulwatch+动态分片实现Prometheus采集端高可用

架构图

image

开源项目地址:

image

项目说明

prometheus采集端单点问题

采集类型

  • 采集机器级别的指标
  • 采集k8s基础监控指标
  • 采集部署在lb后面的vm业务指标
  • 采集部署在pod里的业务指标
  • 采集各种中间件的指标 如kafka zk clickhouse等

面对如此复杂的采集类型,一般会使用一批采集Prometheus各司其职

sd发现问题

面对不同的采集来源,有对应的服务发现类型,如k8s_sd,我们修改Prometheus代码适配不同的服务发现类型,

  • 比如有一些指标挂在lb的后面,需要通过lb的服务发现来感知后端server的变化
  • 但是问题是每个采集器都是单点的,而且修改适配不同的发现源
  • 当然也可可以无脑启动多个相同的采集器采集同一组jobs,配合remote_write等补足单点问题,但带来额外的成本开销

各自适配不同发现源缺点总结

  • prometheus版本无法统一
  • 配置文件五花八门
  • 需要定义各种采集源或者sd方法

本项目介绍

使用一组采集器注册server到consul中,通过python反射运行定时任务,通过服务树等外部接口拿到targets池,一致性哈希分发给后端,统一通过file_sd生效,consul会对各组采集器实例做探活,当节点变化(宕机或扩容)会触发targets rebalance达到HA目的

架构说明

  • 解析配置文件
  • 同步注册服务到consul中
  • 开启监听watch结果变化的消费者
  • 异步watch各服务
  • 触发/get_service生成哈希环
  • 定时获取目标列根据哈希环生成各个节点的专属文件
  • 通过ansible下发 sd_result文件并reload prometheus

现有方式

  • 配置文件定义方法名称和对应的实例列表,在get_targets中反射定义对应的方法
  • sd本质说明:均能转换成file_sd,只需要给出对应的 target结构体就可以

consul watch问题

  • golang 中

image
在golang中可以轻松做到,具体请看我的文章开源项目 : dynamic-sharding: 解决pushgateway HA问

  • 本项目 python中稍微复杂,需要改为blocking query
    def block_get_health(self, service_name, service_hash_map, dq):
        index = None
        while True:
            try:
                index, d = self.consul.health.service(service_name, passing=True, index=index)
                if d:
                    data = d
                    new_nodes = []
                    for x in data:
                        address = x.get("Service").get("Address")
                        if address:
                            new_nodes.append(address)

                    old_nodes = service_hash_map[service_name].nodes

                    if set(old_nodes) != set(new_nodes):
                        logging.info("[new_num:{} old_num:{}][new_nodes:{} old_nodes:{}]".format(
                            len(new_nodes),
                            len(old_nodes),
                            ",".join(new_nodes),
                            ",".join(old_nodes),

                        ))
                        new_ring = ConsistentHashRing(100, new_nodes)
                        service_hash_map[service_name] = new_ring
                        dq.appendleft(str(service_name))
                        # dq.put(str(service_name))
                        M_SERVICE_CHANGES.labels(service_name=service_name, old_nodes=len(old_nodes),
                                                 new_nodes=len(new_nodes)).set(len(new_nodes))
            except Exception as e:
                logging.error("[watch_error,service:{},error:{}]".format(service_name, e))
                time.sleep(5)
                continue

采集器单点/固定分片问题

  • 无论是单点还是固定分片,都不是ha的,只要某一个分片的采集器挂了,那么损失对应的数据
  • 采用consul_watch_service方式,根据返回的健康实例生成一致性哈希环
  • 将target做分片分配给健康的节点采集即可

使用方法

git clone https://github.com/ning1875/prome_shard

添加配置

填写config.yaml中的consul地址等

填写job 需要跟get_targets.py同步

  • get_targets.py 是prome_shard发现采集targets pool的方法
  • 使用时需要实现 GetTarget的方法,方法名需要和config.yaml中相同
  • 比如 在config.yaml中 有个job名为scrape_prome_ecs_inf
  • 那么需要在 GetTarget中定义方法
 @classmethod
    def scrape_prome_ecs_inf(cls):
  • 这个方法返回值是发现到的target列表,形如
[{
 "labels": {
 "group": "SGT",
 "env": "prod",
 "service": "scrape_prome",
 "region": "ap-southeast-3",
 "scrape_type": "vm"
 },
 "targets": ["1.1.1.1:9090" ]
 }]
  • prome_shard根据返回的targets池做一致性哈希分配给配置中定义好的nodes

监控系统和运维开发
监控系统的源码解析,运维开发经验交流
158 声望
55 粉丝
0 条评论
推荐阅读
k8s默认调度器关于pod申请资源过滤的源码细节
思考 Q1 k8s的默认调度器是在哪个环节过滤满足这个pod资源的节点的?如果问你是否了解k8s的调度原理,大家估计都会滔滔不绝说一通但是是否真正的了解其中的细节估计就不好说了下面是我阅读k8s调度器的源码分析的...

ning1875阅读 1k

python里打印list的四种方法
原文链接标题:Print lists in Python (4 Different Ways)用for循环来打印 {代码...} 结果1 2 3 4 5用 * 星号来打印 {代码...} 结果 {代码...} 把list转换为str来打印 {代码...} 结果 {代码...} 用map把数组里非...

chiiinnn阅读 10.4k

封面图
Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4k评论 1

日常Python 代码片段整理
1、简单的 HTTP Web 服务器 {代码...} 2、单行循环List {代码...} 3、更新字典 {代码...} 4、拆分多行字符串 {代码...} 5、跟踪列表中元素的频率 {代码...} 6、不使用 Pandas 读取 CSV 文件 {代码...} 7、将列表...

墨城2阅读 340

Unicode 正则表达式(qbit)
前言本文根据《精通正则表达式》和 Unicode Regular Expressions 整理。本文的示例默认以 Python3 为实现语言,用到 Python3 的 re 模块或 regex 库。基本的 Unicode 属性分类 {代码...} 基本的 Unicode 子属性Le...

qbit阅读 4.4k

Python + Sqlalchemy 对数据库的批量插入或更新(Upsert)
由于不同数据库对这种 upsert 的实现机制不同,Sqlalchemy 也就不再试图做一致性的封装了,而是提供了各自的方言 API,具体到 Mysql,就是给 insert statement ,增加了 on_duplicate_key_update 方法。

songofhawk1阅读 2.1k评论 4

封面图
打脸了兄弟们,Go1.20 arena 来了!
大家好,我是煎鱼。大概半年前,我写过一篇文章《Go 要违背初心吗?新提案:手动管理内存》。有兴趣了深入解的同学,可以再回顾一下。当时我们还想着 Go 团队应该不会接纳,至少不会那么快:懒得翻也可以看我再次...

煎鱼1阅读 3.3k

158 声望
55 粉丝
宣传栏