Poslua Blog

「你是一个出色的程序员」要比「你是一个开发总监」要有意义的多

Lua table 如何实现最快的 insert?

Fastest Table Inserts

前两天群里有个朋友贴出一段代码: function _M.table_keys(self, tb) if type(tb) ~= "table" then ngx.log(ngx.WARN, type(tb) .. "was given to table_keys") return tb end local t = {} f...

Nginx vs Envoy vs Mosn 平滑升级原理解析

TCP 连接迁移

本文适合对 Nginx 实现原理比较感兴趣的同学阅读,需要具备一定的网络编程知识。 平滑升级的本质就是 listener fd 的迁移,虽然 Nginx、Envoy、Mosn 都提供了平滑升级支持,但是鉴于它们进程模型的差异,反映在实现上还是有些区别的。这里来探讨下它们其中的区别,并着重介绍 Nginx 的实现。 Nginx 相信有很多人认为 Nginx 的 reload 操作就能完成...

关于 etcd 的一些谣言

纸上谈兵

1. 分区脑裂 这是一个被广为流传的误解,众所周知 etcd 使用 Raft 协议来解决数据一致性问题。一个 Raft Group 只能有一个 Leader 存在,如果一旦发生网络分区,Leader 只会在多数派一边被选举出来,而少数派则全部处于 Follower 或 Candidate 状态,所以一个长期运行的集群是不存在脑裂问题的。etcd 官方文档也明确了这一点: The m...

VS Code 快速查看 Golang 接口

工欲善其事,必先利其器

背景 使用 vscode 阅读 Go 项目源码时,有个不太方便的地方,就是跟踪 interface 的实现。vscode 只能追到 interface 定义的地方,而无法定位到其具体的实现。比如,我在追 etcd 关于 revision 的读取的时候只能追到这里: 如果项目比较小,还比较容易对付,因为按照习惯来讲,其实现往往都在对应接口的下方。但是遇到这种像 etcd 的项目就抓瞎了...

聊一聊字符串内部化

String Interning

缘起 字符串作为一种不可变值类型,在多数的语言里,其底层基本都是个只读的字节数组:一旦被创建,则不可被改写。正是因为其只读特性,如果有大量相同的字符串需要处理,那么在内存中就会保存多份,显然是非常浪费内存的。 对于 C 来说字符串本质上就是 const char*;而对于 Lua,虽然字符串并不是以 \0 结尾,但是 TString 的数据本质上也是一个 const char* ...

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...