从2016年入行开始,伴随着前期几年的的项目和工作变动,陆续的接触到一些服务架构,包括现在的微服务架构;
因为在现有的公司这两年接触的Service Mesh比较多,确切来说我一共在两个团队分别实践和使用了两套框架,虽然对现有的架构脉络梳理清楚(庞大且黑盒),引发了我对之前的架构认知的思考,想着既然打算年后换工作,先整理一下自己对服务架构这块浅显的理解,也欢迎大家指教
真要动笔才发现对服务架构理解真的很浅,只能持续的阅读和汲取一些优秀博主的精华,加之自己的理解,产出这一篇文章;
一、单体/集群模式
1. Server-Agent模式
最开始16年是在一家传统的DB数据库厂商旗下的项目部工作,可以说没有任何的互联网基因;
Agent也是一个java项目,只不过那会市场上springboot还没大面积使用,借助springmvc的mvc配置模式,启动一个java项目协助主服务处理数据;
基本上SpingMvc是主流,MVC模式,系统层面来看,真要说架构的话,也谈不上,基本上是下图的一种结构:
服务A着重于提供实时的软件功能服务,搭配多个Agent来进行不间断的处理服务A写入的任务或者数据;
2.多模块-分布式单集群
好在第二、第三个公司,算是为我进入微服务做了铺垫,接触到知道SpringBoot的SPI机制,即自定义一个通用的starter,功能性package(面向接口的编程设计,引入方只需要关注实现,不需要关注细节);
这种相对于纯单体服务的优势非常突出,非常适合当时兴起的敏捷开发/迭代,开发者进行简单的引包后,就可以启动&部署;
3.SOA服务
面向服务的架构(SOA)是一种软件开发方法,它使用称为服务的软件组件来创建业务应用程序;算是一种微服务的前身,只不过这种模式下,对微服务中各个服务多样性,有很大的包容度,只要服务之间约定好通信协议,即可对外提供完整的服务,也为跨语言服务提供了很大的支撑;
核心要素:企业服务总线Bus,保证集中化的基础组件
我没有遇到过纯粹的SOA服务架构,也认为不会有纯粹的SOA服务架构,都是基于现状各种模式架构混用,可能在大型的集团这种模式要更适合一些;
思考
这种模式有一个限制,就是服务之间是提供API进行通信,功能上互相独立松耦合,无状态,供开发人员选用组合;【QPS高的时候就是灾难】
各种?AAS的区别:
二、微服务模式
1.Spring体系的微服务架构
传闻微服务模式是借鉴SOA而来,避免集中化带来的后续维护、迭代的高成本(中心化意味着任何小的调整都必须要考虑整个系统的稳定性,牺牲灵活性);因此,微服务模式下的体系,单一性和灵活性是很重要一个选项指标,来应对当时互联网告诉发展带来的迭代开发模式;
微服务天然的独立性,及其核心设计是围绕业务发展的,业务的划分决定了微服务的功能划分,有时候,A->B->A循环调用,也是常有的事情,而这里面带来的网络、负载、监控的问题,随着迭代时间长以后,会非常的庞杂;
当时的微服务流行架构和技术选型只有两种:Dubbo和Cloud;
配合SpringCloud自带的微服务处理方案,熔断、限流、服务ribbon负载等,功能齐全
- 客户端请求->DNS解析->网关(鉴权)->注册中心->服务节点
- 跨服务集群的feign请求->网关(鉴权)->注册中心->鉴权
- 服务集群内的feigin请求->注册中心->服务节点
dubbo当时的微服务结构也差不多,区别就在于使用方式有区别,因为当初的理念主要还是基于这样的分层结构去做设计
思考
- 此类型服务架构,只需在jekins部署项目时,运维提供一个网段内互通的ip,一个人就能构建一套这样的系统,成本很小;
- 当时开发要关注的真的很多,运行监控、注册中心、配置中心、通信延时等指标方面,任何一个点有问题对开发来说排查都是很烦躁的,无法专注于业务开发,另外,cloud生态中很多组件的jar包大部分都可插拔,运维只能提供最基础的技术价值;只有崩了才会想起运维,但是他们可以参与进来的空间真的很大,分担开发的压力;
2.服务网格
当微服务模式,发展到成千上万的时候,微服务模式的局限性就出来了,由于微服务模式下的服务调用,都是非中心化的,虽然有gateway网关或者前置的ngnix可以做负载,但是这个比较考验开发团队的技术规范约束性,在高密度开发模式(倒排期)和程序员技术参差不齐的现状下,牺牲规范是常有的事情,再好的团队也没办法天天CR别人的代码,或者了解调用链路是否符合最初的设计;因此,服务网格出现了,也称Service Mesh
;
其实,当微服务的体量逐渐变大,而原cloud和dubbo微服务模式形成开发、负载、监控一系列可闭环的技术选型,对开发很不友好,需要关注开发以外的东西,分散注意力;运维也不能仅仅只是关注网络是否通畅、机器是否健康这些基础指标上,也即将要参与到服务设计、安全考究、规划这各个环节上,各司其职,维持这庞大的微服务体系架构;
用凤凰架构书籍中的三张图片来感受一下演进的区别:
SpringCloud微服务体系:
K8S优化后的微服务体系:
**目标一:**尽可能缩减非业务功能代码的比例。
在 Fenix’s Bookstore 中,用户服务(Account)、商品服务(Warehouse)、交易服务(Payment)三个工程是真正承载业务逻辑的,认证授权服务(Security)可以认为是同时涉及到了技术与业务,而配置中心(Configuration)、网关(Gateway)和服务注册中心(Registry)则是纯技术性。我们希望尽量消除这些纯技术的工程,以及那些依附在其他业务工程上的纯技术组件。
**目标二:**尽可能在不影响原有的代码的前提下完成迁移。
得益于 Spring Framework 4 中的 Conditional Bean 等声明式特性的出现,对于近年来新发布的 Java 技术组件,声明式编程(Declarative Programming)已经逐步取代命令式编程(Imperative Programming)成为主流的选择。在声明式编程的支持下,我们可以从目的而不是过程的角度去描述编码意图,使得代码几乎不会与具体技术实现产生耦合,若要更换一种技术实现,只需要调整配置中的声明便可做到。
服务网格体系:
**目标一:**实现在大规模虚拟服务下可管理、可观测的系统。
必须找到某种方法,针对应用系统整体层面,而不是针对单一微服务来连接、调度、配置和观测服务的执行情况。此时,可视化整个系统的服务调用关系,动态配置调节服务节点的断路、重试和均衡参数,针对请求统一收集服务间的处理日志等功能就不再是系统锦上添花的外围功能了,而是关乎系统是否能够正常运行、运维的必要支撑点。
**目标二:**在代码层面,裁剪技术栈深度,回归单体架构中基于 Spring Boot 的开发模式,而不是 Spring Cloud 或者 Spring Cloud Kubernetes 的技术架构。
我们并不是要去开历史的倒车,相反,我们是很贪心地希望开发重新变得简单的同时,又不能放弃现在微服务带来的一切好处。在这个版本的 Fenix’s Bookstore 里,所有与 Spring Cloud 相关的技术组件,如上个版本遗留的 Zuul 网关、Hystrix 断路器,还有上个版本新引入用于感知适配 Kubernetes 环境的 Spring Cloud Kubernetes 都将会被拆除掉。如果只观察单个微服务的技术堆栈,它与最初的单体架构几乎没有任何不同——甚至还更加简单了,连从单体架构开始一直保护着服务调用安全的 Spring Security 都移除掉(由于 Fenix’s Bookstore 借用了 Spring Security OAuth2 的密码模式做为登陆服务的端点,所以在 Jar 包层面 Spring Security 还是存在的,但其用于安全保护的 Servlet 和 Filter 已经被关闭掉)
在谈服务网格之前,需要先了解边车模式;而谈到边车模式,需要先了解一下云原生;
云原生
云原生架构是一种基于云环境设计和构建应用程序的方法,它天然利用了云计算的优势,如弹性、可扩展性、自动化和敏捷性;
云原生应用的概念由云和原生两个部分组成,云在这里指的是云平台,也就是平台即服务(Platform as a Service,PaaS);原生应用指的是专门针对云平台而设计和实现的,充分利用了云平台的特性。应用的微服务可以专注于实现业务逻辑,而把微服务架构的复杂度交给云平台(基础架构)来解决。
解决的问题
- 解放开发,专注与业务场景的设计,技术选型的考究;
- 云平台提供运营、监控、可插拔组件选用功能;
核心要素
- 微服务【springboot cloud、dubbo】
- 容器化【docker、k8s】
- DevOps【开发和运维合体,提供持续交付,核心是CICD】
- 持速交付【持续交付是不误时开发,不停机更新,小步快跑,反传统瀑布式开发模型】
- 服务网格【用于处理服务间通信的专用基础设施层,负责在微服务间进行可靠地请求传递】
- 不可变基础设施【公共镜像不可变】
发布流程
边车模式
先看一张图,这就是边车(Sider Car)模式,将服务治理功能从应用本身剥离出来作为单独进程的方式;
就像边车一样,方向盘进行控制(控制面),挎斗专注业务(业务面)。
边车模式的特点包括:
- 边车是独立部署的进程,这降低了应用程序代码和底层代码的耦合度,有助于异构服务通过边车快速接入微服务体系。
- 边车与父应用程序共享相同的生命周期,与父应用程序一起创建和退役。
- 边车服务不一定是应用程序的一部分,而是与之相关联。
如何理解边车(业务面),它不一定是一个业务服务,但一定是和业务关联的子服务,我目前的公司有时候会将它部署成一个canal-client,或者mysql事务日志监听的listener,只要它是业务体系一环的中间件,都可以参与进去;
下图就是边车模式集群,看起来更直观一些:
方向盘(控制面)的理解,从我自己这两年具象一些的接触经验来看,我们利用Devops进行构建的基础镜像,除了有jar包以外,还有一层前置的路由/负载服务(nginx或ingredient或isito),即流量请求在进入到这个集群之前,是这样的:请求->前置路由->服务,这个前置路由将和云平台整体的流量或DNS解析进行整体调度,体会到这种模式会感觉它真的很强很灵活,有时候一些中间件的,比如MQ之类的路由,都可以进行调度;
再具象化一些,对应到k8s云上,pod是由jar包的应用和前置/后置中间件代理构成;
这种对于开发来说,一个http请求,到自己的服务这段路程,自然会感觉链路会很长(但其实都不慢,因为参与到链路中的组件,一定是低延时且有对应的缓存服务器来容错,基本都是1ms以内甚至更快),出现问题很难排查,确实是这样,但是从另一个角度去看,这何尝不是一个好事,链路长,意味着网络和机房、负载的策略很灵活,于开发者而言,则而是有更多的技术选型,这种在机房和服务迁移的时候,体系的会玲离尽致,所以我们要去了解公司的网络架构和链路,要搞清楚这个请求到我们中间到底经历了哪些组件,组件对应的部门、开发是谁,现在问在座一个问题:测试说,你接口很慢,要是你怎么查,再者如果咱们的接口不慢,但是前端收到的就是超时,如何给出证据让别人协助去查?
和服务网格的关系
边车模式是实现服务网格的一环,更多的是关注服务本身的控制代理;
服务网格是一个更加全面的架构模式,它用于处理微服务之间的通信;
边车到服务网格,是一个逐渐忽略语言差异的过程,只要符合微服务的理念和网格代理的管控,都可以参与进去;
服务网格通过在每个微服务实例旁边部署一个轻量级的网络代理(通常是边车进程),来实现服务间的流量管理、安全性、可观察性等功能。这些代理形成了一个网络层,称为服务网格,负责处理服务间的请求路由、负载均衡、熔断、重试等逻辑。【即又抽象了边车代理之上的网络层,来管控所有的微服务,统一调度】
感兴趣可以了解一下ingress和istio的资料;
https://cloud.tencent.com/developer/article/2371166
参考资料
- https://juejin.cn/post/7125999608991318030?searchId=202409301114327F98A01FC81692113DE2
- https://juejin.cn/post/7342391308614877196?searchId=20240929192148779A42CE3A5B72BCB60C
- https://juejin.cn/post/7344571285849178124?searchId=202410021107511162288A84290265EFC8
- https://www.infoq.cn/article/k4E7IXHOgihMNSEoUz9w【强推,高质量文章】