go语言监控进程 go语言多进程

golang 可以监听多个端口吗

由于linux的socket监听机制和TCP协议,多个进程无法监听同一个端口,但是具体到nginx,可以多个nginx进程监听到不同端口,通过一个主进程端口做upstream来实现负载均衡,这个有点类似于网络的汇聚,可以设置不同的策略,比如iphash,urlhash或者RR。

创新互联长期为上千多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为丰泽企业提供专业的网站设计、成都网站建设,丰泽网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。

Golang的pprof的使用心得(CPU,Heap)

参照的是 这个文章

首先自己写一段demo

里面负责2件事

doSomeThingOne

genSomeBytes

运行这个程序go run main.go

To install thewrk,you need only:

git clone

cd wrk

make

wrk relies on the openssl and luajit, learn more from its github page

Generating requests

Our demo is listening on the port 9876 ,so let's generate some requests for that.

./wrk -c400 -t8 -d5m

-c400means we have 400 connections to keep open

-t8means we use 8 threads to build requests

-d5mmeans the duration of the test will last for 5 minutes

用这段命令来压服务器

Our server is very busy now and we can see some information via browser. Inputlocalhost:9876/debug/pprofyou will see:

然后用命令进入

在这里能看见各种方法的运行时间

所以我们安装Graphviz 在mac下

brew install graphviz

之后再这个(pprof)里面输入web

会生产一个svg文件

用浏览器打开我们就会看到

很显然gensomebytes里面的math方法最消耗时间。这个就是我们优化的对象

其实也很方便在

localhost:9876/debug/pprof/profile改成

localhost:9876/debug/pprof/heap

后面的结果一样。。和cpu一样可以看到那个heap占用了大量的内存到时候优化吧

这个文章里面的第一个方法就可以做测试内存占用的.

有空试试把

分布式程序 A B C D 4个进程在服务器. 监控程序E 打包程序F

写一个监控程序定时监控这4个进程的CPU 内存(搞成配置文件)

达到性能瓶颈(例如 90%CPU 内存剩下10%)  E用shell触发打包程序F把pprof等信息打包.并发送邮件

给配置者.

go是什么编程语言?主要应用于哪些方面?

Go语言由Google公司开发,并于2009年开源,相比Java/Python/C等语言,Go尤其擅长并发编程,性能堪比C语言,开发效率肩比Python,被誉为“21世纪的C语言”。

Go语言在云计算、大数据、微服务、高并发领域应用应用非常广泛。BAT大厂正在把Go作为新项目开发的首选语言。

Go语言能干什么?

1、服务端开发:以前你使用C或者C++做的那些事情,用Go来做很合适,例如日志处理、文件系统、监控系统等;

2、DevOps:运维生态中的Docker、K8s、prometheus、grafana、open-falcon等都是使用Go语言开发;

3、网络编程:大量优秀的Web框架如Echo、Gin、Iris、beego等,而且Go内置的 net/http包十分的优秀;

4、Paas云平台领域:Kubernetes和Docker Swarm等;

5、分布式存储领域:etcd、Groupcache、TiDB、Cockroachdb、Influxdb等;

6、区块链领域:区块链里面有两个明星项目以太坊和fabric都使用Go语言;

7、容器虚拟化:大名鼎鼎的Docker就是使用Go语言实现的;

8、爬虫及大数据:Go语言天生支持并发,所以十分适合编写分布式爬虫及大数据处理。

Golang实验性功能SetMaxHeap 固定值GC

简单来说, SetMaxHeap 提供了一种可以设置固定触发阈值的 GC (Garbage Collection垃圾回收)方式

官方源码链接

大量临时对象分配导致的 GC 触发频率过高, GC 后实际存活的对象较少,

或者机器内存较充足,希望使用剩余内存,降低 GC 频率的场景

GC 会 STW ( Stop The World ),对于时延敏感场景,在一个周期内连续触发两轮 GC ,那么 STW 和 GC 占用的 CPU 资源都会造成很大的影响, SetMaxHeap 并不一定是完美的,在某些场景下做了些权衡,官方也在进行相关的实验,当前方案仍没有合入主版本。

先看下如果没有 SetMaxHeap ,对于如上所述的场景的解决方案

这里简单说下 GC 的几个值的含义,可通过 GODEBUG=gctrace=1 获得如下数据

这里只关注 128-132-67 MB 135 MB goal ,

分别为 GC开始时内存使用量 - GC标记完成时内存使用量 - GC标记完成时的存活内存量 本轮GC标记完成时的 预期 内存使用量(上一轮 GC 完成时确定)

引用 GC peace设计文档 中的一张图来说明

对应关系如下:

简单说下 GC pacing (信用机制)

GC pacing 有两个目标,

那么当一轮 GC 完成时,如何只根据本轮 GC 存活量去实现这两个小目标呢?

这里实际是根据当前的一些数据或状态去 预估 “未来”,所有会存在些误差

首先确定 gc Goal goal = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100

heap_marked 为本轮 GC 存活量, gcpercent 默认为 100 ,可以通过环境变量 GOGC=100 或者 debug.SetGCPercent(100) 来设置

那么默认情况下 goal = 2 * heap_marked

gc_trigger 是与 goal 相关的一个值( gc_trigger 大约为 goal 的 90% 左右),每轮 GC 标记完成时,会根据 |Ha-Hg| 和实际使用的 cpu 资源 动态调整 gc_trigger 与 goal 的差值

