Tag Archives: golang

实现 go 的 goroutine 本地存储又一种方式

go 本身没有对外提供 goroutine 本地存储,而现实中,又经常需要在上下文中传递一些数据。使用 context 也是一种方式,但是要求在所有需要的地方都要传递,还是非常麻烦,而且有侵入性。

偶然发现 go 已经提供了一个用于 profile 的 pprof label,可以在 goroutine 中携带一些数据。不过这个东西既然是用于 pprof 的,随意往里塞太多东西显然也不适合,还会对 pprof 产生干扰。所以,想办法只用其中一个 label,用一些黑科技把一个 map 放了进去,将影响降到最小。同时,pprof 包中已经有一些基于 context 访问处理 label 的逻辑,所以还要做一些兼容处理,避免被其覆盖。

写了个简单的库:https://github.com/xiezhenye/gls

go http client 设置连接超时

go 语言的 http 客户端可以在初始化话的时候通过

client := http.Client{
	Timeout: 5 * time.Second,
}

来设置请求超时,即整个 http 请求到完成响应的时间限制。那么如果想另外设置 tcp 连接阶段的超时可以这样玩:

client := http.Client{
	Transport: &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   2  * time.Second,
			Deadline:  time.Now().Add(3  * time.Second),
			KeepAlive: 2 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 2 * time.Second,
	},
	Timeout: 5 * time.Second,
}

通过设置 Transport 结构中的 Dial 的属性来实现。如上面的代码中,Dial 的 Timetout 是在 tcp 连接时设置的连接超时,Deadline 则会在超过这个时间后强制关闭连接,在连接无响应的时候回有用。KeepAlive 则会发起心跳,检测连接是否存活。此外,可以设置 TLSHandshakeTimeout 作为 https 握手的超时。具体可以参考 net.Dialer 的文档。由于直接构造了 Transport 结构,不会自动设置 Proxy 属性,这里还得再这里补上。可以用 http.ProxyFromEnvironment 表示根据环境变量来设置,即 http_proxy 和 https_proxy 两个变量设置的 http 代理。如果想强制不使用代理,可以设置为

...
	Proxy: func(*http.Request) (*url.URL, error) {return nil, nil},
...