验证目的
我想通过测试搞清楚以下问题:
1、Linux下每秒内最大能启动多少应用进程?
2、这些大量的进程启动事件是否每次都能被监控到?监控率是多少?
验证结论
1、我这台Linux主机上每秒启动的进程数极限也就1000左右,多线程可以提升但是到达1000左右后多使用多线程也不会进一步提升。
2、采用NetLink监控进程事件在极限进程数的情况下消息(提前CPU资源分的足够,比如不小于10%)并不会丢,CPU占用单核的10%左右。
验证过程
要启动的程序
被测试的程序尽量简单,我们实现以下程序:
package main
func main() {
//fmt.Println("Hello, World!")
i := 0
i++
}
为了排除IO打印的时间,print也去掉。
尽可能快的启动
然后再实现一个程序:循环启动上述程序,等待程序运行结束再启动。执行10秒后统计每秒钟进程打开和关闭的次数。
package main
import (
"fmt"
"os/exec"
"time"
)
func main() {
duration := 10 * time.Second
count := 0
start := time.Now()
for time.Since(start) < duration {
cmd := exec.Command("/home/testApp")
if err := cmd.Start(); err != nil {
fmt.Println("启动程序出错:", err)
continue
}
if err := cmd.Wait(); err != nil { //800次左右
fmt.Println("等待程序出错:", err)
}
// 等待 3 微秒
//time.Sleep(3 * time.Microsecond) //586次左右
count++
}
averageCount := float64(count) / float64(duration.Seconds())
fmt.Printf("10 秒内平均打开和关闭次数:%.2f\n", averageCount)
}
经过测试:如果等待进程结束再启动运行,进程的执行次数大概是800次左右。
如果改成启动后等待3us,那进程的执行次数大概只有586次左右。
多线程测试
我们改成多线程再次测试:
package main
import (
"fmt"
"os/exec"
"sync"
"time"
)
func runApp(appName string, wg *sync.WaitGroup, count *int) {
defer wg.Done()
start := time.Now()
for time.Since(start) < 30*time.Second {
cmd := exec.Command("/home/" + appName)
if err := cmd.Start(); err != nil {
fmt.Println("启动", appName, "出错:", err)
continue
}
if err := cmd.Wait(); err != nil {
fmt.Println("等待程序出错:", err)
}
*count++
}
}
func main() {
var wg sync.WaitGroup
count1, count2, count3, count4, count5, count6, count7, count8, count9, count10 := 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
wg.Add(10)
go runApp("testApp1", &wg, &count1)
go runApp("testApp2", &wg, &count2)
go runApp("testApp3", &wg, &count3)
go runApp("testApp4", &wg, &count4)
go runApp("testApp5", &wg, &count5)
go runApp("testApp6", &wg, &count6)
go runApp("testApp7", &wg, &count7)
go runApp("testApp8", &wg, &count8)
go runApp("testApp9", &wg, &count9)
go runApp("testApp10", &wg, &count10)
wg.Wait()
totalCount := count1 + count2 + count3 + count4 + count5 + count6 + count7 + count8 + count9 + count10
averageCount := float64(totalCount) / 30
fmt.Printf("平均每秒打开和关闭总次数:%.2f\n", averageCount)
}
从3个线程(936个)依次提升到10个线程,测试结果可以逐步提升到940多个左右,无法再提升了。
此时CPU占用情况
因为我们是等待程序执行结束后再启动所以任务数并没有大量增加。CPU占用也仅有1个核的12.3%。
如果我们不等待进程结束,直接全部并发执行,再次看下结果:
每秒内平均打开和关闭总次数:488.53
并没有增加,反而下降了近一半。
进程事件监控
我们再看下如此高频的短生命周期的进程事件可以监控到多少。
我另外实现一个监控程序采用Netlink机制进行进程启动事件的监控并进行计数,将进程名包含testApp作为过滤条件,用户输入q后打印监控的进程数。
并没有丢,1个都没有丢。CPU占用最高也就到了10%左右。