聊SpringCloud之前先聊聊微服务
微服务架构是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦
微服务架构是个很有趣的概念,它的主要作用是将功能分解到离散的各个服务当中,从而降低系统的耦合性,并提供更加灵活的服务支持。
**概念:**把一个大型的单个应用程序和服务拆分为数个甚至数十个的支持微服务,它可扩展单个组件而不是整个的应用程序堆栈,从而满足服务等级协议。
**定义:**围绕业务领域组件来创建应用,这些应用可独立地进行开发、管理和迭代。在分散的组件中使用云架构和平台式部署、管理和服务功能,使产品交付变得更加简单。
**本质:**用一些功能比较明确、业务比较精练的服务去解决更大、更实际的问题。
微服务架构不是一下就出来的,而是经过市场的发展,技术的升级而逐渐出现的。
单体应用就是将所有的功能都打包成一个独立的单元。当网站访问量很小是,只需要一个应用,将所有功能部署到一起,以便减少部署节点和成本。
特点:
所有的功能都集成在一个项目 中所有的功能打包成war包部署到服务器应用与数据库分开部署通过部署应用集群和数据库集群来提高系统的性能优点:
开发简单。一个IDE就可以快速构建单体应用。便于共享。单个文档包含所有的功能,传递共享很方便。易于测试。一旦部署,所有的服务或特性就可以使用了,简化了测试过程,没有额外的依赖。容易部署。项目就一个war包,Tomcat安装好了之后,丢进去就可以运行。缺点:
妨碍持续交互,就是说产品上线后,如果后期需要修改代码,则需要对整个项目进行重新打包,再次上传到服务器。不够灵活,就是随着时间推移,功能越来越多,那么在编译打包部署项目的时候,就会很慢,降低了团队开发的灵活性。技术栈受限,就是说一旦确定了使用一种语言,就不能使用别的语言,不能混合别的语言,需要考虑各语言之间的兼容性。可靠性差,就说是,一旦一个地方出了问题,整个项目就会崩掉。伸缩性差,就比如说,在某个场景下某功能并发量会很大,需要加机器,但是如果是单体应用,整个应用是一体的,就需要对整个应用都加机器,造成不必要的性能浪费。、技术债务,就是说,单体应用写代码的时候不会分的很细,什么技术都使用了,写在了一起,耦合度很高,后期维护什么的很不方便,原本两天就能完成的工作,就会变得很麻烦。将单体应用的每个功能拆分文为项目独立存在。
特点:
以单体结构规模的项目为单位进行垂直划分,就是将一个大项目拆分成一个一个单体结构项目。项目与项目之间存在数据冗余,耦合性较大,比如上图中三个项目都存在用户信息。项目之间的接口多为数据同步功能,如:数据库之间的数据库,通过网络接口进行数据库同步。优点:
架构简单、开发成本低避免单体无线扩张,就是说单体应用越开发功能越多,但是垂直应用不会,垂直应用本来就是每个功能独立拆分出来的,后期如果要要新增功能,直接独立为一个新的项目就行。系统拆分,流量分担,解决并发问题。单体应用都是在一起的,而垂直应用是拆分开的,对服务器来说,不会像单体应用一样有那么大的压力。可以针对不同的功能进行升级,不用像单体应用一样,一处改动,就需要对整个项目进行编译打包数据。系统间相对独立。各个功能是分开的,一个功能出现问题,最多就是该功能无法使用,而不会造成整个大项目的崩溃。缺点:
垂直应用各个之间是独立了,相同功能代码都需要重复编写,代码冗余。系统之间相互调用,IP如果发生改变,调用系统需要手动更改。各个功能之间的调用是根据IP和端口连接调用的,如果一个功能的ip或者端口发生了改变,则调用该功能的项目都要手动更改为新的ip或者端口。伸缩性依旧很差,如果要加机器,还要对整个拆分后的项目进行增加。成本高。特点:
基于 SOA 的架构思想将重复公用的功能抽取为组件,以服务的形式给各系统提供服务。各项目(系统)与服务之间采用 WebService、RPC 等方式进行通信。使用 ESB 企业服务总线作为项目与服务之间通信的桥梁。优点:
重复的功能抽取为服务,提供开发效率采用该ESB,减少系统中的接口耦合可以针对不同的服务特点指定集群优化方案。缺点:
系统与服务器的界限模糊服务器的拆分粒度比较大,系统与服务之间耦合较高涉及多种中间件,对开发人员技术栈要求比较高服务关系复杂,运维,测试,部署变得困难优点:
团队独立。技术独立。(去中心化)??前后端分离数据库分离微服务拆分粒度更细团队新人可以更快的投入生产可以使用不同的语言适用于互联网时代,产品迭代周期短缺点:
微服务过多,服务治理成本高,不利于维护。分布式系统开发技术成本高(网络问题,容错问题,调用关系,分布式事务…)可能会有异步通信运维,部署…微服务就是SOA发展出来的产物,他是一种比较现代化更细粒度的SOA实现方式。微服务是一种架构风格,架构就是为了解耦,实际开发使用的还是分布式。
通常有一个理念就是:通过机器可以解决容量和可用性问题(一台不行就两台)。
《The Art of Scalability》一书提出了一个系统的可扩展模型——AKF 可扩展立方。这个立方体中沿着三个坐标轴设置分别为 X,Y,Z。
一个叫 AKF 的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。
Y轴
就是微服务的拆分模式,按照功能拆分。
X轴
水平复制,一台机器不行,就再来一台机器…
Z轴
分区,为了更好的使用体验,进行分区,在每个地区(例如:华南区、华东区…)都建立一套自己的服务器,各个地区之间是相互隔离又是完整的。
代表技术:Servlet+JSP+JavaBean
在前后端不分离的应用模式中,前端看到的页面都是由后端控制的。例如JSP就是未分离的,需要在前端页面中写Java代码。可以想象,在前端中写后端代码是一个多么操蛋的事情。
<body> <% request.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); System.out.print(username); %> </body>代表技术::SSH、SSM、Freemarker…
半分离,例如Freemarker模板引擎, 在发起请求的时候,后端返回携带Model数据,然后前端通过模板引擎解析获数据。这种方式虽然不用在前端写后端代码,但是要获取后端返回的数据还需要使用模板引擎的语法去解析数据。
代表技术:Node.js前端开发框架。VueJS,ReactJS,AngularJS
已分离的应用模式中,后端仅仅返回前端所需要的数据(通常是JSON格式),而不再进行其它操作,具体返回的JSON数据怎么使用,由前端开发者安排。这样就可以做到前后端分离,前端和后端,各自做自己要实现的功能,后端写完后只需要给个接口给前端即可。
总结
前后端技术分离,可以由各自的开发团队来对各自的领域进行优化,这样前端的用户体验优化效果更好。
前后端分离模式下,前后端交互界面更清晰,就剩下了接口模型,后端的接口简洁明了,更容易维护。
前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支持多个前端:例如:微信 h5 前端、PC 前端、安卓前端、IOS 前端。
如果一个数据需要被多个服务共享才能完成一笔交易,那么这个数据被称为状态。进而依赖这个"状态"数据的服务被称为有状态服务,反之称为无状态服务。
IP:PORT/接口
JSON报文,轻量级,人机均可阅读HTTP无状态,加密又可以依附HTTPS有一套约定俗成的接口设计风格CAP原则指的是,在构建分布式项目时,只能满足其中两项,三者不可兼得。业界的人花了两年时间论证该信息。
分析:分布式项目,必然会设计数据分区的问题。肯定需要P,那么项目肯定是CP或者AP。
BASE理论其实核心就是:最终一致性。
这里简单说明,具体在Eureka注册中心中描述。
客户端如何访问服务?
后台有N个服务,前台就需要管理N个地址,一个服务的下线/升级/扩容,前端都要从新部署
所以,一般在后台N个服务和客户端之间会有一个代理(API Gateway),作用:
提供统一入口聚合后台服务,节省流量,提供用户体验提供安全、流控、过滤、缓存、路由、监控…服务之间如何通信?
同步通信:
RestfulRPC异步通信:
MQ这么多服务如何查找?
利用注册中心机制,将服务集群注册到注册中心,然后把服务的状态推送到各个节点,比如动态的服务扩容、服务的下线等。通过心跳机制检测服务是否可用。
服务挂了怎么办?
服务容错手段:
请求缓存:支持将一个请求与返回结果做缓存处理请求合并:将相同的请求进行合并然后调用批处理接口请求限流:当请求过多时,可以采取限流措施,降低机器的负载压力服务隔离:限制调用分布式服务的资源,某一个调用的服务出现问题不会影响其它服务调用服务熔断:牺牲局部服务,保证整体系统稳定性的措施服务降级:服务熔断后,客户端调用自己本地方法返回缺省值所有的API调用接入到API网关层,由网关层统一提供入口和输出,屏蔽底层的微服务。
一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个 API 服务提供团队可以专注于自己的的业务逻辑处理,而 API 网关更专注于安全、流量、路由等问题。
微服务架构中,通常存在多个服务之间的远程调用。目前主流的远程调用技术有基于 HTTP 的 RESTful 接口和基于 TCP 的 RPC 协议。以上两种都属于同步通信,还有基于队列模式的异步通信。
REST:一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持HTTP协议。RPC:进程间的通信共享,允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单更透明。RPC 框架负责屏蔽底层的传输方式、序列化方式和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。 比较项RESTRPC通讯协议HTTP一般使用 TCP性能略低较高灵活度高低应用微服务架构SOA 架构服务高可用的保证手段,为了保证高可用,每一个微服务都需要部署多个服务实例来提供服务,此时就需要根据不同的负载均衡策略对服务进行调用。
微服务中,一个请求经常会设计到调用多个服务,如果其中某个服务不可用,没有做服务容错的话,极有可能会造成一连串的服务不可用,这就是服务雪峰效应。最终的结果就是,一个服务不可用,导致一系列服务不可用。
造成雪崩的原因有三点:
服务提供者不可用(硬件故障、程序BUG、缓存击穿、用户大量请求等)重试加大流量(用户重试,代码逻辑重试)消费者服务不可用(同步等待造成的资源浪费)没法预防雪崩效应的发生,只能尽可能去做好容错。服务容错的三个核心思想是:
不被外界环境影响不被上游请求压垮不被下游响应拖垮随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控等等。单纯的理解链路追踪,就是指一次任务的开始到结束,期间调用的所有系统及耗时(时间跨度)都可以完整记录下来。
微服务系统中,每个微服务不仅仅只有代码,还需要连接其他资源,例如数据库的配置或功能性的开关 MySQL、Redis 、Security 等相关的配置。除了项目运行的基础配置之外,还有一些配置是与业务有关系的,比如说七牛存储、短信和邮件相关,或者一些业务上的开关。
但是随着微服务系统的不断迭代,整个微服务系统可能会成为一个网状结构,这个时候就要考虑整个微服务系统的扩展性、伸缩性、耦合性等等。其中一个很重要的环节就是配置管理的问题。
常规配置管理方案的缺点:
硬编码(需要修改代码,繁琐,风险大)properties 或者 yml(集群环境下需要替换和重启)xml(重新打包和重启)常规配置管理有很大的缺点,所以采用 Spring Cloud Config 或 Consul 或 Apollo 或 Nacos 等配置中心集中式的来管理每个服务的配置信息。
从单体应用架构到分布式应用架构再到微服务架构,应用的安全访问在不断的经受考验。为了适应架构的变化、需求的变化,身份认证与鉴权方案也在不断的变革。面对数十个甚至上百个微服务之间的调用,如何保证高效安全的身份认证?面对外部的服务访问,该如何提供细粒度的鉴权方案?
David Borsos 在伦敦的微服务大会上提出了四种解决方案:
这种方案意味着每个面向用户的服务都必须与认证服务交互,这会产生大量非常琐碎的网络流量和重复的工作,随着微服务应用的增多,这种方案的弊端会更加明显。
分布式会话方案原理主要是将关于用户认证的信息存储在共享存储中,且通常由用户会话作为 Key 来实现的简单分布式哈希映射。当用户访问微服务时,用户数据可以从共享存储中获取。这种方案的缺点在于共享存储需要一定保护机制,因此需要通过安全链接来访问,这时解决方案的实现就通常具有相当高的复杂性了。
令牌在客户端生成,由身份验证服务进行签名,并且必须包含足够的信息,以便可以在所有微服务中建立用户身份。令牌会附加到每个请求上,为微服务提供用户身份验证,这种解决方案的安全性相对较好,但身份验证注销是一个大问题,缓解这种情况的方法可以使用短期令牌和频繁检查认证服务等。对于客户端令牌的编码方案,David Borsos 更喜欢使用 JSON Web Tokens(JWT),它足够简单且库支持程度也比较好。
这个方案意味着所有请求都通过网关,从而有效地隐藏了微服务。 在请求时,网关将原始用户令牌转换为内部会话 ID 令牌。在这种情况下,注销就不是问题,因为网关可以在注销时撤销用户的令牌。
微服务架构下,更倾向于 David Borsos 所建议的 JWT 方案,将 OAuth2 和 JWT 结合使用,OAuth2 一般用于第三方接入的场景,管理对外的权限,所以比较适合和 API 网关结合,针对于外部的访问进行鉴权(当然,底层 Token 标准采用 JWT 也是可以的)。
JWT 更加轻巧,在微服务之间进行认证&鉴权已然足够,并且可以避免和身份认证服务直接打交道。当然,从能力实现角度来说,类似于分布式 Session 在很多场景下也是完全能满足需求,具体怎么去选择鉴权方案,还是要结合实际的需求来。
SpringCloud是一个服务治理平台,是若干的框架的集合,提供了全套的分布式系统解决方案。包含服务注册与发现、配置中心、服务网关、智能路由、负载均衡、断路监控跟踪、分布式消息队列等等。
SpringCloud通过SpringBoot风格的封装,屏蔽掉了复杂的配置和实现原理。最终给开发者留出了一套简单易懂、容易部署的分布式系统开发啊工具包。开发者可以快速的启动服务或构建应用,同时能够快速和云平台资源进行队列。微服务是可以独立部署、水平扩展、独立访问(或者有独立的数据库)的服务单元,Spring Cloud 就是这些微服务的大管家,采用了微服务这种架构之后,项目的数量会非常多,Spring Cloud 做为大管家需要管理好这些微服务,自然需要很多小弟来帮忙。
Spring Cloud的优点
集大成者,Spring Cloud包含了微服务架构的方方面面。约定大于配置,基于注解,没有配置文件。轻量级组件,Spring Cloud整合的组件大多比较轻量级,且都是各自领域的佼佼者。开发简便,Spring Cloud 对各个组件进行了大量的封装,从而简化了开发。开发灵活,Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件。Spring Cloud的缺点
项目结构复杂,每个组件或者每个服务器都需要创建一个项目。部署门槛高,项目部署需要配合Docker等容器技术进行进群部署,学习成本高。Netflix是美国的一家公司,提供流媒体播放。
针对多种 Netflix 组件提供的开发工具包,其中包括 Eureka、Ribbon、Feign、Hystrix、Zuul、Archaius 等。
Netflix Eureka:一个基于 Rest 服务的服务治理组件,包括服务注册中心、服务注册与服务发现机制的实现,实现了云端负载均衡和中间层服务器的故障转移。Netflix Ribbon:客户端负载均衡的服务调用组件。Netflix Hystrix:容错管理工具,实现断路器模式,通过控制服务的节点,从而对延迟和故障提供更强大的容错能力。Netflix Feign:基于 Ribbon 和 Hystrix 的声明式服务调用组件。Netflix Zuul:微服务网关,提供动态路由,访问过滤等服务。Netflix Archaius:配置管理 API,包含一系列配置管理 API,提供动态类型化属性、线程安全配置操作、轮询框架、回调机制等功能。和Spring Cloud一样,Spring Cloud Alibaba也是一套微服务解决方案。Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必须组件,方便开发者通过Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
阿里开源组件
Nacos:阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Sentinel:面向分布式服务架构的轻量级流量控制产品,把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架,用于实现服务通信。Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。阿里商业化组件
Alibaba Cloud ACM:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。Alibaba Cloud OSS:阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。Alibaba Cloud SchedulerX:阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。Alibaba Cloud SMS:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。SpringCloud不是使用数字命名版本号,而是使用的英文单词(地铁站名字)命名,是为了避免总版本号与子项目的版本号混淆。
采用伦敦的地铁站名称来作为版本号的命名,根据首字母排序,字母顺序靠后的版本号越大。
Spring 官方详细的版本查看接口:https://start.spring.io/actuator/info
例如:Spring Cloud Alibaba 2.1.0.RELEASE
主版本号。当功能模块有较大更新或者整体架构发生变化时,主版本号会更新。1:次版本号。次版本表示只是局部的一些变动。0:修改版本号。一般是 bug 的修复或者是小的变动。RELEASE:希腊字母版本号。标注当前版本的软件处于哪个开发阶段。