前言
zbot是由我个人编写的简易机器人框架,它依赖于mirai与mirai_api_http,目前实现了关键字回复与定时功能,zbot项目地址。
正文
本文的目的是聊聊zbot的项目架构,这个项目应该是我第一个思考并运用架构知识所编写的框架应用,虽然功能简单,但其中架构部分却值得思考与拓展。
zbot主要由以下几部分组成:
- handler,主要用于处理消息或者定时处理
- receiver,从mirai_api_http接收消息的websocket客户端
- pluginLoader,负责从外部加载用户自定义插件到框架中
- Api,封装mirai_api_http的部分功能供用户插件使用
- registry,注册中心,负责插件注册,调度和转发请求
借鉴主流RPC框架架构
zbot前期架构准备中,借鉴了主流RPC框架的架构,以dubbo框架为例,这是一张dubbo的架构图。
在dubbo中,provider,即服务提供方通过主动方式向注册中心注册服务;而消费端则是通过向注册中心获取已经注册的服务列表,需要时通过协议直接对服务提供方进行调用。这么做的好处是注册中心只负责了服务注册与发现,不转发请求,减小了注册中心的压力,这对整个架构是必须的。
更换架构
虽然dubbo框架的架构方案十分不错,但考虑到以下几点
- 需要设计私有协议
- 服务提供方必须提供其注册中心地址进行注册,但zbot插件必须是无配置或者少配置的,因为需要令插件无需配置就能运行在各个环境中
- 为了开箱即用,注册中心无需成为单独节点,如zk,而是直接整合进框架中
- 对提供方可能得编写单独依赖,如TCP支持,自动注册等等
zbot的目的是插件开发简单,并且开箱即用。综合以上几点,主流RPC框架的架构其实并不适用与zbot。随后我借助RPC框架的各个节点角色重新设计架构。以下是项目架构图。
架构说明
首先谈谈关键的插件部分,对应到RPC框架中就是服务提供方,那在zbot中,服务提供方不再通过主动方式去注册,而是通过pluginLoader对服务进行扫描,主要做法是读取框架配置与目录下的插件,再将开启的有效插件进行统一注册。那在后续的思考中,我认为zbot的架构中registry与pluginLoader应该合并为一个新的registry,由注册中心主动扫描并注册插件。但考虑到框架整体已经完成,并没有太大必要去整合架构,此处只是提出个人看法。
其次就是服务消费端的调用流程,在zbot中,服务消费端就是msghandler,他通过订阅注册中心的关键词列表,负责消息的处理。重点是,在RPC框架中,当需要消费提供者的服务时,是由消费端主要通过协议调用提供者,而在zbot中,则是消费端需要调用服务时,将消息与服务端的id转发至注册中心,由注册中心进行调用。
这么做的好处是消费端不用存储服务端的地址,前面提到,提供方需要简单开发,尽管通过依赖与注解或许能暴露服务端的接口,但需要占用端口,并且框架的开发难度也会加大。那么坏处就是注册中心的压力变大,不仅需要负责服务发现并且需要请求转发。
最后是调用方式,从消费端转发给注册中心,再从注册中心调用消费端,均采用异步方式,因为消费端不依赖与服务提供者,所以可以不用同步进行调用。这样可以防止服务提供方的故障,或者说避免API方面故障使得框架出现异常卡死。
后续思考
目前想到的点其实是插件热加载。如果以目前的架构来说,热加载只能让pluginLoader再次去加载插件,因此需要从头开始扫描。如果是主动服务注册的方式,那么热加载实现可能会更灵活。只能说各有利弊,前面也有提到,插件不能分离与框架,插件不应该独立运行,而是依托于整个框架。并且采用主动注册方式也就需要重新加载所有插件,令插件自行去注册。从这方面来看,zbot不管采用主动注册方式还是被动加载方式都没有什么差别。
目前的实现方案还是在zbot框架前套一个启动器,zbot包含以上几个部分,因为需要将这几个部分组合起来。在不影响现有代码的情况下,通过编写不同工厂方法能在原有zbot的基础上封装一个类似命令行的界面,reload命令实现重新加载插件与配置,这是目前的方案。至于实现日期,咕咕咕。