AdairXie Blog

坚持做对的事情,并把事情做对

Goroutine调度分析

golang标准库

golang的调度模型 调度的机制用一句话描述: runtime准备好G,P,M,然后M绑定P,M从各种队列中获取G,切换到G的执行栈上并执行G上的任务函数,调用goexit做清理工作并回到M, 如此反复。 基本概念 M (machine) * M代表着真正的执行计算资源,可以认为它就是os thread(系统线程)。 * M是真正调度系统的执行者,每个M就像一个勤劳的工作者,总是从...

请问sync.Pool有什么缺点?

golang标准库

1.12及之前版本的sync.Pool有三个问题: 每次GC都回收所有对象,如果缓存对象数量太大,会导致STW1阶段的耗时增加。 每次GC都回收所有对象,导致缓存对象命中率下降,New方法的执行造成额外的内存分配消耗。 Pool.Get方法底层有锁,极端情况下,要尝试最多P次抢锁,也获取不到缓存对象,最后得执行New方法返回对象。 这些问题就对sync.Pool的使用提...

sync.Pool原理及源码分析

golang标准库

pool关键作用 减轻GC的压力。 复用对象内存。又是不一定希望复用内存,单纯是想减轻GC压力也可主动给pool塞对象。 Pool’s purpose is to cache allocated but unused items for later reuse, relieving pressure on the garbage collector. Tha...

并发扣款,如何保证数据的一致性?

数据一致性

沈老师解答星球水友提问。 === 沈老师,我们有个业务,同一个用户在并发”查询,逻辑计算,扣款“的情况下,余额可能出现不 一致,请问有什么优化方法么? === 扣款的业务场景是怎样的? 用户购买商品的过程中,要对余额进行查询与修改,大致的业务流程如下: 第一步,从数据库查询用户现有余额: SELECT money FROM t_yue WHERE uid = $uid; 不妨设...

Golang 是否有必要内存对齐?

内存模型

有些同学可能不知道,struct 中的字段顺序不同,内存占用也有可能会相差很大。比如: type T1 struct { a int8 b int64 c int16 } type T2 struct { a int8 c int16 b int64 } 在 64 bit 平台上,T1 占用 24 bytes,T2 占用 16 bytes 大小;而在 32 bit 平台上...

线上一次大量 CLOSE_WAIT 复盘

redigo 的超时机制

最近,我在压测线上的一个长连接服务时,发现服务端出现大量的 CLOSE_WAIT 状态长时间不会释放,并且伴随着 goroutine 暴增,这里做个复盘,介绍下排查思路。 说起 CLOSE_WAIT,就不得不再复习一遍 TCP 的状态变迁: 出现 CLOSE_WAIT 本质上是因为服务端收到客户端的 FIN 后,仅仅回复了 ACK(由系统的 TCP 协议栈自动发出),并没有发 4 次...

Go 1.12 关于内存释放的一个改进

并不是内存泄露

一直以来 go 的 runtime 在释放内存返回到内核时,在 Linux 上使用的是 MADV_DONTNEED,虽然效率比较低,但是会让 RSS(resident set size 常驻内存集)数量下降得很快。不过在 go 1.12 里专门针对这个做了优化,runtime 在释放内存时,使用了更加高效的 MADV_FREE 而不是之前的 MADV_DONTNEED。具体可以参考这里: ...

Golang RabbitMQ 故障排查一例

断线重连的正确姿势

作为一个常识,当我们在处理一些长连接的业务时,客户端往往需要负责断线重连。比如,在我们的一个系统中,是这么处理 RabbitMQ 的断线重连的: func (c *Consumer) Start() error { if err := c.Run(); err != nil { return err } go c.ReConnect() return nil } func ...

Goroutine 泄露排查

pprof 无他

我们在发布一个 go 应用时,默认都会启用两个 http handler: 一个是 pprof,方便线上动态追踪问题;另外一个是 prometheus 的 metrics,这样就可以通过 grafana 准实时的监控当前 runtime 信息,及时预警。就像下面这样: package router import ( "net/http" _ "net/http/pprof" "g...

谈谈 Golang 中的 Data Race(续)

编译器是可以优化的, 并且没有 memory barrier

我在上一篇文章中曾指出:在 Go 的内存模型中,有 race 的 Go 程序的行为是未定义行为,理论上出现什么情况都是正常的。并尝试通过一段有 data race 的代码来说明问题: package main import ( "fmt" "runtime" "time" ) var i = 0 func main() { runtime.GOMAXP...