SpringCloud-微服务框架

SpringCloud-微服务框架

微服务架构设计介绍

单体架构

单体架构概述

单体架构也被称为单体系统或者是单体应用,就是一种系统中所有的功能、模块耦合在一个应用中的架构方式。用简单的方式理解就是将整个应用包括应用、数据库等都在同一个服务器上。而分布式从简单的角度上理解就是将应用和数据等分开到不同的服务器上,就然后对于应用和数据库进行不同方向上的性能优化等等操作。将系统的导报成一个独立的单元(导入称为一个jar包或者是一个war包)部署完成应用之后,应用通过一个进程的方式来运行。

单体架构明显优缺点

存在单体架构的明显意义是:

  • 部署简单:由于是完整的结构体,可以直接部署在一份服务器上即可
  • 技术单一,易于管理:项目不需要复杂的技术栈,往往一套熟悉的技术栈就可以完成开发,并且管理简单
  • 用人成本低:单个程序员可以完成业务接口道数据库的整个流程
    单体项目的不足之处
  • 系统启动慢测试成本高:一个进程包含了所有的业务逻辑,涉及到的启动模块过多,导致系统的启动时间周期过长
  • 系统错误隔离性差:可用性差,任何一个模块的错误均可能造成整个系统的宕机
  • 可伸缩性差:系统的扩容只能对这个应用进行扩容,不能做到对莫讴歌功能点进行扩容
  • 线上问题修复周期长,迭代困难:任何一个线上问题修复需要对整个应用系统全面升级
    就因为单体项目短板过于明显,并且随着各种技术蓬勃发展,产生了新的开发模式微服务

微服务架构

微服务概述

微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每一个服务运行在自己的进程中,服务间通信采用的轻量级通信机制,这些服务围绕业务能力构建并且可通过全自动部署机制独立部署,这些服务公用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术,各个微服务之间是松耦合的,每个微服务仅仅关注于完成一件任务并很好的完成该任务。通过拆分之后,这个复杂的应用系统变的更加的高效。

微服务优势

我们常用的常见的架构风格,包括

客户端与服务器端 :包括C/S 和B/S两种,而B/S比较特殊。
基于组件模型的架构(EJB)
分层架构(MVC)
面向服务架构(SOA)

微服务具有以下特点,一个完整系统包括多个微服务组成,每个微服务代表了单个的业务功能;每个服务可以独立部署;服务内部高内聚,外部低耦合。

  • 易于开发和维护:一个微服务只会关注一个特定的业务功能,所以他的业务清晰,代码量少,开发和维护单个微服务相当简单,而整个应用是若干个微服务构建而成的,所以整个应用也被维持在一个可控状态
  • 单个微服务启动较快:单个微服务代码量较少,所以启动会比较快
  • 局部修改容易部署
  • 技术栈不受限
  • 按需收缩:可根据需求,实现细粒度的扩展,例如:系统中的某个微服务遇到了瓶颈,可以结合这个微服务的业务特点,增加内存,升级CPU或者增加节点
  • 可以承受高并发
    明显不足就是运维成本过高,部署数量较多、分布式系统本身的复杂性
微服务设计原则
  • AKF分拆原则
    AKF可扩展立方。这个立方体沿着三个坐标轴的方向分别是XYZ。
    在这里插入图片描述
    Y轴扩展会加将庞大的整体应用拆分为多个服务。每个服务实现一组相关功能,例如订单管理、客户管理等。在工程上常见的方案是服务化架构(SOA),比如对一个电子商务平台,我们可以拆分成为不同的服务,
    在这里插入图片描述
    X轴扩展是面向前面朴素理念是一致的,通过绝对平等的服务复制服务与数据,一解决容量和可用性的问题。其实就是将微服务运用多个实例,做集群加负载均衡的模式。
    在这里插入图片描述
    Z轴扩展通常是指基于请求者或者用户独特的需求,进行系统划分,并使得划分出来的子系统是相互隔离但又是完整的。以生产汽车的工厂来举例:福特公司为了发展中国的业务,或者利用中国的廉价劳动力,在中国建立一个完整的子工厂,与美国工厂一样,负责完整的汽车生产,这就是Z轴拓展。常见的Z轴扩展方案有以下两种:单元化架构和数据分区

  • 前端后端分离原则

  • 无状态服务
    对于无状态服务,首先介绍什么是状态:如果一个数据需要被多个服务共享,才能完成一笔交易,那么和这个数据被称为状态。进而依赖这个状态的数据的服务被称为是状态服务,反之称为无状态服务。
    那么这个无状态服务原则并不是说在微服务里就不允许存在状态,表达的真实意思是要把所有状态的业务服务改变为无状态的计算类服务,那么状态数据也就是相应的迁移到对应的有状态数据服务中。 场景说明:例如我们以前在本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中,就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不需要考虑缓存数据如何同步的问题。

  • RestFul的通行风格
    作为一个原则来讲,本来应该是一个“无状态通信原则”,这里直接推荐一个实践优选的RestFul通信风格,因为他有很多好处:

    • 无状态协议HTTP,具备先天优势,扩展能力很强,例如需要安全加密,有现有的成熟解决方案HTTPS即可
    • JSON报文序列化,轻量简单,人与机器均可读,学习成本低,搜索引擎友好
    • 语言无关,各大热门语言都提供了成熟的RestFul API 框架,相对其他的一些RPC框架生态更加完整。

