开源项目agent-Updater源码阅读
开源工具Agent-Updater主要用来批量更新所有机器上的Agent。分为Meta和Updater两部分。 工具作者秦晓辉,代码在这里,相应的视频教程。 本文是我个人的源码阅读笔记。
前言:
agent-updater可以看做是一个微缩版的__部署系统__。 之所以这么说,是因为它确确实实做到了部署系统应该做的事:上线代码、版本管理、甚至小流量的支持。 然而这么说又不太对,就我个人看法,部署系统应该是__与公司业务相关的__,不同的网络、IDC的选型,不同的服务划分的选型,应该有不同的部署解决方案。 如果说监控系统还可以独立于业务之外的话,部署系统是实在无法与业务分开,因为部署必须要依赖于服务树,服务树是业务架构的划分,业务线与机器之间的对应关系。
整体架构:
- 项目分为meta和updater两部分
- meta作为一个服务端,用户在meta上统一进行配置
- updater作为一个agent,运行在每台客户端上,向上联系meta获取信息,向下管理着机器上的各种agent
Meta:
- Config模块,主要加载用户配置,来处理各updater对应的agent版本等信息
- HTTP模块,用来和updater做交互,同时对外提供各updater的状态信息
- DOWNLOAD模块,用来提供一个文件服务器,提供给updater拉取tar包
Updater:
- HTTP模块,用来和meta交互,上报本机agent信息,下拉配置信息和tar包
- cron模块,用来拉取tar包,部署对应agent,同时获取各agent运行信息
配置的加载:
这是我学习的第一个golang的项目,之前只是使用过beego,看过beego的部分代码。学习UlricQin的这个项目让我受益良多。感谢UlricQin。
-
配置的加载是用的json格式的文件
-
读取直接使用json.Unmarshal即可,需提前定义好结构体
-
放在g包的一个全局变量中,带一把读写锁
var ( ConfigFile string config *GlobalConfig configLock = new(sync.RWMutex) ) func Config() *GlobalConfig { configLock.RLock() defer configLock.RUnlock() return config }
Heartbeat请求的实现:
为了解决同时请求meta,造成meta压力过大的问题,要让updater在第一个心跳请求之前sleep一个随机的时间(0 < t < 心跳周期)。 第一次心跳请求之后,每次请求sleep心跳骤起的时间就可以了。
func SleepRandomDuration() {
ns := int64(g.Config().Interval) * time.Second
// 以当前时间为随机数种子
r := rand.New(rand.NewSource(time.Now().UnixNano()))
d := time.Duration(r.Int63n(ns)) * time.Nanosecond
time.Sleep(d)
}
缺点:
使用updater上报-下拉的方式,诚然减少了服务端压力,然而meta对于各agent的控制力降低,无法实时监控各agent状态,也无法及时获取到agent的各异常信息。
改进:
服务端维护一个全量的机器列表,不管用DB、内存还是文件。可定时查看各agent详细情况。
后记:
回头想想,使用updater主动连meta的这种方式,确实带来了诸多优点,同时也导致了meta中央控制力的减弱。对agent的状态无法实时掌控,是一个运维工程师无法忍受的。 当然也可以通过其他的方式来弥补这一点,比如定时查询状态等,但如此一来,又违反了我们这样设计的初衷。 真正的部署系统,是应当与服务树、与公司的业务紧密相关的。所以,UlricQin在视频里说“这并不是一个真正的部署系统,因为一个真正的部署系统应该有各种更加复杂的逻辑”。