SpringCloud 基础
SpringCloud 基础
一、概述
- 微服务:将传统的一站式应用,拆分成一个个的服务,彻底去耦合,一个微服务就是单功能业务,只做一件事。
- 微服务是一种架构模式或者一种架构风格,提倡将单一应用程序划分成一组小的服务独立部署服务之间相互配合、相互协调,每个服务运行于自己的进程中。服务与服务间采用轻量级通讯,如HTTP的RESTful API等避免统一的、集中式的服务管理机制 。
- 微服务优点
- 每个服务足够内聚,足够小,比较容易聚焦。
- 开发简单且效率高,一个服务只做一件事情。
- 微服务能用不同的语言开发
- 易于和第三方集成,微服务允许容易且灵活的自动集成部署(持续集成工具有Jenkins,Hudson,bamboo等)
- 微服务易于被开发人员理解,修改和维护。
- 微服务只是业务逻辑的代码,不会和HTML,CSS或其他界面组件融合
- 每个微服务都可以有自己的存储能力,数据库可自有也可以统一,十分灵活
- 微服务缺点
- 开发人员要处理分布式系统的复杂性
- 多服务运维难度,随着服务的增加,运维的压力也会增大
- 依赖系统部署
- 服务间通讯的成本
- 性能监控的难度大
- 系统集成测试难度大
- 数据的一致性维护比较困难
- Spring Cloud是一个基于Spring Boot实现的云原生应用开发工具,它为基于JVM的云原生应用开发中涉及的配置管理、服务发现、熔断器、智能路由、微代理、控制总线、分布式会话和集群状态管理等操作提供了一种简单的开发方式。
- SpringCloud 核心子项目
- Spring Cloud Netflix:核心组件,可以对多个Netflix OSS开源套件进行整合,包括以下几个组件:
- Eureka:服务治理组件,包含服务注册与发现
- Hystrix:容错管理组件,实现了熔断器
- Ribbon:客户端负载均衡的服务调用组件
- 基于Ribbon和Hystrix的声明式服务调用组件
- Zuul:网关组件,提供智能路由、访问过滤等功能
- Archaius:外部化配置组件
- Spring Cloud Config:配置管理工具,实现应用配置的外部化存储,支持客户端配置信息刷新、加密/解密配置内容等。
- …
- Spring Cloud Netflix:核心组件,可以对多个Netflix OSS开源套件进行整合,包括以下几个组件:
二、服务发现组件 Eureka
1. 介绍
- Eureka是Spring Cloud Netflix微服务套件中的一部分,是一套成熟的服务注册和发现组件,可以与Springboot构建的微服务很容易的整合起来。Eureka包含了服务器端和客户端组件。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。
2. 搭建 Maven 父工程
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <groupId>com.offcn</groupId>
<artifactId>APartenProject</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging> <properties>
<java.version>1.8</java.version>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</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>
3. 创建 Eureka 集群
新建子模块 eureka-server01
pom.xml
<parent>
<artifactId>APartenProject</artifactId>
<groupId>com.offcn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.offcn</groupId>
<artifactId>eureka-server01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server01</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>
</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>
配置 application.yml
#内置的tomcat服务启动监听端口号
server:
# port: 8888
port: 10086 #应用名称
spring:
application:
name: eureka-server #EurekaServer配置
eureka:
client:
# register-with-eureka: false #此EurekaServer不再注册到其他的注册中心
# fetch-registry: false #不再从其他中心中心拉取服务器信息
service-url:
#defaultZone: http://localhost:${server.port}/eureka #注册中心访问地址
defaultZone: http://localhost:10087/eureka #指向另外一台Eureka服务器
server:
enable-self-preservation: false # Eureka开启自动保护模式
eviction-interval-timer-in-ms: 4000
为启动类添加注解
@SpringBootApplication
// 开启 EurekaServer
@EnableEurekaServer
public class EurekaServer01Application { public static void main(String[] args) {
SpringApplication.run(EurekaServer01Application.class, args);
}}
和 eureka-server01 一样,新建一个子模块eureka-server02,只改一下配置文件 application.yml,其它保持一致。
server:
port: 10087 spring:
application:
name: eureka-server eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 4000
client:
service-url:
defaultZone: http://localhost:10086/eureka
运行两个服务器 http://localhost:10086/ 和 http://localhost:10087/ 都可以
4. 创建服务提供方集群
新建子模块 userprovider01
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 8001 spring:
application:
name: userprovider
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
#一定注意eureka与spring属于平级 注意格式
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka/ # 数据
ProviderVersion: UserProvider:0.02V
创建实体类User
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue
private Long id; @Column(name="name",nullable = true,length = 200)
private String name; @Column(name = "age",nullable = true,length = 4)
private Integer age;
}
UserDao 实现 JpaRepository<User, Long>,创建UserService、UserServiceImpl、UserController(RESTful风格)
// UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService; @Value("${ProviderVersion}")
private String ProviderVersion; @GetMapping("/getall")
@ApiOperation(value = "获取全部用户信息", notes = "获取全部用户信息")
public Map<String,Object> getUsers() {
Map<String,Object> map=new HashMap<>();
List<User> list = userService.getUserList();
map.put("list", list);
map.put("ProviderVersion", ProviderVersion);
return map;
}
......
}
启动类添加注解
@EnableDiscoveryClient
新建子模块 userprovider02,除了 application.yml 和 UserController的getAll方法有些差别外,其它全部一样
server:
port: 8002 spring:
application:
name: userprovider
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
#一定注意eureka与spring属于平级 注意格式
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka/
// UserController 中的getUser方法中 ProviderVersion 的值与 UserProvider01项目有所区别(ProviderVersion: UserProvider:0.02V),这是为了后面负载均衡的时候看出差别。
@GetMapping("/getall")
public Map<String,Object> getUsers() {
Map<String,Object> map=new HashMap<>();
List<User> list = userService.getUserList();
map.put("list", list);
String ProviderVersion="用户服务UserProvdier002:0.01V";
map.put("ProviderVersion", ProviderVersion);
return map;
}
运行两个提供者
5. 创建服务消费方
新建子模块 userweb01
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
配置 application.yml
server:
port: 9001 spring:
thymeleaf:
cache: false
application:
name: userweb01 eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka/
修改启动类
@SpringBootApplication
@EnableDiscoveryClient
public class Userweb01Application { public static void main(String[] args) {
SpringApplication.run(Userweb01Application.class, args);
} @Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
新建 User,UserController,UserService,UserSerivceImpl
// UserController.java
// 因为使用了 thymeleaf,所以需要转发到相应模版,使用 Model 携带数据
@Controller
public class UserController {
@Autowired
UserService userService; @GetMapping("/")
public String getUserList(Model model){
Map map = userService.getUserMap();
List<User> list=(List<User>) map.get("list");
model.addAttribute("page", list);
model.addAttribute("ProviderVersion", map.get("ProviderVersion")); return "user/list";
}
......
}
// UserSerivceImpl.java
@Service
public class UserServiceImpl implements UserService {
//远程服务调用客户端
@Autowired
RestTemplate restTemplate;
//Eureka客户端
@Autowired
DiscoveryClient discoveryClient; /***
* 通过客户端负载均衡器获取生产者服务器基础地址
* @return
*/
public String getServerUrl() {
//通过客户端调用器查找指定服务
List<ServiceInstance> instList = discoveryClient.getInstances("USERPROVIDER");
//获取第一个服务器
ServiceInstance inst = instList.get(0);
//获取服务提供者服务器ip、端口号
String ip = inst.getHost();
int port = inst.getPort();
//拼接调用地址
String url="http://"+ip+":"+port+"/user";
return url;
} @Override
public Map getUserMap() {
Map map = restTemplate.getForObject(getServerUrl()+"/getall", Map.class);
return map;
} @Override
public void createUser(User user) { restTemplate.postForObject(getServerUrl()+"/save", user,String.class); } @Override
public User getUser(Long id) { return restTemplate.getForObject(getServerUrl()+"/get/"+id, User.class);
} @Override
public void updateUser(Long id, User user) {
restTemplate.put(getServerUrl()+"/update/"+id, user); } @Override
public void deleteUser(Long id) {
restTemplate.delete(getServerUrl()+"/delete/"+id);
}
}
启动服务,跳转地址 http://localhost:9001/
三、服务调用组件
SpringColud中已经帮我们集成了一系列负载均衡组件:LoadBalancerClient、Ribbon(缎带)、Feign(装作),简单修改代码即可使用。
1. 调用服务基于 LoadBalancerClient
新建子模块 userweb02
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
配置文件 application.yml
server:
port: 9002 spring:
thymeleaf:
cache: false
application:
name: userweb02 eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka/
启动类、Bean、UserController、UserService 还和 UserWeb01 项目保持一直,只有UserServiceImpl 有一些变化
// UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
//远程服务调用客户端
@Autowired
RestTemplate restTemplate;
//支持负载均衡的调用客户端
@Autowired
LoadBalancerClient loadBalancerClient; /***
* 通过客户端负载均衡器获取生产者服务器基础地址
* @return
*/
public String getServerUrl() {
//通过客户端调用器查找指定服务,只有这里发生了变化。
ServiceInstance inst = loadBalancerClient.choose("USERPROVIDER");
//获取服务提供者服务器ip、端口号
String ip = inst.getHost();
int port = inst.getPort();
//拼接调用地址
String url="http://"+ip+":"+port+"/user";
return url;
}
......
// 方法还和以前保持一致
}
2. 调度服务基于 Ribbon
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。
新建子模块 UserWeb03
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
</dependencies>
配置文件 application.yml
- 负载均衡策略:
- com.netflix.loadbalancer.RoundRobinRule:轮询
- com.netflix.loadbalancer.RandomRule:随机
- com.netflix.loadbalancer.RetryRule:重试
- com.netflix.loadbalancer.WeightedResponseTimeRule:根据响应时间权重分配一个weight,响应时间越长,weight越小,被选中的可能性越低。
- com.netflix.loadbalancer.BestAvailableRule:选择一个最小的并发请求的server
- AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)
- ZoneAvoidanceRule:复合判断server所在区域的性能和server的可用性选择server
server:
port: 9003 spring:
thymeleaf:
cache: false
application:
name: userweb03
#开启Spring Cloud的重试功能
cloud:
loadbalancer:
retry:
enabled: true eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka/ USERPROVIDER:
ribbon:
# 配置指定服务的负载均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# Ribbon的连接超时时间
ConnectTimeout: 250
# Ribbon的数据读取超时时间
ReadTimeout: 250
# 是否对所有操作都进行重试
OkToRetryOnAllOperations: true
# 切换实例的重试次数
MaxAutoRetriesNextServer: 1
# 对当前实例的重试次数
MaxAutoRetries: 1
启动类修改
@SpringBootApplication
@EnableDiscoveryClient
public class Userweb03Application { public static void main(String[] args) {
SpringApplication.run(Userweb03Application.class, args);
} @Bean
// 开启 ribbon
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
User、UserController、UserService都和上一个保持一致,只有UserServiceImpl有所不同
@Service
public class UserServiceImpl implements UserService {
//远程服务调用客户端
@Autowired
RestTemplate restTemplate; //开启Ribbon后,RestTemplate直接使用服务名就可以发起调用
String url="http://USERPROVIDER";
......
其它代码一致,取消了getUrl方法
}
5.运行服务 http://localhost:9003/
3. 调度基于 Feign
Feign是一个声明性的web服务客户端,使用Feign创建接口并对其进行注释,就可以通过该接口调用生产者提供的服务。Spring Cloud对Feign进行了增强,使得Feign支持了Spring MVC注解。
- Feign采用的是接口加注解;
- Feign 整合了ribbon
创建子模块 UserWeb04
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
配置文件 application.yml
server:
port: 9004 spring:
thymeleaf:
cache: false
application:
name: userweb04
#开启Spring Cloud的重试功能
cloud:
loadbalancer:
retry:
enabled: true eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka/,http://localhost:10087/eureka/ USERPROVIDER:
ribbon:
# 配置指定服务的负载均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# Ribbon的连接超时时间
ConnectTimeout: 250
# Ribbon的数据读取超时时间
ReadTimeout: 250
# 是否对所有操作都进行重试
OkToRetryOnAllOperations: true
# 切换实例的重试次数
MaxAutoRetriesNextServer: 1
# 对当前实例的重试次数
MaxAutoRetries: 1 # 设置对应包的日志级别
logging.level.com.offcn.userweb04: debug
编写配置类,定义日志级别,Feign支持4种级别:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
@Configuration
public class FeignConfig {
@Bean
public Logger.Level getFeignlogger(){
return Logger.Level.FULL;
}
}
启动类添加注解
@EnableFeignClients
User、UserController与其它 UserWeb 项目保持一致,但是要删除UserServiceImpl,修改UserService
@FeignClient(value = "USERPROVIDER", configuration = FeignConfig.class)
public interface UserService {
@GetMapping("/user/getall")
public Map<String, Object> getUserMap();
@PostMapping("/user/save")
public void createUser(User user);
@GetMapping("/user/get/{id}")
public User getUser(@RequestParam("id") Long id);
@PutMapping("/user/update/{id}")
public void updateUser(@RequestParam("id") Long id, @RequestBody User user);
@DeleteMapping("/user/delete/{id}")
public void deleteUser(@RequestParam("id") Long id);
}
运行服务 <>
四、熔断器组件 Hystrix
1. 介绍
Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。在分布式系统中应用这一模式之后,服务调用方可以自己进行判断某些服务反应慢或者存在大量超时的情况时,能够主动熔断,防止整体系统被拖垮。不同于电路熔断只能断不能自动重连,Hystrix可以实现弹性容错,当情况好转之后,可以自动重连。
2. Ribbon使用Hystrix
修改子模块 UserWeb03,引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
修改配置文件
# 添加Hystrix熔断超时时间,要求熔断超时 > ribbon 读取超时
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 700
在启动类添加注解
@EnableCircuitBreaker
修改 UserServiceImpl
@Override
@HystrixCommand(fallbackMethod="getUserMapFallbackMethod")
public Map getUserMap() {
long beginTime = System.currentTimeMillis();
Map map = restTemplate.getForObject(url+"/user/getall", Map.class);
long endTime=System.currentTimeMillis();
System.out.println("程序执行时间:"+(endTime-beginTime));
return map;
} // 熔断超时,就会执行该方法
public Map<String, Object> getUserMapFallbackMethod() {
Map map = new HashMap();
map.put("list", new ArrayList<>());
map.put("ProviderVersion", "获取远程调用失败");
return map;
}
修改 UserProvider01,模拟超时情况
@GetMapping("/getall")
@ApiOperation(value = "获取全部用户信息", notes = "获取全部用户信息")
public Map<String,Object> getUsers() {
Map<String,Object> map=new HashMap<>();
List<User> list = userService.getUserList();
map.put("list", list);
map.put("ProviderVersion", ProviderVersion);
// 模拟超时
try {
Thread.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map;
}
7.运行服务 http://localhost:9003/
3. Feign使用Hystrix
pom 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Feign默认也有对Hystrix的集成,只不过,默认情况下是关闭的。我们需要通过下面的参数来开启,修改UserWeb04 模块的配置文件:
feign:
hystrix:
enabled: true
#设定Hystrix熔断超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 700
添加类 UserServiceImpl
@Service
public class UserServiceImpl implements UserService { @Override
public Map<String, Object> getUserMap() {
Map map = new HashMap();
map.put("list", new ArrayList<>());
map.put("ProviderVersion", "获取远程调用失败");
return map;
} @Override
public void createUser(User user) {
System.out.println("创建用户失败:"+user); } @Override
public User getUser(Long id) {
System.out.println("获取id:"+id+" 的用户失败");
return null;
} @Override
public void updateUser(Long id, User user) {
System.out.println("更新id:"+id+"的用户失败"); } @Override
public void deleteUser(Long id) {
System.out.println("删除id为:"+id+"的用户失败"); }
}
在 UserService中,使用注解@FeignClient声明熔断调用实现类
@FeignClient(value = "USERPROVIDER", configuration = FeignConfig.class, fallback = UserServiceImpl.class)
。熔断超时,就会到该指定类执行对应的方法。
4. Hystrix监控服务器
1. 搭建Hystrix Dashboard管理控制中心
新建子模块 hystrix-dashboard,编辑pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
修改配置文件 application.yml
spring:
application:
name: hystrix-dashboard
server:
port: 1301
启动类添加注解
@EnableHystrixDashboard
2. 启用客户端Hystrix监控
pom 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
修改 UserWeb04 启动类,在服务实例的主类中已经使用@EnableCircuitBreaker或@EnableHystrix注解,开启断路器功能。同时增加监控路径访问地址定义/hystrix.stream可以访问。
@SpringBootApplication
@EnableDiscoveryClient
// 开启伪装客户端
@EnableFeignClients
// 开启断路器功能
@EnableHystrix
public class Userweb04Application { public static void main(String[] args) {
SpringApplication.run(Userweb04Application.class, args);
} @Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
} @Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1); //系统启动时加载顺序
registrationBean.addUrlMappings("/hystrix.stream");//路径
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
启动服务,先执行请求后,然后查看 http://localhost:9004/hystrix.stream
使用Hystrix Dashboard对Hystrix监控数据进行图形化监控。在Hystrix Dashboard的首页输入http://localhost:9004/hystrix.stream,点击“Monitor Stream”按钮。
五、分布式配置中心组件Spring Cloud Config
1. 介绍
- 在SpringBoot应用中,配置内容写在application.yml,也可以使用 application-{profile}.yml 的形式设置,但是在微服务架构中,配置文件的分散并不利于系统的管理和维护。
- 微服务对配置管理有更高的要求:
- 集中管理:服务需要集中管理配置,否则维护困难、容易出错。
- 运行期动态调整:某些参数需要在应用运行时动态调整,并且调整时不停止服务。
- 自动更新配置:微服务能够在配置发生变化是自动更新配置。
- Spring Cloud Config主要是为了分布式系统的外部配置提供了服务器端和客户端的支持,只要体现为Config Server和Config Client两部分。
- Config Server: 是一个看横向扩展的,集中式的配置服务器,它用于集中管理应用程序各个环境下配置,默认使用Git存储配置内容。
- Config Client: 是一个Config Server的客户端,用于操作存储在Config Server上的配置属性,所有微服务都指向Config Server,启动的时候会请求它获取所需要的配置属性,然后缓存这些属性以提高性能。
2. 构建Config Server
新建子模块 ConfigServer001,修改pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
修改配置文件 application.yml
server:
port: 7001 spring:
application:
name: config-server
cloud:
config:
server:
git:
# 根据自己的情况进行配置
uri: https://github.com/username/repositoryname
search-paths: src/main/resources
username: username
password: password eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka
修改UserProvide01的配置文件 application.yml 为 UserProvider01-test.yml 并上传,运行服务执行 http://localhost:7001/UserProvider01-test.yml
3. 构建Config Client
将 UserProvider01、UserProvider02、UserWeb01、UserWeb02、UserWeb03、UserWeb04 的配置文件 application.yml 修改为 application-dev.yml 并上传到 git 远程仓库,项目本身的配置文件不修改,只是上传git的时候需要改名。
修改以上子模块
pom.xml 引入config
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
新建配置文件 bootstrap.yml
spring:
application:
# 根据自己上传的 yml 文件来定
name: UserProvider01
cloud:
config:
discovery:
enabled: true
# 根据 configserver001 的 application.name 来定。
service-id: config-server
# 根据自己上传的 yml 文件来定
profile: dev
label: master eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka
将原有的 application.yml 清空,加上新的内容,可以在配置文件中的内容有改动的时候,不用重启服务,动态刷新,需要在相应的调用类上加新的注解
@RefreshScope
。management:
endpoints:
web:
exposure:
include: refresh,health,info
运行服务,然后启动任意一个客户端,查看运行情况
六、服务网关组件Netflix Zuul
1. 介绍
- Zuul是Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
- 认证和安全 :对每一个resource进行身份认证
- 追踪和监控 :实时观察后端微服务的TPS、响应时间,失败数量等准确的信息
- 日志 :记录所有请求的访问日志数据,可以为日志分析和查询提供统一支持
- 动态路由 : 动态的将request路由到后端的服务上去
- 压力测试 :逐渐的增加访问集群的压力,来测试集群的性能
- 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
- 静态响应 :直接在网关返回一些响应,而不是通过内部的服务返回响应
2.Zuul服务网关搭建
新建子模块 ZuulGateWay,修改 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
修改配置文件:application.yml
spring:
application:
name: zull-gateway server:
port: 80 # 通过 url 直接映射
#zuul:
# routes:
# userprovider001:
# # userprovider001 部分为路由的名字,可以任意定义,但是一组映射关系的path和url要相同
# path: /userprovider001/**
# url: http://localhost:8001/
# userprovider002:
# path: /userprovider002/**
# url: http://localhost:8002/ # 通过 serviceId的映射方式支持了断路器,对于服务故障的情况下,可以有效的防止故障蔓延到服务网关上而影响整个系统的对外服务。
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka zuul:
routes:
userprovider:
path: /service/**
service-id: USERPROVIDER
# 就是将web中的配置 到zuul中 这样多个web都用熔断 仅需要写一次 而不必要每个web 都配置。
retryable: true #打开重试 ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
ConnectionTimeOut: 250
ReadTimeout: 1000
OkToRetryOnAllOperations: true
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1 #设定Hystrix熔断超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000
启动类
@EnableZuulProxy
// 包含了 @SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker
@SpringCloudApplication
public class ZuulgatewayApplication { public static void main(String[] args) {
SpringApplication.run(ZuulgatewayApplication.class, args);
}
}
Zuul服务网关过滤器
public class AccessFilter extends ZuulFilter { /**
* 四种不同生命周期
* pre:可以在请求被路由之前调用
* routing:在路由请求时候被调用
* post:在routing和error过滤器之后被调用
* error:处理请求时发生错误时被调用
* @return
*/
@Override
public String filterType() {
return "pre";
} /**
* 过滤器的执行顺序
* @return
*/
@Override
public int filterOrder() {
return 0;
} /**
* 过滤器是否要执行
* @return
*/
@Override
public boolean shouldFilter() {
return true;
} @Override
public Object run() throws ZuulException {
RequestContext ctx= RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("accesstoken");
if(token == null) {
// 过滤该请求,不对其进行路由
ctx.setSendZuulResponse(false);
// 返回的错误码。也可以通过ctx.setResponseBody(body)对返回
ctx.setResponseStatusCode(401);
return null;
}
return null;
}
}
在启动类中实例化该过滤器
@Bean
public AccessFilter accessFilter() {
return new AccessFilter();
}
启动服务,进行测试
SpringCloud 基础的更多相关文章
- 微服务架构案例(05):SpringCloud 基础组件应用设计
本文源码:GitHub·点这里 || GitEE·点这里 更新进度(共6节): 01:项目技术选型简介,架构图解说明 02:业务架构设计,系统分层管理 03:数据库选型,业务数据设计规划 04:中间件 ...
- SpringCloud基础概念学习笔记(Eureka、Ribbon、Feign、Zuul)
SpringCloud基础概念学习笔记(Eureka.Ribbon.Feign.Zuul) SpringCloud入门 参考: https://springcloud.cc/spring-cloud- ...
- 微服务之SpringCloud基础
SpringCloud微服务基础 微服务架构--SpringCloud网站架构模式 单点应用/分布式系统面向于服务架构(SOA) /微服务架构web项目三层架构1.控制层2.业务逻辑层3.数据访问层传 ...
- SpringCloud基础教程学习记录
这个学习记录是学习自翟永超前辈的SpringCloud的基础教程. 自己写这个教程的目的主要是在于,想要更凝练总结一些其中的一些实用点,顺便做个汇总,这样自己在复习查看的时候更加方便,也能顺着自己的思 ...
- spring-cloud - 基础环境搭建
spring-cloud中文文档:https://springcloud.cc/ spring-cloud中文导航:http://springcloud.fun/ 文章纯属用于个人学习的一个归纳,哪里 ...
- SpringCloud基础组件总结,与Dubbo框架、SpringBoot框架对比分析
本文源码:GitHub·点这里 || GitEE·点这里 一.基础组件总结 1.文章阅读目录 1).基础组件 Eureka组件,服务注册与发现 Ribbon和Feign组件,实现负载均衡 Hystri ...
- SpringCloud基础篇AOP之拦截优先级详解
前面两篇分别介绍了AOP的基本使用姿势和一些高级特性,当时还遗留了一个问题没有说明,即不同的advice,拦截同一个目标方法时,优先级是怎样的,本篇博文将进行详细分析 同一个切面中,不同类型的advi ...
- SpringCloud学习笔记(一、SpringCloud 基础)
目录: 概述 观察者模式 代理模式 概述: spring系列中使用了大量的设计模式,而最常见的便是这观察者.代理模式,所以在讲解SpringCloud之前我们先学习下这两个最常见的设计模式. 观察者模 ...
- SpringCloud基础
SpringCloud极大的简化了分布式系统的开发,实现了微服务的快速部署和灵活应用 SpringCloud主要框架 * 服务发现--Netfix Eureka * 服务调用--Netfix Feig ...
随机推荐
- JAVA中的四种JSON解析方式详解
JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...
- JS基础 —— 数据类型
JS数据类型分为简单数据类型(基本数据类型)和复杂数据类型(引用数据类型). 基本数据类型:Undefined.Null.Boolean.Number.String.Symbol. 引用数据类型:Ob ...
- 前端Q的小小小里程碑
很多关注我的人都不太了解前端Q这个名字的由来,这篇文章就来讲讲前端Q的前世今生,顺便送大大福利(文末有惊喜),哈哈-- 恭喜!前端Q总用户数突破千啦~~ 前端Q前世 前端Q这个公众号,其实很早很早的时 ...
- [转]QT中的D指针与Q指针
Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念. 那么为什么d指针能实现二进制兼容呢? 为了回答这个问题,首先弄清楚什么是二进制兼容? 所谓二进制兼容动态库,指的是一个在老版本库下运行 ...
- poi坑点(springboot)
工作上需要写了一个将数据库数据生成excel表的接口,在此过程中遇到了一些坑点,现在此纪录 PS:一部分可能是因为我没用明白 1. 样式问题 自动调整尽量不要使用,部分列留白过多,空列列宽过窄,可能是 ...
- Wordpress 设置中文语言包
从官方安装的是英文版的,想要切换成中文语言包 1.修改项目目录下面的wp-config文件: 添加define(‘WPLANG’, ‘zh_CN’); 保存文件 2.进入站点控制板(dashboard ...
- 使用fio命令查看磁盘iops
具体命令: fio -filename=./localhost.2019-05-08.log -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psy ...
- springboot日常问题处理手记
springboot启动问题 1.@Autowired报错Could not autowire. No beans of xxx 解决:只需在DAO接口加上@Component 或者 @Reposit ...
- Comet OJ - Contest #10 C.鱼跃龙门
传送门 题意: 求最小的\(x\),满足\(\frac{x(x+1)}{2}\% n=0,n\leq 10^{12}\). 多组数据,\(T\leq 100\). 思路: 直接考虑模运算似乎涉及到二次 ...
- 05-C#笔记-基本变量
1. 不支持括号初始化: 2. 支持强制类型转化: 3.运算规则同C++ 参考: http://www.runoob.com/csharp/csharp-variables.html