微服务框架-依赖于SpringBoot的框架集合全家桶SpringCloud

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

SpringBoot和SpringCloud的版本对应关系

SpringBootSpringCloud
1.2.xAngel
1.3.xBrixton
1.4.xCamden
1.5.xDalston、Edgware
2.0.xFinchley

SpringCloud组件集包括

Spring Cloud Config
Spring Cloud Bus
Spring Cloud Netflix(Eureka、Hystrix、Zuul、Archaius…)
Spring Cloud for Cloud Foundry
Spring Cloud Cluster
Spring Cloud Consul
Spring Cloud Security
Spring Cloud Sleuth
Spring Cloud Data Flow
Spring Cloud Stream
Spring Cloud Task
Spring Cloud Zookeeper
Spring Cloud Connectors
Spring Cloud Starters
Spring Cloud CLI

SpringCloud的组件介绍之Eureka

spring cloud 的微服务框架的核心组件(管理单位);完成当前所有集群微服务的注册与发现逻辑的核心组件;可以动态的处理所有的负载均衡访问,时对集群serverList的管理工作;
在Eureka中,所有的Eureka服务都被称为实例(instance),这些实例又分成为两大类:

  • Eureka Server: Eureka的服务端,即服务注册中心,负责维护所有实例的注册信息
  • Eureka Client: Eureka的客户端,根据功能又分为两类
    • Service Provider:服务提供方,向Eureka Server做服务注册、续约和下线等操作,注册的主要数据包括服务名、机器ip、端口号、域名等等
    • Service Consumer:服务消费方, 向Eureka Server获取Service Provider的注册信息,并通过远程调用与Service Provider进行通信
      可以将Service Provider和Service Consumer理解为角色。一个Eureka Client可以只是Service Provider,也可以只是Service Consumer,也可以同时即是Service Provider也是Service Consumer。
      主要功能包括注册和发现:
      服务注册:微服务的节点作为真正的服务,功能的提供者。动态注册在Eureka的服务端在这里插入图片描述
      服务发现:客户端具备访问eureka的能力,动态的获取某个一个服务的真正提供者信息,从而发起访问调用;
      在这里插入图片描述
使用方式
服务端简单实用。

Eureka是SpringCloud的组件,SpringCloud是基于SpringBoot的项目。在pom文件中导入SpringBoot的内容和SpringCloud的内容

<!--SpringBoot -->
<parent>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-parent</artifactId>
  	<version>1.5.9.RELEASE</version>
</parent>
<!-- 引入springcloud资源dependencyManagement import导入-->
<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
</dependencyManagement>

还需要引入Eureka依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
Properties文件配置

配置主要分为三类:

  • eureka.instance.*:Eureka实例注册配置项,这些是无论Eureka是做Server端,还是做Client端都需要的公共配置项。这些属性配置在类org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean中
  • eureka.server.*: Eureka做为Eureka Server才需要配置的选项,即使用eureka做注册中心时才需要配置这个选项。这些属性配置在类org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中
  • eureka.client.*: Eureka做为Eureka Client才需要配置的选项,即服务需要向注册中心注册(实例做为Service Provider时)或使用注册中心中的服务(实例做为Service Consumer时)时才需要配置这些选项。这些属性配置在类org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean中
    举例如下:
#与网络访问有关的主机名称,作为一个eureka的启动实例可以通过这个hostname进行访问(www.eureka01.com),必须配合网路配置(dns服务器,hosts文件)
eureka.instance.hostname=localhost
#与eureka客户端角色相关的配置,注册中心eureka服务端.本身启动时即具备服务端角色,也可以是本身服务端的客户端
eureka.client.registerWithEureka=false
#自身启动的进程的客户端角色既不注册在自己,也不从自己的服务列表中发现服务
eureka.client.fetchRegistry=false
#对外暴露的注册地址(作为服务段向其他客户端暴露自己注册接口)
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
启动类书写,主要是加入注解@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer //启动eurekaserver的注解
public class StarterEurekaServer {
	//通过run方法将反射信息发送给初始化过程
	//启动过程加载eureka相关依赖资源,自动配置eureka进程启动
	public static void main(String[] args) {
		SpringApplication.run(StarterEurekaServer.class, args);
		}
	}
客户端加载使用

其他操作不便,在Properties配置文件中修改部分

#eureka client config
spring.application.name=service01
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
Eureka管理逻辑
  1. 续约,和剔除
    启动的每一个eureka客户端进程.都会根据配置到eureka注册中心进行注册,注册之后,每30秒发送一个心跳检测(续约),每60秒注册中心检测一次所有的服务续约,一旦发现超过90秒没有发送心跳检测的话,将会把服务对应的实例节点剔除;
  2. Eureka注册信息结构
    每一个服务的提供者注册到服务端时,访问调用localhost:8762/eureka发送请求.并且携带一些信息,Eureka服务端将这些信息保管在一个双层map中
    在这里插入图片描述
  3. eureka注册中心.提供一种保护微服务集群注册服务信息的机制,防止由于网络波动导致大量的注册心跳检测发送未成功,造成的误剔除,给集群,给微服务带来的巨大伤害,所出现的一种机制–保护机制。当整个集群15%以上同一时间检测到超过90秒未发送心跳.将会开启保护机制,一旦开启,所有的服务注册信息,在eureka中心不会进行任何剔除;默认情况保护机制是开启的,若想修改默认,在配置文件中修改以下属性。eureka.server.enable-self-preservation=false(关闭自我保护)
Eureka的高可用配置

上面简单的配置了单机的Eureka,这种是及不可靠的,那么需要我们吧Eureka变成高可用。
修改Eureka的properties的配置信息,大致内容为:

  • spring.application.name=eureka-server
  • 注册与发现开启,registry和fetch=true
  • 服务端互相注册发现必须配置 ip优先的内容eureka.instance.preferIpAddress=true
  • 相互注册与发现,serviceUrl.defaultZone的值互相指向对方
#eureka config
eureka.instance.hostname=localhost
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true
# 另一台设置为这一台的地址即可
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka

值得注意的是若是三台甚至多台的情况下,我们假设三台一种方案是两两双向发现和注册,另一种是采用一对二的模式,一向二发现,二向一注册。
另外在其他博文上看到Netflix的组件停止更新,好多新的替代性组件也已经跃然纸上。

SpringCloud的组件之一 ribbon

看了众多好多文章唯一记住的也就是,ribbon是一个客户端负载均衡器,负载均衡是很好理解的。对于现在的我来说,将一个单体项目拆分的话,为了避免某一服务的压力过大,将每一个服务做成高可用。而ribbon也就是在众多同种微服务的调用做负载均衡处理。

ribbon概述

Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当我们将Ribbon和Eureka一起使用时,Ribbon会到Eureka注册中心去获取服务端列表,然后进行轮询访问以到达负载均衡的作用,客户端负载均衡也需要心跳机制去维护服务端清单的有效性,当然这个过程需要配合服务注册中心一起完成。注意:像Eureka的微服务一样,ribbon是属于客户端的。

ribbon的基本原理

springcloud中,提供一个客户端组件,用来负载均衡的访问某个服务用的;启动之后,作为eureka的客户端到eureka注册中心实现抓取服务端的list服务提供者列表(30秒重新抓取一次),可以实现动态的对服务负载均衡访问的过程(绕过了类似nginx的静态文件配置.修改环境重启nginx);这个客户端的访问服务的功能,需要依赖RestTemplate(发起http请求,请求的是服务名称)

使用

启动类的配置

