2017 年度小结(Golang、错误处理、服务状态页等)

从今年年初开始,我就尝试在业余时间和一个朋友开发一个容器平台,更多地是实验一些新的技术,也但愿可以经过它将本身的一些小应用管理起来,在基本完成后可能会考虑开源。之因此说是实验是由于我选择了一个我几乎彻底不了解的技术栈:主要编程语言是 Golang、只使用 Etcd 做为数据库、基于 Docker Swarm 管理容器。前端

不得不说 Golang 是一个很是难用的语言,在语言层面,为了所谓的「简单」而没有添加 异常泛型 这两个对于高级编程很是重要的特性;在生态上仍没有统一出一个包管理器,若是只发布编译好的二进制程序却是没问题,但若是发布源代码的话,缺乏统一的包管理会带来不少麻烦,以致于不少开发者选择将 vendor 直接包含在版本控制中。node

在这个项目中,没有异常和泛型真的给我带来了很大的困扰,几乎一半的代码都在进行繁琐的错误检查,没有泛型则很难实现一些通用的函数,或者不得不进行强制类型转换。这让我以为 Golang 的使用场景很是受限:由于有 GC,它难以胜任对实时性要求较高的底层的工做;又由于缺乏高层次的抽象手段,不适合业务逻辑复杂的应用编程(例如 Web 后端),能够说不上不下,只适合于一些业务逻辑不复杂的中间件,或者一些客户端命令行工具(毕竟在三个平台下都没有运行时依赖)。git

Etcd 是一个我以前没有接触过的数据库类型,它是分布式的键值数据库,能够在大多数节点存活的状况下保证读写的强一致性,也提供了事务、订阅修改、TTL、检索历史快照等功能。我在这个项目中直接使用 Etcd 做为惟一的数据库存储全部数据,也使用 Golang 对 Etcd 的 API 进行了简单的封装,以便更好地使用 JSON 和 Etcd 的事务。github

由于毕竟是业余项目,这个项目一直进展缓慢,在今年的最后我还尝试在 Swarm 上实现高可用的有状态容器,例如 Redis 和 MongoDB。我在容器内用 Shell 编写了一系列的脚本,在启动时从 Etcd 获取集群信息和本身的角色,而后经过长轮询完成配置的切换,再运行一个 Nginx 将从节点的流量转发给主节点,容器的数量则由 Swarm 保证,实现了一个「自维护」的数据库容器。数据库


在去年 Node.js 错误处理实践 的基础上,今年我又在继续探索错误处理和日志的最佳实践。以前的方法存在一个问题,即我特别关注于将错误对象原样地传递出去,但有时看到一个很是底层、很是细节的错误(例如 CONNTIMEOUT),则难以判断究竟发生了什么。虽然从异常的调用栈中能够看出调用路径,但并不能看到一些关键变量的值,例如这个链接错误是在请求哪一个地址,主要参数是什么,这是由于在异常传递的过程当中,咱们并无记录这个信息。最后只能获得一个很是细节的错误信息,而不知道这个错误发生在更上层的哪一个环节。编程

因而我开始使用 verror 这个库,它最主要的功能是帮助你建立一个「异常链」,你能够在每一个层级来向异常上补充路径信息(会被反映到 err.message 例如一个来自底层的错误信息多是 request failed: failed to stat "/junk": No such file or directory 这样)。这个异常链信息也会和其余元信息一块儿以结构化的方式存储在错误对象上,这个库也提供了一些工具函数来获取这些结构化信息。我尝试使用 verror 来管理全部的异常,报告带有详细的、每一层级信息的异常。同时我也会向错误对象上附加一些元信息用来指示如何响应客户端、是否须要发到 Sentry、是否能够重试等。小程序

除了异常,我也开始尝试使用 bunyan 打印结构化的日志,并存储到 Elasticsearch。经过 Kibana 的 Web UI 能够很简单地对日志进行筛选和查询,在排查问题时找到相关的那部分日志。对于一个既有的系统来讲,调整异常和日志能够说是一个很是庞杂的工做,在调整的过程当中也我也在不断地修正本身的实践,今年一全年我都在作这样的尝试。后端


对于一个稍微复杂一点的项目来讲,并非全部的数据都在事务的保护下 —— 其实不少互联网项目也并不会使用事务。这样就不免出现数据不一致的状况,这种不一致多是数据的关系出现损坏、缓存和数据不一致,也多是多种数据库甚至外部资源的状态没有同步。微信小程序

今年我探索了解决这个问题的一种实践:编写脚本去自动地检查和恢复这种不一致,这种脚本是常态化运行的,例如个人一个项目中如今有 4 个脚本以每 10 分钟左右的频率在进行各类检查和恢复。这样不一致的数据会在很短的时间内被恢复(也会留下可查的记录),对于用户来讲就是碰到问题的次数变少了,在一些重大的的故障发生时,这种脚本也能够帮助你快速地恢复服务。缓存

