Go pprof使用之记录一次项目中的分析

对于一个后端开发者,性能分析及其重要,在Go语言中, 提供了一些优秀的诊断工具来帮助我们深入分析应用程序的执行情况,这些工具中最常用的当属pprof。 提出问题 Go性能分析要关注什么 pprof 如何使用 pprof分析报告解读 性能分析 CPU:程序对CPU的使用,时间都花在哪里; Heap:堆内存分配及占用内存的情况,是否存在内存泄漏; goroutine:goroutine 运行堆栈信息 Block:阻塞等待信息 Mutex: 锁竞争情况 pprof 使用 开启 pprof 方法一,引入 “net/http/pprof” import _ "net/http/pprof" 这样我们就可以通过访问http://localhost:6060/debug/pprof来访问pprof 方法2,自定义端口及地址 func RunProf(port int) { mux := http.NewServeMux() mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) mux.HandleFunc("/debug/pprof/profile", pprof.Profile) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) mux.HandleFunc("/debug/pprof/trace", pprof.Trace) if port != 0 { ip := "localhost" go func() { addr := fmt.Sprintf("%v:%v", ip, port) tlog.Infof("pprof httpserver server listening on: %v", addr) err := http....

March 20, 2022 · 1 分钟 · 孩子不会飞

读ants源码,理解goroutine pool

