【技术·真相】微服务的状态管理

我们都被告知,并且倾向于认为,失败是一件不好的事情。

本次我们来开一个新坑,聊聊服务器分布式架构的那点事 。首先看看微服务管理中的服务依赖管理。

微服务

经典的分布式架构是典型三层架构

各层各司其职:

  1. 负载均衡服务器接受大量客户端的连接
  2. 应用服务器集群处理客户端的逻辑请求
  3. 存储层在最后,供应用服务器存储数据,存储层往往又分为缓存和数据库,需要一定的缓存策略保证数据的写入性能和一致性

随着项目规模的提升和理念发展,原有经典架构遇到了问题

  • 项目规模提升,一个大团队可能几十、几百甚至上千人,不太可能将所有业务放在一个应用服务中处理,怎么合作开发,提高开发效率是个大问题
  • 不同团队熟悉的技术栈和语言不同,需要有区分又要能合作
  • 产品面对的用户数量庞大,业务众多,客观上需要从业务上进行拆分,出问题时不能影响所有业务及所有用户

于是,满足这些需求的微服务出现。

有了微服务:

  • 大的团队可以各自负责一部分服务,互相之间没有耦合
  • 不同团队可以使用不同的语言或技术栈,通过网络来互相通信
  • 部分服务出现问题,不影响其他服务,也只影响一部分用户

游戏服务器在做架构设计的时候也大量应用了微服务的思想。

服务器可以将很多功能拆成了一个个微服务,各个微服务组合给玩家提供服务,典型的有 game、battle、guild、social、rank、name、mail 等,分别提供基础游戏逻辑、战斗、工会、社交、排行、名字、邮件服务。

微服务架构解决了我们上面提到的问题,但是其本身也新增了一堆问题,而对于这些新增的问题,还会衍生出更多的子问题,这就需要我们不断地用各式各样的技术和手段来解决这些问题。所谓任何技术方案都不会是银弹,都是处理问题的 trade-off:权衡。

本文要讨论的依赖管理就是其中的一个问题:

在之前的经典分层分布式架构中,应用服务器内部的状态由其构成的多个模块来做协调,都是在服务内部;

到了微服务架构中,服务之间是相互独立的,微服务之间需要通过网络通信来等待或者通知自身的状态,可能会有互相依赖的情况,这就需要依赖管理。

微服务状态

一个微服务进程对外服务之前,需要做一些事情,在这些事情做完之后才可以正常服务。在做每件事情时,就会处于不同的状态。

一个典型的微服务在其整个生命周期内的状态可能有:

  1. 初始状态
  2. 等待服务状态。因为有个进程涉及主备,备进程通常处于等待状态。
  3. 组网状态
  4. 等待依赖的服务状态
  5. 加载数据状态
  6. 可服务状态
  7. 热更新状态
  8. 准备下线状态
  9. 停止服务状态

为什么要设计不同状态呢?

  • 比如微服务之间 TCP 连接组网还未完成,如果要去 DB 微服务加载需要的数据,必然失败;

  • 某微服务还未进入可对外服务状态,其他服的请求就过来了,很可能发生异常;

  • 某 A 微服务依赖的 B、C 微服务还未启动或未准备好,从 A 到 B、C 的请求,必然失败或异常;

  • 整个服务器系统还未进入可对外服务状态,玩家进来了,很可能发生异常;

依赖管理

微服务之间是存在依赖关系的。

举个很简单的例子,gateserver 是网关服务器,在对玩家开放之前,必须等待 gameserver 处于可服务状态。因此我们可以配置其依赖关系:

类似的,gameserver 上承担主逻辑,其上的玩法依赖于其他微服务,如战斗服务、工会服务、邮件服务、数据存储服务等。

如何查询以及标记依赖关系呢?

比较直观的想法是直接通过消息来发起查询及同步。

但是,很多服务不是直连的,可能通过 proxy 转发,发消息及互相同步(如 gossip 协议)会比较繁琐。

一个比较合理的方式是借助公用的第三方组件来做同步。我们可以借助服务发现组件(之后的文章会讨论),不管什么服务及互相之间的连接关系,都统一向服务发现写入自己及定时查询所依赖的服务的状态:

状态切换流程

单个微服务内部状态的切换流程如下:

业务钩子

进程状态的流程切换是统一的,不可更改。

很多情况下,上层的业务也需要依赖该微服务当前的状态:例如,一个模块可能需要知道什么时间适合去发起该模块的数据拉取请求。

为了方便业务使用,各个状态在进入前,会提供业务钩子(hook) 给各个业务订阅自己要做的逻辑。例如:

Data 订阅自己的表格同步逻辑:

Go 复制代码
commonfsm.SubscribeLoad(func() error {
    // load data logic
    ...
})

Game 订阅对外服务时的逻辑:

C++ 复制代码
CCommonFsm::Instance()->SubscribeInService([] {
    // logic business, timer logic
    // ...
})

好了,有关微服务中的服务依赖管理,我们就说这么多,希望能为你提供一点参考。希望你方便的话点个免费的赞,感谢!

作者:我是码财小子,会点编程代码,懂些投资理财;期待你的关注,不要错过我后续的文章更新。

相关推荐
程序员爱钓鱼35 分钟前
Go语言实战案例-创建模型并自动迁移
后端·google·go
javachen__40 分钟前
SpringBoot整合P6Spy实现全链路SQL监控
spring boot·后端·sql
uzong6 小时前
技术故障复盘模版
后端
GetcharZp7 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程7 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研7 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi7 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国8 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy9 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack9 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt