GopherChina 2018 keynote 点评

作为一名参加了两届GopherChina的「老人」,今年为了去沟里吃樱桃,就没去现场凑热闹了。不过,会议的keynote是绝不会错过的。AstaXie也在会议结束后的第一时间放出了会议的ppt. 看了一下,里面的ppt并不完整,缺了第二天的第一个keynote. 手上有这个资源的同学可以分享我一下?

1.1 基于Go构建滴滴核心业务平台的实践

介绍了滴滴老服务迁移到Go的过程。很多内容感同身受,因为在一年前,我们也完成了类似的操作。从slides看,其日志收集、分布式调用追踪等微服务演进过程中解决的问题都是一笔带过,但是其实都是挺花时间的事情。可以参考微服务troubleshooting利器——调用链

比较遗憾的是没有看到其在服务迁移的时候如何确定服务边界和问题领域,更没有深入谈如何拆分低耦合高内聚的微服务的思考。

解决WaitGroup和GC问题比较有意思,了解一下即可。

最后介绍了两个开源工具Gendryjsonitr, 典型的瑞士军刀、直击目标风格,很棒。

Gendry是一个数据库操作辅助工具,核心是sql builder。我非常喜欢其设计理念:为什么要开发Gendry。简单讲,就是在不透明和不易调优的ORM与繁琐、低效的裸写sql之间找一个平衡。

jsosniter则是一个高效的json encodec. 虽然benchmark亮眼,但是我想大部分场景下,我还是会优先选择标准库。因为很多json序列换和反序列化的细节处理上,标准库还是最完善的。

1.2 Go在Grab地理服务中的实践

从slides看,应该是最容易听懂的一个keynote吧。没有贬义的意思,而是对于作者的思维清晰程度和表达能力非常佩服。基于地理位置做供需匹配的同学可以把这个当做范文,看看作者是如何把系统从基于PostGIS开始逐步演进到geohash/redis/shard/cell方案的。

整个内容非常顺畅,似乎作者在现场还普及了一个「能够做叫车服务就能够做送外卖」的梗。

1.3 Rethinking Errors for Go 2

来自 Golang 核心组的 Marcel 同学向大家介绍了Go 2中可能会引入的 error 处理机制。我个人还是能够接受Go 2中这个draft阶段的错误处理方式的。

作者在demo中使用errcerrd两个lib做演示,想了解细节的同学可以直接点进去看看如何使用。

与现有的错误处理方式比较,能够显著减少 if err != nil 这种代码,并且有更强的语言表达能力。虽然很多人吐槽说 Go 2 最终还是可能会引入关键字 try,但是从 Marcel 的介绍看,这只不过是一个语法糖而已,编译时候就inline掉了。另外,即使最终的方案通过 try 实现了更多的其他功能,也没有必要一定要避免try关键字与其他语言撞车的事实吧。毕竟语言设计追求的是尽可能的合理性和正确性,而不是独特性。

Go在区块链的发展和演进

仅从slides看,就是个区块链科普文,当然,不排除作者现场演讲能力比较强,抖了很多现场才能听到的料。如果你已经对区块链比较了解,可以略过。

Badger_ Fast Key-Value DB in Go

一个pure go的基于LSM tree的 key-value 数据库。如果你不是很了解LSM Tree, 可以参考鄙人的拙文:LSM Tree/MemTable/SSTable基本原理。Badger主要有以下几个特点:

  1. pure go实现,没有cgo依赖。
  2. Badger的LSM tree存储的是 {key, value_pointer},因此可以有效降低LSM tree的大小, 直接load到内存。
  3. 印度小哥现场跑分,读写性能比boltDB 和 RocksDB 都有相当优势。
  4. bloom-filter和file merge实现中规中矩。
  5. 支持无锁的并发事物。

开源那是必须的,想进一步研究的同学可以移步dgraph-io/badger.

Golang在阿里巴巴调度系统Sigma中的实践