先思考一个问题: go team 说我们可以创建成千上万个 goroutine 用于处理并发,那么我们还需要 goroutine pool 吗? go team 这么说的底气在于其调度模型 G-P-M,确实 但是,没有什么是绝对的,比如100w goroutines or more and more 那么一旦 goroutine 数量过多就会导致资源侵占,CPU暴涨,那么怎么办? 池化! 复用goroutine ants是一个高性能的协程池,实现了对大规模goroutine的调度管理、goroutine复用,允许使用者在开发并发程序的时候限制协程数量,复用资源,达到更高效执行任务的效果。 提纲 池化技术 ants 如何在项目中使用 *ants 代码设计 学习到的优秀源码 池化技术 池化技术是一种通过创建池子来提高对象复用的常用技术,减少重复创建、销毁的开销。常用池化技术有内存池、对象池、线程池、连接池等。在go语言,goroutine的复用可以理解为线程池技术。ants是一个优秀的代码库,被广泛用于生产环境。 ants 的使用 在其官方的README文件有详细的用法说明,这里简单介绍下基础使用 p, err := ants.NewPool(workerNum) if err != nil { // 错误处理 } defer p.Release() // 关闭时释放 // 工作任务 worker := func() { xxx } // 提交任务 err := p....

March 6, 2022 · 2 分钟 · 孩子不会飞

对go调度的浅读

go语言为什么能变的如此受欢迎,很大一个原因是其原生支持高并发,而这核心来自goroutine的设计,而对goroutine的管理则离不开go的调度器。 调度的定义 要理解调度,就必要先理解操作系统、进程、线程等调度的基本概念。 操作系统:一种计算机程序,管理硬件与软件资源,计算机系统的"底层软件",如windows,macOS,Linux 进程:操作系统下程序运行单位,有独立的内存,由内核调度 线程:操作系统调度最小单元,一般属于进程,共享进程的内存与资源,由内核调度(比进程轻量) 协程:用户级线程,不由内核调度,通过程序员显示的调度(比线程轻量) 调度:调度本质上就是一个资源分配算法。 Go 调度设计 goroutine 和线程的关系即一个main函数创建一个操作线程——主线程,之后会由go的调度模型来负责创建和管理 goroutine 分配到具体哪个线程. 历史 最简单的调度器(Go 0.x):单线程 G-M:缺陷是程序只能存在一个活跃线程 改进为多线程(Go 1.0):G-M:互斥锁带来的开销 进阶版本(Go 1.2 至今):G-P-M:多了一层P抽象 G-P-M 定义:src/runtime/runtime2.go G:goroutine,需要绑定一个 m 来运行 type g struct { ... m *m // current m; offset known to arm liblink preempt bool // 抢占标记 stackguard0 uintptr // ... } P:processor, a resource that is required to execute Go code....

January 9, 2022 · 3 分钟 · 孩子不会飞

漫谈游戏服务器节点通信

最近工作上做了一些关于跨服玩法的内容,对于 RPC 通信实现这块做下学习笔记整理。 分布式架构 当下的大环境下,服务器架构基本都是分布式架构。分布式架构带来的最大好处在于服务扩展,我们 SLG 游戏服务器从游戏特性上来说,符合小服架构(一个服即一个生态),这样从分布式架构的设计理念,按功能划分,网关、支付、战场(这里不是指单服的战斗要实现一个节点,而是一些副本玩法,跨服玩法等设计的)、第三方等,这样的每个 server 我们称之为一个节点(Node)。 RPC RPC:允许运行于一台计算机的程序调用另一个计算机的程序。RPC是一种服务器-客户端(Client/Server)模式。 RPC 的核心概念即调用远程服务就像调用本地的一个函数一样简单。 通过原理我们知道 RPC 需要实现的几个点: 通信:在两个 server 之间建立连接 寻址:如何定位需要调用 x-Server 序列化:两个 server 之间是网络通信,那么二进制传输就需要序列化 一些常用的框架(轮子必然是有的): gRPC: 谷歌开源 RPC 框架,基于 HTTP/2 协议通信和 ProtoBuf 序列化协议 Thrift: Apache 旗下,基于 Facebook 的 RPC 框架开发 JsonRPC: 无状态、轻量级,基于 json 序列化 框架选择:两个项目,早期的一个选择 thrift (当时 gRPC 才开源初期),另一个选择了 gRPC ,对比来说,两者在使用上区别不是很大,但是 gRPC 能拥有良好的文档,更加简洁和拥有广泛使用的 ProtoBuf,而 thrift 的大优势是支持多语言。选择根据项目自身的特性来,对于我们项目,文档和简洁比较重要。(技术选型还得是项目初始大佬们的选择:joy:) 节点间通信 如上,RPC 框架选择 gRPC,基于此,整个通信流程: client -> gateway -> game server -> other server -> 处理后返回...

March 14, 2021 · 2 分钟 · 孩子不会飞

一道GO编程题的反思

题目:循环按序打印"dog"、“cat”、fish",分别使用三个 goroutine. 拿到题目,感觉简单又不简单的样子,先动手写一个最简单的打印: func main() { times := 100 go func() { for i := 0; i<times; i++ { println("dog") println("cat") println("fish") } }() time.Sleep(100 * 1000) // 这时间我能算出来么,那用 channel 来接收吧 } 改进一下这让人无法预估的等待时间:使用 channel,在 goroutine 执行完之后通知主程序,巩固依稀 gorutine 和 channel 的基础知识: gorutine 是并发核心,main 函数也是一个 gorutine go func() {}() 匿名函数要注意参数传入 channel 通过 make 创建,make(chan typ) 需要声明好类型 channel 通过 <-ch ch <- data 来接收和发送信息 channel make(ch, int, 1 表示该 ch 是一个有1个数据缓冲的 chan,即在没有接收数据的情况下,第二条数据发送之后才会阻塞 func (ch chan <- int) 声明 ch 是一个单向 channel close后的 chan 依然可以接收缓冲通道的数据,但不可发送数据 select {case <- ch: xx} 处理不同消息 func main() { waitCh := make(chan struct{}, 1) times := 100 go func() { for i := 0; i < times; i++ { println("dog") println("cat") println("fish") } waitCh <- struct{}{} }() <-waitCh } waitCh 听起来怎么这么熟悉呢?go 本身在面对这些情况已经实现了一个工具类,sync 包中提供的基础原语: waitGroup 。巩固一下:...

March 6, 2021 · 2 分钟 · 孩子不会飞