深入理解 Golang HTTP Timeout

深入理解 Golang HTTP Timeout

背景

前段时间,线上服务器因为部分微服务提供的 HTTP API 响应慢,而我们没有用正确的姿势来处理 HTTP 超时(当然,还有少量 RPC 超时), 同时我们也没有服务降级策略和容灾机制,导致服务相继挂掉?。服务降级和容灾需要一段时间的架构改造,但是以正确的姿势使用 HTTP 超时确是马上可以习得的。

超时的本质

所有的 Timeout 都构建于 Golang 提供的 Set[Read|Write]Deadline 原语之上。

服务器超时

server timeout

  • ReadTimout 包括了TCP 消耗的时间,可以一定程度预防慢客户端和意外断开的客户端占用文件描述符
  • 对于 https请求,ReadTimeout 包括了 TLS 握手的时间;WriteTimeout 包括了 TLS握手、读取 Header 的时间(虚线部分), 而 http 请求只包括读取 body 和写 response 的时间。

此外,http.ListenAndServe, http.ListenAndServeTLS and http.Serve 等方法都没有设置超时,且无法设置超时。因此不适合直接用来提供公网服务。正确的姿势是:

客户端超时

client timeout

  • http.Client 会自动跟随重定向(301, 302), 重定向时间也会记入 http.Client.Timeout, 这点一定要注意。

取消一个 http request 有两种方式:

  1. Request.Cancel
  2. Context (Golang >= 1.7.0)

后一种因为可以传递 parent context, 因此可以做级联 cancel, 效果更佳。代码示例:

Credits

  1. The complete guide to Go net/http timeouts
  2. Go middleware for net.Conn tracking (Prometheus/trace)

GitLab搭建笔记

GitLab搭建笔记

GitLab使用Omnibus package搭建是分分钟就可以搞定的事情,但是我搭建的GitLab服务:

  1. 服务器在墙内;
  2. 服务器在一个路由器后面;

因此,浪费了一个晚上时间才把几分钟计划完成的事情搞定。这里给遇到类似情况的程序员做个简单的笔记,希望可以为他们节约一点时间吧。

服务器在墙内

Omnibus package(大小约340MB)通过AWS S3(AWS Region为美国新泽西)进行分发。墙内下载该package的速度极慢(电信百兆宽带下载速度约8KB/S),且部分时间段packages-gitlab-com.s3.amazonaws.com域名疑似被污染(四川成都地区)。因此,只好通过墙外的VPS中转下载。当前最新版(2015.08.30)为gitlab-ce_7.14.1-ce.0_amd64.deb. 上传了一份到百度网盘, 密码: qf38。阅兵在即,墙外要中转一个文件进来真是浪费生命,唉…

服务器在路由器后

这个比较好解决,需要映射两个端口。

  1. 映射Web端口: 映射路由器外部GitLab端口到GitLab配置端口(/etc/gitlab/gitlab.rb external_url ‘http://your-host:PORT’ );
  2. 映射SSH端口: 映射路由器外部GitLab SSH端口到22端口, 然后修改/etc/gitlab/gitlab.rb文件:
    • gitlab_rails[‘gitlab_shell_ssh_port’] = 路由器外部GitLab SSH端口
    • 注意:gitlab_rails[‘gitlab_shell_ssh_port’]只是配置代码库地址的端口,不会修改SSH真实使用的端口。
  3. sudo gitlab-ctl reconfigure

为你的LAMP配置SSL证书

问题背景

对于一些涉及隐私以及对安全级别有一定要求的web业务,最简单的做法是走https,如网银、github、google的加密搜索。

当客户端通过https访问web服务时,服务器通过想客户端传递其持有的CA (Certificate Authority)颁发的证书,以证明其可信的身份。然后配合服务器的私钥对会话进行加密,从而保证客户端与服务器“安全”的通信。具体的流程及细节可以参见这个视频

其实https能提供的安全保护是极其有限的,有很多绕过/攻破这条线,顺利拿到用户数据的案例。其中比较有名的是黑帽09上面的一次公开展示,感兴趣的话,有两篇文章可以研究一下:

回到主题,我为自己的LAMP配置SSL证书的原因是升级到iOS 7.1后,以前通过in-house发布的几个app无法安装了,提示“证书错误”。7.1以前,可以通过http的方式把in-house发布的app挂上去,7.1及以后,必须走https。知道原因以后,解决起来就很简单了:

  1. 生成私钥server.key, server.csr
  2. 向CA申请证书server.crt
  3. 配置apache SSL证书

生成私钥server.key, server.csr

可以在线生成,也可以通过openssl自己生成server.key:

openssl genrsa -des3 -out server.key 2048 // 推荐至少2048以上
openssl req -new -key server.key -out server.csr -config openssl.cnf // 生成csr (Certificate Signing Request)
cp server.key server.key.orig // 养成习惯,备份私钥
openssl rsa -in server.key.orig -out server.key // 移除私钥的pass phrase

向CA申请证书server.crt

申请证书的意义在于:因为给我颁发证书的结构是可信的,且我可以证明我持有的这个证书是这个可信结构颁发给我的,因此我也是可信的。

证书的获取一般有两种方式:

  • 自己签发证书,这是二逼青年的做法。很不幸,我们的12306.cn同学就是这么搞的。虽然自己签发证书约等于没有安全性,但是天朝人民还找不到第二个在线买火车票的地方,所以,你懂的……
  • 向可信CA申请,这是普通青年的做法。之于文艺青年嘛,都去做全球仅有的那几个可信Root CA去了。

CA方面,有人说天朝的基本不靠谱,严重不推荐。我没去深究,有这方面实践经验的同学不妨谈谈。就我个人使用情况来看,推荐两个国外的:

  • VeriSign, 产品全面,服务优质,价格也比较贵。提供短期测试证书申请,但是trial测试周期只有30天,且必须在浏览器上加一个测试的根证书,基本没有可用性。如果开发者要测试证书可用性,还不如自己签发一个来的方便。天威诚信主要就代理VeriSign的产品,另外,支付宝就是用的天威的办法的证书。
  • StartSSL, 价格低廉,且可以提供免费一年的Class 1证书。免费一年证书申请可以参考这里

在墙内,中国金融认证中心也在业界做的不错。我手里有一份全球各大CA的价格表,能比官网给出的价格优惠不少,对于创业公司来说还是有必要考虑节省一下这部分开销,感兴趣的可以email我 liudaning[at]gmail.com。

配置apache SSL证书

假设CA颁发的证书为server.crt,对应的私钥为server.key(已移除pass phrase)。apache配置主要有两部分:

  • 开启ssl module
  • 设置证书和私钥的路径

httdp.conf参考配置如下:

完成以后,重启apache。