slides看不出太多架构、思路和案例的内容,可能是一个干货在心中的speaker,ppt只是提词器罢了。Golang语言采坑部分比较基础,稍微有经验的gopher应该都知道。不过从去年对阿里分享的失望看,今年大家对阿里的分享好评率要好很多。

罗辑思维Go语言微服务改造实践

都说这次大会speaker的幽默水平历届最高,来自罗辑思维的方圆老师更是重新定义了「系统可用性」:只要老板觉得是就可以。

分享的内容涵盖了一个中小互联网企业微服务化的方方面面:api gateway, 服务注册、服务发现、多级缓存、熔断降级。基本可以作为一个公司微服务进程第一阶段的范文来研究。微服务化的后续阶段,比如容器化以及与之配合的CI/CD、日志管理、分布式追踪、auto-scale、立体监控,从其展望上看也有计划。因此可以持续关注方圆老师的后续动作。

Golang打造下一代互联网-IPFS全解析

本质上是一个p2p的去中心化分布式存储系统。基于其之上,可以构建各种应用。最promising的当然是http服务。

整个IPFS使用的基本都是现成的,但是却组合出了一个非常有意思的场景应用。因为之前也有关注IPFS,内容本身没有太多其他收获。权当是一次复习吧。

如何用GO开发一个区块链项目

从slides看,就是介绍了一些区块链的基础概念,后面两页ppt才遇到go,一笔带过. 个人没有太多收获。

Bazel build Go

对Bazel不是太熟悉,在看这个keynote前,只在tensorflow 教程中跟着走过一下Bazel,因此看到国内有公司把 Bazel 拿来在实际开发中应用还是心生敬仰的。

就我经历的项目看,go的build和依赖管理都有不错的轻量级工具,使用 Bazel 来 build 应该更加适合大型的多语言混合项目。

基于Go-Ethereum构建DPOS机制下的区块链

又是一个区块链科普文,不过相对更加聚焦到共识算法上。

深入CGO编程

打开slides我就被震惊了,足足145页ppt, 内容也毫无灌水,问题聚焦,示例丰富。 本来觉得自己是知道什么叫做CGO的,但是看完以后,感觉自己才真正开始入门。建议谢大应该给这样负责的speaker加鸡腿。

这应该是我见过的关于Golang中使用CGO最全面、丰富、深入的资料了。虽然在大部分场景下,都会避免使用CGO,但是如果遇到绕不开的场景的时候,这绝对是第一手的学习资料。

runv-kata-gopher-china

kata container: 安全如虚拟机,快如容器。在去年的kubeCOn’17 就发布了,目前还没有看到国内有公司在生成环境使用。持观望态度吧。slides内容太少,脑补不出来。不评价细节了。

Go toolchain internals and implementation based on arm64

介绍了golang arm64 的编译工具链。除了开始提到的AST分析最近体会较深(基于AST写代码生成器),其他的还停留在概念了解上。不过还是向作者深入钻研的精神致敬。

Go在探探后端的工程实践

又是一个公司落地go生态的例子。亮点是在测试部分做得非常全面和细致。对于在落地完善CI流程的同学(比如我),这部分有非常深远的参考意义。

其他

golang从出生开始就提供了非常完善的基于 go pprof 的一系列性能profiling工具,这是很多其他语言羡慕不来的。而今年的会议有一个共同点是,性能调优工具除了使用 go pprof 以外,都会结合使用 Uber 开源的golang火焰图工具go-torch:

著名开源项目OpenResty作者章亦春也非常推崇使用火焰图来诊断性能问题。看来火焰图真的越来越火了?

看到去了现场的不少同学吐槽这次会议区块链内容比较多。其实我觉得这个topic还好,毕竟会议也需要结合一些当前的热点。比较遗憾的是区块链相关的 slides 质量都不是很高,这可能才是被吐槽的真正原因。

