微服务架构演进

背景:

在许多中小企业制造业中,单体应用仍然是一种常见的软件架构选择。这主要是因为单体应用相对简单,易于实现和部署,对于业务需求较为简单、规模相对较小的企业来说,这种架构模式能够满足其基本需求。但是随着时代的进步发展,传统制造业也随着硬件制造工艺的水平的提高,对工控软件的要求也越来越高。传统软件大多都是各种独立系统的堆砌,这些系统的问题总结来说就是扩展性差,可靠性不搞,维护成本高。争对这种问题,软件架构的改革势在必得。

互联网行业发展:

传统企业软件的单一性一直是互联网所诟病的缺点。在传统企业停滞不前的同时,互联网企业的业务却在在不断的飞速发展,进而导致系统的架构也在不断的发生着变化。总体来说,系统的架构大致经历了:单体应用架构—>垂直应用架构—>分布式架构—>SOA架构—>微服务架构的演变。 当然,很多互联网企业的系统架构已经向Service Mesh(服务化网格)演变。

企业当下:

目前公司主要经营的系统项目有小料,上辅机,立体库,mes等,都是以单体应用架构为主。

单体架构有啥问题?

单体架构在规模比较小的情况下工作情况良好,但是随着系统规模的扩大,它暴露出来的问题也越来越多,主要有以下几点:

(1)复杂性逐渐变高

比如有的项目有几十万行代码,各个模块之间区别比较模糊,逻辑比较混乱,代码越多复杂性越高,越难解决遇到的问题。

(2)技术债务逐渐上升

公司的人员流动是再正常不过的事情,有的员工在离职之前,疏于代码质量的自我管束,导致留下来很多坑,由于单体项目代码量庞大的惊人,留下的坑很难被发觉,这就给新来的员工带来很大的烦恼,人员流动越大所留下的坑越多,也就是所谓的技术债务越来越多。

(3)部署速度逐渐变慢

这个就很好理解了,单体架构模块非常多,代码量非常庞大,导致部署项目所花费的时间越来越多,曾经有的项目启动就要一二十分钟,这是多么恐怖的事情啊,启动几次项目一天的时间就过去了,留给开发者开发的时间就非常少了。

(4)阻碍技术创新

比如以前的某个项目使用struts2写的,由于各个模块之间有着千丝万缕的联系,代码量大,逻辑不够清楚,如果现在想用spring mvc来重构这个项目将是非常困难的,付出的成本将非常大,所以更多的时候公司不得不硬着头皮继续使用老的struts架构,这就阻碍了技术的创新。

(5)无法按需伸缩

比如说电影模块是CPU密集型的模块,而订单模块是IO密集型的模块,假如我们要提升订单模块的性能,比如加大内存、增加硬盘,但是由于所有的模块都在一个架构下,因此我们在扩展订单模块的性能时不得不考虑其它模块的因素,因为我们不能因为扩展某个模块的性能而损害其它模块的性能,从而无法按需进行伸缩。

但是随着像拓普,美昱等重量级合作伙伴多设备多维度的生产过程中就会发现单体的不适用性,所以在实施的过程中对软件架构的升级尤其考验。

升级改造:

争对当下的单体应用的弊端,将当前的软件架构由单体应用升级为微服务的集群架构。接下将对微服务架构展开详细的分析。

项目架构图

服务架构图:

分析:

从应用架构和服务架构看,

  • 将系统部署的过程中将多集群的部署方式,防止单点故障,有点的保证了服务的高可用,即使一个集群节点故障,用户也能平稳和无感的继续使用系统

  • 每个集群节点都是微服务的方式部署项目,每个项目都拆解成多个服务模块。例如,上辅机系统抽离出日志模块,用户模块,物料模块,配方模块做成单独的服务。这些模块可以独立部署的形式可以供其他系统使用,在小料,立体库中用户模块,物料,日志等都可以共用,省去了代码的重复性和服务间调用的数据同步一致性问题,同时也避免了服务的单点故障导致整个系统的不可用,大大节省了研发周期和项目的稳定性。

  • 数据对一个企业尤为重要,其中db数据,redis也是采用实时同步和集群的模式,有效保证了因为设备机器宕机引起的数据丢失

总结

优点:

  • 易于开发和维护

由于微服务单个模块就相当于一个项目,开发这个模块我们就只需关心这个模块的逻辑即可,代码量和逻辑复杂度都会降低,从而易于开发和维护。

  • 启动较快

这是相对单个微服务来讲的,相比于启动单体架构的整个项目,启动某个模块的服务速度明显是要快很多的。

  • 局部修改容易部署

在开发中发现了一个问题,如果是单体架构的话,我们就需要重新发布并启动整个项目,非常耗时间,但是微服务则不同,哪个模块出现了bug我们只需要解决那个模块的bug就可以了,解决完bug之后,我们只需要重启这个模块的服务即可,部署相对简单,不必重启整个项目从而大大节约时间。

  • 技术栈不受限

