23

利用Prometheus 打造企业分布式监控平台(2)--服务发现

 4 years ago
source link: https://studygolang.com/articles/28091
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

nAba2yV.png!web

服务发现在Wikipedia的描述是:

Service discovery is the automatic detection of devices and services offered by these devices on a computer network.

换句话说,它允许应用程序动态发现服务,而不是在应用程序配置中静态定义服务。

对于Prometheus,可以使用多种方法进行服务发现,包括云提供商API(例如AWS,Azure,GCE,Openstack),基于DNS的发现(使用SRV记录)以及查询Kubernetes API中正在运行的服务。

可想而知,在目前云原生环境下,应用具备高度弹性,通过静态配置监控目标的行为是多么的低效。

Hotreload

当然Prometheus 提供了Hotreload机制,在配置文件变更的时候,可以通知Prometheus进行reload。而且在reload的过程中,服务不会停机

热更新的加载方法有两种:

当然新版本的Prometheus 的热加载功能默认是关闭的,你需要在Prometheus的启动参数中,添加如下参数:

--web.enable-lifecycle

但是这种方式,并不是最优雅的,你需要维护整个配置文件。

服务发现

除静态配置之外,Prometheus 已经支持了如下的服务发现方式:

# List of Azure service discovery configurations.
azure_sd_configs:
  [ - <azure_sd_config> ... ]

# List of Consul service discovery configurations.
consul_sd_configs:
  [ - <consul_sd_config> ... ]

# List of DNS service discovery configurations.
dns_sd_configs:
  [ - <dns_sd_config> ... ]

# List of EC2 service discovery configurations.
ec2_sd_configs:
  [ - <ec2_sd_config> ... ]

# List of OpenStack service discovery configurations.
openstack_sd_configs:
  [ - <openstack_sd_config> ... ]

# List of file service discovery configurations.
file_sd_configs:
  [ - <file_sd_config> ... ]

# List of GCE service discovery configurations.
gce_sd_configs:
  [ - <gce_sd_config> ... ]

# List of Kubernetes service discovery configurations.
kubernetes_sd_configs:
  [ - <kubernetes_sd_config> ... ]

# List of Marathon service discovery configurations.
marathon_sd_configs:
  [ - <marathon_sd_config> ... ]

# List of AirBnB's Nerve service discovery configurations.
nerve_sd_configs:
  [ - <nerve_sd_config> ... ]

# List of Zookeeper Serverset service discovery configurations.
serverset_sd_configs:
  [ - <serverset_sd_config> ... ]

# List of Triton service discovery configurations.
triton_sd_configs:
  [ - <triton_sd_config> ... ]

下图是一个Prometheus + consul sd 的架构。对于线上环境我们可能会划分为:dev, stage, prod不同的集群。每一个集群运行多个主机节点,每个服务器节点上运行一个Node Exporter实例。Node Exporter实例会自动注册到Consul中,而Prometheus则根据Consul返回的Node Exporter实例信息动态的维护Target列表,从而向这些Target轮询监控数据。

Qzu2yiJ.png!web

当然目前官方对于增加新的服务发现方式比较慎重,与Alertmanager 通知类型情况类似,官方不希望新的不稳定服务发现方式会影响Prometheus自身的稳定性。

能够与其他SD机制(例如Docker Swarm)集成是源源不断的需求。为了解决这个问题,最近,Prometheus存储库中的文档目录进行了一些小的代码更改,并提供了一个示例,以实现自定义服务发现集成,而无需将其合并到Prometheus主分支中。

例如,我在实际落地Prometheus的工程中,增加了下面两种服务发现方式:

  • 基于负载均衡器服务自动发现:根据负载均衡器的地址,获取后端服务器组。在Cloud上,后端服务器组大多要配置HPA,决定了需要动态的发现。
  • 基于自动伸缩组的服务自动发现:有些任务型工作负载,根据工作负载来扩缩worker节点数,比如根据消息队列的消息堆积数,来扩缩消费者的数量。此时根据自动伸缩组,获取实际运行的Worker节点。

如何实现自定义服务发现?

官方推荐的方式:按照官方的接口约定,实现新的服务发现方式,将发现的目标和标签写到文件中,然后结合prometheus本身支持的file_sd方式。Prometheus会定期到指定文件中获取最新的目标。

如下所示:

scrape_configs:
  - job_name: "custom-sd"
    scrape_interval: "15s"
    file_sd_configs:
    - files:
      - /path/to/custom_sd.json

Adapter

首先了解一下adapter.go文件,您可以复制此文件以实现自定义SD实现。

// Adapter runs an unknown service discovery implementation and converts its target groups
// to JSON and writes to a file for file_sd.
type Adapter struct {
    ctx     context.Context
    disc    discovery.Discoverer
    groups  map[string]*customSD
    manager *discovery.Manager
    output  string
    name    string
    logger  log.Logger
}

// Run starts a Discovery Manager and the custom service discovery implementation.
func (a *Adapter) Run() {
    go a.manager.Run()
    a.manager.StartCustomProvider(a.ctx, a.name, a.disc)
    go a.runCustomSD(a.ctx)
}

Adapter利用 Discovery.Manager 在goroutine中启动自定义SD提供程序的Run函数。Manager有一个通道,自定义SD将向其发送更新。这些更新包含SD目标。groups字段包含所有目标和标签。

type customSD struct {
    Targets []string          `json:"targets"`
    Labels  map[string]string `json:"labels"`
}

存在这个 customSD 结构主要是为了帮助我们将内部Prometheus targetgroup.Group 结构转换为JSON以用于 file_sd 格式。

运行时,Adapter将在通道上监听来自我们的自定义SD实现的更新,接收到更新后,它将解析 targetgroup.Groups 到另一个映射 [string]* customSD 中,并将其存储在Adapter,如果两者不同,我们将新组分配给Adapter结构,并将它们作为JSON写入输出文件中。

自定义SD实现

现在我们要实际使用Adapter来实现我们自己的自定义SD。完整的工作示例位于此处的 examples目录 中。

在这里,您可以看到我们导入Adapter代码“ github.com/prometheus/prometheus/documentation/examples/custom-sd/adapter”以及其他一些Prometheus库。为了编写自定义SD,我们需要一个实现Discoverer接口:

// Discoverer provides information about target groups. It maintains a set
// of sources from which TargetGroups can originate. Whenever a discovery provider
// detects a potential change, it sends the TargetGroup through its channel.
//
// Discoverer does not know if an actual change happened.
// It does guarantee that it sends the new TargetGroup whenever a change happens.
//
// Discoverers should initially send a full set of all discoverable TargetGroups.
type Discoverer interface {
    // Run hands a channel to the discovery provider(consul,dns etc) through which it can send
    // updated target groups.
    // Must returns if the context gets canceled. It should not close the update
    // channel on returning.
    Run(ctx context.Context, up chan<- []*targetgroup.Group)
}

我们实际上只需要实现一个函数 Run(ctx context.Context,up chan <-[] * targetgroup.Group) 。这是Adapter代码中的管理器将在goroutine中调用的函数。Run函数包含了知道何时退出的上下文,并传递了用于发送目标组更新的通道。

查看提供的示例中的Run函数,我们可以看到在另一个SD的实现中需要做的一些关键事情。

总结

如果实际场景中,公司已经有统一的服务注册中心或是配置中心,那么完全可以自定义SD,这样的好处是,利用了现有的基础设施,实现无缝对接。

另外一点是,Prometheus 中kubernetes SD的方式,对于容器化部署的业务,更加简单。

欢迎关注我们的微信公众号,每天学习Go知识

FveQFjN.jpg!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK