1、Eureka采用了C/S的设计架构。Eureka Server作为服务注册工程的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳链接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。SpringCloud的一些其他模块(比如Zuul)就可以通过Eureka Server来发现系统中的其他微服务,并执行相关的逻辑。
Eureka包含两个组件:Eureka Server和Eureka Client
Eureka Server提供服务注册服务
各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中看到。
Eureka Client是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eurkea Server将会从服务注册表中把这个服务节点移除(默认90秒)。
1、SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
2、Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。SpringCloud的负载均衡算法可以自定义
3、LB:即负载均衡,分为集中式LB和进程内LB
(1)集中式LB:即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5(超级贵),也可以是软件,如nginx),由改设施负责把访问请求通过某种策略转发至服务的提供方,偏向于硬件
(2)进程内LB:将LB逻辑集成到消费方,消费从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器,偏向于软件。
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过他来获取到服务提供方的地址。
项目演示
1、首先导入pom文件(客户端的子工程)
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.cloud
spring-cloud-starter-config
2、修改application配置文件
eureka:
client:
register-with-eureka: false //自己不注册
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
3、在ConfigBean添加新注解@LoadBalanced,获得Rest时加入Ribbon的配置
@Configuration
public class ConfigBean //boot -->spring applicationContext.xml --- @Configuration配置 ConfigBean = applicationContext.xml
{
@Bean
@LoadBalanced//Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
@Bean
public IRule myRule()
{
//return new RoundRobinRule();
//return new RandomRule();//达到的目的,用我们重新选择的随机算法替代默认的轮询。
return new RetryRule();
}
}
4、在启动类加上@EnableEurekaClient
5、修改客户端类的微服务名字
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
负载均衡演示(Ribbon,默认轮询算法)
1、创建余下的子工程
2、修改配置文件,以8001为例,这里需要改端口、数据库名、Eureka别名
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
mapper-locations:
- classpath:mybatis/mapper/**/*.xml # mapper映射文件
spring:
application:
name: microservicecloud-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/cloudDB01 # 数据库名称
username: root
password: root
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
eureka:
client: #客户端注册进eureka服务列表内
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#Eureka页面微服务的名字(别名)
instance:
instance-id: microservicecloud-dept8001
prefer-ip-address: true #访问路径可以显示IP地址(内网坏境的ip地址)
#关于微服务的描述
info:
app.name: atguigu-microservicecloud
company.name: www.atguigu.com
#这里不写死,灵活调用
build.artifactId: $project.artifactId$
build.version: $project.version$
负载均衡算法(IRule),七个。
RetryRule():如果多个服务在运行中,突然有一个服务故障,那么它将继续执行,直到发现该服务确实不能访问了,那么才跳过该服务,重新轮询。
//其他算法,不定义该方法,默认轮询算法
@Bean
public IRule myRule()
{
//return new RoundRobinRule(); //轮询算法
//return new RandomRule();//达到的目的,用我们重新选择的随机算法替代默认的轮询。
return new RetryRule();
}
自定义IRule,这里写一个让每个微服务都访问五次,在跳到下一个微服务的算法
1、在启动类加上注解,注意:这个自定义配置类不能放在@ComponenScan所扫描的当前包下以及子包下,否则自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说达不到我们想要的目的
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
@Configuration
public class MySelfRule
{
@Bean
public IRule myRule() {
//return new RandomRule();// Ribbon默认是轮询,我自定义为随机
//return new RoundRobinRule();// Ribbon默认是轮询,我自定义为随机
return new RandomRule_ZY();// 我自定义为每台机器5次,这里返回我们自定义的IRule类
}
}
public class RandomRule_ZY extends AbstractLoadBalancerRule
{
// total = 0 // 当total==5以后,我们指针才能往下走,
// index = 0 // 当前对外提供服务的服务器地址,
// total需要重新置为零,但是已经达到过一个5次,我们的index = 1
// 分析:我们5次,但是微服务只有8001 8002 8003 三台,OK?
//
private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
private int currentIndex = 0; // 当前提供服务的机器号
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List upList = lb.getReachableServers();
List allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes only get more
* restrictive.
*/
return null;
}
// int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
// server = upList.get(index);
// private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
// private int currentIndex = 0; // 当前提供服务的机器号
if(total < 5) {
server = upList.get(currentIndex);
total++;
}else {
total = 0;
currentIndex++;
if(currentIndex >= upList.size()) {
currentIndex = 0;
}
}
if (server == null) {
/*
* The only time this should happen is if the server list were somehow trimmed.
* This is a transient condition. Retry after yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key)
{
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig)
{
// TODO Auto-generated method stub
}
}
1、Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,使其支持SpringMVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组护使用以支持负载均衡。
Feign是一个声明式的Web服务客户端,使得编写Web服务客户端变得非常容易,只需要创建一个接口,然后在上面添加注解即可。
2、Feign集成了Ribbon,利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,就可以实现服务调用
项目演示
1、新建子工程,添加Feign相关依赖,这里的子工程是复制上一个80的子工程的,所有有些文件和类都是相同的
org.springframework.cloud
spring-cloud-starter-feign
2、修改api公共工程,pom文件添加Feign依赖,创建一个service接口并新增注解@FeignClient
org.springframework.cloud
spring-cloud-starter-feign
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService {
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List list();
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(Dept dept);
}
3、再修改feign工程的controller,并将刚刚在api工程编写的接口注入到controller中
@RestController
public class DeptController_Consumer {
@Autowired
private DeptClientService service;
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return this.service.get(id);
}
@RequestMapping(value = "/consumer/dept/list")
public List list() {
return this.service.list();
}
@RequestMapping(value = "/consumer/dept/add")
public Object add(Dept dept) {
return this.service.add(dept);
}
}
4、修改feign启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages= {"com.atguigu.springcloud"})
@ComponentScan("com.atguigu.springcloud")
public class DeptConsumer80_Feign_App{
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}
Feign和Ribbon都可以实现负载均衡
Feign通过接口的方法调用Rest服务(之前是Ribbon+RestTemplate),通过Feign直接找到服务接口,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡。
服务雪崩
1、多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,就是所谓的“雪崩效应”。
2、Hystrix是一个处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个微服务单元发生故障之后,通过断路器的故障监控(类似于熔断保险丝),向调用方返回一个符合预期的响应,而不是长时间的等待或抛出无法处理的异常,这样就保证了服务调用方线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
服务熔断
一般是某个服务故障或者异常引起,类似于现实世界中的“保险丝”,当某个异常条件被触发,直接熔断整个服务,而不是一直等到此服务超时。
熔断机制是应对雪崩效应的一种微服务链路保护机制,注解:@HystrixCommand
项目演示(参考8001微服务)
1、创建子工程
2、修改pom文件,引入Hystrix依赖,修改application配置文件的自定义id
org.springframework.cloud
spring-cloud-starter-hystrix
3、修改controller,@HystrixCommand注解的意思就是如果微服务不能调用get方法,那就就调用下面的processHystrix_Get()方法,如果能调用get()方法,就返回dept。说白了就是能成功调用,那么就返回一个异常数据,不能调用,也要返回一个不能调用的数据。
@RestController
public class DeptController
{
@Autowired
private DeptService service = null;
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
//一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
@HystrixCommand(fallbackMethod = "processHystrix_Get")
public Dept get(@PathVariable("id") Long id) {
Dept dept = this.service.get(id);
if (null == dept) {
throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
}
return dept;
}
public Dept processHystrix_Get(@PathVariable("id") Long id) {
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand")
.setDb_source("no this database in MySQL");
}
}
4、在启动类加上新注解,@EnableCircuitBreaker
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker//对hystrixR熔断机制的支持
public class DeptProvider8001_Hystrix_App {
public static void main(String[] args) {
SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
}
}
服务降级
整体资源快不够了,忍痛将某些服务先关掉,待度过难关,在开启回来。
服务降级处理实在客户端实现完成的,与服务端没有关系
先前那样写,会导致,有一个业务方法,那么就要写一个对应处理的fallback方法,所以,下面对这个问题进行改善。
项目演示
1、修改microservicecloud-api工程,根据已经有的DeptClientService接口,新建一个实现了FallbackFactory接口的类DeptClientServiceFallbackFactory,该类上面要添加@Component
@Component // 不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable)
{
return new DeptClientService() {
@Override
public Dept get(long id)
{
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
.setDb_source("no this database in MySQL");
}
@Override
public List list()
{
return null;
}
@Override
public boolean add(Dept dept)
{
return false;
}
};
}
}
2、在api公共工程的接口中添加fallbackFactory属性
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
3、在feign工程的application配置文件添加相应的配置,因为这种处理是在@FeignClient中的,所以需要在feign工程的配置文件中配置
feign:
hystrix:
enabled: true
实现这种方式是为了,主业务方法、异常处理、熔断处理的解耦,避免方法膨胀
服务监控HystrixDashboard
项目演示
1、新建一个HystrixDashboard工程,修改pom和application配置文件
pom:
org.springframework.cloud
spring-cloud-starter-hystrix
org.springframework.cloud
spring-cloud-starter-hystrix-dashboard
yml:
server:
port: 9001
2、启动类添加新注解
@SpringBootApplication
@EnableHystrixDashboard//监控注解
public class DeptConsumer_DashBoard_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer_DashBoard_App.class, args);
}
}
3、所有的服务中都要有(8001、8002、8003)
org.springframework.boot
spring-boot-starter-actuator
4、访问服务监控页面出现下图所示,则为监控成功
(1)Delay:该参数用来控制服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。
(2)Title:该参数对应了头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。
5、数据展示:访问某个服务监控的后缀名为hystrix.stream,例如:http://8001/hystrix.stream
6、图形化展示,在文本框填写需要监控服务的地址
7、怎么看?注意:需要多次刷新监控的微服务
7色、一圈、一线
一圈:实心圆,他通过颜色的变化代表了实例的健康程度,从绿色<黄色<橙色<红色递减。该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大实心圆越大。所以通过实心圆的展示,就可以在大量的实例中快速的发现故障实例的高压力实例。
1、Zuul包含了对请求的路由和过滤两个最主要的功能:
(1)其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
(2)Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册Erueka
提供=代理+路由+过滤
项目演示(基本路由配置)
1、新建工程,导入Zuul相关依赖
org.springframework.cloud
spring-cloud-starter-zuul
org.springframework.cloud
spring-cloud-starter-eureka
2、修改application配置文件,修改端口、微服务名称、别名ip(instance-id)
server:
port: 9527
spring:
application:
name: microservicecloud-zuul-gateway
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
instance:
instance-id: gateway-9527.com
prefer-ip-address: true
info:
app.name: atguigu-microcloud
company.name: www.atguigu.com
build.artifactId: $project.artifactId$
build.version: $project.version$
3、域名映射,hosts文件修改,这里我都注释了
4、启动类添加新注解@EnableZuulProxy
@SpringBootApplication
@EnableZuulProxy
public class Zuul_9527_StartSpringCloudApp {
public static void main(String[] args)
{
SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
}
}
5、启动成功的Eureka页面,会多出一个微服务
6、如何去进行业务访问(访问规则),myzuul.com是域名映射的名称
例如:http://myzuul.com:9527/microservicecloud-dept/dept/get/2
7、设置访问映射规则
zuul:
#ignored-services: microservicecloud-dept
prefix: /atguigu #设置公共前缀
ignored-services: "*" #过滤所有的真实路径,只能使用自己固定的路径(mydept)
routes:
mydept.serviceId: microservicecloud-dept
mydept.path: /mydept/**
访问路径为:myzuul.com:9527/atguigu/mydept/dept/get/3
1、SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。
2、SpringCloud Config分为服务端和客户端两部分
(1)服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。
(2)客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。
SpringCloud Config服务端配置
1、用自己的GitHub账号创建一个Config文件,点击creat,复制SSH协议链接
2、在本地新建一个Config文件夹,然后执行Git复制命令,里面建立一个application.yml文件(必须UTF-8形式保存),另存为编码格式就行
3、Git命令进行提交
4、新建maven子工程,config工程,添加配置依赖
org.springframework.cloud
spring-cloud-config-server
org.eclipse.jgit
org.eclipse.jgit
4.10.0.201712302008-r
5、修改application配置文件,填写git地址
server:
port: 3344
spring:
application:
name: microservicecloud-config
cloud:
config:
server:
git:
uri: [email protected]:zzyybs/microservicecloud-config.git #GitHub上面的git仓库名字
6、启动类添加新注解@EnableConfigServer
@SpringBootApplication
@EnableConfigServer
public class Config_3344_StartSpringCloudApp
{
public static void main(String[] args)
{
SpringApplication.run(Config_3344_StartSpringCloudApp.class, args);
}
}
7、windows下修改hosts文件
增加映射:127.0.0.1 config-3344.com
8、访问规则,application后面加个“-”就行:config-3344.com:3344/application-dev.yml
SpringCloud Config客户端配置
1、在原来的本地config文件夹中,创建一个新的config-client.yml配置文件,里面写
2、通过git命令提交
3、新建maven子工程,修改pom文件
org.springframework.cloud
spring-cloud-starter-config
4、resources包下建立bootstrap.yml和application.yml文件,注意看代码注释
application.yml是用户级的资源配置项
bootstrap.yml是系统级的,优先级更高,负责从外部加载配置信息
bootstrap.yml文件内容
spring:
cloud:
config:
name: microservicecloud-config-client #需要从github上读取的资源名称,注意没有yml后缀名
profile: test #本次访问的配置项
label: master
uri: http://config-3344.com:3344 #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取GitHub的服务地址
application.yml文件内容
spring:
application:
name: microservicecloud-config-client
5、做域名访问映射(hosts文件)
6、创建rest包和ConfigClientRest类
@RestController
public class ConfigClientRest
{
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServers;
@Value("${server.port}")
private String port;
@RequestMapping("/config")
public String getConfig()
{
String str = "applicationName: " + applicationName + "\t eurekaServers:" + eurekaServers + "\t port: " + port;
System.out.println("******str: " + str);
return "applicationName: " + applicationName + "\t eurekaServers:" + eurekaServers + "\t port: " + port;
}
}
7、创建启动类
@SpringBootApplication
public class ConfigClient_3355_StartSpringCloudApp
{
public static void main(String[] args)
{
SpringApplication.run(ConfigClient_3355_StartSpringCloudApp.class, args);
}
}
8、启动服务,先启动3344在启动3355
SpringCloud Config配置实战
1、本地config文件夹,新建eureka-client.yml文件和dept-client.yml文件
eureka-client.yml内容
dept-client.yml内容
2、git命令提交文件