goal 与 gc_trigger 的差值即为,为 GC 期间分配的对象所预留的空间

GC pacing 还会预估下一轮 GC 发生时,需要扫描对象对象的总量,进而换算为下一轮 GC 所需的工作量,进而计算出 mark assist 的值

本轮 GC 触发( gc_trigger ),到本轮的 goal 期间,需要尽力完成 GC mark 标记操作,所以当 GC 期间,某个 goroutine 分配大量内存时,就会被拉去做 mark assist 工作,先进行 GC mark 标记赚取足够的信用值后,才能分配对应大小的对象

根据本轮 GC 存活的内存量( heap_marked )和下一轮 GC 触发的阈值( gc_trigger )计算 sweep assist 的值,本轮 GC 完成,到下一轮 GC 触发( gc_trigger )时,需要尽力完成 sweep 清扫操作

预估下一轮 GC 所需的工作量的方式如下:

继续分析文章开头的问题,如何充分利用剩余内存,降低 GC 频率和 GC 对 CPU 的资源消耗

如上图可以看出, GC 后,存活的对象为 2GB 左右,如果将 gcpercent 设置为 400 ,那么就可以将下一轮 GC 触发阈值提升到 10GB 左右

前面一轮看起来很好,提升了 GC 触发的阈值到 10GB ,但是如果某一轮 GC 后的存活对象到达 2.5GB 的时候,那么下一轮 GC 触发的阈值,将会超过内存阈值,造成 OOM ( Out of Memory ),进而导致程序崩溃。

可以通过 GOGC=off 或者 debug.SetGCPercent(-1) 来关闭 GC

可以通过进程外监控内存使用状态,使用信号触发的方式通知程序,或 ReadMemStats 、或 linkname runtime.heapRetained 等方式进行堆内存使用的监测

可以通过调用 runtime.GC() 或者 debug.FreeOSMemory() 来手动进行 GC 。

这里还需要说几个事情来解释这个方案所存在的问题

通过 GOGC=off 或者 debug.SetGCPercent(-1) 是如何关闭 GC 的?

gc 4 @1.006s 0%: 0.033+5.6+0.024 ms clock, 0.27+4.4/11/25+0.19 ms cpu, 428-428-16 MB, 17592186044415 MB goal, 8 P (forced)

通过 GC trace 可以看出,上面所说的 goal 变成了一个很诡异的值 17592186044415

实际上关闭 GC 后, Go 会将 goal 设置为一个极大值 ^uint64(0) ,那么对应的 GC 触发阈值也被调成了一个极大值,这种处理方式看起来也没什么问题,将阈值调大,预期永远不会再触发 GC

那么如果在关闭 GC 的情况下,手动调用 runtime.GC() 会导致什么呢?

由于 goal 和 gc_trigger 被设置成了极大值, mark assist 和 sweep assist 也会按照这个错误的值去计算,导致工作量预估错误,这一点可以从 trace 中进行证明

可以看到很诡异的 trace 图,这里不做深究,该方案与 GC pacing 信用机制不兼容

记住,不要在关闭 GC 的情况下手动触发 GC ,至少在当前 Go1.14 版本中仍存在这个问题

SetMaxHeap 的实现原理,简单来说是强行控制了 goal 的值

注: SetMaxHeap ,本质上是一个软限制,并不能解决 极端场景 下的 OOM ,可以配合内存监控和 debug.FreeOSMemory() 使用

SetMaxHeap 控制的是堆内存大小, Go 中除了堆内存还分配了如下内存,所以实际使用过程中,与实际硬件内存阈值之间需要留有一部分余量。

对于文章开始所述问题,使用 SetMaxHeap 后,预期的 GC 过程大概是这个样子

简单用法1

该方法简单粗暴,直接将 goal 设置为了固定值

注:通过上文所讲,触发 GC 实际上是 gc_trigger ,所以当阈值设置为 12GB 时,会提前一点触发 GC ,这里为了描述方便,近似认为 gc_trigger=goal

简单用法2

当不关闭 GC 时, SetMaxHeap 的逻辑是, goal 仍按照 gcpercent 进行计算,当 goal 小于 SetMaxHeap 阈值时不进行处理;当 goal 大于 SetMaxHeap 阈值时,将 goal 限制为 SetMaxHeap 阈值

注:通过上文所讲,触发 GC 实际上是 gc_trigger ,所以当阈值设置为 12GB 时,会提前一点触发 GC ,这里为了描述方便,近似认为 gc_trigger=goal

切换到 go1.14 分支,作者选择了 git checkout go1.14.5

选择官方提供的 cherry-pick 方式(可能需要梯子,文件改动不多,我后面会列出具体改动)

git fetch "" refs/changes/67/227767/3 git cherry-pick FETCH_HEAD

需要重新编译Go源码

注意点:

下面源码中的官方注释说的比较清楚,在一些关键位置加入了中文注释

入参bytes为要设置的阈值

notify 简单理解为 GC 的策略 发生变化时会向 channel 发送通知,后续源码可以看出“策略”具体指哪些内容

返回值为本次设置之前的 MaxHeap 值

$GOROOT/src/runtime/debug/garbage.go

$GOROOT/src/runtime/mgc.go

注:作者尽量用通俗易懂的语言去解释 Go 的一些机制和 SetMaxHeap 功能,可能有些描述与实现细节不完全一致,如有错误还请指出


标题名称:go语言监控进程 go语言多进程
分享地址:http://scyanting.com/article/doociih.html