我开发了一个基于 Beancount 的账本托管服务 HostedBeans,欢迎大家来了解纯文本复式记账并试用我的服务。
归档 2019 年 1 月

2018 年度小结(技术方面)

今年我完成的业余项目确实非常少,勉强算下来也就只有 DeployBeta 的 0.4 版本和 Elecpass 的 v3 版本。

所以我今年得到的一个重要的教训就是 一次要专注于一个项目,同时尽快完成一个阶段性的可用版本,尽快发布。尤其是对于我来说,还有全职工作,业余时间并不多,如果不能尽快发布,获得一些反馈,就失去了继续完善的动力,而且会摊子越铺越大,一直无法发布。

在这一点上,DeployBeta 是一个反面的例子,持续了两年的时间,但也没到可以对外发布的标准。而 Elecpass 是一个正面的例子,在 2017 年 10 月,我花了半个月的时间就发布了两个版本,之后一年多的时间我自己一直在使用,然后在今年十一月集中花了一周的时间发布了 v3 版本(筛选框、布局优化、强化编辑功能、编译 Windows 版),这个项目大部分的时候都是「已发布」状态,而不是还有功能做到一半。


在 DeployBeta v4 版本的前夕我将 DeployBeta 开源了,在 v4 和后续的未发布版本中,我实现了 MySQL、Redis、MongoDB 三种数据库的支持、重写了基于 Etcd 的 ORM。所以今年我也写了一些 Golang,今年我主要的怨念在于 Golang 中缺乏对于接口数组(或者说泛型数组)的支持,只能使用 interface{} 和反射来实现 ORM 中「获取结果数组」的功能。

这个 ORM 其实就是将 JSON 数据存储在 Etcd 中,同时提供关系和事务的简单封装。这其实和 Kubernetes 中的 api-server 做的事情差不多,但因为没有找到比较好的关于 Kubernetes 使用 Etcd 的文档,所以我没有太多地参考它。


为什么容器平台能够简化容器的管理工作呢?我认为一个重要的原因是容器平台提供了一种纯描述式的定义文件,让开发者去描述所期望的最终状态。这一点在 Kubernetes 中实现得最为彻底,我相信这也是 Kubernetes 成功的原因之一。

今年因为工作的原因,我非常深度地接触了 Kubernetes,在其基础上进行封装,来提供容器服务。Kubernetes 不仅仅是一个工具,同时也是一个平台,它以 RESTFul 风格的 API 将所有功能抽象为资源,然后由每种资源的 Controller 去将对象的实际状态同步到预期的状态。这意味着在 Kubernetes 的基础上你可以去添加自定义的资源和相应的 Controller 去拓展它的功能。

在对 Dockerfile 的抽象能力忍无可忍之后,今年我用 Node.js 为 Dockerfile 实现了一个简易的 DSL,主要是将 Dockerfile 分为多个段落,然后在每个段落中结构化地保存指令数据,以便在对 Dockerfile 的整个处理过程中随时向任何段落添加或修改指令,最后等到完成所有的处理之后再将结构化的指令数据生成真正的 Dockerfile。经过这样的过程生成的 Dockerfile 有着更规范的格式,更有利于跨应用甚至跨语言之间的缓存。

其实我们在生产环境使用容器技术已经很多年了,但很多时候只是将已有的程序跑在容器里而已,而没能做到 Container Native。例如我们实际上还有很多容器在依赖本地存储、没有有效的健康检查、不能正确地处理信号来实现平滑关闭。


我司今年发布了一个 游戏后端解决方案,它本质上是一个「消息转发服务」,帮助游戏的客户端之间来转发消息、同步状态。

但出于反作弊的需要,我们还需要提供一种在服务器端运行游戏逻辑的能力。对于暴露这种能力的方式,一开始我们内部有两种方案。我认为比较好的方案是将这种在服务器端运行的游戏逻辑也作为一个客户端去加入到消息服务中,以消息服务为中心与其他客户端进行交互。这样做的好处是:

  • 在服务器和客户端之间复用大部分的游戏逻辑
  • 单机游戏 => 动作同步 => 状态同步 的迁移过程非常平滑
  • 服务器端的游戏逻辑和消息转发服务解耦