这样自动地修复不一致也引入了一个问题:就是在核心业务中会不自觉地下降对一致性的追求 —— 反正有脚原本修复,问题不会暴露出来。目前只能是为检查和恢复的状况绘制图表,在不一致的频率超出预期时及时地发现。


由于云引擎的 负载均衡 逻辑比较复杂,以前是在一个开源的 Node.js 反向代理组件上进行了一些二次开发,但在高峰时的性能不是很理想,一直有想法换成 Nginx。因而今年年初我就开始基于 Openresty 用 Lua 重写了负载均衡组件,效果很是理想,只用了 Node.js 十分之一的 CPU 和内存,再也没有出现容量不足的状况。

缘由固然是 Nginx 对内存有着很是细粒度的管理,只在请求开始和结束时申请和释放整块内存,也没有 GC,保持一个长连接几乎不须要消耗多少资源。Openresty 则将 Lua 嵌入到了 Nginx 中,在 Nginx 高性能的请求处理和丰富的 HTTP 功能的基础上,让你能够用 Lua 去实现一些逻辑,对于负载均衡确定是够用了。


我以前一直有在使用 pass 这个基于 GPG 和 Git 的命令行密码管理器,并将密码仓库托管在 GitHub 上。之因此用它是由于它基于可靠的开源工具、自己也是开源的,同时它足够简单,简单到我不须要它也能够操做个人密码。

也一直有想法为它开发一个 UI, 因而今年九月我用 Electron 开发了一个名为 Elecpass 的密码管理器,在机制和数据格式上与 pass 彻底兼容。以前其实我并无用过 Electron, 但上手的体验仍是至关不错的,没有遇到什么问题。由于 Electron 自带了 commonjs 的模块加载系统,也再也不须要像前端开发那样复杂的构建过程。

目前 Elecpass 一共发布了两个版本,虽然还很是简陋并且有一些 Bug,但已经能够知足基本需求了,我本身也一直在使用,明年我应该会为它添加更多的功能。


今年年初腾讯发布了微信小程序,我表明公司在「小小程序,大有做为」的线下活动里作了一个主题为「在微信小程序中使用 LeanCloud」的分享,在准备期间我也了解了一下微信小程序。

能够说微信小程序就是腾讯为了在微信中构建一个封闭的「操做系统」的产物,但你们迫于微信自己的平台能力,好比用户信息、推送、支付,不得不使用它。做为一个平台,微信小程序绑定了一个数据绑定框架,也绑定了一套模板语言,同时和前端现有的工具链(编译打包)的整合也很是差,很难利用现有的 JavaScript 生态。做为结果,我相信微信小程序不会有什么技术层面的社区和生态,只能做为最末端的用户界面。


年初由于发现我司的 服务状态页 年久失修,我决心重写一个服务状态页,参考一下 GitHub 等网站。我但愿它能同时展现三个节点的状态、可以展现过去一天的历史状态、容许运维同事在服务状态页上快速地发布通知。最后这个状态页也开源了出来,在 leancloud/leancloud-status

为了可以让服务状态页自己老是保持可用,我设计了一个比较有趣的架构:后端(检查器)分别运行在咱们三个节点的云引擎上,交叉对全部节点进行检查,将结果和展现历史图表所须要的数据写入到 S3(或其余对象存储上);状态页面做为静态页面托管在 CDN 上,从 S3 分别拉取三个节点的检查结果和历史图表数据,对来自三个节点的数据进行汇总,决定显示为「正常」仍是「故障」。

这样就保证了服务状态页自己的可用性和三个节点隔离,可用性仅依赖于 S3(理论上能够同时写入多个对象存储做为热备),检测程序又运行在咱们本身的云引擎上(比单独部署在一台机器上更易于维护),架构又并不复杂。

为了在前端合并三个节点的时序数据并绘制图表,我实际上是费了很大的功夫的,但在实际部署的过程当中遇到了不少细节的问题,作了不少妥协。例如咱们的美国节点到国内的访问一直不顺畅等等,最后并无把我制做的历史图表展现出来。


以前几个北京的同事写了一个 聊天机器人 放在公司的 IM 上,天天看他们调戏机器人以为挺幼稚的。但等我搬到北京以后也加入了他们的队伍,我给机器人加了几个有趣的功能,虽然实现上并不复杂,但你能够经过聊天的方式把它展现给别人看,也可让别人参与人来,仍是个很是有意思的事情。

首先我写了一个 帮助你们决定晚上吃什么 的功能,这一写我就来了兴趣,后来又写了 确认你们是否都准备好吃晚饭了帮助运维同事简单地更新服务状态页,还 为公司免费午饭的福利随机人选

https://jysperm.me/2018/01/pr...

相关文章
相关标签/搜索