Profiling a Go Service in Production

参考 Julia Evans: Profiling Go programs with pprof How I investigated memory leaks in Go using pprof on a large codebase Memory Profiling a Go Service Russ Cox: Profling Go Programs Package pprof overview github: pprof Issue: Why ‘Total MB’ in golang heap profile is less than ‘RES’ in top? Issue: Cannot free memory once occupied by bytes.Buffer Issue: FreeOSMemory() in production Issue: Is this an idiomatic worker thread pool in Go? ...

April 7, 2021 · 1 min · 72 words · Me

Life of an HTTP request in a Go server

这篇文章的启发是我在阅读Go的http源码时获得的,之前对这块缺乏深入的了解,这篇文章会结合源码讨论包括典型http request的路由,还会涉及到一些并发和中间件的issue。 我们先从一个简单的go server谈起,下面的代码从https://gobyexample.com/http-servers 截取: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package main import ( "fmt" "net/http" ) func hello(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "hello\n") } func headers(w http.ResponseWriter, req *http.Request) { for name, headers := range req.Header { for _, h := range headers { fmt.Fprintf(w, "%v: %v\n", name, h) } } } func main() { http.HandleFunc("/hello", hello) http.HandleFunc("/headers", headers) http.ListenAndServe(":8090", nil) } 追踪请求的生命周期我们从http.ListenAndServe这个方法开始,下面的图示说明了这一层的调用关系: 这里实际上inlined了一些代码,因为初始的代码有很多其他的细节不好追踪。 ...

February 20, 2021 · 3 min · 639 words · Me

A Million WebSocket and Go

这篇文章是我研究高负载网络服务器架构看到的的一个有趣的story,添加了我自身学习websocket的感受和记录,希望我能在飞机落地前写完:-) Preface 我们先描述一个问题作为讨论的中心:用户邮件的存储方法。 对于这种主题,有很多种方式在系统内对邮件状态进行持续的追踪,比如系统事件是一个方式,另一种方式可以通过定期的系统轮询有关状态变化。 这两种方式各有利弊,不过当我们讨论到邮件的时候,用户希望收到新邮件的速度越快越好。邮件轮询每秒约有50000个HTTP请求,其中60%返回304状态,也就是邮箱内没有任何修改。 因此,为了减少服务器的负载并加快向用户传递邮件的速度,我们决定通过编写publisher-subscriber服务器(即bus, message broker, event channel)来重新发明轮子。一方面接受有关状态变更的通知,另外一个方面接受此类通知的订阅。 改进前: +--------------+ (2) +-------------+ (1) +-----------+ | | <--------+ | | <--------+ | | | Storage | | API | HTTP | Browser | | | +--------> | | +--------> | | +--------------+ (3) +-------------+ (4) +-----------+ 改进后: +--------------+ +-------------+ WebSocket +-----------+ | Storage | | API | +----------> | Browser | +--------------+ +-------------+ (3) +-----------+ + ^ | (1) | (2) v + +-----------------------------------------+ | Bus | +-----------------------------------------+ 改进前的方案也就是browser定期去查询api并访问存储更改 ...

January 16, 2021 · 2 min · 361 words · Me

fasthttp对性能的优化压榨

最近在看网络模型和go net的源码,以及各web框架例如fasthttp, weaver, gnet(更轻量)源码。fasthttp在github上已经写上了一个go开发的best practices examples,这里我也记录一些在源码中看到的一些技巧 []byte buffer的tricks 下面的一些tricks在fasthttp中被使用,自己的代码也可以用 标准Go函数能够处理nil buffer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var ( // both buffers are uninitialized dst []byte src []byte ) dst = append(dst, src...) // is legal if dst is nil and/or src is nil copy(dst, src) // is legal if dst is nil and/or src is nil (string(src) == "") // is true if src is nil (len(src) == 0) // is true if src is nil src = src[:0] // works like a charm with nil src // this for loop doesn't panic if src is nil for i, ch := range src { doSomething(i, ch) } 所以可以去掉一些对[]bytebuffer的nil校验: ...

January 10, 2021 · 6 min · 1136 words · Me

[源码分析]sync pool

- 当多个goroutine都需要创建同一个对象,如果gorountine数过多,导致对象的创建数目剧增,进而导致GC压力增大,形成“并发大-占用内存大-GC缓慢-并发处理能力弱-并发更大”这样的恶性循环 - 在这个时候,需要一个对象池,每个goroutine不再自己单独创建对象,而是从对象池中取出一个对象(如果池中已有)

January 1, 2021 · 1 min · 4 words · Me