学习目标
- 回顾架构的演进。
- 明确springcloud是什么?
- 明确spring、springboot和springcloud之间的关系。
- 了解springcloud的常用组件及其作用。
第1章 架构演进
1、单体架构
我相信,绝大部分同学都用过SSM框架进行过开发,当时你们所在项目组肯定是将所有的功能模块全部放在了同一个框架里面,只是不同的功能建了一个不同的包,然后所有的功能模块数据存储在一个数据库里面,然后通过一台Tomcat容器去启动服务。
这种架构在最开始公司业务量、数据量、并发量小的情况下是没问题的,甚至对于开发人员更友好。
但是来了,但是随着你公司的发展,业务量增大,功能需求增多,数据量并发量也增大的时候,单体架构就不行了,为什么呢?
- 随着业务量增大,单台Tomcat很容易达到性能瓶颈,一般的服务器上Tomcat的最大并发量也就在200左右。
- 因为只有一台服务器,出现问题就直接挂掉了,此时客户端都访问不了服务,这个时候就让我想起了,读大学的时候选选修课,每次都要等好几个小时才能选上,体验极差。
2、集群架构
为了解决上面的这些问题,必须要从根源上进行优化。此时集群架构出现。
集群架构的逻辑其实很简单,它就是把整个系统从一台服务器上部署变成了多台服务器部署,只是对整个系统的复制拷贝。然后增加Nginx服务器做负载均衡而已。
但是集群架构也存在一些问题:
- 如果系统中的某个很小的功能发生了版本迭代,那这个时候就需要将所有的系统全部停掉,然后进行更新。而且可能整个系统非常庞大了,开发这个大系统的部门人员可能也非常多组织架构也不好管理。
- 虽然你系统做了集群,但是数据库往往才是制约你系统性能的最大因素,当并发量大了,数据量大了,数据库是处理不过来的。
3、业务垂直化拆分
针对上面的问题,架构再一次需要改进,整个大系统不适用了,就将不同的功能模块拆分成小系统。
对业务进行垂直化拆分,简单来说,就是可以按照系统的业务功能拆分出多个业务模块子系统。每个子系统由不同的业务团队负责。
4、服务化改造
随着对业务系统进行垂直化改造之后,以业务功能纬度拆分出来多个子系统,而在各个子系统中,会存在比较多的共享业务,比如用户信息查询,在支付业务中会涉及到、在首页中也会涉及到。那么势必会造成重复开发产生非常多的冗余代码。那么这个时候就引入了服务化改造的思想,也就是 SOA把一些通用的、会被多个上层服务调用的模块独立拆分出来,形成一些共享的基础服务。这些被拆分出来的共享服务相对来说是比较独立,并且可重用。 比如用户管理服务,包含用户注册、用户查询等功能。比如单点登录服务。
SOA 的核心目标就是通过服务的流程化来实现业务的灵活性,而这个流程化其实就是由一系列相关联的任务组成,这一系列相关联的任务可以通过一系列的服务组合来实现具体的业务功能SOA 面向服务架构,从语义上说,它与面向过程、面向对象、面向组件一样,是一种软件组建及开发的方式。所以在 SOA 中,服务是最核心的抽象手段,业务被划分为一些列粗粒度的业务服务和业务流程。
SOA 中更强调 ESB 企业服务总线,企业服务总线可以使得服务之间的交互是动态的,以及服务位置是透明的。这样的好处是服务的调用者和服务的提供者之间是高度解耦的。从而使得服务有更高的灵活性以及隔离性。
ESB: 是从面相服务架构(SOA)发展过来的,主要是对多个系统中的服务调用者和服务提供者的解耦。ESB 本身提供了服务暴露、接入、协议转化、数据格式转化、路由等功能。
SOA 主要解决的问题:
- 信息孤岛
- 互联互通
- 业务重用
5、微服务架构
业务系统实施服务化改造后,原本共享的业务被拆分,形成可复用的服务,可以在最大程度上避免共享业务的重复建设、资源连接瓶颈等问题出现。那么那些被拆分出来的服务,是否也需要以业务功能为维度来进行拆分,使之能够独立进行部署,以降低业务藕合和提升容错性呢?
微服务并不是一种新思想的方法。它更像是一种思想的精炼,是一种服务化思想的最佳实践方向而已,所以我认为微服务其实是在 SOA 思路下,随着各个企业对于服务化治理上不断地完善,以及对软件的交付链路以及基础设施逐步成熟之下的一种自然的产物。 微服务也是一种面向服务的架构模型,只是它更强调服务的粒度。也就是服务的职责更加单一更加精炼我们也可以把 SOA 看成是微服务的超集。 也就是多个微服务可以组成一个 soa 服务。
6、微服务和 SOA 架构的区别
经常会有同学问,微服务和 SOA 架构有什么区别。这个区别一定要从架构的发展过程来了解。这两种架构模式,其实本质上应该是在分布式架构这条时间线上,基于服务化思想的不断完善,以及基础设施的逐步成熟之下的一种升级。既然存在于时间线的先后,那也就意味着,这两种架构模式所关注的点不一样。
SOA | MSA(微服务) |
遵循“尽可能多地共享”架构方法 | 遵循“尽可能少地共享”架构方法 |
重要性在于业务功能重用 | 重要性在于“有界上下文”的概念 |
他们有共同的治理和标准 | 他们注重人、合作和其他选择的自由 |
使用企业服务总线(Enterprise Service bus,ESB)进行通信 | 简单消息传递系统 |
它们支持多种消息协议 | 使用轻量级协议,如HTTP/REST等 |
具有更多开销的多线程来处理I/O | 单线程通常使用事件循环特性来进行非锁定I/O处理 |
最大限度地提高应用程序服务的可重用性 | 重点在于解耦 |
传统的关系数据库更常用 | 现代的关系数据库更常用 |
一个系统性的改变需要修改整体 | 一个系统性的改变是创造一个新的服务 |
DevOps/Continuous Delivery正在变得流行,但还没有成为主流 | 人们强烈关注DevOps/Continuous Delivery |
第2章 Spring Cloud
上一章讲到了架构的演进过程,事实上不管什么架构,都是需要通过合适的框架技术进行落地,从最开始的spring框架,到后来的springboot,再到现在的springcloud,那为什么需要springcloud呢?spring为什么不行呢?
要想整体弄明白这些问题,那我们接下来先弄清楚几个概念,自己在脑海里面形成一套体系:
- spring在开发过程中有什么问题?
- springboot的出现解决了什么?
- springboot跟springcloud是什么关系
- springcloud是什么?它包含了什么?
1、spring的问题
事实上spring的出现就是为了简化开发的,spring的核心概念绝大部分同学都能说出来,无非就是3个,IoC、DI、AOP,下面稍微解释一下这仨兄弟是干嘛的。
- IoC实际上就是一个容器,它就是用来装Bean对象的;回到最最基础的层面,我们java开发就是在不断的通过new创建对象,然后拿到对象之后调用对象里面的方法。OK,那在实际开发过程中,如果所有的对象都需要手动去创建将是一个非常繁琐的过程,也许你有1万个类,然后这1万个类在各种地方都要创建对象,这个时候假设用到了A类的对象,然后你在B类中new了对象,如果要在C、D、E等等类中要用到这个对象的话,将会很麻烦,这只是一种情况,在开发中这种类似的现象随处可见,所以spring为了解决这个过程,设计了一个IoC的功能,你就理解成一个中心容器,用来装项目中几乎所有需要用到的Bean对象。
- IoC的概念理解了,那么这个时候你要想,对象创建了,但是对象里面可能会存在别的一些成员属性,而这些成员属性又是另外的一些对象,举个例子就是A对象里面有个成员属性是B对象,那这个时候你要去进行引用的关联,这一步也非常麻烦和繁琐,怎么办呢?spring的DI帮你完成了,在A对象new的过程中,spring就会去中心容器找有没有B对象,有的话就把这个B对象赋值给A对象的属性。
- AOP的概念其实更好理解,它是基于动态代理完成的,你们要清晰的指导,代理就是做增强的,什么意思呢?假设有一个对象的业务功能就是创建订单,OK,那我不想直接调用这个对象的创建订单功能,我想在创建订单之前和之后干点别的事情,比如说打印日志这个事,这个时候就用到了代理。
OK,spring基于这仨兄弟确实简化了很多开发的流程,但是,在最开始的过程中spring在进行IoC注入对象的过程中,它是基于XML方式的,这个逻辑很容易理解,就是你要把什么对象放到容器中去,只需要在XML文件中配置一下就好了。
但是,正因为这个,使得spring变的无比的繁琐,你想想,一个项目中得用到多少个对象,每个对象都去配置一下,完犊子了。要写无数个XML文件了。
spring开始发力,要优化了,引入注解,但是没用啊,如果你项目要集成别的组件呢?比如redis,比如mybatis。甚至在微服务项目中要引入集成各种组件的话,那更加崩溃。
其实归根结底,spring还是没有解决IoC注入的复杂流程,以及外部化配置的统一管理。
2、springboot
看过springboot源码的同学都知道,springboot底层其实会走一遍spring的流程。也就是springboot依赖于spring,同时它也在spring的基础之上作了一些工作。
具体作了啥,实际上就是解决IoC自动注入和配置统一管理,使得这个工作不再需要程序员去做了,框架自己干了。具体怎么解决的参照之前的内容。
3、springcloud生态
先明确springcloud是什么?网上都说,啊呀springcloud就是做微服务的,它是一个生态啊等等。进说一些我们听不懂的。
那我这里用最简单的语言去解释一下:
springcloud就是springboot集成各种各样starter组件的一个集体,springcloud底层核心框架就是springboot,然后springboot集成不同组件的时候不需要程序员去写XML文件以及配置文件了,而是一些好事之徒,他们基于springboot自动装配原理写了starter组件,然后将这些starter组件和springboot的整体我们给了一个名字叫做springcloud。
明白了吧,那知道springcloud是什么之后,在来看这个生态里面包含了啥,springboot我知道了,starter组件有哪些呢?
这个不用去背,我们自己根据数据流向从整体上去串一串就好了,当你串明白了,那你离架构师就不是太远了。
(1)网关
Gateway组件
我们知道 spring cloud 可以用来开发微服务,但是应该很少有同学真正知道 spring cloud 是什么。
官方的解释是:spring cloud 提供了一些可以让开发者快速构建分布式应用的工具,这些服务可以很好的工作在任何分布式环境下。
既然提供的是一些快速构建微服务应用的工具,那么我们需要了解微服务开发过程中需要解决哪些问题?
在微服务实施之后,各个服务的拆分粒度很小,对于客户端来说,做一个操作可能会涉及到后端的多个服务组件的调用,那意味着它需要频繁的发起多次访问才能进行数据聚合实现用户的功能。
如果我们在所有的微服务之前增加一个网关,对于客户端来说它需要做什么功能操作直接调用网关并且告诉网关所要做的事情即可,网关根据请求的功能对后端的多个服务的数据进行聚合聚合哦从而减少客户端的调用频次。
并且,由于有了网关的聚合,我们还可以在网关层对请求进行统一鉴权和认证; 包括还可以实现限流、请求日志统一记录、 灰度发布等等。
(2)远程通信
Openfeign、Dubbo
服务拆分以后就会涉及到服务的远程通信,比如 http 协议或者 rpc 协议。
(3)服务发现
Eureka、Nacos
在满足基础通信的基础上,如何做到服务的统一管理以及服务的动态感知,就需要涉及到服务的注册中心来实现服务注册和发现的功能。
(4)负载均衡
Ribbon、Dubbo
假设服务提供者为了扩大吞吐量,采用 10 台机器的集群部署,这个时候客户端从注册中心获得服务以后,应该调用哪台机器呢?
所以必然有一种负载均衡的机制,来实现客户端请求的分发。
(5)熔断、限流、降级
Hystrix、Sentinel
在分布式架构中,各个服务节点一定需要满足高可用,所以对于服务本身来说,一方面是在有准备的前提下做好充足的扩容。另一方面,服务需要有熔断、限流、降级的能力。
当一个服务调用另外一个服务,可能因为网络原因、或者连接池满等问题导致频繁出现错误,需要有一种熔断机制,来防止因为请求堆积导致整个应用雪崩。
当发现整个系统的确负载过高的时候,可以选择降级某些功能或某些调用,保证最重要的交易流程的通过,以及最重要的资源全部用于保证最核心的流程。
在设置了熔断以及降级策略后,还有一种手段来保护系统,就是限流算法。
我们能够通过全链路压测了解到整个系统的吞吐量,但实际上的流量可能会超过我们预期的值,比如存在恶意攻击、或者突然的高峰流量。在这种情况下可以通过限流来保护系统不崩溃,但是对于部分用户来说,会出现被限流导致体验不好的情况。
(6)配置中心
Config、Nacos
服务拆分以后,服务的数量非常多,如果所有的配置都以配置文件的方式放在应用本地的话,非常难以管理,可以想象当有几百上千个进程中有一个配置出现了问题,是很难将它找出来的,因而需要有统一的配置中心,来管理所有的配置,进行统一的配置下发。
在微服务中,配置往往分为几类,一类是几乎不变的配置,这种配置可以直接打在容器镜像里面,第二类是启动时就会确定的配置,这种配置往往通过环境变量,在容器启动的时候传进去,第三类就是统一的配置,需要通过配置中心进行下发,例如在大促的情况下,有些功能需要降级,哪些功能可以降级,哪些功能不能降级,都可以在配置文件中统一配置。
(7)分布式事务
Seata
对于数据库的垂直拆分,已经服务的拆分,单体的数据库事务完全不能满足需求了,这个时候就需要一个第三方的协调工具来做到统一管理事务提交回滚等操作,这个时候Seata出现了。
4、服务带来的问题
(1)业务团队的痛点
- 对于业务开发团队而言,最强的是技术吗?一定不是,业务团队最强的一定是对于业务的理解和熟悉程度。
- 而业务应用的核心价值,就是为了实现业务场景,而不是写微服务,微服务只是一种实现业务的手段。
- 业务团队除了关心业务之外,他们所面临的最大的挑战在于,如何保证系统的稳定性何可扩展性、如何设计一个安全的 open api。如果对服务进行拆分、如何保证跨库的数据一致性。以及对于旧系统的改造。
- 于公司层面而言,业务团队的压力还来自于时间人力的投入,我们用于被各种 deadline 赶着走。所以作为一个业务程序员,如果在这个 deadline 之前还需要花更多的时间投入在spring cloud 这些工具的学习上,那无疑是雪上加霜。公司对于业务团队的考核,永远只看结果!
(2)跨语言带来的问题
微服务有一个很重要的特性,就是不同的微服务可以采用自己最擅长的语言来编写程序。这种特性在企业中落地的时候又会带来一些问题。
比如公司内部会开发一些公共的类库或者框架,也或者会使用第三方的类库或者框架来实现某些功能。
但是由于公司的微服务用了各种各样的语言,那意味着这些类库需要针对不同的语言开发兼容版本。如果是主流语言还好,如果是一些小众语言,那对于这些基础组件的开发者而言无疑是晴天霹雳.
(3)总结
从这些痛点中可以发现,我们所做的所有非业务类的事情,都是为了保证把请求发送到正确的地方,并且能够及时或得正确的结果。那对于对于业务开发人员而言,是否有必要去关心这些呢?
回到最开始我们说的一个例子,在进行计算机网络通信的时候,开发人员有必要去关心网络通信的细节吗? 我们在使用 http 协议进行数据传输时,关心过底层是使用 TCP 还是 udp?数据是怎么传输的?
既然我们不需要关心这些,那对于微服务架构中的这些问题,业务开发人员为什么一定要关心服务的通讯呢?