项目情景发展历程
:很久很久以后,敏小言和老胡开的小超市,突然发生了一些变故:数据管理【分为历史数据、实时数据、预测数据】、视频监控模块、预警处理等三个模块
,也是SSM下的,那么跟超市是一个路子。用户太多了访问量太大了怎么办
?---->这样来解决,看框图中用硬件或者软件实现的负载均衡
(横向扩展(水平拆分)服务器数量----->假设有两台服务器,A服务器占用98%资源,B服务器占用了10%资源,首先资源分配不公平,万一A服务器崩了多数人不久疯了,所以得让AB服务器资源均衡一点----------->负载均衡:Nginx,让用户觉得就像在访问一台服务器,但其实不是
)----->通过负载均衡技术,将流量尽可能均摊
到集群中的每台机器上,以此克服单台机器硬件资源的限制
,做到横向扩展
。四种负载均衡策略
:https://blog.csdn.net/m0_52436398/article/details/125180182咱们的业务系统本身中有些流量较小的服务只需要几台机器构成的集群即可,而核心业务则需要成百上千的机器来支持
,此时将一个巨型业务系统拆分成多个微服务,然后根据不同服务对资源的不同要求,选择更合理的硬件资源就可以最大化系统资源的利用率。并且除了最大化系统资源的利用率,还可以在服务维度进行重用,在需要某个服务的时候,直接接入即可,从而提高开发效率。】,你像上面横向扩展服务器数量就解决不了这个问题---------->将原来的整体项目拆开模块化各个模块(IDEA中一个module或者一个jar包)放到不同的电脑上(所有的模块都有自己的数据库),模块之间相互调用就行了,就可以实现给操作量高的功能模块分多一点服务器,给操作量少的功能模块分少一点服务器(HTTP RestFul风格,上一个模块所在的电脑把上一个操作处理完之后给下一个模块所在的另一台电脑发个请求,让另一个电脑上的模块去处理)
----->但是问题来了,你把原来整体项目的各个功能模块分为不同的单独的模块,这些模块之间肯定要相互通信相互联系呀,在解决相互通信中产生的问题(问题主要分为四个方面,从这四个方面进行解决)的过程中出现了很多的解决方案---->)分布式服务架构下,系统被拆分成不同的服务比如短信服务、安全服务,每个服务独立提供系统的某个核心服务
。拆分为多个微服务模块就可以最大化系统资源的利用率
。整个服务可以最大化地实现重用,也可以更加灵活地扩展
。你把原来整体项目的各个功能模块分为不同的单独的模块,这些模块之间肯定要相互通信相互联系呀,在解决相互通信中产生的问题
四个方面问题之一
:1.这么多服务,客户端该如何去选择哪一个去访问(API网关,服务路由)
网关主要做了一件事情:请求过滤
】【服务网关(API Gateway)不是为了解决微服务之间调用的紧耦合问题,服务网关(API Gateway)主要是为了简化客户端的工作。其实它还可以用来降低函数之间的耦合度。有了API Gateway之后,一旦服务接口修改,你可能只需要修改API Gateway, 而不必修改每个调用这个函数的客户端
,这样就减少了程序的耦合性。】
四个方面问题之二
:2.这么多服务,位于不同服务器上的服务之间该如何通信或者说互相调用(HTTP,RPC框架,异步调用)
服务调用有两种方式,一种是RPC方式【紧耦合的RPC方式】,另一种是事件驱动(Event-driven)方式,也就是发消息方式【消息方式是松耦合方式】
。也有换一个角度看服务调用的两种方式的:紧耦合的主要问题就是客户端和服务端的升级不同步。服务端总是先升级,客户端可能有很多,如果要求它们同时升级是不现实的。它们有各自的部署时间表,一般都会选择在下一次部署时顺带升级
。一般有两个办法可以解决这个问题:
服务端向后兼容:这是更通用的方式
。例如你要加一个新功能或有些客户要求给原来的函数增加一个新的参数,但别的客户不需要这个参数。这时你只好新建一个函数,跟原来的功能差不多,只是多了一个参数。这样新旧客户的需求都能满足。它的好处是向后兼容(当然这取决于你使用的协议)。有点像方法重载emmm
使用一个支持向后兼容的RPC协议,现在最好的就是Protobuf gRPC,尤其是在向后兼容上【它给每个服务定义了一个接口,这个接口是与编程语言无关的中性接口,然后你可以用工具生成各个语言的实现代码,供不同语言使用。函数定义的变量都有编号,变量可以是可选类型的,这样就比较好地解决了函数兼容的问题。】
。它能自动调整服务端处理能力去匹配请求数量。第三和第四,接口耦合和发送方式耦合,这两个确实是RPC方式的软肋
。RPC是点对点方式,需要知道对方是谁,它的好处是能够传回返回值。消息既可以点对点,也可以用广播的方式,这样减少了耦合,但也使返回值比较困难
。AI今后会渗入到具体程序中,使程序具有学习功能。而RPC模式注定没有自适应功能。事件驱动本身就具有对事件进行反应的能力,这是自我学习的基础
。把系统中所有的数据都以事件(Event)的方式记录下来,它的持久存储叫Event Store, 一般是建立在数据库或消息队列(例如Kafka)基础之上,并提供了对事件进行操作的接口,例如事件的读写和查询
。事件溯源是由领域驱动设计(Domain-Driven Design)提出来的。事件溯源是微服务的一种存储方式,它是微服务的内部实现细节
。因此你可以决定哪些微服务采用事件溯源方式,哪些不采用,而不必所有的服务都变成事件溯源的。通常 整个应用程序只有一个Event Store【Event Store内部可以分成不同的stream(相当于消息队列中的Topic), 供不同的微服务中的领域实体(Domain Entity)使用。】, 不同的微服务都通过向Event Store发送和接受消息而互相通信
。数据库存储方式只能保存当前状态,而事件溯源则存储了所有的历史状态,因而能根据需要回放到历史上任何一点的状态,具有很大优势。但它也不是一点问题都没有
。
这个网络编程就是来解决咱们位于不同服务器上的服务之间通信的,而网络编程领域的王者就是Netty【网络编程框架】
】可以使用 Java RMI(Java Remote Method Invocation)、Hessian这种支持远程调用的RPC框架来简单地暴露和引用远程服务
。但是!当服务越来越多之后,服务调用关系越来越复杂。当应用访问压力越来越大后,负载均衡以及服务监控的需求也迫在眉睫。我们可以用 F5 这类硬件来做负载均衡,但这样增加了成本,并且存在单点故障的风险
。所以,Dubbo出现了四个方面问题之三
:3.这么多服务,如果对服务们进行统一管理(也就是如何实现服务注册与发现,高可用)
四个方面问题之四
:4.4.这么多服务,用着用着服务突然挂了怎么办
甚至分不清哪个应用要在哪个应用之前启动
,架构师都不能完整的描述应用的架构关系。Dubbo 可以为我们解决服务之间互相是如何调用的
。Dubbo优点是RPC长连接+NIO,性能更高;但协议的局限性,会限制生态发展和兼容性
。
Dubbo 主要是从 RPC 服务调用的特性入手,而Spring Cloud 更多的是强调其在微服务方面提供的整体解决方案
。Dubbo 更多关注远程服务调用功能特性,Spring Cloud 则包含了整体的解决方案,可以认为 Dubbo 支持的功能是 Spring Cloud 的子集
。或者说 Dubbo 和 Spring Cloud 的目标不同,关注的是微服务实现的不同维度
。Dubbo 看重远程服务调用,Spring Cloud 则是作为一个微服务生态,覆盖了从服务调用,到服务治理的各个场景。Spring Cloud 一般使用 HTTP 协议的 RESTful API 调用,RESTful 接口相比 RPC 更为灵活,服务提供方和调用方可以更好地解耦,不需要依赖额外的 jar 包等,更适合微服务的场景。从性能角度考虑,一般来说,会认为 PRC 方式的性能更高,但是如果对请求时延不是特别敏感的业务,是可以忽略这一点的
。Spring Cloud 有各种服务发现组件,包括 Eureka、Consul、Nacos 等。前面提到过,ZooKeeper 实现的是 CAP 中的 CP 一致性,Spring Cloud 中的 Eureka 实现的是 AP 一致性,AP 更适合服务发现的场景
。使用 Spring Cloud 就很少有这个问题,因为各种功能都有了对应的开源实现,应用起来更加简单。特别是,如果项目中已经应用了 Spring 框架、Spring Boot 等技术,可以更方便地集成 Spring Cloud,减少已有项目的迁移成本
。微服务系统架构的一站式解决方案
(springcloud,是一套生态,就是用来解决以上分布式架构的4个问题的(springcloud是基于springboot的,想用springcloud之前就得把springboot学好,Spring Cloud 基于 Spring Boot,是一系列组件的集成,为微服务开发提供一个比较全面的解决方案,包括了服务发现功能、配置管理功能、API 网关、限流熔断组件、调用跟踪等一系列的对应实现
。))Java基基老师的用 Spring Boot 创建微服务的替代方案的文章在 Spring Boot 的基础上轻松地实现微服务项目的构建【SpringCloud中每个服务都是一个单独的SpringBoot,】
。技术组件的完备性是 Spring Cloud 框架的主要优势
】【整体流程大概就是:用户的url经过网关,由网关拦截住URL请求映射到服务调用端中的哪个Controller中(此时的Controller就算是咱们的客户端,而每个controller都可以部署在不同的节点上或者说服务器上
),而controller也是很多controller服务,或者说web端的微服务是很多的,每一个微服务都是单独部署在一个机器上【对应不同的IP地址和port号】,而客户端每建立一个连接都会产生一个session,为了实现sessionid等信息的共享,搞了session共享数据信息。【此时做集群,因为所有的流量都经过网关,平衡一下负载,并且提高吞吐量】。做一个最简单的微服务,用户—>controller—>service(调用远程service像调用本地service一样,@Service,像不像RPC或者说Dubbo)】用于将服务和服务实例与分布式消息系统链接在一起的事件总线
。在集群中传播状态更改很有用(例如配置更改事件)
。拥有了 Spring Cloud Bus 之后,我们只需要创建一个简单的请求,并且加上 @ResfreshScope 注解就能进行配置的动态修改了
管理和广播分布式系统中的消息
,也就是消息引擎系统中的广播模式。当然作为 消息总线 的 Spring Cloud Bus 可以做很多事而不仅仅是客户端的配置刷新功能。Spring Cloud拥有更成熟的Spring社区生态,更多成熟的企业应用案例;但也存在一定不足,比如跨语言平台问题、微服务治理对代码侵入性较强
。【Spring Cloud应用特性:Spring Cloud 目前主要的解决方案包括 Spring Cloud Netflix 系列,以及 Spring Cloud Config、Spring Cloud Consul 等。】Linux有架构,MySQL有架构,JVM也有架构,使用Java开发、MySQL存储、跑在Linux上的业务系统也有架构
,应该关注哪一个?想要清楚以上问题需要梳理几个有关系又相似的概念:系统与子系统、模块与组建【模块是逻辑单元,组件是物理单元。】、框架与架构
:
软件系统的顶层结构,架构分类可细分为业务架构、应用架构、技术架构, 代码架构, 部署架构
】。芋道源码老师关于架构分类的文章,很赞 + 码农翻身关于架构师养成的文章
涉及四方面
:就跟咱们最早学面向对象时,思考问题的步骤就分为三步:有哪些类哪些对象,类或者对象中哪些方法哪些成员属性等等、有没有继承等关系。
比如技术选型、解决方案等。也就是这么多技术我该用哪个和哪个呢
。明确系统有哪些部分组成
其实就是开一个连锁店,每个店里面干的事情是一模一样的
。垂直应用架构(第二代架构)。可以看到第二代架构是通过 水平扩展
解决应用级别的扩展等问题,经过优化后,该架构支撑了几十万用户的访问需求,在这一阶段有部分应用已经使用java 完成了mvc架构的重写。当然也存在一些问题。微服务是一起合作的独立小服务单元,可以同步异步调用,也可以独立拆分、独立部署、独立升级,后端中间件、存储资源、数据库等也是独立的,最佳实践是每个微服务都有自己的database,真正意义上实现微服务应用解耦
。五大关键条件
:
如果单体程序已经没法管理了,那么你别无选择。如果没有管理上的问题,那么微服务带给你的只有问题和麻烦。其实,一般公司都没有太多选择,只能采用微服务,不过你可以选择建立比较少的微服务。如果还是没法决定,有一个折中的方案,“内部微服务设计”【如果你还是不能确定是否采用微服务架构,可以先从“内部微服务设计”开始,再逐渐拆分。】
。来自SpringForAll老师的文章那如果我想要从单体改造到微服务的时候,应该怎样搞:
数据管理【分为历史数据、实时数据、预测数据】、视频监控模块、预警处理等三个模块
代码库是分开了,但每个服务都在独立迭代吗?是不是每个需求都要协调一大堆同步接口
?】;CI/CD分开了,每个拆分后的服务都可以独立开发、部署、运行【CI/CD是分开了,但每次发布都是自由的吗?是不是每次功能的发布都拖上了一大推的服务要一起发布?
】;数据库分开了,独立运行,不同业务模块不会互相影响【数据库是分开了,但似乎有个服务挂了,依然导致很多功能就都不正常了?
】但在程序内部可以按照微服务的思想来进行设计。它可以分成多个模块,每个模块是一个微服务,可以由不同的团队管理
。
这个所谓的“内部微服务设计”其实就是DDD,但当时还没有微服务,因此外表看起来是单体程序,但内部已经是微服务的设计了
。它是一个单体程序,省去了多个微服务带来的部署、运维的麻烦
。但它内部是按微服务设计的,如果以后要拆分成微服务会比较容易。至于什么时候拆分不是一个技术问题。【如果负责这个单体程序的各个团队之间不能在部署时间表,服务器优化等方面达成一致,那么就需要拆分了。】将原来的内部service调用改成dubbo或feign这样的远程调用
原本我们在单体应用中,未拆分的远程调用都是内部调用,这个内部调用所能引发的故障率是微乎其微的,而将这部分内容拆成了远程调用后,每一个调用都增加了网络IO的因素,每一次调用的故障率都增加了。那么系统的整体故障率是随着系统拥有多少同步远程调用的数量增加而增加的。当运维团队与开发水平没有没有支持好这部分增加的复杂度的时候,那么改造的系统,必然的稳定性会比原来的单体应用更差
。可以先创建比较大的微服务(更像是服务组合)
后来微服务建立了全套的自动化体系,从程序集成到部署,从全链路跟踪到日志,以及服务检测,服务发现和注册,这样才把微服务的工作量降了下来
。
领域拆分的不合理,引出了过多的同步远程调用【在做拆分的时候,尽可能的减少同步远程调用,取而代之的是走消息的异步交互,同时根据业务需要也可以做适当的数据冗余。这样就能保证,每个被拆分后的微服务之间可以获得更低耦合度。】
缺少分布式的保护机制【很容易出现对远程调用不做足够的保护机制,比如:接口提供方的限流策略(保护自己不被别人搞死),接口调用方的降级策略(保护业务更高的可用性),接口调用方的熔断策略(保护自己不被别人拖死)。只有认真对待每一个分布式环境下的依赖点,那么才能解决因为分布式改造所牵连出的诸多问题。】
咱们做项目,要达到的目标
:
用户发出请求到用户收到系统处理结果所需要的时间。响应时间是系统最重要的性能指标,其直观地反映了系统的“快慢”。
】
这个数字反映了系统的负载特性
。【并发数=QPS*平均响应时间】
一个系统在大部分时间都是可用的【高可用代表系统即使在发生硬件故障或者系统升级的时候,服务仍然是可用的。】,可以为我们提供服务的
。因为有了集群所以就可以东方不亮西方亮。这块出问题了那边可以顶上来,说明我的菜馆是不用歇业关门的。也就是实现了高可用
对于服务来说,冗余的思想就是相同的服务部署多份
,如果正在使用的服务突然挂掉的话,系统可以很快切换到备份服务上,大大减少系统的不可用时间,提高系统的可用性。冗余的思想就是相同的数据备份多份
,这样就可以很简单地提高数据的安全性。由于网络问题、系统或者服务内部的 Bug、服务器宕机、操作系统崩溃等问题的不确定性,我们的系统或者服务永远不可能保证时刻都是可用的状态。为了最大限度的减小系统或者服务出现故障之后带来的影响,我们需要用到的 超时(Timeout) 和 重试(Retry) 机制
。【单体服务通常只涉及数据库、缓存、第三方 API、中间件等的网络调用,而微服务系统内部各个服务之间还存在着网络调用。】通常情况下,我们建议读取超时设置为 1500ms ,这是一个比较普适的值。如果你的系统或者服务对于延迟比较敏感的话,那读取超时值可以适当在 1500ms 的基础上进行缩短。反之,读取超时值也可以在 1500ms 的基础上进行加长,不过,尽量还是不要超过 1500ms 。连接超时可以适当设置长一些,建议在 1000ms ~ 5000ms 之内
。【可以将超时弄成可配置化的参数而不是固定的,比较简单的一种办法就是将超时的值放在配置中心中。这样的话,我们就可以根据系统或者服务的状态动态调整超时值了
。】重试机制一般配合超时机制一起使用,指的是多次发送相同的请求来避免瞬态故障和偶然性故障
。云原生就是在云中构建、运行应用程序的一套完整的技术体系和方法论【技术体系和方法论就目前来说指的是 微服务+DevOps+持续交付+容器化】
应用程序部署在云中
充分利用和发挥云平台的弹性+分布式优势,提升云上资源利用率、缩短开发周期
上云跟云原生确实是不能划等号的
。 上云只是简单地把基础设施能够搬到云上,而云原生是上云的更深层面。云原生它需要借助的是云的 弹性伸缩的能力 ,还有 按量付费 的这种模式,去实现云上的开发、运维、测试、部署等生命周期,只有充分享受到云计算红利的这种模式,我觉得才是叫是真正的云原生
。
按照你的需要给你提供不同粒度的服务
【服务模式是分层模型】,你用的话付费就行【这种模式提供了可用的便捷的按需的网络访问、资源共享池(池子中有网络、服务器、存储、应用、服务)】、提供了 以租代买
的商业模式
从具体的能力上来说,比如说像微服务的拆分能力,容器化的改造能力,服务治理的能力,包括以及像 DevOps 的这些能力,其实都是开发者需要去必备的一些技能。我觉得云原生知识积累跟储备,对于开发者来讲还是尤为重要的
。但服务端的应用都跑在 Linux 上,所以对于业务来说也无伤大雅
。】一个系统由不同语言、不同技术框架所实现的服务来组成在微服务时代是完全合理的
。
如果将字节码直接编译成可以脱离 Java 虚拟机的原生代码则可以解决所有问题
。这也将意味着启动时间长的问题能够彻底解决,因为此时已经不存在初始化虚拟机和类加载的过程、已经不存在即时编译器运行时编译【所有代码都是在编译期编译和优化好的】、厚重的 Runtime 也不会出现在镜像中。Spring 推出了面向云原生的技术 Spring Native、RedHat 开源了 Java 云原生服务框架 Quarkus
。为什么拥抱,就是因为云原生有这些那些好处和优势呀。云原生有什么优势?从两个方面来说:
对于应用程序来说, 云原生可以赋予其更快速开发上线的能力
。应用程序可以更实时、更稳定、更频繁地被部署,而无需完全重新部署。并且,还可以针对特定的服务进行扩缩容,以节省资源
你不需要再花精力搭建复杂的持续交付环境,敏捷基础设施(如 K8S、Docke)开箱即用,自带一站式微服务开发解决方案
扩展性非常差
。这个时候,我们往往需要将单体架构拆分为整体更松散,模块更内聚的微服务架构。每个微服务都在运行在独立的线程下,它们之间通过轻量级通信机制(通常是 REST)进行通信。并且,各个微服务可以使用不同的技术栈,不同的存储技术
。各个微服务独立部署,对于单个微服务的修改,我们仅仅需要重新部署对应的微服务,而不需要重新部署整个系统
。并且,系统中不同的微服务访问压力不同,我们可以对具体的微服务进行扩容缩容,这样更节省资源,节约成本
微服务架构下,服务治理
是不得不面临的一个难题。业界缺少一个多语言的、框架无关、支持异构基础设施的服务治理标准实现。腾讯云在 Techo Day 发布了一款重量级的产品 TSE Polarismesh(北极星)【TSE Polarismesh(北极星) 是腾讯开源的一款功能全面的服务治理中心,支持多种语言(如 Java、Go、C/C++)与异构基础设施(不与具体的部署架构、网络及存储架构绑定),与框架无关。可以将它看成是一站式的分布式和微服务架构解决方案,开箱即用,提供的能力包括服务注册与发现、服务配置、服务限流、服务熔断、服务降级、动态路由等。 Spring Cloud Tencent 的核心就依托于北极星,说到这,可以在看看javaGuide老师写的腾讯正式开源 Spring Cloud Tencent文章】
DevOps 是一种软件交付的理念和方法
。从名字可以看出,DevOps 将开发(Development)和运维(Operations)结合在了一起。不过,DevOps 所代表的理念和实践要比这广阔的多。DevOps 关注的是如何实现应用程序的全生命周期(开发,测试,运维)自动化管理,从而实现更快速、更高质量、更频繁、更稳定的软件交付
。DevOps 团队通常会使用微服务架构来构建应用程序,借助于持续集成和持续部署(CI/CD)来实施 DevOps
。
为了简化开发工作专门抽象出来的一层,通常作为透明的一层接入到现有的分布式应用程序里
未完待续…
巨人的肩膀:
凤凰架构~大佬的书,跟深入理解JVM一样值得多次翻阅
Spring Cloud dalstoon版中文文档:https://www.apiref.com/spring-cloud-zh/dalston/#_router_and_filter_zuul
B站的各位大佬
JavaGuide
Zookeeper官方文档
Dubbo官方文档
https://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247568029&idx=2&sn=9aae8d03e4e9c941db78a3673394e613&chksm=9bd26705aca5ee13a0b0a9ada7432741a7e5c11676e50661da34b7e7632f54882c66c4ce4d20&scene=178&cur_album_id=1776403731354337285#rd
蛮三刀把刀老师关于COLA是由阿里大佬张建飞所提出的一种业务代码架构的最佳实践的文章
SpringForAll老师的计算机架构的伟大思想们
胡说云原生的Daniel Hu老师关于GitLab + Jenkins + Harbor 工具链的快速落地指南
程序猿DD老师关于单体架构服务转型至分布式的经验文章:什么是架构、单体架构类型及其优缺点、分布式架构、单体架构如何向分布式架构转型(对功能进行了拆分、对业务进行拆分、如何划分业务模块、如何在原有模块上拆分、我们在拆分业务的过程中,需要做一些什么操作、)、CQRS 的思想:命令职责查询分离,不单单指代码,同样也是适用于服务
博客园的古霜卡比老师的一文详解微服务架构:以一个网上超市应用为例来说明从单体应用到微服务逐渐演变的过程
vivo互联网技术 Chen Dongxing老师从 热点代码优化 与 Jvm GC两方面调优实战改善服务负载与性能的文章
倚天码农老师的关于微服务之间的最佳调用方式
大佬的关于微服务的比较完整比较细致的文章,值得细看
alauda老师在灵雀云的关于企业级微服务治理与开发的关键概念及选型指南
芋道源码老师有对网关系统设计的模板通用思路:网关【连接两个不同的网络都可以叫网关(工作在数据链路层,在不同或相同类型的LAN之间存储并转发数据帧,必要时进行链路层上的协议转换)、网关所管理的服务粒度可粗可细、网管需要具备的功能【请求路由、服务注册、负载均衡、安全方面】、网关设计思路(网关设计重点主要是三个, 高性能、高可用、高扩展)】与网桥、常见网关对比,用到时可以好好看看
B 站的周志明博士的主题是云原生时代下 Java视频,主要内容是云原生时代下的挑战与 Java 社区的对策:https://mp.weixin.qq.com/s/N6KkffUhsbyIXqDfp1moag