最近给 libatapp 增加了一系列改造,非常多且琐碎,这里简单记录下吧。

首先是重构了配置管理。原来是手写在代码里的,因为原来上层的 libatbus 是不依赖 protobuf 的,现在 既然已经依赖 protobuf 了就转为 protobuf 管理了。同时现在还支持YAML配置,使用 yaml-cpp 来解析YAML文件,这个库也被一些其他知名的大型项目使用了,比如 Envoy proxy 。 原来的conf/ini模式的配置也是支持的,现在加载配置的时候会尝试猜测以下配置文件是yaml还是conf/ini模式。 并且增加了统一的 YAML转protobufconf/ini转protobuf指定层级配置导出到protobuf 的接口来方便使用。比较特殊的是自定义日志配置后端的接入接口有了一些小变化,问题也不大。

前言

最近在抽时间整理之气的游戏服务器框架和解决方案里atsf4g-co,现在的架构是使用etcd的是atproxy。简单得说就是服务集群是分组的,每个分组有分组代理服务atproxy做组间通信。然后atproxy之间使用etcd来做分组服务的服务发现和保活,并且以此来实现平行扩容。

之前做服务间通信组件libatbus的时候也提到了有一个暂时没实现的功能,就是全局路由表的自动通知。但是这个功能的实现主要也是用于后面不同种服务间感知到哪些节点是可用的,哪些是不可用的。而且我的简单实现必然是走心跳的模式,因为心跳的形式肯定不能把心跳设置得太短,同时也要考虑网络异常抖动和断线重连和丢包,所以肯定不是丢一个心跳包就认为丢失。所以故障或者扩缩容期间的感知时间就会比较长一些。另外就是因为可能有网络孤岛问题,所以可能短期内数据不一致(当然肯定会保证最终一致性)。

再加上由于libatbus是支持多级父子节点关系的,所以变化通知和同步包就要考虑自己与父节点、兄弟节点、自己与子节点的不同关系并作不同的同步流向,会比较复杂。比如:子节点下线,既要通知父节点,又要通知兄弟节点。那么这时候给兄弟节点通知就有两个通路,一个是经由父节点中转,另一种是直接发。当然这时候并不一定和兄弟节点有直接通路。所以可能兄弟节点会收到两次通知,一次来自兄弟节点,另一次来自公共父节点。然后又会有其他问题,就是万一又收到一条冲突的消息,来自父节点和来自兄弟节点的顺序是没有保证的,这里又得加入版本机制。总的来说,细节会比较复杂,具体在实现libatbus的这个功能的时候在谈吧。

上面说的libatbus的功能暂时没实现的最重要原因是etcd可以比较完美的解决上面的延迟问题和不一致问题。缺点就是请求的消耗会高于使用libatbus的通信机制。不过这玩意本身不是高频操作,而且故障和容灾本身不是一个频发的事情所以关系不大。而之前etcd的接入是直接写死在atproxy里的,那么这次重构的目的主要就是能够抽象出模块化的工具,以便后面不同的服务可以根据需要取用。

统一管理驱动管理器和模块化

按现在的功能划分,etcd的接入总共被分为3个模块,etcd_cluster、etcd_keepalive和etcd_watcher以及一个通用工具etcd_packer。etcd_packer用于对etcd的一些通用的打解包操作。

模块关系图

etcd_cluster

etcd v3版本内部的通信已经使用了grpc。本来我是想等他的grpc接口进入官方文档并且提供出的grpc的proto再接入的,可是它一直没有整理出直接grpc的proto文件列表。另外我看了一下它的proto文件里用到了一些gogoprotobuf的扩展,其他语言不一定可以无缝接入。考虑到etcd使用了grpc-gateway提供HTTP+JSON的网关层,所以我还是基于他的HTTP接入层来做。因为这里身频次不高,也没有那么在意性能。而且一组etcd服务的QPS也就在十万的级别,只要管理好连接,不要老新建立和关闭连接,HTTP的性能还是够的。