@SpringBootApplication
@EnableEurekaClient
public class StarterRibbonClient {
public static void main(String[] args) {
	SpringApplication.run(StarterRibbonClient.class, args);
}
//生成一个具备ribbon拦截功能的restTemplate
@Bean
@LoadBalanced //会根据负载均衡策略对象IRule的实现类
//实现访问服务的负载均衡方式 默认roundRobin轮询
public RestTemplate initRestTemplate(){
	return new RestTemplate();
}}

pom文件配置,除了基本的SpringBoot和SpringCloud的配置之外需要添加依赖Eureka和Ribbon的依赖

<!--Eureka相关依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!--Ribbon相关依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>

负载均衡策略

名称意义
RoundRobinRule轮询策略,Ribbon以轮询的方式选择服务器,这个是默认值。所以示例中所启动的两个服务会被循环访问
RandomRule随机策略,也就是说Ribbon会随机从服务器列表中选择一个进行访问
BestAvailableRule最大可用策略,即先过滤出故障服务器后,选择一个当前并发请求数最小的;
WeightedResponseTimeRule带有加权的轮询策略,对各个服务器响应时间进行加权处理,然后在采用轮询的方式来获取相应的服务器;
AvailabilityFilteringRule可用过滤策略,先过滤出故障的或并发请求大于阈值的一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个
ZoneAvoidanceRule区域感知策略,先使用主过滤条件(区域负载器,选择最优区域)对所有实例过滤并返回过滤后的实例清单,依次使用次过滤条件列表中的过滤条件对主过滤条件的结果进行过滤,判断最小过滤数(默认1)和最小过滤百分比(默认0),最后对满足条件的服务器则使用RoundRobinRule(轮询方式)选择一个服务器实例。

使用的时候只需要在配置类中.利用@Bean创建当前想使用的对象即可

//创建一个自定义负载均衡策略
@Bean
public IRule myRule(){
	return new RandomRule();
}

zuul网关(gateway)路由过滤

微服务场景下,每一个微服务对外暴露了一组细粒度的服务。客户端的请求可能会涉及到一串的服务调用,如果将这些微服务都暴露给客户端,那么会增加客户端代码的复杂度。并且降低安全性
zuul可以通过加载动态过滤机制,具有下列优势

  • 验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
  • 审查与监控在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
  • **动态路由 **以动态方式根据需要将请求路由至不同后端集群处。
  • **压力测试:**逐渐增加指向集群的负载流量,从而计算性能水平。
  • 负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
  • 静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
  • 多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
    下面是关键的过滤器介绍:
  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • **ROUTING:**这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
  • **POST:**这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
使用

在pom中的配置

<!--除了SpringCloud和SpringBoot之外的-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

启动类的书写方式


@SpringBootApplication
@EnableZuulProxy//加入zuul的组件
public class GatewayServiceZuulApplication {
	public static void main(String[] args) {
		SpringApplication.run(GatewayServiceZuulApplication.class, args);
	}

配置文件的书写properties

spring.application.name=serviceZuul
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=service01
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=service02

关于配置文件的一些解释

定义了路由的规则;路由地址匹配逻辑
zuul.routes.api-a.path:定义一个与访问api-a相关服务配置的path的映射地址 /api-a/**,意义是请求的路径中url 以/api-a/多级路径匹配,一旦当前请求和某一个路由匹配成功,将会根据zuul.routes.XX.path中的,寻找当前properties中一个zuul.routes.XX.serviceId=service01(微服务名称),从而找到对应的访问服务(ribbon+restTemplate访问服务获取响应)

匹配规则了解

符号匹配规则
?匹配一个字符,例如/api-a/? 只能匹配到/api-a/a,/api-a/b
*匹配一个一级路径字符串,/api-a/*,匹配到/api-a/a,/api-a/haha,/api-a/a/b匹配不到了
**只要是起始匹配成功.后续的多级,多字符串匹配都通配/api-a/**
当将所有技术点结合起来的流程是
  • 路由的逻辑
    浏览器发起的js请求地址
    http://www.ssm.com/user/query/poinst?userId=1
    |nginx判断端口80.域名www.ssm.com
    |以/user起始,转向zuul关工程地址
    http://localhost:9005/users/user/query/point?userId=1
    |路由规则/users/** 匹配上
    |转向内部服务userdemoservice
    http://userdemoservice/user/query/point?userId=1
    |ribbon的restTemplate发起请求,拦截
    |userdemoservice拦截拼接一个后端服务提供者的集群list做负载均衡
    http://localhost:8093/user/query/point?userId=1

扩展-CAP理论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值