公司层面,现在不仅中小互联网公司大量使用go做基础架构,也越来越多大厂开始使用go构建一些基础组件。相信以后gopher不仅会在创业公司持续活跃,也会有更多到大厂工作的机会。

本站开启支持 QUIC 的方法与配置

在越来越讲究用户体验的今天,网络带宽的提高已经很难有显著的页面加载改善,而低延迟的优化往往能够起到意想不到的效果。在《TLS1.3/QUIC 是怎样做到 0-RTT 的》中我们分析了TLS1.3和QUIC在低延迟方面的原理和低延迟优势。在从源代码编译 nginx docker 镜像开启 TLS 1.3中我们已经把玩了TLS1.3,没有理由不把玩一下QUIC,对吧?

起初以为,在普及程度上,QUIC因为主要是Google主导,会曲高和寡。但是,查了一下,发现腾讯早在2017年就在生产环境应用了QUIC:让互联网更快的协议,QUIC在腾讯的实践及性能优化. 结果显示:

灰度实验的效果也非常明显,其中 quic 请求的首字节时间 (rspStart) 比 http2 平均减少 326ms, 性能提升约 25%; 这主要得益于 quic 的 0RTT 和 1RTT 握手时间,能够更早的发出请求。

此外 quic 请求发出的时间 (reqStart) 比 h2 平均减少 250ms; 另外 quic 请求页面加载完成的时间 (loadEnd) 平均减少 2s,由于整体页面比较复杂, 很多其它的资源加载阻塞,导致整体加载完成的时间比较长约 9s,性能提升比例约 22%。

既然大厂都已经发车,我司也就可以考虑跟进了。稳妥起见,决定先在自己的博客开启QUIC,然后再逐步在线上业务进行推广。

方案概览

方案非常简单:不支持QUIC的浏览器依旧通过nginx tcp 443访问;支持QUIC的浏览器通过caddy udp 443访问。

由于nginx近期没有支持QUIC的计划, 作为一名gopher, 因此这里选择caddy作为QUIC的反向代理。后面会介绍caddy的具体安装和配置方法。

对于支持QUIC的浏览器来说,第一次访问支持QUIC的网站时,会有一次服务发现的过程。服务发现的流程在QUIC Discovery
有详细介绍。概括来说,主要有以下几步:

  1. 通过TLS/TCP访问网站,浏览器检查网站返回的http header中是否包含alt-svc字段。
  2. 如果响应中含有头部:alt-svc: 'quic=":443"; ma=2592000; v="39"',则表明该网站的UDP 443端口支持QUIC协议,且支持的版本号是draft v39; max-age为2592000秒。
  3. 然后,浏览器会发起QUIC连接,在该连接建立前,http 请求依然通过TLS/TCP发送,一旦QUIC连接建立完成,后续请求则通过QUIC发送。
  4. 当QUIC连接不可用时,浏览器会采取5min, 10min的间隔检查QUIC连接是否可以恢复。如果无法恢复,则自动回落到TLS/TCP。

这里有一个比较坑的地方:对于同一个域名,TLS/TCP和QUIC必须使用相同的端口号才能成功开启QUIC。没有什么特殊的原因,提案里面就是这么写的。具体的讨论可以参见Why MUST a server use the same port for HTTP/QUIC?

从上面QUIC的发现过程可以看出,要在网站开启QUIC,主要涉及两个动作:

  1. 配置nginx, 添加alt-svc头部。
  2. 安装和配置QUIC反向代理服务。

配置nginx, 添加alt-svc头部

一行指令搞定:

安装QUIC反向代理服务器caddy

上面我们提到对于同一个域名,TLS/TCP和QUIC必须使用相同的端口号才能成功开启QUIC。然而,caddy服务器的QUIC特性无法单独开启,必须与TLS一起开启,悲剧的是TLS想要使用的TCP 443端口已经被nginx占用了?

场面虽然有点尴尬,但是我们有docker:将caddy安装到docker中,然后只把本地的UDP 443端口映射到容器中即可。