比如订单微服务和电影微服务原来都是用java写的,现在我们想把电影微服务改成nodeJs技术,这是完全可以的,而且由于所关注的只是电影的逻辑而已,因此技术更换的成本也就会少很多。

  • 按需伸缩

上面说了单体架构在想扩展某个模块的性能时不得不考虑到其它模块的性能会不会受影响,对于我们微服务来讲,完全不是问题,电影模块通过什么方式来提升性能不必考虑其它模块的情况。

缺点:

  • 运维要求较高

对于单体架构来讲,我们只需要维护好这一个项目就可以了,但是对于微服务架构来讲,由于项目是由多个微服务构成的,有一个模块出问题虽然不影响整个项目的运行,但是想要知道是哪个模块造成的问题往往是不容易的,因为我们无法一步一步通过debug的方式来跟踪,这就对运维人员提出了很高的要求。

  • 分布式的复杂性

对于单体架构来讲,我们可以不使用分布式,但是对于微服务架构来说,分布式几乎是必会用的技术,由于分布式本身的复杂性,导致微服务架构也变得复杂起来。

  • 接口调整成本高

比如,用户微服务是要被订单微服务和电影微服务所调用的,一旦用户微服务的接口发生大的变动,那么所有依赖它的微服务都要做相应的调整,由于微服务可能非常多,那么调整接口所造成的成本将会明显提高(其实单体应用改了代码对应对接的也需要调整)。


微服务集群的高可用性是通过冗余部署、负载均衡、异步化设计、限流降级熔断、架构拆分和服务治理等多项措施共同实现的。如下是使用微服务过程中使用的一些组件:

注册中心:

注册中心存储了所有服务的注册信息,包括实例的IP、端口、状态等信息。在容灾过程中,注册中心可以帮助快速发现和定位故障实例,并进行切换和恢复。

负载均衡器:

负载均衡器可以帮助将请求分配给多个服务实例,从而提高了系统的可用性和容灾能力。在容灾过程中,负载均衡器可以根据权重等配置自动调整请求分发策略,以保证系统的可用性。

服务发现:

服务发现可以帮助服务实例快速找到其他服务实例的地址和端口等信息,从而避免了直接访问数据库等单点故障的发生。在容灾过程中,服务发现可以帮助快速找到可用的服务实例,并进行切换和恢复。

熔断机制:

熔断机制可以在某个服务出现故障时快速地切断请求,从而避免了故障的扩散和影响其他服务。在容灾过程中,熔断机制可以帮助快速定位故障服务,并进行切换和恢复。

消息队列:

消息队列可以帮助解耦服务和消费者之间的依赖关系,从而使得服务消费者在处理消息时不会因为单个服务实例的故障而受到影响。在容灾过程中,消息队列可以帮助快速转移未处理的消息到备用服务实例进行处理。

存储管理:

存储管理可以帮助管理和维护数据存储空间,从而保证了数据的可用性和一致性。在容灾过程中,存储管理可以帮助快速备份和恢复数据,并进行切换和恢复。

链路追踪:

链路追踪可以与监控系统集成,当某个服务的性能指标出现异常时,可以触发告警,及时通知开发团队进行处理。当某个服务实例出现故障时,链路追踪可以迅速识别并自动将请求路由到其他可用的服务实例,实现容灾。

通过链路追踪,可以快速定位故障服务,并迅速进行恢复。同时,链路追踪还可以记录故障发生时的详细信息,为后续的问题分析提供数据支持。

API网关

当某个微服务出现故障时,API网关可以阻止对该服务的进一步访问,从而避免故障扩散到其他服务。当某个微服务无法正常处理请求时,API网关可以将其请求转发到其他可用的微服务实例,实现容灾。

在容灾过程中,API网关可以动态调整请求的路由规则,将请求分配给多个可用的微服务实例,实现负载均衡。

数据库实现高可用性主要依赖于以下几个方面:

数据库集群:通过建立数据库集群,可以实现在多个节点上的数据同步和备份,确保在某个节点发生故障时,其他节点可以继续提供服务。

数据库备份与恢复:定期对数据库进行备份,并在需要时进行恢复,可以确保数据的完整性和可用性。

负载均衡:通过负载均衡技术,可以将请求分散到多个数据库节点上,避免单个节点的过载,提高系统的吞吐量和可用性。

故障转移:当某个节点发生故障时,可以通过故障转移机制,将请求自动转移到其他可用的节点上,确保服务的连续性。

监控与告警:建立数据库监控和告警机制,实时监测数据库的状态和性能,及时发现并处理异常情况,确保系统的稳定性和可用性。

总之结合实际应用场景应用,在不考虑运维开发成本的前提下优点还是大于缺点的