上一篇文章一、Prometheus源码分析之:数据采集),分析promentheus是如何采集target的指标数据的,接下来分析下,Prometheus的服务发现能力。在1.3版本后,服务发现能力成为独立模块。
2.1、简介
Prometheus通过pull拉取target数据,在上一篇文章中,target是通过静态文件配置的,难道后面增加一个target就需要手动配置,然后重新加载配置吗?其实加载target还支持一种方式:动态发现。
Prometheus目前支持以下平台的动态发现能力:
- 容器编排系统:kubernetes
- 云平台:EC2、Azure、OpenStack
- 服务发现:DNS、Zookeeper、Consul 等。
2.2、加载配置
ServiceDiscoveryConfig配置结构如下:
1 | type ServiceDiscoveryConfig struct { |
在Prometheus初始化过程中,通过执行discoveryManagerScrape.ApplyConfig进行服务发现相关配置的加载。
移除目前正在运行的providers,根据新的provided 配置,启动新的providers。。
1 | func (m *Manager) ApplyConfig(cfg map[string]sd_config.ServiceDiscoveryConfig) error { |
2.2.1、注册Providers
其中m.registerProviders的主要作用就是根据cfg(配置)注册所有provider实例,保存在m.providers
1 | func (m *Manager) registerProviders(cfg sd_config.ServiceDiscoveryConfig, setName string) { |
2.2.2、启动Provider
在ApplyConfig,执行m.startProvider(m.ctx, prov)启动provider。
1 | func (m *Manager) startProvider(ctx context.Context, p *provider) { |
这里分析DNS 服务发现对应的Run方法。需要标注下,DNS对应的Discovery其实是refresh中的Discovery的Run实现。
1 | d.Discovery = refresh.NewDiscovery( |
Run实现如下:
1 | func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { |
2.2.3、更新服务
当服务发现变化的targets时,通过updates chan进行更新。最终更新Discovery Manager的targets。
1 | func (m *Manager) updater(ctx context.Context, p *provider, updates chan []*targetgroup.Group) { |
2.3、启动discovery manager
加载完配置,并且完成注册、启动、更新操作后,开始执行discoveryManagerScrape.Run方法。
1 | func (m *Manager) Run() error { |
定时执行,当接收到服务发现的更新通知,通过m.allGroups()同步服务快照信息到scrapeManager
1 | func (m *Manager) sender() { |
2.4、关联ScrapeManager
2.4.1、关联
在ScrapeManager在启动的时候会关联discoveryManagerScrape.SyncCh()。
1 | func() error { |
2.4.2、更新
更新ScrapeManager的targets
1 | func (m *Manager) Run(tsets <-chan map[string][]*targetgroup.Group) error { |
执行更新
1 | func (m *Manager) updateTsets(tsets map[string][]*targetgroup.Group) { |
2.5、总结
discoveryManager在加载配置的时候,顺便完成provider的注册、启动、以及discovery的自更新通知操作。discoveryManager与ScrapeManager通过discoveryManager的syncCh通道来关联同步。
整个服务发现的流程很值得学习,尤其是discoveryManager支持多种服务发现的扩展配置的相关设设计很值得学习。