你如果但凡看一眼 API Requests 或者 Solar Network 的 HTTP 请求你就会意识到一个事情,几乎所有请求都是到 api.solian.app 的,难不成 Solar Network 的服务器是个巨大的石山?所有功能都在一个服务器里面?那维护起来还得了?!
当然羊是不可能允许那种东西存在的,不然的话又要重构了;仔细观察 HTTP Request 的 URL 基本上都是这样格式的:
https://api.solian.app/<service name>/<path>
中间总是有一个意义不明的 Service Name,比如说 stargate、sphere 什么的。这是干什么的?
Blade
隆重介绍 Solar Network 的自主研发,遥遥领先的微服务网关 —— Blade。这个名字来源于刀片服务器,也是 Solar Network 继处理 HTTPS 的反向代理后得到 API 请求的第一线,所以起名刀片来劈开所有的请求(?)
Blade 会按照 Service Name 把对应的请求转发给对应的服务。啊你可能想这种东西手动配置个 nginx 或者 caddy 的配置文件也能做到。确实,但是 Blade 同时兼顾服务注册、发现、健康检查、以及最后一个最重要的 WebSocket 网关。
Solar Network 的 WebSocket 包都会按照下列信封格式发送:
// reference https://kb.solsynth.dev/zh/solar-network/developers/routing/
{
"type": "包类型",
"data": "包数据,可能为任何结构、类型",
"endpoint": "包需要请求的服务,在服务器传来的包不会携带此项;若客户端需要向服务器发送数据包,需要将此项填写为对应服务的 ID 以帮助网关转发此包",
"error_message": "服务器回传包的错误信息"
}
其中的 endpoint 就是 Service Name,Blade 收到对应的服务包就会将其通过消息队列发送给对应的服务;当服务有要发出的 WebSocket 包也会通过消息队列找 Blade 发送给对应的用户或者 Device ID。
曾经 WebSocket 发包的操作是通过 gRPC 完成的,但是随着消息服务对 WebSocket 的依赖日益增加,WebSocket 投递的稳定性变得日益重要,所以使用的消息队列让失败的推送可以重拾。
你可能也注意到了 “发送给对应的用户或者 Device ID”,所以这也是为什么不能随便用一个 WebSocket Gateway 的原因,Blade 会负责鉴权,同时也负责用户在线状态的提供(WebSocket 链接状态)和最后活动时间的更新。是符合羊国国情的基础设施。因为有 Blade 的存在,所以服务器到客户端只用维护一个 WebSocket 链接即可,不用每个服务单独维护一个链接浪费内存。
星门
Stargate 是我们行进的身份验证服务,具体它怎么工作在上期 Devlog 已经讲过了。这里就不再赘述,其也是我们非常重要的基础设施,之前在迁移到 Stargate 也看到身份服务坏掉的威力了,基本就是只读状态,什么都干不了 (´・ω・`)
没了你照样转
得益于 Solar Network 的微服务架构,所以部分服务宕机的情况不会导致整个 Solar Network API 不可用。这当然是极好的,但是可能会让小羊忽略的部分服务失效的事实,过了许久才反应过来。目前来说微服务的健康检查并没有接入 status.solsynth.dev;上面呈现的是整个 Solar Network API 的基础可用性,换句话说就是 Blade 又没有宕机。
Remote Producable Calls
gRPC plays an important role in the Solar Network inter-services communication. 没有什么意义,就是单纯想用一下 plays an important role 这个句式(
Solar Network 服务之间的通信全部依赖 gRPC 协议,而不是 HTTP。有两个好处,第一个是效率高,protobuf 会比 JSON 解码编码起来更快;第二个是明确的划分作用域,因为 gRPC 都是 Admin-level 的 API,暴露可能会导致资安危机,索性不让 gRPC 的端口暴露在公网中就好了。
同时 Solar Network 的 gRPC 用自签的 CA 和证书做了 mTLS 验证,也就是客户端和服务器双方都要提供证书的验证来保证安全。
如此依赖,Solar Network 的服务尽管被切成了一小块一小块的也能流畅的协作了。
事件巴士
EventBus(消息总线)也是 Solar Network 微服务协作的重要部分,有的时候单纯的点到点 gRPC Call 不是很足够。有的事情要公之于众,让全体服务知道,比如帐号被删除了、订单支付了等等。
这时候消息总线就该登场了,其是基于消息队列,会将一个事件广播给全体服务,然后每个服务按照自己的需求处理、响应。就拿帐号被删除举例,每个服务收到 accounts.deleted 事件之后会去自己的数据库里看看有什么这个用户相关的数据,进行删除,非常高效。
横向扩展
这些设计东西都是在设计上就支持横向扩展的,Blade 有 LB,消息队列也可以接受多个实例的广播和不会重复消耗。但是实际上因为算力紧俏并没有什么机会用到就是了,不过这样子也是好的,未来如果做大做强的话不用再花精力重构了。
差不多这就是 Solar Network 的微服务怎么工作的了。虽然搭框架的时候蛮麻烦的,但是这些基础设施搭好了之后写新的服务真的是越来越快了。比如新的索尔幸兹物流只花了我一天就上线了,不过这个就是下一章的课题了。
Thanks for you reading.