为了验证这个方案的可行性,我花了一些时间制作了一个 Demo,实现了一个 简单的回合制卡牌游戏,这种模式后来也被我司发布为了正式的产品:Client Engine

在这个过程中我其实是第一次接触游戏后端的开发,其实我并没有去了解既有的游戏框架,但在不知不觉中也重新发明了一些轮子,例如「动作」和「状态」的概念,感觉去探索游戏的开发过程还是挺有意思的一键事情。


今年年初的时候我尝试为云引擎加上了 任务队列 的功能,因为云引擎本来已经有了基于 HTTP 的云函数功能,所以我想这个任务队列只提供一种调度的能力,而不提供计算资源,依然通过 HTTP 来调用原本的云函数。我认为这样的形式可以减少引入的新概念,降低介入的成本。

但低调公布之后的效果并不是很好,我觉得其中一个原因是是我自己就比较少用任务队列,所以比较难站在用户的角度去考虑他们需要任务队列有怎样的功能、希望超时和并发的控制是怎样的。在新的一年里我还会继续改进这个功能,去参考其他类似的云服务如何设计任何队列的功能。

大概是因为我的服务器端编程经验都在 Node.js 上,Node.js 中异步任务的成本很低,所以不需要出于减少线程开销的考虑去使用任务队列;同时我会通过 Redis 来维护一些关键状态,消除单点、保证因应用重启而中断的任务可以恢复,所以也几乎不需要任务队列去保证任务执行的连续性。

在这个功能的实现上我重度地使用了 Redis:使用 Redis 存储所有的状态、提供一致性保证,用 Node.js 去实现 Worker,调用 Lua Script 去实现原子操作。说起来 Redis 是我用过最好的服务器端软件之一,我认为 Redis 找到了一个非常好的切入点、找准了自己的定位,才使得它的设计看起来那么简单。

应该说任务队列的需求是非常多样化的,每种业务可能都会对任务队列有不同的需求,再加上很大程度上又是语言相关的,所以我觉得在这个方面如果能做一些开源项目也会有比较大的空间,例如我就觉得 Redis 5 中的 Stream 类型就是为任务队列设计的,想去写一个充分利用 Stream 特性的任务队列。

游轮之行

就如 2018 年度小结 中说的那样,蛋黄并不喜欢出门旅行,就喜欢宅在家里,那怎么办呢,于是我们想到了一种合适的「佛系旅行项目」—— 游轮。在游轮上不需要做计划、想去哪就去哪,绝大部分项目不需要额外付费,在船上只需要走几步路就可以回到室内、找到卫生间,再多走几步就可以回到房间或者找到餐厅(也不需要额外付费)。

我们去的是「喜悦号」的游轮,往返上海和福冈(船每次出海停靠日本不同的港口)。5 天 4 夜,其实就是四个整天(两天在海上、一天停靠在日本、登船和下船加起来一天)。总体上我是比较满意的,船上设施和房间内都非常新、非常干净(蛋黄非常看重这一点),这艘船只启用了一年半,三月末就会离开中国,所以还是要把握机会的。

整个行程人均 2900 元(2200 房费 + 400 固定支出的「小费」+ 300 额外付费项目),这个性价比我觉得也非常可以了,这个价格是淡季的价格,赶上假期就会贵很多。我们住的是阳台房,基本就是比快捷酒店小一些的房间,卫生间很小但设施设计得很好,所以并不难用,有一个露天阳台可以看海。

关于船上设施网上的介绍很全了,我就只谈个人感受。

我们全部吃的是免费餐厅(因为网上测评说收费餐厅并没有比免费的强多少,然后价格很贵),吃得还是很好的,有两种免费餐厅,一种是自助餐,面积很大,饮料、水果和糕点很全、主菜每天会变化但品种不多、没什么海鲜。

另一种是正餐厅,每天有一套不同的菜单(五、六个菜),中西餐的菜混合,每天都有一道虾(很大),还有牛排和三文鱼,这些食材的品质我觉得都是非常好的。然而中餐做得比较「西式」,不看菜单根本猜不出来是什么菜,经蛋黄点拨发现原来是他们不会炒菜,感觉都是炖出来的 … 西餐的话我还是非常满意的。

