ã¯ããã« ããã«ã¡ã¯ãã¿ã€ããŒã§ãšã³ãžãã¢ãããŠãã埳å¯( @yannkazu1 )ã§ãã ã¯ã©ãŠããã€ãã£ãäŒè°2026 ã§çºè¡šãããã ãã¢ãŒãºæ¬çªç°å¢ã§ã®cgroup-awareåãšã®æ»éé² ãããã¡ããã¡ãé¢çœãã£ãã®ã§ãèªåã®æã§ãäœæããããªããŸããã Goã®GOMAXPROCSãã³ã³ããã®CPUå¶éãç¡èŠããã£ãŠãå®éã«èŠããšã©ããªãã®ãïŒ éå°äžŠåã®ã¹ã«ãŒãããäœäžã£ãŠãæ°åã§èŠããšã©ã®ãããã€ã³ãã¯ããããã®ãïŒ ã¹ããããªã³ã°ãšã¹ã¬ããæ°ã®é¢ä¿ãèªåã®ç®ã§ããããããïŒ èªåã§åãããŠæ°åãèŠãªããšè
ã«èœã¡ãªãã¿ã€ããªã®ã§ã ããŒã«ã«ã®Macç°å¢ã§å
šéšåçŸããŠã¿ãŸããã çºè¡šã®èŠçŽ ãã¢ãŒãºã®ããã¯ãšã³ã pairs-main ã¯Go補ã§Amazon EKSäžã§çšŒåã48ã³ã¢ã®Nodeã§ limits.cpu: 5000m ïŒ5ã³ã¢ïŒã®PodãåããŠãããã Goã®GOMAXPROCSãããã©ã«ãã§48 ïŒïŒNodeå
šäœã®ã³ã¢æ°ïŒã«ãªã£ãŠãããããã«ãã以äžã®åé¡ãçºç: éå°äžŠå : 5ã³ã¢ãã䜿ããªãã®ã«48ã¹ã¬ãããèµ°ã â Goã¹ã±ãžã¥ãŒã©ã®ãªãŒããŒãããå¢å€§ CPUã¹ããããªã³ã° : cgroupã®ã¯ã©ãŒã¿ïŒCPUæéã®äžéïŒãã¹ã¬ãããå
±é£ã â å
šã¹ã¬ãããåæã«åæ¢ ç£èŠã®æ»è§ : CPU䜿çšçã¯æ£åžžã«èŠããããå®éã¯ã¹ããããªã³ã°ã§æç¶çã«åæ¢ åãåé¡ãHAProxyïŒ nbthread=48 ãCPUå¶é1ã³ã¢ïŒã§ãçºçããŠããã ããããcgroup-awareãªèšå®ïŒGOMAXPROCS=5, nbthread=1ïŒã«ä¿®æ£ãããšããã倧å¹
ã«æ¹åããããšãã話ã§ããã çšèªã®æŽç ããããå
ã§åºãŠãããã³ã¢ããGOMAXPROCSããã¯ã©ãŒã¿ããã¹ããããªã³ã°ããããããã³ãšæ¥ãªããŠã倧äžå€«ã§ããèšäºå
šäœã§ç¹°ãè¿ãç»å Žããã®ã§ãæåã«ãã£ããæŽçããŠãããŸãïŒãã§ã«éŠŽæã¿ãããæ¹ã¯ã¹ãããã§OKïŒã CPUã³ã¢ã»ããã»ã¹ã»ã¹ã¬ãã çšèª ãã£ããããæå³ CPUã³ã¢ èšç®ãå®è¡ããç©ççãªå®äœã1ã³ã¢ = åæã«1ã€ã®åŠçãé²ãããã ããã»ã¹ åããŠããããã°ã©ã 1ã€åã®åäœ ã¹ã¬ãã ããã»ã¹å
ã§å®éã«CPUã«å²ãåœãŠãããäœæ¥ã®åäœã1ããã»ã¹ã¯è€æ°ã¹ã¬ãããæãŠã ãã£ããèšããšã ã³ã¢ã®æ° = åæã«é²ããããã¹ã¬ããã®æ°ã®äžé ã§ãã8ã³ã¢ã®CPUãªããããäžç¬ã«é²è¡ã§ããã®ã¯æå€§8ã¹ã¬ãããŸã§ããã以äžã®ã¹ã¬ãããç«ã¡äžããå Žåã¯ãOSãé çªã«ã³ã¢ãå²ãåœãŠçŽããªããåããŸãïŒ= ã³ã³ããã¹ãã¹ã€ããïŒã ã³ã³ãããš cgroup çšèª ãã£ããããæå³ ã³ã³ãã åããµãŒããŒäžã§è€æ°ã®ã¢ããªãäºãã«å¹²æžããªãããã«åããä»çµã¿ïŒDocker ã Kubernetes ã®äžèº«ïŒãå®äœã¯ãã¹ãã®ã«ãŒãã«ããã®ãŸãŸäœ¿ã ãnamespaces ã§èŠããç¯å²ããcgroup ã§äœ¿ããéãå¶éããããã»ã¹ïŒçŸ€ïŒã ã«ããããVM ã®ããã«å°çšã«ãŒãã«ãæã€ããã§ã¯ãªã cgroup ïŒControl GroupsïŒ Linuxã«ãŒãã«ã®æ©èœã§ããã®ããã»ã¹çŸ€ã¯CPUããããŸã§ã»ã¡ã¢ãªã¯ãããŸã§ããšäžéãèšå®ããä»çµã¿ CPUå¶é ããã®ã³ã³ããã¯CPU 1ã³ã¢åãŸã§ãã®ãããªäžéèšå®ãå®äœã¯ cgroup ã® cpu.max ãã¡ã€ã« ã³ã³ããã®ãCPU 0.5ã³ã¢ãŸã§ããšããèšå®ã¯ãLinuxã«ãŒãã«ã cgroup ãéããŠã100msã®ãã¡50msãŸã§ããCPUã䜿ãããªãããšãã圢ã§åŒ·å¶ããŸãããã® 100msã®æ ããããªãªããããã®äžã§äœ¿ã£ãŠããæééããã¯ã©ãŒã¿ã ãšåŒã³ãŸãïŒ cpu.max: 50000 100000 ãªãã100msã®ãã¡50ms䜿ãã = 0.5ã³ã¢çžåœãïŒã CFS ã¹ã±ãžã¥ãŒã© Linux ã®ããã©ã«ãã® CPU ã¹ã±ãžã¥ãŒã©ã CFSïŒCompletely Fair SchedulerïŒ ãšåŒã³ãŸããå
ã»ã©ã®ãããªãªãããã¯ã©ãŒã¿ãã¯ãCFS ãæã€ 垯åå¶åŸ¡ïŒBandwidth ControllerïŒ ãšããæ©èœã®çšèªã§ãcgroup ã® cpu.max ã®å€ãå®éã«ã¹ã¬ãããžé©çšããïŒïŒã¯ã©ãŒã¿ã䜿ãåã£ãã忢ãããïŒã®ã¯ãã® CFS ã®ä»äºã§ãã ã€ãŸããcgroup ãå¶éå€ãæã¡ãCFS ãããã宿œããããšããåæ
é¢ä¿ãåŸã®å®éšã§åºãŠãã nr_periods ïŒCFS ãæéãåºåãåäœã®ç·æ°ïŒã nr_throttled ïŒCFS ã忢ãããããªãªãã®æ°ïŒãããã® CFS 垯åå¶åŸ¡ã®çµ±èšãèŠãŠããŸãã Goroutine ãš GOMAXPROCSïŒGoç¹æã®è©±ïŒ çšèª ãã£ããããæå³ goroutine Goã®è»œéã¹ã¬ãããOSã¹ã¬ããããé¥ãã«è»œãã1ããã»ã¹ã§æ°äžãæ°çŸäžåç«ã¡äžãããã OSã¹ã¬ãã OSãå®éã«CPUã«ã¹ã±ãžã¥ãŒã«ããã¹ã¬ãããã³ã¢ãåãåãã®ã¯ãã¡ã GOMAXPROCS Goã©ã³ã¿ã€ã ãåæã«èµ°ãããOSã¹ã¬ããã®æ°ã®äžéãããã©ã«ãã¯ãã¹ãã®CPUã³ã¢æ° goroutine ãäœäžåç«ã¡äžããŠããGoã©ã³ã¿ã€ã 㯠GOMAXPROCS åã® OSã¹ã¬ããã®äžã«ããããå€éåããŠå®è¡ããŸããã€ãŸãåæã« CPU ãæ¡ã£ãŠããã®ã¯æå€§ã§ã GOMAXPROCS åããã®å²ãåœãŠã管çããã®ã Goã¹ã±ãžã¥ãŒã© ã§ãã ãã€ã³ãã¯ã ã³ã³ããã®CPUå¶éãäžãã£ãŠãããã©ã«ãã® GOMAXPROCS ã¯ãã¹ãã®CPUæ°ã®ãŸãŸ ãšããããšããããããããä»åã®ããŒãã§ãåŸã®å®éšã§ãã®æåãå®éã«ç¢ºãããŸãã éå°äžŠå CPU å¶éãããå€ãã®ã¹ã¬ããïŒã goroutineãã¯ãŒã«ãŒïŒãåæã«èµ°ãããŠããç¶æ
ãæããŸããããšãã° 5 ã³ã¢çžåœã® CPU å¶éã«å¯Ÿã㊠GOMAXPROCS=48 ãªããçŽ 9.6 åã®éå°äžŠåãå®éã«èµ°ããã®ã¯å¶éåã®ã¹ã¬ããã ããªã®ã§ãæ®ãã¯ã¹ã±ãžã¥ãŒã©ã®äžã§é çªåŸ
ã¡ããã€ã€ãå
±æã¯ã©ãŒã¿ãæ©é£ããåãããšã«ãªããŸãã Go ã® GOMAXPROCS ã«éã£ã話ã§ã¯ãªããHAProxy ã® nbthread ãNginx ã® worker_processes ãPuma ã® workers ãªã©ã ãäžŠåæ°ã®ããã©ã«ãããã¹ã CPU æ°ã«äŸåãããèšå®ã¯ãã¹ãŠåãæ§é ã§éå°äžŠåãèµ·ãããŸã ã CPUã¹ããããªã³ã° cgroupã§CPU 0.5ã³ã¢åã«å¶éãããã³ã³ããããããããã®ã¹ã¬ããã§CPUãäžæ°ã«äœ¿ãããšãããšãLinuxã«ãŒãã«ã ãã¯ã©ãŒã¿ã䜿ãåã£ãã®ã§ã次ã®ããªãªããŸã§å
šã¹ã¬ããäžæåæ¢ã ãšåŒ·å¶çã«ãããã¯ããŸããããã CPUã¹ããããªã³ã° ã§ãã ã¹ããããªã³ã°ãé »çºãããšãã¬ã¹ãã³ã¹ãæç¶çã«æ¢ãŸã£ãããã¹ã«ãŒããããèœã¡ããããŸãããã®çµæãããªããé
å»¶ãã¹ãã€ã¯ãããåå ã«ãªã£ãŠããã±ãŒã¹ãå€ãã§ããçºçç¶æ³ã¯ /sys/fs/cgroup/cpu.stat ã«åºåãããŠãããæ¬èšäºã§ã¯ä»¥äžã®3ææšã远ããŸã: nr_periods : ã¹ã±ãžã¥ãŒã©ã®èšæž¬åäœïŒããªãªã = 100msïŒã®ç·æ° nr_throttled : ãã®ãã¡ã¹ããããªã³ã°ãèµ·ããããªãªãã®æ°ïŒåæ°ïŒ throttled_usec : ã¹ããããªã³ã°ã§å®éã«CPUãæ¢ããããçŽ¯ç©æéïŒãã€ã¯ãç§ïŒ ãåæ°ãã ãã§ãªãã 环ç©åæ¢æé ããèŠãã®ãéèŠã ããšããã®ãçºè¡šã®å±±å Žã®äžã€ã§ãåŸã®å®éš3ã§ãã®éããããããªåºãŸãã Thundering Herd ã¹ããããªã³ã°ã§åæ¢ããŠããå
šã¹ã¬ãããã æ¬¡ã®ããªãªãã®ãªã»ããã§äžæã«èµ°ãåºãããŸãäžç¬ã§ã¯ã©ãŒã¿ãé£ã朰ããŠåæã«æ¢ãŸã ããšãããµã€ã¯ã«ãç¹°ãè¿ãããç¶æ
ã ãThundering HerdïŒé·é³Žã®çŸ€ãïŒã ãšåŒã³ãŸããå
ã¯ãœã±ãã accept ãªã© I/O æèã®çšèªã§ãããcgroup ã®åž¯åå¶åŸ¡äžã§ãåãæ§é ã®åé¡ãèµ·ããŸããã¹ã¬ããæ°ãå€ãã»ã©è¢«å®³ã倧ãããªãã®ã¯ãããã«ç«¯ãçºããŠããŸããå®éš4ã§ãã®æåã芳å¯ããŸãã cgroup-aware ããã°ã©ã ãã©ã€ãã©ãªã cgroup ã®å¶éïŒ cpu.max ãªã©ïŒãèªåã§èªã¿åãããã®å€ã«åãããŠäžŠå床ã調æŽãã èšèšã®ããšã ãcgroup-awareã ãšåŒã³ãŸããGo 1.25 以éã®ã©ã³ã¿ã€ã ã uber-go/automaxprocs 㯠cgroup-aware ã« GOMAXPROCS ãèšå®ããŸããéã« Go 1.24 以åã®ããã« cgroup ãèŠãã«ãã¹ãã® CPU æ°ã ãèŠãæåã¯ãcgroup-aware ã§ã¯ãªããç¶æ
ã§ãä»åã®éå°äžŠåã¯ããããçãŸããŠããŸãã ãã®èšäºã§æ€èšŒããããš # æ€èšŒããŒã çºè¡šã§ã®ãã€ã³ã 1 GOMAXPROCSã®ããã©ã«ãå€ ã³ã³ããã®CPU Limitãç¡èŠããŠãã¹ãã®CPUæ°ã«ãªã 2 éå°äžŠåã®ããã©ãŒãã³ã¹åœ±é¿ GOMAXPROCSã倧ãããããšã¹ã«ãŒããããäœäžãã 3 CPUã¹ããããªã³ã°ã®çºç ã¹ã¬ããæ°ãå€ãã»ã©ã¯ã©ãŒã¿ãæ©ãæ¶è²»ãã忢æéãå¢ãã 4 ã¹ã¬ããæ°ãšã¹ããããªã³ã°ã®çžé¢ ã¹ã¬ããæ°ã«æ¯äŸã㊠throttled_usec ãå¢å ãã 1. ããŒã«ã«ç°å¢æ§ç¯ïŒMacïŒ åææ¡ä»¶ macOS ïŒApple Silicon / Intel 䞡察å¿ïŒ Docker Desktop ãã€ã³ã¹ããŒã«æžã¿ ãªãDockerã§æ€èšŒã§ããã®ã cgroupïŒControl GroupsïŒã¯ Linuxã«ãŒãã«ã®æ©èœ ã§ãmacOS èªäœã«ã¯ååšããŸãããããã Docker Desktop ã¯å
éšã§ Linux VM ãåãããŠãããã³ã³ããã¯ãã® Linux äžã§åäœããŸãã âââââââââââââââââââââââââââââââââââââââââââââââ â macOS â â ââââââââââââââââââââââââââââââââââââââââââ â â â Docker Desktop (Linux VM) â â â â ââââââââââââââââââââââââââââââââââââ â â â â â ã³ã³ãã â â â â â â /sys/fs/cgroup/cpu.max â ããïŒ â â â â â â /sys/fs/cgroup/cpu.stat â â â â â ââââââââââââââââââââââââââââââââââââ â â â ââââââââââââââââââââââââââââââââââââââââââ â âââââââââââââââââââââââââââââââââââââââââââââââ Docker ã® --cpus ãã©ã°ã¯ Kubernetes ã® limits.cpu ãšåãã cgroup ã® cpu.max ã«å€æãããŸããã€ãŸã Kubernetes ãšåãä»çµã¿ãããŒã«ã«ã§åçŸ ã§ããŸãã Docker Kubernetes cgroup v2 --cpus=0.5 limits.cpu: 500m cpu.max: 50000 100000 --cpus=1.0 limits.cpu: 1000m cpu.max: 100000 100000 --cpus=5.0 limits.cpu: 5000m cpu.max: 500000 100000 ã»ããã¢ããæé Step 1: Docker Desktop ã®ã€ã³ã¹ããŒã« Docker Desktop for Mac ããã€ã³ã¹ããŒã«ã docker --version # Docker version 27.x.x, build xxxxxxx Step 2: æ€èšŒçš Go ã¢ããªã±ãŒã·ã§ã³ æ¬èšäºã®æ€èšŒã³ãŒãã¯ä»¥äžã®ãªããžããªã«ãŸãšããŠããŸã: hirosi1900day/cgroup-throttling-lab git clone https://github.com/hirosi1900day/cgroup-throttling-lab.git cd cgroup-throttling-lab 3ã€ã®ã¢ãŒããæã€Goã¢ããªã±ãŒã·ã§ã³ãæžããŸããã ã¢ãŒã çšé info GOMAXPROCSã®å€ãšcgroupã®èšå®ã衚瀺 benchmark CPUè² è·ããããŠã¹ã«ãŒããããèšæž¬ throttle-demo CPUè² è·ããããŠã¹ããããªã³ã°ã® Before/After ã衚瀺 ã³ãŒã解説 åããŒããé ã«èŠãŠãããŸãã 1. CPUè² è·ãçºçããã颿° // cpuIntensiveWork ã¯CPUè² è·ããããèšç®åŠç // å¹³æ¹æ ¹ãšäžè§é¢æ°ã1äžåã«ãŒãããæå³çã«CPUã䜿ãåã func cpuIntensiveWork() float64 { result := 0.0 for i := 0 ; i < 10000 ; i++ { result += math.Sqrt( float64 (i)) * math.Sin( float64 (i)) } return result } ãã®é¢æ°ãå®éšã®èŠã§ãã math.Sqrt ãš math.Sin ã®èšç®ã1äžåç¹°ãè¿ãããšã§ã çŽç²ãªCPUè² è· ãçºçãããŸããI/OåŸ
ã¡ãäžåãªãã®ã§ãGOMAXPROCSïŒïŒã¯ãŒã«ãŒã¹ã¬ããæ°ïŒã®åœ±é¿ããã€ã¬ã¯ãã«çŸããŸãã 2. infoã¢ãŒã â Goã©ã³ã¿ã€ã ãšcgroupã®CPUèšå®ã衚瀺 func showRuntimeInfo() { // runtime.GOMAXPROCS(0) ã¯ãçŸåšã®å€ãè¿ãã倿Žããªãã // â ãããã³ã³ããã®CPUå¶éãšäžèŽããŠãããããã€ã³ã fmt.Printf( "GOMAXPROCS: %d \n " , runtime.GOMAXPROCS( 0 )) fmt.Printf( "NumCPU: %d \n " , runtime.NumCPU()) // --- cgroup ã®CPUå¶éãçŽæ¥èªã --- // /sys/fs/cgroup/cpu.max 㯠cgroup v2 ã®CPUå¶éãã¡ã€ã« // äžèº«ã¯ "ã¯ã©ãŒã¿ ããªãªã" ã®åœ¢åŒïŒäŸ: "100000 100000"ïŒ // Kubernetes ã® limits.cpu ã Docker ã® --cpus ãããã«åæ ããã if data, err := os.ReadFile( "/sys/fs/cgroup/cpu.max" ); err == nil { fmt.Printf( "cpu.max: %s" , string (data)) } // /sys/fs/cgroup/cpu.stat ã¯CPUã¹ããããªã³ã°ã®çµ±èšæ
å ± // nr_periods: CFSã¹ã±ãžã¥ãŒã©ã®ããªãªãïŒ100msïŒã®ç·æ° // nr_throttled: ã¹ããããªã³ã°ãçºçããããªãªãã®æ° // throttled_usec: ã¹ããããªã³ã°ã§CPUã忢ããçŽ¯ç©æéïŒÎŒsïŒ if data, err := os.ReadFile( "/sys/fs/cgroup/cpu.stat" ); err == nil { fmt.Printf( "cpu.stat: \n %s" , string (data)) } } ãã®ã¢ãŒãã§ã¯ã Goã©ã³ã¿ã€ã ãcgroupã®CPUå¶éãèªèããŠããã ãèŠãŸããGo 1.24以åã§ã¯ã GOMAXPROCS ããã¹ãã®CPUæ°ã®ãŸãŸãªã®ã確èªã§ããã¯ãã§ãã 3. benchmarkã¢ãŒã â ã¹ã«ãŒãããã®èšæž¬ func runBenchmark() { // ç°å¢å€æ°ã§ãã³ãããŒã¯æéãšgoroutineæ°ãå¶åŸ¡å¯èœã«ããŠãã duration := 10 * time.Second // BENCH_DURATION ã§å€æŽå¯ goroutines := 100 // BENCH_GOROUTINES ã§å€æŽå¯ // --- ãããããèšæž¬ã®ã³ã¢ --- var totalOps atomic.Int64 // goroutineéã§å®å
šã«ã«ãŠã³ããå
±æ var wg sync.WaitGroup // å
šgoroutineã®å®äºãåŸ
〠// ã¿ã€ããŒã§çµäºãéç¥ãããã£ãã« done := make ( chan struct {}) go func () { <-time.After(duration) close (done) // â å
šgoroutineã«ãçµäºããäŒãã }() // goroutinesåã®goroutineãèµ·åãããããããç¬ç«ã«CPUè² è·ãããã // ãããã®goroutine㯠GOMAXPROCS åã®ã¯ãŒã«ãŒã¹ã¬ããã« // Goã¹ã±ãžã¥ãŒã©ã«ãã£ãŠå²ãåœãŠããã for i := 0 ; i < goroutines; i++ { wg.Add( 1 ) go func () { defer wg.Done() localOps := int64 ( 0 ) // goroutineããŒã«ã«ã§ã«ãŠã³ãïŒç«¶åãé¿ããïŒ for { select { case <-done: totalOps.Add(localOps) // æåŸã«ãŸãšããŠå ç® return default : cpuIntensiveWork() // CPUè² è·ãããç¶ãã localOps++ } } }() } wg.Wait() // Ops/sec = åäœæéãããã®åŠçåæ° // ãã®å€ãé«ãã»ã©ã¹ã«ãŒããããè¯ã opsPerSec := float64 (totalOps.Load()) / elapsed.Seconds() } 100åã®goroutineã cpuIntensiveWork() ãåŒã³ç¶ããããããGOMAXPROCSåã®OSã¹ã¬ããäžã§ã¹ã±ãžã¥ãŒã«ãããæ§é ãCPUå¶éãããç°å¢ã§ã¯ãã¹ã¬ãããå€ãã»ã©cgroupã®ã¯ã©ãŒã¿ãæ©ã䜿ãåããã¹ããããªã³ã°ã§ã¹ã«ãŒããããèœã¡ãããã§ãã ïŒè±ç·ïŒãã³ãããŒã¯ã³ãŒãã®å·¥å€« â ãã£ãã·ã¥ã³ããŒã¬ã³ã·ã®è©± cgroup ã®æ€èšŒãšã¯çŽæ¥é¢ä¿ãªãã§ããããã®ãã³ãããŒã¯ã³ãŒãã«ã¯ãèšæž¬èªäœãçµæãæªããªãããã®å·¥å€«ããå
¥ã£ãŠããŸãããã£ãããªã®ã§è§£èª¬ããŸãã select + default ã§ãã³ããããã³ã°ã«çµäºãã§ãã¯ãã€ã€CPUåŠçãåãç¶ããããšããã®ã¯Goã®å®çªãã¿ãŒã³ãªã®ã§è»œãè§Šããã ãã«ããŠãæ¬é¡ã¯ã«ãŠã³ã¿ã®èšèšã§ãã localOps := int64(0) // goroutineããŒã«ã«ïŒæ®éã®intïŒ for { select { case <-done: totalOps.Add(localOps) // â çµäºæã«1床ã ãatomicæäœ return default: cpuIntensiveWork() localOps++ // â æ®éã®ã€ã³ã¯ãªã¡ã³ããè¶
é«é } } ã«ãŒãå
ã§ã¯ localOps++ ïŒæ®éã® int ã€ã³ã¯ãªã¡ã³ãïŒã ãã䜿ããçµäºæã«1床ã ã totalOps.Add(localOps) ïŒ atomic æäœïŒã§åç®ããŠããŸãã ãæ¯å totalOps.Add(1) ã§ããã®ã§ã¯ïŒããšæããããããŸããããããã ãš100åã® goroutine ãåãã¡ã¢ãªã¢ãã¬ã¹ã«æ¯ã«ãŒãæžã蟌ã¿åãã ãã£ãã·ã¥ã³ããŒã¬ã³ã·ïŒCache CoherencyïŒ ã®ãªãŒããŒãããã§æ§èœã倧ããèœã¡ãŸãã ãã£ãã·ã¥ã³ããŒã¬ã³ã·ãšã¯ ãŸãåæãšããŠãCPUãããŒã¿ã«ã¢ã¯ã»ã¹ããä»çµã¿ãæŽçããŠãããŸãã CPU ã®ã¡ã¢ãªéå±€ CPUã倿°ãããŒã¿ãèªã¿æžããããšããæ¯åã¡ã€ã³ã¡ã¢ãªïŒDRAMïŒãŸã§åãã«è¡ãã®ã¯é
ãããŸããããã§ CPU㯠ã¡ã¢ãªéå±€ïŒMemory HierarchyïŒ ãšãã倿®µã®ãã£ãã·ã¥æ§é ãæã£ãŠããŸã: âââââââââââââââââââââââââââââââââââââââââââââââââââ â CPU ã³ã¢ â â âââââââââââââ â â â ã¬ãžã¹ã¿ â â æéïŒ~0.3nsïŒãæ°åãæ°çŸå â â âââââââ¬ââââââ â â âââââââŽââââââ â â â L1 ãã£ãã·ã¥â â 32ã64KB / ã³ã¢ã~1ns â â â (ããŒã¿+åœä»€)â â â âââââââ¬ââââââ â â âââââââŽââââââ â â â L2 ãã£ãã·ã¥â â 256KBã1MB / ã³ã¢ã~3-10ns â â âââââââ¬ââââââ â â â ââââââââââââ â â â â TLB â â ä»®æ³âç©çã¢ãã¬ã¹ â â â â â 倿ã®ãã£ãã·ã¥ â â â ââââââââââââ â ââââââââââŒâââââââââââââââââââââââââââââââââââââââââ âââââââŽââââââ â L3 ãã£ãã·ã¥â â æ°MBãæ°åMBãå
šã³ã¢å
±æã~10-30ns âââââââ¬ââââââ âââââââŽâââââââââââââââââââ â ã¡ã€ã³ã¡ã¢ãªïŒDRAMïŒ â â æ°GBãæ°çŸGBã~50-100ns âââââââ¬âââââââââââââââââââ âââââââŽâââââââââââââââââââ â ã¹ãã¬ãŒãžïŒSSD/HDDïŒ â â ~10,000ns (SSD) ã 10,000,000ns (HDD) âââââââââââââââââââââââââ éå±€ 容é ã¬ã€ãã³ã· ç¹åŸŽ ã¬ãžã¹ã¿ æ°çŸãã€ã ~0.3ns CPUãçŽæ¥æŒç®ããå Žæ L1ãã£ãã·ã¥ 32ã64KB/ã³ã¢ ~1ns ããŒã¿çšãšåœä»€çšã«åé¢ãã³ã¢ããšã«å°æ L2ãã£ãã·ã¥ 256KBã1MB/ã³ã¢ ~3-10ns ã³ã¢ããšã«å°æïŒã¢ãŒããã¯ãã£ã«ããïŒ L3ãã£ãã·ã¥ æ°MBãæ°åMB ~10-30ns å
šã³ã¢å
±æ ããããã³ã¢éã®ããŒã¿ã®æ©æž¡ã TLB æ°çŸãæ°åãšã³ã㪠~1nsïŒãããæïŒ ä»®æ³ã¢ãã¬ã¹âç©çã¢ãã¬ã¹ã®å€æãã£ãã·ã¥ ã¡ã€ã³ã¡ã¢ãª æ°GBã ~50-100ns L1ã®50ã100åé
ã CPUã localOps++ ãå®è¡ãããšãããã®å€æ°ãã¬ãžã¹ã¿ã L1 ã«ããã° 1ns 以äžã§å®äºããŸããããã L1 ã«ãªãïŒãã£ãã·ã¥ãã¹ïŒãš L2 â L3 â ã¡ã€ã³ã¡ã¢ãªãšé ã«ãã©ãå¿
èŠããããææª100nsãããã L1ããããšã¡ã€ã³ã¡ã¢ãªã¢ã¯ã»ã¹ã§ã¯çŽ100åã®é床差 ãããããã§ãã TLBïŒTranslation Lookaside BufferïŒ ã¯å°ã圹å²ãéã£ãŠãä»®æ³ã¡ã¢ãªã®ã¢ãã¬ã¹å€æãé«éåãããã£ãã·ã¥ã§ããããã»ã¹ã䜿ãã¡ã¢ãªã¢ãã¬ã¹ïŒä»®æ³ã¢ãã¬ã¹ïŒãå®éã®ç©çã¢ãã¬ã¹ã«å€æããã«ã¯ããŒãžããŒãã«ãåŒãå¿
èŠããããŸãããæ¯ååŒããšã¡ã¢ãªã¢ã¯ã»ã¹ã2åã«ãªãã®ã§ããã䜿ãå€æçµæã TLB ã«ãã£ãã·ã¥ããŠããŸããTLB ãã¹ãçºçãããš ããŒãžããŒãã«ãŠã©ãŒã¯ ãèµ°ããæ°ånsã®è¿œå ã³ã¹ããããããŸããgoroutine ã倧éã®ã¹ã¿ãã¯ãããŒãã䜿ãã¯ãŒã¯ããŒãã§ã¯ãTLB ãã¹ãããã©ãŒãã³ã¹ã«å¹ããŠããŸãã ãã®åæãèžãŸãããšããã«ãã³ã¢ã§ã®ãã£ãã·ã¥äžè²«æ§ããªãéèŠããããããŸãã ãã£ãã·ã¥ã³ããŒã¬ã³ã·åé¡ ãã«ãã³ã¢CPUã§ã¯ãåã³ã¢ãç¬èªã® L1/L2ãã£ãã·ã¥ ãæã£ãŠããŸããããã³ã¢ã倿°ãæŽæ°ãããšãä»ã®ã³ã¢ãæã€åã倿°ã®ãã£ãã·ã¥ã©ã€ã³ã¯ å€ãå€ïŒstaleïŒ ã«ãªããŸãããããæŸçœ®ãããšåã³ã¢ãç°ãªãå€ãèŠãŠããŸããããããŒããŠã§ã¢ã¬ãã«ã§äžè²«æ§ãä¿ã€ä»çµã¿ãå¿
èŠã§ããããã ãã£ãã·ã¥ã³ããŒã¬ã³ã·ãããã³ã« ïŒä»£è¡šçãªãã®ã« MESI ãããã³ã« ïŒã§ãã MESI ãããã³ã«ã§ã¯ããã£ãã·ã¥ã©ã€ã³ã¯ä»¥äžã®4ç¶æ
ãé·ç§»ããŸã: ç¶æ
æå³ M odified èªã³ã¢ã ãã倿޿žã¿ã®å€ãæã€ E xclusive èªã³ã¢ã ããæã£ãŠããããã¡ã¢ãªãšåãå€ S hared è€æ°ã³ã¢ãåãå€ãæã£ãŠããïŒèªã¿åãå°çšïŒ I nvalid ä»ã³ã¢ãæŽæ°ããã®ã§ããã®ãã£ãã·ã¥ã©ã€ã³ã¯ç¡å¹ atomic 倿°ãžã®æžã蟌ã¿ãçºçãããš: æžã蟌ãã³ã¢ããã£ãã·ã¥ã©ã€ã³ã® æä»çæææš© ãèŠæ± ä»ã®å
šã³ã¢ã®åããã£ãã·ã¥ã©ã€ã³ã Invalid ã«å€ããïŒç¡å¹åïŒ æ¬¡ã«ãã®ã³ã¢ãåã倿°ã«ã¢ã¯ã»ã¹ãããšã ãã£ãã·ã¥ãã¹ â ã¡ã¢ãªïŒor ä»ã³ã¢ã®ãã£ãã·ã¥ïŒããåååŸ ãããæ¯ã«ãŒãã»100 goroutine ã§çºçãããš: [NG] æ¯å atomicïŒãã£ãã·ã¥ã©ã€ã³ã®ãã³ãã³ïŒ ã³ã¢1: totalOps.Add(1) â ãã£ãã·ã¥ã©ã€ã³ååŸ (Exclusive) â å€ãæŽæ° (Modified) â ä»ã®å
šã³ã¢ã®ãã£ãã·ã¥ã©ã€ã³ã Invalid ã« ã³ã¢2: totalOps.Add(1) â Invalid ãªã®ã§åååŸãå¿
èŠïŒãã£ãã·ã¥ãã¹ïŒïŒ â ã³ã¢1ãã転é â Exclusive â Modified â ä»ã®å
šã³ã¢ã®ãã£ãã·ã¥ã©ã€ã³ã Invalid ã« ã³ã¢3: totalOps.Add(1) â ãŸã Invalid â ãŸãåååŸ...ïŒä»¥äžãã³ãã³ç¶æ
ïŒ â å®éã®CPUèšç®ã§ã¯ãªãããã£ãã·ã¥ã®åæã«CPUæéãæ¶ãã ãã®ãã£ãã·ã¥ã©ã€ã³ã®å¥ªãåã㯠ããã£ãã·ã¥ã©ã€ã³ããŠã³ã·ã³ã°ã ã ãfalse sharingã ïŒåããã£ãã·ã¥ã©ã€ã³ã«å¥ã®å€æ°ãä¹ã£ãŠããå ŽåïŒãšãåŒã°ãããã«ãã¹ã¬ããããã°ã©ãã³ã°ã®æåãªããã©ãŒãã³ã¹èœãšã穎ã§ãã äžæ¹ãããŒã«ã«ã«ãŠã³ã¿ãªã: [OK] ããŒã«ã«ã«ãŠã³ã¿ + æåŸã«1åã ã atomic ã³ã¢1: localOps++ â èªã³ã¢ã®ã¬ãžã¹ã¿ or L1ãã£ãã·ã¥ã ããä»ã³ã¢ã«åœ±é¿ãªã ã³ã¢2: localOps++ â åäžãågoroutineãç¬ç«ããã¡ã¢ãªãè§Šã ... ïŒçµäºæã ã totalOps.Add â atomic æäœã¯10ç§éã§åèšãã£ã100åïŒ ã ãã³ãããŒã¯ãã®ãã®ã®ã³ã¹ãã§ãã³ãããŒã¯çµæãæªã ãã®ãé²ããã¯ããã¯ã§ããcgroup ã®ã¹ããããªã³ã°ãæ£ç¢ºã«æž¬ããªããèšæž¬ã®ãªãŒããŒãããã¯æ¥µååã£ãŠããããã 4. throttle-demoã¢ãŒã â ã¹ããããªã³ã°ã®èŠ³æž¬ func runThrottleDemo() { // GOMAXPROCSåã®ã¯ãŒã«ãŒãèµ·åïŒ= OSã¹ã¬ããæ°ãšäžèŽãããïŒ numWorkers := runtime.GOMAXPROCS( 0 ) // Before: ã¹ããããªã³ã°åã®çµ±èšãèšé² // cpu.stat ã® nr_throttled, throttled_usec ãç¢ºèª fmt.Println( "--- Before ---" ) readCgroupStat() // numWorkersåã®goroutineã§CPUè² è·ãããã // GOMAXPROCS=8 ãªã8æ¬ãGOMAXPROCS=1 ãªã1æ¬ // â ã¹ã¬ããæ°ã®éããã¹ããããªã³ã°ã«ã©ã圱é¿ãããã芳枬 for i := 0 ; i < numWorkers; i++ { go func () { for { cpuIntensiveWork() // å
šã¹ã¬ããã§CPUå
šé } }() } // 5ç§é CPUè² è·ããããåŸ... // After: ã¹ããããªã³ã°åŸã®çµ±èšãèšé² // Before ãšã®å·®åãããã®5ç§éã§çºçããã¹ããããªã³ã°ã fmt.Println( "--- After ---" ) readCgroupStat() } GOMAXPROCS ã®å€ããã®ãŸãŸã¯ãŒã«ãŒæ°ã«ãªããŸããGOMAXPROCS=8 ãªã8ã¹ã¬ãããåæã«CPUã䜿ãããšããã®ã§ãå
±æã¯ã©ãŒã¿ãäžç¬ã§é£ã朰ããŸããBefore/After ã® throttled_usec ã®å·®åã§ã å®éã«ã©ãã ãCPUãæ¢ããããã ãããããŸãã Dockerfile # ãã«ãã¹ããŒãž: Go 1.24 ã§ã³ã³ãã€ã« FROM golang:1.24-bookworm AS builder WORKDIR /app COPY go.mod ./ COPY main.go ./ RUN go build -o /app/cgroup-bench . # å®è¡ã¹ããŒãž: 軜éãªã€ã¡ãŒãžã§å®è¡ FROM debian:bookworm-slim COPY --from=builder /app/cgroup-bench /usr/local/bin/cgroup-bench ENTRYPOINT ["cgroup-bench"] CMD ["info"] Go ããŒãžã§ã³ã«ã€ã㊠Go ã®ææ°å®å®ç : 1.26.3ïŒ2026幎5ææç¹ïŒ container-aware GOMAXPROCS ãå°å
¥ãããããŒãžã§ã³ : Go 1.25 æ¬èšäºã§äœ¿ãããŒãžã§ã³ : Go 1.24ïŒ1.25çŽåã®æçµçïŒ Go 1.25以éã§ã¯ã©ã³ã¿ã€ã ãcgroupã® cpu.max ãèªåã§èªã¿åããGOMAXPROCSãCPUå¶éã«åãããŠèšå®ããŸããä»å㯠åé¡ãçºçããŠããåœæã®æåãåçŸ ããããããããŠGo 1.24ã䜿çšããŠããŸãã main.go å
šæïŒã¯ãªãã¯ã§å±éïŒ ```go package main import ( "encoding/json" "fmt" "math" "os" "runtime" "strconv" "sync" "sync/atomic" "time" ) type Result struct { GOMAXPROCS int `json:"gomaxprocs"` NumCPU int `json:"num_cpu"` CPULimit string `json:"cpu_limit"` Duration time.Duration `json:"duration_ns"` DurationStr string `json:"duration"` TotalOps int64 `json:"total_ops"` OpsPerSec float64 `json:"ops_per_sec"` GoroutineCount int `json:"goroutine_count"` } func cpuIntensiveWork() float64 { result := 0.0 for i := 0; i < 10000; i++ { result += math.Sqrt(float64(i)) * math.Sin(float64(i)) } return result } func main() { mode := "benchmark" if len(os.Args) > 1 { mode = os.Args[1] } switch mode { case "benchmark": runBenchmark() case "info": showRuntimeInfo() case "throttle-demo": runThrottleDemo() } } func showRuntimeInfo() { fmt.Println("=== Go Runtime Information ===") fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0)) fmt.Printf("NumCPU: %d\n", runtime.NumCPU()) fmt.Printf("GOVERSION: %s\n", runtime.Version()) envGOMAXPROCS := os.Getenv("GOMAXPROCS") if envGOMAXPROCS == "" { fmt.Println("ENV GOMAXPROCS: (not set â using default)") } else { fmt.Printf("ENV GOMAXPROCS: %s\n", envGOMAXPROCS) } fmt.Println("\n=== cgroup CPU Information ===") if data, err := os.ReadFile("/sys/fs/cgroup/cpu.max"); err == nil { fmt.Printf("cpu.max: %s", string(data)) } if data, err := os.ReadFile("/sys/fs/cgroup/cpu.weight"); err == nil { fmt.Printf("cpu.weight: %s", string(data)) } if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("cpu.stat:\n%s", string(data)) } } func runBenchmark() { duration := 10 * time.Second if d := os.Getenv("BENCH_DURATION"); d != "" { if parsed, err := time.ParseDuration(d); err == nil { duration = parsed } } goroutines := 100 if g := os.Getenv("BENCH_GOROUTINES"); g != "" { if parsed, err := strconv.Atoi(g); err == nil { goroutines = parsed } } maxprocs := runtime.GOMAXPROCS(0) var totalOps atomic.Int64 var wg sync.WaitGroup done := make(chan struct{}) go func() { <-time.After(duration) close(done) }() start := time.Now() for i := 0; i < goroutines; i++ { wg.Add(1) go func() { defer wg.Done() localOps := int64(0) for { select { case <-done: totalOps.Add(localOps) return default: cpuIntensiveWork() localOps++ } } }() } wg.Wait() elapsed := time.Since(start) ops := totalOps.Load() opsPerSec := float64(ops) / elapsed.Seconds() fmt.Printf("GOMAXPROCS=%d Ops/sec=%.2f Total=%d\n", maxprocs, opsPerSec, ops) jsonData, _ := json.Marshal(Result{ GOMAXPROCS: maxprocs, OpsPerSec: opsPerSec, TotalOps: ops, }) fmt.Printf("JSON: %s\n", string(jsonData)) if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("\ncpu.stat:\n%s", string(data)) } } func runThrottleDemo() { fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0)) fmt.Println("\n--- Before ---") if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("%s", string(data)) } numWorkers := runtime.GOMAXPROCS(0) duration := 5 * time.Second if d := os.Getenv("DEMO_DURATION"); d != "" { if parsed, err := time.ParseDuration(d); err == nil { duration = parsed } } var wg sync.WaitGroup stop := make(chan struct{}) go func() { <-time.After(duration) close(stop) }() for i := 0; i < numWorkers; i++ { wg.Add(1) go func() { defer wg.Done() for { select { case <-stop: return default: cpuIntensiveWork() } } }() } wg.Wait() fmt.Println("\n--- After ---") if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("%s", string(data)) } } ``` Step 3: ãã«ã docker build -t cgroup-bench go-app/ ããã§æºåå®äºã§ãã 2. å®éšãšçµæ æ€èšŒç°å¢: - macOSïŒApple SiliconïŒ - Docker Desktop - Docker VM: 11ã³ã¢ ïŒãããKubernetesã®ã48ã³ã¢Nodeãã«çžåœïŒ å®éš1: GOMAXPROCS ã¯ã³ã³ããã® CPU å¶éãç¡èŠãã äœã確èªããã çºè¡šã§ã¯ãã³ã³ããã® limits.cpu: 5000m ã«å¯Ÿã㊠GOMAXPROCS ã 48ïŒããŒãã®ã³ã¢æ°ïŒã«ãªã£ãŠããããšããåé¡ã®çºç«¯ã§ããããŸãã¯ã Goã©ã³ã¿ã€ã ãcgroupã®CPUå¶éãèŠãŠããªã ãšããç¶æ
ãããŒã«ã«ã§ç¢ºèªããŸãã å®è¡ã³ãã³ã # A: CPUå¶éãªã docker run --rm cgroup-bench info # B: CPUå¶é 1ã³ã¢ docker run --rm --cpus=1.0 cgroup-bench info # C: CPUå¶é 0.5ã³ã¢ docker run --rm --cpus=0.5 cgroup-bench info å®éã®çµæ A: CPUå¶éãªã === Go Runtime Information === GOMAXPROCS: 11 â Docker VMã®å
šCPUã³ã¢æ° NumCPU: 11 GOVERSION: go1.24.13 ENV GOMAXPROCS: (not set â using default) === cgroup CPU Information === cpu.max: max 100000 â "max" = äžéãªã B: CPUå¶é 1ã³ã¢ïŒ --cpus=1.0 ïŒ === Go Runtime Information === GOMAXPROCS: 11 â å¶éããããã®ã«11ã®ãŸãŸïŒ NumCPU: 11 GOVERSION: go1.24.13 ENV GOMAXPROCS: (not set â using default) === cgroup CPU Information === cpu.max: 100000 100000 â cgroupã«ã¯1ã³ã¢åã®å¶éãæ£ããèšå®ãããŠãã C: CPUå¶é 0.5ã³ã¢ïŒ --cpus=0.5 ïŒ === Go Runtime Information === GOMAXPROCS: 11 â ãŸã 11ã®ãŸãŸïŒ NumCPU: 11 === cgroup CPU Information === cpu.max: 50000 100000 â cgroupã«ã¯0.5ã³ã¢åã®å¶éãèšå®ãããŠãã çµæãèŠãŠã¿ã CPUå¶é cpu.maxïŒcgroupïŒ GOMAXPROCS éå°äžŠåã®åç ãªã max 100000 ïŒç¡å¶éïŒ 11 - 1ã³ã¢ 100000 100000 11 11å 0.5ã³ã¢ 50000 100000 11 22å å®å
šã«ç¡èŠããŠãŸããcgroupã«ã¯ cpu.max ãšããŠæ£ããCPUå¶éãèšå®ãããŠããã®ã«ã Go 1.24ã®ã©ã³ã¿ã€ã ã¯äžåèŠãŠããªã ãGOMAXPROCSã¯åžžã«ãã¹ãïŒDocker VMïŒã®CPUæ°=11ãããã©ã«ãã çºè¡šã®æ¬çªç°å¢ã§ã¯48ã³ã¢Nodeã§ limits.cpu: 5000m ã ã£ãã®ã§ã GOMAXPROCS=48ïŒçŽ10åã®éå°äžŠåïŒ ãèµ·ããŠãããããŒã«ã«ã§ãåãæ§é ã®åé¡ãåçŸã§ããŸããã cpu.max ã®èªã¿æ¹ : ã¯ã©ãŒã¿ ããªãªã ã®åœ¢åŒãããªãªãïŒããã©ã«ã100ms=100000ÎŒsïŒã®ãã¡ãã¯ã©ãŒã¿åã ãCPUã䜿ããã 50000 100000 ãªãã100msã®ãã¡50ms䜿çšå¯èœ = 0.5ã³ã¢åãã å®éš2: éå°äžŠåã¯ã¹ã«ãŒããããäœäžããã äœã確èªããã çºè¡šã§ã¯ GOMAXPROCS ã48â5ã«å€ãããã¹ã«ãŒãããã倧å¹
æ¹åãGoã¹ã±ãžã¥ãŒã©ã® CPU䜿çšçã50%ä»¥äžæžã£ããšã®ããšãåãäœéšãããŒã«ã«ã§ãæ°åã§èŠãŠã¿ãŸãã å®è¡ã³ãã³ã CPUå¶é1ã³ã¢ã®ç°å¢ã§ã100åã®goroutineã10ç§éèµ°ãããŸããå€ããã®ã¯GOMAXPROCSã ãã # GOMAXPROCS=1ïŒCPUå¶éã«äžèŽ = é©åïŒ docker run --rm --cpus=1.0 \ -e GOMAXPROCS=1 -e BENCH_DURATION=10s -e BENCH_GOROUTINES=100 \ cgroup-bench benchmark # GOMAXPROCS=8ïŒCPUå¶éã®8å = éå°äžŠåïŒ docker run --rm --cpus=1.0 \ -e GOMAXPROCS=8 -e BENCH_DURATION=10s -e BENCH_GOROUTINES=100 \ cgroup-bench benchmark å®éã®çµæ GOMAXPROCS=1ïŒé©åãªäžŠåæ°ïŒ: GOMAXPROCS=1 Ops/sec=21503.63 Total=215525 cpu.stat: nr_periods 101 nr_throttled 56 throttled_usec 43791 GOMAXPROCS=8ïŒéå°äžŠåïŒ: GOMAXPROCS=8 Ops/sec=6832.54 Total=68646 cpu.stat: nr_periods 102 nr_throttled 101 throttled_usec 70703432 çµæãèŠãŠã¿ã ææš GOMAXPROCS=1 GOMAXPROCS=8 å·®å Ops/secïŒã¹ã«ãŒãããïŒ 21,504 6,833 68.2% äœäž nr_throttled / nr_periods 56/101 (55%) 101/102 ( 99% ) ã»ãŒå
šããªãªãã§åæ¢ throttled_usecïŒçޝç©åæ¢æéïŒ 43,791ÎŒs (0.04ç§) 70,703,432ÎŒs (70.7ç§) 1,614å æ£çŽããããŸã§å·®ãåºããšã¯æã£ãŠããŸããã§ããã GOMAXPROCS ã1â8ã«ããã ãã§ã ã¹ã«ãŒããããçŽ3åã®1ã«èœã¡ã 10ç§éã®ãã¹ã㧠环èš70.7ç§ãã®CPU忢 ïŒ8ã¹ã¬ãããåçŽ8.8ç§ãã€æ¢ãŸã£ãèšç®ïŒ ã¹ããããªã³ã°ç99% â ã»ãŒæ¯ããªãªãã§å
šã¹ã¬ãããæ¢ããããŠãã çºè¡šã§èª¬æãããŠããã ã¯ã©ãŒã¿ãã¹ã¬ãããå
±é£ããã ãçŸè±¡ãã®ãã®ã§ãã âââââââââ 1ããªãªã (100ms) âââââââââ GOMAXPROCS=1 ã®å Žå: [ââââââââ å®è¡ ââââââââ][ââ 忢 ââ] â 1ã¹ã¬ããã§ç©ããã«äœ¿ã GOMAXPROCS=8 ã®å Žå: [â 8ã¹ã¬ããäžæå®è¡ â][ââââââââââââââââââââââ é·æé忢 ââââââââââââââââââââââ] â ã¯ã©ãŒã¿æ¯æž â å
šã¹ã¬ãããåæã«ã¹ããããªã³ã° å®éš3: ã¹ããããªã³ã°ã®æ·±å»åºŠã¯ã¹ã¬ããæ°ã§å€ãã äœã確èªããã çºè¡šã§ã æéãèŠãã°ãããªãªãã®%ãåãã§ãæ·±å»åºŠã®éããåãã ããšææãããŠããŸããããããå®éã« nr_throttled ïŒåæ°ïŒã¯åãããããªã®ã« throttled_usec ïŒåæ¢æéïŒã«ã¯å€§ããªå·®ãåºããšããããšãªã®ã§ãèªåã®ç®ã§èŠãŠã¿ãŸãã å®è¡ã³ãã³ã CPUå¶é0.5ã³ã¢ïŒããªãå³ããå¶éïŒã§GOMAXPROCS=8 vs 1 ãæ¯èŒã # éå°äžŠåïŒGOMAXPROCS=8, CPU=0.5ã³ã¢ïŒ docker run --rm --cpus=0.5 -e GOMAXPROCS=8 -e DEMO_DURATION=5s cgroup-bench throttle-demo # é©åãªäžŠåïŒGOMAXPROCS=1, CPU=0.5ã³ã¢ïŒ docker run --rm --cpus=0.5 -e GOMAXPROCS=1 -e DEMO_DURATION=5s cgroup-bench throttle-demo å®éã®çµæ GOMAXPROCS=8ïŒéå°äžŠåïŒ: --- After --- nr_periods 52 nr_throttled 51 â 98%ã®ããªãªãã§ã¹ããããªã³ã° throttled_usec 39039180 â 39ç§ã®CPU忢 GOMAXPROCS=1ïŒé©åïŒ: --- After --- nr_periods 51 nr_throttled 50 â 98%ã®ããªãªãã§ã¹ããããªã³ã°ïŒã»ãŒåãïŒïŒ throttled_usec 2644221 â 2.6ç§ã®CPU忢 çµæãèŠãŠã¿ã ææš GOMAXPROCS=8 GOMAXPROCS=1 å·®å nr_throttled / nr_periods 51/52 (98%) 50/51 (98%) ã»ãŒåã throttled_usec 39,039,180ÎŒs (39ç§) 2,644,221ÎŒs (2.6ç§) 14.8å æ°åãèªåã§äžŠã¹ãŠã¿ãŠãåããŠæ·±å»ããããããŸããã nr_throttled ã®å²åïŒã¹ããããªã³ã°çïŒã ãèŠããšã©ã£ã¡ã98%ã§å
šãåãã«èŠããŸããã§ã throttled_usec ïŒå®éã®åæ¢æéïŒã«ã¯14.8åãã®å·®ãããã ãããçºè¡šã§èšãããŠãããCPU䜿çšçã ãã§ã¯æ°ã¥ããªãããç£èŠã®æ»è§ãã®æ£äœã§ãã ãªãCPU䜿çšçã§ã¯èŠããªãã®ã ãããããå°ãæãäžããŸããå®ã¯ãã®å®éšã ã©ã¡ãã®ã±ãŒã¹ãCPU䜿çšçã¯çŽ100% ãšè¡šç€ºãããŸãããããGOMAXPROCS=8 ã®ã»ããé
ãã®ã«CPU䜿çšçã¯åãïŒããšæããããããŸããããããã«ã¯ã«ã©ã¯ãªããããŸãã CPU䜿çšçã®èšç®åŒã¯æ¬è³ªçã«ããã§ã: $$ \text{CPU䜿çšç} = \frac{\text{æ¶è²»ããCPUæé}}{\text{å²ãåœãŠã¯ã©ãŒã¿}} $$ ä»åã®å®éšã§ã¯ --cpus=0.5 ãªã®ã§ã1ããªãªãïŒ100msïŒãããã®ã¯ã©ãŒã¿ã¯ 50ms ã§ãã GOMAXPROCS=1 GOMAXPROCS=8 ã¯ã©ãŒã¿ 50ms / period 50ms / period æ¶è²»CPUæé 50msïŒäœ¿ãåãïŒ 50msïŒäœ¿ãåãïŒ CPU䜿çšç â100% â100% æ¶è²»ããŒã¹ 1ã¹ã¬ãã à 50ms = 50msãããŠåŸã
ã« 8ã¹ã¬ãã à 6.25ms = çŽ6msã§äžæ°ã« æ®ãã®æé 50mséã¯åæ¢ïŒç©ããïŒ 94msé å
šã¹ã¬ããåçµ ã©ã¡ããã¯ã©ãŒã¿50msã䜿ãåãã®ã§ãCPU䜿çšçã¯åã100%ã§ããããã æ¶è²»ã®ããŒã¹ããŸãã§éããŸã ã 1ããªãªãïŒ100msïŒã®å
èš³: GOMAXPROCS=1: |ââââââââââââââââââââââââââââââââââââââââââââââ| â 1ã¹ã¬ããã§50mså®è¡ ââ 50ms åŸ
æ© â CPU䜿çšç: 50/50 = 100% ã¬ã€ãã³ã·: å®å® GOMAXPROCS=8: |âââââââââââââââââââââââââââââââââââââââââââââ| â6msâââââââââââ 94ms å
šã¹ã¬ããåçµ âââââââââââ CPU䜿çšç: 50/50 = 100% ã¬ã€ãã³ã·: ã¹ãã€ã¯çºç GOMAXPROCS=1 ã¯1ã¹ã¬ããã§50msãç©ããã«æ¶è²»ããã®ã§ãåŠçã¯éåãã€ã€ãæ¯èŒçåçã«é²ã¿ãŸããäžæ¹ GOMAXPROCS=8 ã¯8ã¹ã¬ãããåæã«CPUãèŠæ±ããããããããçŽ6msã§ã¯ã©ãŒã¿ãé£ãå°œããã æ®ãã®94msã¯å
šã¹ã¬ãããå®å
šã«åçµ ããŸãã ã€ãŸãCPU䜿çšç100%ã®è£ã§èµ·ããŠããããšãå
šãç°ãªãã®ã«ã éçŽã¡ããªã¯ã¹ã§ã¯ãã®éããæ¶ããŠããŸã ãããããç£èŠã®æ»è§ãã®æ¬è³ªã§ãã ãŸãšãããš: nr_throttledçãåãã§ãã 8ã¹ã¬ãããåæã«æ¢ãŸã ã®ãš 1ã¹ã¬ããã ãæ¢ãŸã ã®ã§ã¯æ·±å»åºŠããŸãã§éã CPU䜿çšç㯠ã¯ã©ãŒã¿ãæ¶è²»ããé ãã瀺ããã æ¶è²»ã®ããŒã¹ïŒããŒã¹ãæ§ïŒãäžååæ ããªã throttled_usec ãåãããŠç£èŠããªããšãã¹ããããªã³ã°ã®å®æ
ã¯ã€ãããªã å®éš4: ã¹ã¬ããæ°ãšåæ¢æéã®çžé¢ äœã確èªããã ã¹ã¬ããæ°ãæ®µéçã«å¢ããããšãã throttled_usec ãæ¯äŸããŠå¢ããã®ããçºè¡šã¹ã©ã€ãã®ã ã¯ã©ãŒã¿ã¯ã¹ã¬ããéã§å
±æ ãã ã¹ã¬ãããå€ãã»ã©æ©ãæ¶è²» ããšãã説æããã°ã©ãã§äœæããŠã¿ãŸãã å®è¡ã³ãã³ã for MAXPROCS in 1 2 4 8 16; do echo "--- GOMAXPROCS=$MAXPROCS ---" docker run --rm --cpus=1.0 -e GOMAXPROCS=$MAXPROCS -e DEMO_DURATION=5s \ cgroup-bench throttle-demo 2>&1 \ | grep -E "nr_periods|nr_throttled|throttled_usec" | tail -3 echo "" done å®éã®çµæ --- GOMAXPROCS=1 --- nr_periods 51 nr_throttled 20 throttled_usec 21885 --- GOMAXPROCS=2 --- nr_periods 51 nr_throttled 50 throttled_usec 5075001 --- GOMAXPROCS=4 --- nr_periods 51 nr_throttled 50 throttled_usec 15053306 --- GOMAXPROCS=8 --- nr_periods 52 nr_throttled 51 throttled_usec 35847841 --- GOMAXPROCS=16 --- nr_periods 51 nr_throttled 51 throttled_usec 50338309 çµæãèŠãŠã¿ã GOMAXPROCS nr_throttled ã¹ããããªã³ã°ç throttled_usec 环ç©åæ¢æé 1 20 / 51 39% 21,885 0.02ç§ 2 50 / 51 98% 5,075,001 5.1ç§ 4 50 / 51 98% 15,053,306 15.1ç§ 8 51 / 52 98% 35,847,841 35.8ç§ 16 51 / 51 100% 50,338,309 50.3ç§ åæ¢æé (ç§) 50 †â GOMAXPROCS=16 â â± 40 †Ⱡâ â± 35 †â â± GOMAXPROCS=8 â â± â± 20 †Ⱡâ â± 15 †â â± GOMAXPROCS=4 â â± â± 10 †Ⱡâ â± 5 †â â± GOMAXPROCS=2 â â²â± 0 â€â GOMAXPROCS=1 ââââ¬âââ¬âââ¬âââ¬âââ¬âââ¬ââ 1 2 4 8 12 16 GOMAXPROCS GOMAXPROCS=1ã8ã®ç¯å²ã§ã¯ã»ãŒç·åœ¢ã«æ¯äŸããŠããŸãã GOMAXPROCS=1 â 0.02ç§ïŒã»ãŒåæ¢ãªãïŒ GOMAXPROCS=16 â 50.3ç§ïŒ5ç§ã®ãã¹ãã§çޝèš50ç§åã®åæ¢ïŒïŒ ãã ã GOMAXPROCS=16 ã§ã¯ãåæã«CPUã䜿ããã¹ã¬ããæ°ã Docker VM ã®ç©çCPUæ°ïŒ11ã³ã¢ïŒã§é æã¡ã«ãªããããçŽç²ãªç·åœ¢ã¢ãã«ã®äºæž¬ïŒ75ç§ïŒããäœã50.3ç§ã«é£œåããŠããŸãã16ã¹ã¬ããäžãåæã«å®è¡ã§ããã®ã¯æå€§11ã¹ã¬ãããªã®ã§ã忢æé㯠$\min(n, 11) \times P - Q$ ã«è¿ã¥ããŸãã GOMAXPROCS=8 以äžã§ã¯ç©çCPUæ°ã®å¶çŽãåããªãããããããã« $n \times P - Q$ ã®ç·åœ¢ã¢ãã«ãšäžèŽããŠããŸãïŒ8ã¹ã¬ããæã®äºæž¬35ç§ vs 宿ž¬35.8ç§ïŒã çºè¡šã§ãã Thundering Herd åé¡ ãã®ãã®ã§ãã¯ã©ãŒã¿ãªã»ããã§å
šã¹ã¬ãããäžæã«åé â å
±æã¯ã©ãŒã¿ãç¬æ®º â å
šã¹ã¬ããåæåæ¢ãã®ãµã€ã¯ã«ãç¹°ãè¿ãããã 3. èå¯: ãªãã¹ã¬ãããå¢ãããšãé
ããªããã®ã å®éš4ã®çµæãæ¹ããŠèŠããšã throttled_usec ãã¹ã¬ããæ°ã«ã»ãŒæ¯äŸããŠå¢ããŠããŸãããã¹ã¬ãããå¢ããã»ã©æããããã£ãŠãçŽæã«åããŸãããCFS 垯åå¶åŸ¡ã®ä»çµã¿ããæ°åŒã§èª¬æã§ããŸãã CFS 垯åå¶åŸ¡ã®æ°ç â ã¯ã©ãŒã¿æ¶è²»ã®ã¢ãã« cgroup ã® CPU å¶éã¯ã1ããªãªãïŒ100msïŒããã $Q$ ã ã CPU ã䜿ããããšããã¯ã©ãŒã¿å¶ã§ãã --cpus=1.0 ãªã $Q = 100\text{ms}$ ã§ãã $n$ æ¬ã®ã¹ã¬ãããåæã«ãã«çšŒåãããšãCPU æé㯠$n$ åã®éåºŠã§æ¶è²»ãããŸããã€ãŸã: ã¯ã©ãŒã¿æ¯æžãŸã§ã®æé : $\frac{Q}{n}$ æ®ãã®ããªãªã : å
š $n$ ã¹ã¬ãããåæã«åæ¢ 1ã¹ã¬ãããããã®åæ¢æé : $\text{ããªãªã} - \frac{Q}{n}$ 环ç©åæ¢æé ïŒ= throttled_usec ïŒ: $n \times \left(\text{ããªãªã} - \frac{Q}{n}\right)$ -cpus=1.0 ïŒ$Q = 100\text{ms}$ãããªãªã $= 100\text{ms}$ïŒã§ $n = 8$ ã®å Žå: ã¯ã©ãŒã¿æ¯æž: $\frac{100}{8} = 12.5\text{ms}$ ã§äœ¿ãåã åã¹ã¬ããã®åæ¢: $100 - 12.5 = 87.5\text{ms}$ 1ããªãªããããã®çޝç©åæ¢: $8 \times 87.5 = 700\text{ms}$ 5ç§éïŒ50ããªãªãïŒãªã $50 \times 700\text{ms} = 35\text{ç§}$ãå®éš4ã® GOMAXPROCS=8 ã®çµæïŒ35.8ç§ïŒãšã»ãŒäžèŽããŸãã USL ã§èŠããšã¹ã«ãŒãããæªåã説æãã€ã ãã®çŸè±¡ãã¹ã±ãŒãªã³ã°æ³åã®èгç¹ããèŠããšãNeil Gunther ã® USLïŒUniversal Scalability LawïŒ ãåœãŠã¯ãŸããŸã: $$ S(n) = \frac{n}{1 + \alpha(n-1) + \beta \cdot n(n-1)} $$ ãã©ã¡ãŒã¿ æå³ cgroup ç°å¢ã§ã®å
·äœäŸ $\alpha$ ç«¶å â çŽååããã«ã㣠Go ã¹ã±ãžã¥ãŒã©ã®ããã¯ç«¶åãã©ã³ãã¥ãŒç®¡ç $\beta$ äžè²«æ§ â ã¹ã¬ããéã®å調ã³ã¹ã CFS ã¯ã©ãŒã¿ã®å
±ææ¶è²» + å
šã¹ã¬ããäžæåæ¢ USL ã§å¹ããŠããã®ã¯ $\beta$ ã®é
ã§ãã$\beta \cdot n(n-1)$ 㯠$n 2 $ ãªãŒããŒã§å¢å€§ãããããããéŸå€ãè¶
ãããšã¹ã«ãŒãããã ããŒã¯ããæžå°ã«è»¢ããŸã ãå®éš2ã®ãGOMAXPROCS=8 ã§ 68% äœäžãã¯ããã® retrogradeïŒéè¡ïŒé åã«å
¥ã£ãçµæã§ãã ã¹ã«ãŒããã â â ããŒã¯ïŒGOMAXPROCS=1ïŒ â â±â² â â± â² â USL ã® retrograde é å â â± â² ââ± â² â GOMAXPROCS=8ïŒ68%äœäžïŒ ââââââââââââ ã¹ã¬ããæ° cgroupå¶éäžã§ã¯ãã¹ã¬ãã1æ¬ããããŒã¯ã å¢ããã»ã©ã¯ã©ãŒã¿ã®å¥ªãåãã§æãããã éåžžã®äžŠåããã°ã©ãã³ã°ã§ã¯ãã³ã¢æ°ãŸã§ã¯ã¹ã±ãŒã«ãããã®ãåžžèã§ãããcgroup ã§ãªãœãŒã¹ãå¶éãããç°å¢ã§ã¯ ã¹ã¬ãã1æ¬ããã§ã«æé©è§£ ãšããçŽæã«åããçµæã«ãªããCPU æéã®ç·éãåºå®ããããŒããµã ç°å¢ãªã®ã§ãã¹ã¬ãããå¢ããã»ã©ãã¯ã©ãŒã¿ã®å¥ªãåã â äžæåæ¢ â åé â ãŸãæ¯æžãã®ãµã€ã¯ã«ãéããªãã ãã ãI/O åŸ
ã¡ãããå Žåã¯ã©ããªã®ãïŒã ãããŸã§ã®å®éšã¯ cpuIntensiveWork() ã«ãã çŽç²ãª CPU ããŠã³ãåŠç ã§ãããI/O åŸ
ã¡ããããªãã¹ã¬ãããå¢ãããã»ãããããããïŒããšæããŸããããäžè¬è«ãšããŠã¯ãã®éãã§ãã¹ã¬ããã I/O ã§åŸ
ã£ãŠããé㯠CPU ã¯ã©ãŒã¿ãæ¶è²»ããªãã®ã§ãCPU æ°ããå€ãã¹ã¬ãããæå¹ãªå Žé¢ã¯ãããŸãã ãã ã Go ã®å Žåã¯è©±ãå¥ ã§ããGoã©ã³ã¿ã€ã ã«ã¯ä»¥äžã®ä»çµã¿ãããã®ã§ãGOMAXPROCS ã I/O ã®ããã«å¢ããå¿
èŠã¯åºæ¬çã«ãªãã§ã: I/O ã®çš®é¡ Goã©ã³ã¿ã€ã ã®æå GOMAXPROCS ãžã®åœ±é¿ ãããã¯ãŒã¯ I/O netpoller ãéåæåŠçãgoroutine ã¯åŸ
ã€ã OS ã¹ã¬ããã¯ãããã¯ããªã 圱é¿ãªã ããããã³ã° syscall ïŒãã¡ã€ã« I/O, CGO çïŒ ã©ã³ã¿ã€ã ã GOMAXPROCS ãšã¯ å¥ã«è¿œå ã® OS ã¹ã¬ãããèªåçæ åœ±é¿ãªã ã€ãŸã Go ã§ã¯ããããã¯ãŒã¯ I/O 㯠goroutine ã¬ãã«ã§å€éåãããããããã³ã° I/O 㯠GOMAXPROCS ã®æ å€ã§åŠçããããGOMAXPROCS ãå¶åŸ¡ããã®ã¯ CPU ãå®éã«äœ¿ãã¹ã¬ããã®æ° ã ããªã®ã§ãI/O ã®å€å¯¡ã«é¢ããã GOMAXPROCS = CPU å¶é ãæ£è§£ã§ãã DB ã¯ãšãªã API åŒã³åºãã倧éã«è¡ã Web ãµãŒãã¹ã§ããGOMAXPROCS=5ïŒCPU å¶éã«äžèŽïŒã§å€§å¹
ã«æ¹åããäºäŸãããã®ã¯ããã®ä»çµã¿ãããããã§ãã äžæ¹ãGo 以å€ã®ã©ã³ã¿ã€ã ã§ã¯ãããããäºæ
ãéãã®ã§æŽçããŠãããŸã: ã©ã³ã¿ã€ã 䞊åã®ä»çµã¿ cgroup ã®åœ±é¿ Java ã¹ã¬ããããŒã«ïŒForkJoinPool çïŒã§äžŠååã Runtime.availableProcessors() ã®å€ãåºæºã«ããŒã«ãµã€ãºã決ãŸãããšãå€ã ã¹ã¬ããããŒã«ãµã€ãºã CPU limit ãã倧ããå€ã«ãããšã¹ããããªã³ã°çºç Node.js ã¡ã€ã³ã¹ã¬ããã¯ã·ã³ã°ã«ã UV_THREADPOOL_SIZE ïŒããã©ã«ã4ïŒã§ fs/dns çã®ããããã³ã° I/O ãåŠçãCPU ããŠã³ãåŠç㯠worker_threads ã§äžŠåå worker_threads ã®æ°ã CPU limit ãã倧ããå€ã«ãããšã¹ããããªã³ã°çºç Ruby (CRuby) GVLïŒGlobal VM LockïŒããããããã¹ã¬ãããå¢ãããŠã CPU ããŠã³ãåŠçã¯äžŠåå®è¡ãããªã ãPuma çã® Web ãµãŒããŒã¯ workers ïŒfork ã«ãããã«ãããã»ã¹ïŒã§äžŠåå Puma ã® workers ã CPU limit ãã倧ããå€ã«ãããšã¹ããããªã³ã°çºç 4. çºè¡šã®å
容ãããŒã«ã«ã§åçŸã§ãããïŒ å
šæ€èšŒçµæãŸãšã # çºè¡šã®ãã€ã³ã ããŒã«ã«æ€èšŒã®çµæ åçŸ 1 GOMAXPROCSã¯cgroupã®CPUå¶éãèæ
®ããªãïŒGo 1.24以åïŒ --cpus=0.5 ã§ã GOMAXPROCS=11ïŒãã¹ãCPUæ°ïŒã®ãŸãŸ åçŸ 2 limits.cpu 㯠cgroup ã® cpu.max ïŒã¯ã©ãŒã¿/ããªãªãïŒã«å€æããã --cpus=0.5 â cpu.max: 50000 100000 ãç¢ºèª åçŸ 3 éå°äžŠåã¯ã¹ã«ãŒããããäœäžããã GOMAXPROCS 1â8 ã§ Ops/sec ã 68.2% äœäž ïŒ21,504 â 6,833ïŒ åçŸ 4 ã¯ã©ãŒã¿ã¯ã¹ã¬ããéã§å
±æãããå€ãã»ã©æ©ãæ¶è²»ããã ã¹ã¬ããæ°ãš throttled_usec ãã»ãŒç·åœ¢ã«æ¯äŸ åçŸ 5 ã¹ããããªã³ã°æã¯å
šã¹ã¬ãããåæã«åæ¢ãã GOMAXPROCS=16ã§5ç§éã«çޝèš50.3ç§åã®åæ¢ãç¢ºèª åçŸ 6 CPU䜿çšçã ãã§ã¯ã¹ããããªã³ã°ã«æ°ã¥ããªã nr_throttled çã¯åã98%ã§ã throttled_usec ã«14.8åã®å·® åçŸ 7 GOMAXPROCSãCPUå¶éã«åããããšæ¹åãã GOMAXPROCS=1 ã§åæ¢æéã 1/1,614 ã«æ¹å åçŸ ãã¹ãŠæå
ã§åçŸã§ããŸããã Docker ãš Go 1.24 ã ãã§ãããŸã§äœéšã§ããã®ã¯ããã£ãŠã¿ãŠããã£ããšçŽ çŽã«æããŸãã å人çã«å°è±¡ã«æ®ã£ãæ°å æ¯èŒ éå°äžŠåã®å Žå é©åãªäžŠåã®å Žå åç Ops/secïŒã¹ã«ãŒãããïŒ 6,833 21,504 3.1åã®å·® throttled_usecïŒåæ¢æéïŒ 70.7ç§ 0.04ç§ 1,614åã®å·® GOMAXPROCS=16ã®åæ¢æé 50.3ç§ - 5ç§ã®ãã¹ãã§50ç§åæ¢ æ¬çªç°å¢ãšã®å¯Ÿå¿é¢ä¿ çºè¡š ããŒã«ã«æ€èšŒ 48ã³ã¢Node 11ã³ã¢ Docker VM limits.cpu: 5000m --cpus=0.5 GOMAXPROCS=48ïŒããã©ã«ãïŒ GOMAXPROCS=11ïŒããã©ã«ãïŒ éå°äžŠååç: çŽ10å éå°äžŠååç: æå€§22å /sys/fs/cgroup/cpu.max åããã¹ïŒDockerå
LinuxïŒ cpu.stat ã® nr_throttled åãã¡ããªã¯ã¹ æ¬çªã§ã¯ããã«HAProxyïŒ nbthread=48 , CPUå¶é1ã³ã¢ = 48åã®éå°äžŠå ïŒã§ãåãåé¡ãèµ·ããŠããããã§ãGoã«éã£ã話ã§ã¯ãªããšããããšãããããŸãã ãŸãšã 1. 䞊åèšå®ã cgroup-aware ã«ãã GOMAXPROCS ã«éããã ã³ã³ããå
ã§åããã¹ãŠã®ããã»ã¹ã®äžŠåèšå® ã¯ç¢ºèªããã»ããããã§ãã ãœãããŠã§ã¢ 䞊åèšå® å¯ŸåŠ Go GOMAXPROCS Go 1.25+ ã§èªåå¯Ÿå¿ / 1.24以å㯠uber-go/automaxprocs Ruby (Puma) WEB_CONCURRENCY / workers CPUå¶éã«åãããŠæç€ºæå®ãcgroupé察å¿ã® auto èšå®ã«æ³šæ Java ã¹ã¬ããããŒã«ãµã€ãº JDK 10+ 㯠availableProcessors() ã cgroup èªèãã©ã€ãã©ãªåŽãèŠç¢ºèª Node.js worker_threads æ° CPU ããŠã³ãåŠçã®äžŠåæ°ã CPU å¶éã«åããã HAProxy nbthread æåã§CPUå¶éã«åãããŠèšå® Nginx worker_processes auto ã¯cgroupé察å¿ã®å Žåãããæç€ºæå®ãå®å
š 2. ã¹ããããªã³ã°ãç£èŠãã CPU䜿çšçã ããããªããŠã ã¹ããããªã³ã°ã®ã¡ããªã¯ã¹ãã»ããã§èŠã ããããæ ããšå®éš3ã§èŠããããªæ»è§ã«ããããŸãã ã¡ããªã¯ã¹ Linux Datadog 忢æé throttled_usec kubernetes.cpu.cfs.throttled.seconds 忢ããªãªãæ° nr_throttled kubernetes.cpu.cfs.throttled.periods 3. throttled_usec ãŸã§èŠã ä»åã®å®éšãéããŠäžçªã®åç©«ã¯ã nr_throttled ã®å²åãåã 98% ã§ãã throttled_usec ã« 14.8åã®å·®ããã ãšèªåã®æã§ç¢ºèªã§ããããšãã¹ããããªã³ã°çã ãèŠãŠãã å®éã«ã©ãã ãæ¢ãŸã£ãŠãããã¯èŠããªã ã CPUããã£ãšç¥ããããªã£ãæ¹ãž â å人çãªããããæ¬ ä»åã®æ€èšŒãéããŠããã£ãšCPUã®äžèº«ãçè§£ããããªã£ãããšããæ¹ã«ãå人çã«åŒ·ããããããããäžåããããŸãã ãããã°ã©ããŒã®ããã®CPUå
¥é â CPUã¯åŠäœã«ããŠãœãããŠã§ã¢ãé«éã«å®è¡ãããã ãã€ãã©ã€ã³ãã¹ãŒããŒã¹ã«ã©ãåå²äºæž¬ããã£ãã·ã¥ãã¡ã¢ãªãªãŒããªã³ã°ãšãã£ãã æ®æ®µã¯æèããªãããã©æ§èœã«çŽçµããCPUå
éšã®ã¡ã«ããºã ããããã°ã©ããŒã®ç®ç·ã§äžéãæŽçãããŠããæ¬ã§ããæ¬èšäºã®è±ç·ã§è§Šãããã£ãã·ã¥ã³ããŒã¬ã³ã·ãŸãããããã®æ¬ãèªããšããè
ã«èœã¡ããšæããŸãã ããªããã®ã³ãŒãã¯éãã®ãïŒé
ãã®ããããããŒããŠã§ã¢å¯ãã®èŠç¹ããèããããããã«ãªãæ¬ãªã®ã§ãcgroup ã®æåã®å
ãèŠããŠã¿ããæ¹ã«ãŽã£ããã§ãã åè ãã¢ãŒãºæ¬çªç°å¢ã§ã®cgroup-awareåãšã®æ»éé²ïŒçºè¡šã¹ã©ã€ãïŒ â æ¬èšäºã®ããŒã¹ãšãªã£ãçºè¡š ã¯ã©ãŠããã€ãã£ãäŒè°2026 ã»ãã·ã§ã³ããŒãž Container-aware GOMAXPROCS | Go 1.25 Release Notes uber-go/automaxprocs â Go 1.24以åã§äœ¿ããcgroup-aware GOMAXPROCS Kubernetes CPU limits and requests: A deep dive | Datadog æ€èšŒã³ãŒã æ¬èšäºã®æ€èšŒã«äœ¿ã£ãã³ãŒãã¯ä»¥äžã®ãªããžããªã«ãããŸã: git clone https://github.com/hirosi1900day/cgroup-throttling-lab.git cd cgroup-throttling-lab docker build -t cgroup-bench go-app/ ./scripts/run_experiments.sh # å
šå®éšãäžæ¬å®è¡