首页 > > > Golang中的自动伸缩和自防御设计-2
Golang进程间通信(Inter process communication)
如上所述,检测一个Worker进程是否有响应,简单方法是由每个Worker报告上一次完成作业的时间。如果Master进程发现某个Worker时间周期太长,则可以认为它没有响应,并将其替换为新的Worker。要实现这一点,Worker进程需要以某种方式与Master进程通信,以便在它完成任务时保存并通知Master当前时间。实现这一点的方式有很多:
读取和写入文件
设置本地队列系统,如Redis或RabbitMQ
使用Golang rpc包
通过本地网络连接传输数据
利用共享内存
设置命名管道(named pipes)
在我们的例子中,所传输的只是时间戳,而不是重要的客户数据,因此上述这些方式大多数都有些杀鸡用牛刀了。因此最终采取了简单的解决方案——通过Worker进程的标准输出管道进行通信。
通过exec.Command启动新进程后,进程的标准输出管道可通过如下方式得到:
stdoutPipe, err:=cmd.StdoutPipe()
一旦有了标准的输出管道,就可以运行goroutine并发地监听它。在goroutine中,可以使用扫描器从管道读取数据,如下所示。在Worker进程将数据写入标准输出管道时,将执行scanner.Text()并调用之后的业务代码。
scanner:=bufio.NewScanner(stdoutPipe)
forscanner.Scan() {
line:=scanner.Text()
// 此处可处理读取到的具体业务数据
}
无响应监测(Unresponsivenessdetection)
现在进程间通信已经就绪,可以使用它来实现对无响应的Worker进程进行检测。更新现有的Worker逻辑,使之在完成工作时使用Golang fmt包打印出当前时间。而时间戳将被扫描器捕获,并使用与打印时相同的格式解析时间。然后将time对象设置到相关Worker对象的LastJob字段中用于跟踪。
t, err:=time.Parse(time.RFC3339, line)
iferr!=nil {
// 此处为错误异常处理逻辑
} else {
worker.LastJob = t
}
回到定时扫描包含Worker进程的Map的goroutine程序中,现在可以比较每个Worker的当前时间和上一个作业时间。如果这个时间间隔太长,则终止该进程并重新启动新的Worker进程。
funcCheckWorker(procs*map[int]*Worker, worker*Worker, indexint) {
// 如果Worker进程响应时间间隔太长,则终止并重启新的进程
duration:=time.Now().Sub(worker.LastJob)
ifduration.Minutes() > 4 {
KillWorker(procs, index)
StartWorker(procs, index)
}
}
可以通过调用进程对象的Kill函数来杀死进程。这是由生成进程时获得的Command对象提供的。另一件需要做的事是从映射的Map中删除Worker对象。在终止异常的Worker之后,可以通过调用StartWorker函数来启动一个新的Worker。新Worker在映射的Map中使用的key与被终止的Worker进程相同——从而完成了Worker的替换逻辑。
funcKillWorker(procs*map[int]*Worker, indexint) {
worker:= (*procs)[index]
ifworker!=nil {
process:=worker.Command.Process
delete(*procs, index) // 从Map中删除无效Worker进程
err:=process.Kill() // 终止进程
iferr!=nil {
// 错误及异常处理
}
}
}
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69901620/viewspace-3157866/ ,如需转载,请注明出处,否则将追究法律责任。