一、 场景
高可靠性首先要考虑的,就是各种异常场景,尤其是在高负载之前,系统出现的种种响应慢,无响应,或者单点、多点故障情况下,程序自身的存活,业务的调度,或者一个错误请求、命令、控制指令造成的影响。
设计一个高可靠性的客户端需要考虑到以下几个方面的场景:
- 网络不稳定:客户端需要能够处理网络不稳定的情况,例如网络中断、超时、丢包、延时、大量重传、乱序等
- 服务器故障:客户端需要能够处理服务器故障的情况,例如服务器宕机、服务不可用、CPU负载高带来的系统卡慢、内存负载高带来的资源申请失败,IO负载高带来的IO响应迟缓等。
- 客户端崩溃:客户端需要能够处理自身崩溃的情况,例如内存泄漏、句柄泄露、程序异常、输入异常等。
- 安全性问题:客户端需要能够保证数据的安全性,例如防止数据泄露、防止恶意攻击等。可以通过使用加密算法、安全认证等方式来保证数据的安全性。
- 用户体验:客户端需要能够提供良好的用户体验,例如快速响应、界面友好等。可以通过使用缓存、异步加载等方式来提高用户体验。
综上所述,设计一个高可靠性的客户端需要考虑到网络、服务器、客户端、安全性和用户体验等多个方面的场景。
二、总体架构设计
2.1 选型思路
要求客户端高可靠性时,客户端的架构选型需要考虑以下几个方面:
- 分层架构:作为软件设计的基础,好的分层易于维护,无需赘言。
- 异步编程:当要求程序高可用、高可靠性的时候,每个步骤都要考虑到异常场景和异常处理。这种架构设计可以将agent的处理过程分解为多个步骤,每个步骤都可以独立处理,从而提高系统的并发能力。引入mq等,将步骤的控制与执行分开,可以让每个步骤都具备异常场景的处理能力。
- 缓存机制:采用缓存机制可以减少客户端与服务器的交互次数,提高客户端的性能和稳定性。常见的缓存机制包括内存缓存、磁盘缓存、分布式缓存等。尤其在网络异常的情况下,客户端与服务端经常出现失联,没有缓存机制会导致消息丢失,或者消息处理缓慢。
- 错误处理:采用良好的错误处理机制可以及时发现和解决客户端的问题,提高客户端的可靠性。常见的错误处理方式包括异常捕获、错误日志记录等。
- 安全认证:作为客户端必然要考虑与服务端通信的安装问题。采用安全认证机制可以保证客户端的数据安全性,避免恶意攻击和数据泄露。常见的安全认证方式包括OAuth、JWT等。
综上所述,客户端的架构选型需要考虑到分层架构、异步编程、缓存机制、错误处理和安全认证等多个方面。具体选型需要根据项目需求、团队技术水平和开发周期等因素综合考虑。我个人比较推荐采用分层架构、异步编程和缓存机制,同时注重错误处理和安全认证。
2.2 架构设计
以golang为例,常用的agent架构设计包括以下几种:
- 基于goroutine的并发模型:golang天生支持并发,因此可以使用goroutine来实现agent的并发处理。这种架构设计可以提高agent的性能和吞吐量,但需要注意并发控制和资源管理。
- 基于消息队列的异步模型:使用消息队列可以实现agent的异步处理,提高系统的可靠性和稳定性。这种架构设计可以将agent的处理过程分解为多个步骤,每个步骤都可以独立处理,从而提高系统的并发能力。
- 基于微服务的分布式模型:使用微服务可以将agent的功能拆分为多个独立的服务,每个服务都可以独立部署和扩展。这种架构设计可以提高系统的可扩展性和可维护性,但需要注意服务之间的通信和数据一致性。
- 基于事件驱动的架构设计:使用事件驱动可以将agent的处理过程分解为多个事件,每个事件都可以触发相应的处理逻辑。这种架构设计可以提高系统的灵活性和可扩展性,但需要注意事件的设计和管理。
如果是高可靠性场景,我会考虑基于消息队列的异步模型,将执行与控制分离,尽量减少与外界的交互,降低并发,来降低维护成本,简化控制流程,使整个任务流变得更为简单。
2.3 架构图
2.4 技术选型
考虑到高可靠性,我会选择以下技术栈:
- Web框架:Gin或Echo。这两个框架都是轻量级的Web框架,具有高性能和易用性,适合快速开发RESTful API。
- 数据库:如果有兼容性需求作为客户端建议简单使用文件,序列化数据来持久化程序数据,因为客户端是无法保证运行的正常与mysql或者其他关系型数据库正常通信,且运行的设备都装有数据库,而客户端是允许一定程度的数据丢失的,重要数据上传,在恢复的时候再向服务端拉取同步即可,过程数据不建议使用数据库。如果没有兼容性需求,可以考虑MySQL或PostgreSQL。这两个关系型数据库都是成熟的开源数据库,具有高性能和可靠性,适合存储大量结构化数据。
- 缓存:如果有兼容性需求,要尽量减少中间件的使用,减少与外部的交互,我会选择共享内存或者共享信号来进行缓存。如果无类似需求,我会考虑Redis或Memcached。这两个缓存系统都是成熟的开源缓存系统,具有高性能和可靠性,适合缓存大量数据和提高系统性能。
- 消息队列:Kafka或RabbitMQ。这两个消息队列都是成熟的开源消息队列,具有高性能和可靠性,适合处理大量异步消息和解耦系统组件。
- 日志系统:ELK或Zap。这两个日志系统都是成熟的开源日志系统,具有高性能和可扩展性,适合收集、存储和分析大量日志数据。
- 容器化:Docker和Kubernetes。这两个容器化技术都是成熟的开源技术,具有高可靠性和可扩展性,适合部署和管理大规模分布式系统。
当然,具体的技术栈选择还需要根据项目需求、团队技术水平和开发周期等因素综合考虑,如果是再一个极度不稳定的环境,要保证高可靠,原则上尽量减少交互次数,如果有兼容性要求,要考虑运行设备上未安装中间件的情况,在不稳定情况下,与外部设备的通信无法保证,会导致调度不及时等问题,要尽可能减少外部的依赖。