一、Springcloud介绍
pring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
下面只简单介绍下经常用的5个
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config
二、Springcloud自我保护机制
EMERGENCYI EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY' RE NOT. RENEWALS ARE LESSE
这是触发了Eureka的自我保护机制。当服务未按时进行心跳续约时,Eureka会统计服务实例最近15分钟心跳续约的比例是否低于了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka在这段时间内不会剔除任何服务实例,直到网络恢复正常。生产环境下这很有效,保证了大多数服务依然可用,不过也有可能获取到失败的服务实例,因此服务调用者必须做好服务的失败容错,一句话讲解:好死不如赖活着
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
因此服务调用者必须做好服务的失败容错,可以通过在yml中配置来关停自我保护(不建议):
eureka:
server:
enable-self-preservation:false#关闭自我保护模式(缺省为打开)
Springcloud配置案例
1.EurekaServer(服务注册中心)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--security安全认证依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
application.yml
# 端口
server:
port: 8500
# 配置服务的名称
spring:
application:
name: eureka-server
security: #是否开启用户认证,开启后需要账号密码才能注册,例http://root:123456@127.0.0.1:8501/eureka/
basic:
enabled: true
user:
name: root
password: 123456
eureka:
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://root:123456@127.0.0.1:8501/eureka/ #监控交互界面,注册中心地址,多个注册中心相互注册形成高可用集群,多个地址通过","分隔
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
instance: server1
# instance: #eureka服务端的实例名称
# instance-id: eureka-server #修改eureka上默认的描述信息
# hostname: localhost
server:
enable-self-preservation: false
WebSecurityConfig.java
package com.itheima.eurekaserver.crsf;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* Created by itcast on 2019/10/31.
*/
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);//加这句是为了访问eureka控制台和/actuator时能做安全控制
http.csrf().disable();
}
}
EurekaServerApplication.java
package com.itheima.eurekaserveranother;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //服务端启动类,可以接收别人注册进来
@EnableDiscoveryClient //用法上基本与@EnableEurekaClient一致,在服务启动后自动注册到Eureka中,如果是注册中心推荐使用@EnableDiscoveryClient
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
2.goods-provider(服务提供者)
pom.xml
<!--eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml
server:
port: 8750
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/online_retailers?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
application:
name: b2b-goods-provider #在其他提供者与之相同的服务名称,表明提供提供的服务一样,常用于ribbon负载均衡
eureka:
client:
service-url:
defaultZone: http://root:123456@localhost:8500/eureka/
instance:
hostname: localhost
mybatis:
mapper-locations: classpath:/mapper/*
GoodsProviderApplication.java
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
Controller中方法接收值
//绑定@RequestParam或者@RequestBody
@RequestMapping(value = "/selectActivityById",method = RequestMethod.GET)
public Activity selectActivityById(@RequestParam(value = "id")Long id){
return activityDao.selectActivityById(id);
};
3.user-consumer.java(消费者)
pom.xml
<!--feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<!--eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--thymeleaf前面模板依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<!--hystrix熔断依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
application.yml
server:
port: 8893 #服务端口
spring:
application:
name: user-consumer #服务名
main:
allow-bean-definition-overriding: true #遇到同当样名字的时候,是否允许覆盖注册
eureka:
client:
service-url:
defaultZone: http://root:123456@localhost:8500/eureka/ #服务注册地址
instance:
hostname: localhost
thymeleaf:
cache: false #关闭缓存
prefix: classpath:/template/
suffix: .html
encoding: UTF-8
feign: #feign负载均衡,feign集成ribbon
hystrix:
enabled: true
# httpclient:
# enabled: true
UserConsumerApplication.java
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
@EnableHystrix
ActivityService.java
@Component
//熔断配置
@FeignClient(value = "b2b-goods-provider",fallback = ActivityServiceHystix.class)
public interface ActivityService
{
ActivityServiceHystix.java(熔断处理)
//实现并重写接口,在方法内编写熔断处理
@Component
public class ActivityServiceHystix implements ActivityService
{
Ribbon(负载均衡配置)
在消费者端配置
@Configuration
public class RibbonConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
此时消费端访问服务提供者地址应该是一个地址变量,可能有多个服务提供者(基于服务名字访问)
不用担心访问地址和端口号
private static final String url = "http://SPRINGCLOUD-PROVIDER-DEPT"
gateway(路由网关)
pom.xml
<!--zuul网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
Application.java
@EnableZuulProxy
application.yml
zuul:
host:
connect-timeout-millis: 60000
routes:
api-a:
path: /api-a/**
serviceId: user-consumer
api-b:
path: /api-b/**
serviceId: b2b-goods-consumer
add-host-header: true