刚进黄海的时候风景不怎么样,水很浑浊,到靠近日本的地方海才变得非常蓝、非常绿,天也是蓝的,很美。

然后晚上可以看到满天的星星,已经很多年没见过了(当然这一点比较依赖于天气,只有一天晚上没有云,才能看到星星)。船很稳,前两天根本感觉,后面两天开始有一些浪,但还是非常稳的,稳到蛋黄觉得船震没有什么特别的感觉。

上海到日本这片海域,基本全程都能看到其他的船,甲板上有两个望远镜可以用,但蛋黄觉得自己带一个望远镜会更好,可以看海岸、船和海鸥。

室外的气温和昆山差不多,但顶层的风非常大;室内则是恒温的,空调非常足。

甲板上有露天的温水游泳池,还看到有人在里面游。

船上有很多演出和活动(还有广场舞),都是免费的,我们看了两场歌舞剧和一场杂耍。歌舞剧看不太懂,但舞台效果还是很不错的。船上有几个露天的泳池,里面是温水,看到有几个人在游。还有一些乒乓球台,和蛋黄打了很久的乒乓球。

付费娱乐项目我最感兴趣的还是卡丁车,$10 一次五分钟,和之前在昆山玩的比起来价格差不多,但不够刺激:车不够快、不能漂移、赛道窄不容易超车,碰到不会开的人就会一直堵着路,不过既然是在船上也不能要求太高了,我全程玩了三场还是挺开心的。因为船上以大爷大妈为主,所以这些娱乐项目的人很少,不需要排队。

到日本之后的岸上观光项目很坑,基本相当于是被卖给了旅行社(以每个人 500 的价格,不想跟团的话要交 500),带你去一些一点都不好玩的景点、一点都不好吃的「美食广场」、一点都不便宜的免税店,行程还特别赶。

关于这个船三月末离开中国,主要是觉得中国人额外的消费太少,工作人员说在欧美航线一周可以卖 50000 瓶啤酒,然而船上基本都是中老年人,酒吧根本没有人。我和蛋黄觉得很大原因是这个公司(这个公司只有这一艘游轮在中国)不了解中国的情况,没有开发出适合中国大爷大妈的额外消费项目,比如搞搞中医按摩针灸、卖点保健品,实在不行搞个水池让大家扔硬币也行呀。有钱的大爷大妈还是很多的,有一天吃饭和做旁边的一对上海大爷大妈聊天,家里在上海几套房,经常坐游轮(估计这是他们坐的最低端的游轮了),说今天买包买衣服就花了两万多 …. 还觉得特别值。

据说这艘船是为中国人设计的(比如热水和热水壶),船上大部分的服务人员都是中国人,餐厅和客房的服务员则主要是东南亚人。不过总之绝大部分地方都只需要用到中文,对大爷大妈还是非常友好的。东南亚的服务人员的态度非常好,总会笑着打招呼,虽然不会中文也会积极地沟通;然而部分中国的服务人员态度不是很好。

船上网络是额外付费的,大概 500 元全程,我没有买,因为我已经做好准备把「没有网络」作为这次游轮体验的一部分了。实际上因为每天的活动内容都很丰富,没有网络也不会无聊,就看着船下的海浪都可以看很久。我带了电脑、几本书、iPad 和相机,但实际上并没有用到,就是因为船上的活动太丰富;相机的话,因为我换了 iPhone 8,感觉和相机的拍照效果已经差不多了,所以也没怎么用上。

我们在船上看了泰坦尼克号作为安全教育片,我事前事后也了解了不少游轮的背景知识以及泰坦尼克号的故事,经过那之后,现在海上的安全标准应该已经非常可靠了,但蛋黄还是表示想坐一坐救生船(忘记拍救生船的照片了)。

1

精子生于 1995 年,英文 ID jysperm.

订阅推送

通过 Telegram Channel 订阅我的博客日志、产品和项目的动态:

王子亭的博客 @ Telegram


通过邮件订阅订阅我的博客日志、产品和项目的动态(历史邮件):

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-ND  授权发布。最后生成于 2024-04-08.