0. 引言
做了一个管理平台用于管理一组容器的管理,需求很简单:
- 根据前端的请求,后端向对应的容器发送对应的指令,容器执行完毕之后再把结果返回给后端,后端打包之后再返回给前端展示;
- 后端会定期轮询各个容器的状态。
1. 后端与容器的通信模型:RPC
为什么使用RPC模式:
- 因为单次请求之间没有相关性,所以容器不需要记录上一次请求,也不需要保持长连接;
- 对于后端来说,每一次发送命令可以看成是向容器调用一次它的服务,而容器只需要在执行完服务返回一个response即可。
所以我们将每个容器都设置一个RPC进程,让后端通过向容器中的RPC进程发送请求来实现对容器的管理。
2. RPC进程的实现方式
RPC服务的实现我们使用的是rabbitMQ。
首先解释为什么使用消息队列来做RPC:
- 因为后端和容器之间的交互很像生产者和消费者,后端是生产者,负责生产命令,容器是消费者,消费后端生产的命令并返回相对应的结果;
- 后端与容器之间是1对多的关系,借助消息队列可以很方便的对单个容器或者所有容器发消息;
- 消息队列对异步的支持。
使用rabbitMQ是因为rabbitMQ本身针对RPC的实现提供了一组非常方便且稳定的组件,而且相关学习资料多,学习成本较低,所以就使用了rabbitMQ。
Server解决三个问题:
- 命令的实现与注册
- 命令的执行
- RPCServer的开启与维护
- 多个容器之间的维护更新
- 容器状态的更新
相对应的解决方法:
- 通过抽象一个Command作为父类,新的命令只需要继承Command并实现相关接口即可,并且将命令放到指定的文件夹即可
- 设置一个执行命令的单例,它负责两件事:
- 加载指定的文件夹下所有的文件,每个文件对应一个py文件;
- 当收到后端的请求时,根据收到的请求调用相关的函数;
- RPCserver启动后就不会关闭,后端会定期轮询各个容器的状态,如果发现没有回应,会尝试再次发起状态更新请求;如果到达最大次数仍然没有连通,那么就会发出告警;
- 通过git来维护更新,如有更新,只需要向各个容器发送git命令并执行重启命令即可;
- 容器的状态通过设置定时任务的方式由后端向各个容器轮询,使用celery实现。
3. 后端的容器注册
- 在容器侧上传执行一个写好的脚本,脚本的内容包括:
- 安装环境和相关的包;
- 克隆相关的仓库;
- 运行RPCserver;
- 在后端侧填写容器的配置信息,完成。
4. 后续可能遇到的瓶颈
- 如果服务器的数量持续上升,那么瓶颈大概率会出现在两个方面:
- 数据库的读写压力,解决方法:
- 主从模式;
- 分布式数据库;
- 引入redis缓存,减少写压力;
- 服务器的性能压力,解决方法:
- 对服务器进行功能拆分,比如轮询和写数据库操作可以由另一个服务器负责;
- 由容器主动向后端推送个人信息;
- 加一个负载均衡器,引入多台服务器。
- 还有一个解决方法,调整轮询频率,但是是一个过渡的方法
- 数据库的读写压力,解决方法:
总结
优点:
- 这个架构基本保证了增减容器不需要太高的操作成本;
- 对于命令的扩展支持也很友好;
- 屏蔽了操作细节,对于用户来说也降低了使用成本。
缺点:
- 安全性方面其实考虑得比较少;
- 由后端发起轮询的方式比较笨;
- 对于数据库操作的优化还做得比较少;
- RPC对于需要直连容器进行实时操作的支持不够(类似ssh);
之后重构的时间点应该是:
- 服务器数量翻一番;
- 需要进行直连容器的实时操作功能。