于是我们创建了一个docker-caddy项目。Dockerfile 10行内搞定:

caddy 服务配置文件/conf/blog.conf:

启动docker:

开启Chrome浏览器QUIC特性

chrome://flags/中找到Experimental QUIC protocol, 设置为Enabled. 重启浏览器生效。

测试QUIC开启状态

重新访问本站https://liudanking.com, 然后在浏览器中打开:chrome://net-internals/#quic。如果你看到了QUIC sessins,则开启成功:

当然,你也可以给Chrome安装一个HTTP/2 and SPDY indicator(An indicator button for HTTP/2, SPDY and QUIC support by each website) 更加直观的观察网站对http/2, QUIC的支持情况。

从源代码编译 nginx docker 镜像开启 TLS 1.3

nginx最近更新挺频繁的,其中TLS 1.3和是HTTP/2 Server Push是两个比较有意思的特性。前者可以有效的减少握手次数,降低延迟,尤其在恢复会话时候可以将握手开销降低到 0-RTT,后者则可以通过服务器主动推送资源,可以认为是在资源预加载之上更进一步的「资源主动加载」,有效提高网页性能和用户体验。

考虑到平时自己需要比较频繁的测试不同的nginx的新版本,但是又不想破坏机器本地已经安装好的nginx环境,因此我决定制作一个nginx docker镜像。需要说明的是,dockerhub官方是有一个nginx镜像的,但我们希望自己定制nginx版本和需要开启的模块,因此该镜像并不符合需求。

这里以开启TLS 1.3为例制作一个以ubuntu:16.04为基础镜像的 nginx dockerm镜像。顺便把上次在Ubuntu 14.04开启nginx http2支持的方法中埋的坑填了?

nginx开启TLS 1.3的前置条件

  1. nginx >= 1.13.0
  2. openSSL >= 1.1.1 alpha

openSSL版本有几点点需要注意:

  1. 以前可以使用分支tls1.3-draft-18编译支持TLS 1.3,但是现在已经merge到1.1.1版本中了,因此,这里不再推荐使用tls1.3-draft-18编译nginx. 使用openSSL 1.1.1编译nginx会触发nginx的一个config bug: undefined reference to 'pthread_atfork', 解决办法可以参见这里以及nginx mailing list, 这里暂时回退到使用tls1.3-draft-18.
  2. 不要尝试使用tls1.3-draft-19编译nginx, 使用Chrome 64测试无法在nginx 1.13.9上成功开启TLS 1.3, 应该跟Chrome对draft版本的支持有关系。
    • 2018-03-14更新:升级到Chrome 65以后,发现默认支持为TLS 1.3 Draft 23, 后面顺带连通config bug一起解决了再更新。
  3. openSSL目前最新版本是OpenSSL_1_1_1-pre2, 还不是stable版本,因此,不要在生产环境中使用。

Dockerfile

Nginx 开启 TLS1.3

一个完整的配置模板参考如下:

主要新增两个修改:

  1. ssl_protocols添加TLSv1.3.
  2. ssl_ciphers加入TLS13_为前缀的密码套件。

完整项目地址:docker-nginx

验证TLS 1.3

  • Chrome: 将 chrome://flags/ 中的 Maximum TLS version enabled 改为 Enabled (Draft).

如果你刚刚升级到了Chrome 65,选项中开启TLS1.3有三个选项:Enabled(Experiment 2), Enabled(Draft 22), Enabled (Draft 23). 同时很遗憾的告诉你,本文中使用的是Draft 18编译nginx,因此无法配合Chrome 65无法开启TLS1.3,请下面介绍Firefox的开启方法测试TLS1.3?

  • Firefox: 将 about:config 中的 security.tls.version.max 改为 4.

以Chrome 64为例,如果开启成功后Protocol显示TLS 1.3:

你也可以访问tls.liudanking.com来测试自己的浏览器是否已经成功开启TLS 1.3.

参考资料

本博客开始支持 TLS 1.3